hyperledger-fabric-区块链-浅尝


  • 区块链就是分布式的kv数据库
  • peer挂在在channel上,而chaincode又是挂在peer上的
  • 账本ledgel通过通道channel进行隔离
  • 交易与智能合约: 智能合约是函数的声明,而交易是函数的调用过程
  • 什么是背书结果: 既背书节点endorser节点对业务逻辑处理后的数据结果
  • 世界状态: 指的是交易执行后的所有键的最新值
  • 历史溯源(历史读取): 历史数据索引+ 区块读取
    • 某键在某区块的某条交易中被改变
    • 历史数据索引只记录改变动作,不记录具体改变()
  • 适合存储在区块链上的东西: 注意:每个节点都会有数据的备份,因而数据的浪费是比较严重的
    • 区块链可以类比为数据库
    • 比如说什么文件,pdf数据啊,根本不适合

整体架构

节点

  • 网络拓扑
    • 客户端节点(应用程序/SDK/命令行工具),不可以独立存在,只能与order节点连接(channel的创建)或者peer节点(交易的执行)

    • Peer节点(Anchor/Endorser/Commiter) :

      • Anchor: 与组织紧密进行通讯,一个组织有多个peer节点,但是只有一个anchor节点,是锚节点,宕机的时候会自动选举的 ,主节点:
        • 作用: 与Order节点进行通讯
      • Endorser : (担保节点,担保交易的执行)与智能合约进行绑定,
      • Commiter普通的peer节点:专业术语为记账节点: 所有的节点都是commit节点,用于验证order节点发过来的区块的有效性和交易的有效性,然后记录到本地的账本中,同时修改区块链上的状态数据
    • Order节点:排序节点

      • 功能1:从全网客户端接收交易,然后交易进行排序
      • 功能2:将排序好的交易,按照时间间隔打包成区块,分发到其他组织的主节点
        • 官方有两种排序:
          • SOLO:适合于开发和测试,整个网络只有一个排序节点,它收到的就是整个网络收到的排序顺序,缺点: 单点故障严重
          • Kafka: 交个kfaka集群,每个order同时是kafka的生产者和消费者
    • CA 节点( 可选) : 证书颁发机构,只有被ca机构认可的节点才会被接受

    • 注意: 组织节点只是一个逻辑的概念,其实是并不存在的,同时组织之间并不会通讯,数据来源于排序节点


交易流程

模拟执行的意思可以理解为未commit的事务操作

  1. 客户端节点->peer节点的endoser节点 : 提交交易提案
  2. endorser节点是与智能合约相关的,endorser节点执行交易提案并且签名,并且当一个cc绑定了2个endorser,则交易提案需要发到至少2个节点
  3. endorser->客户端节点 : 返回模拟执行结果
  4. 客户端节点-order节点: 提交交易(模拟结果+签名)
    • 当是查询交易的时候: 因为不会对ledger产生影响,因而只会校验签名
    • 当是写交易的时候: 客户端节点必须收到足够的背书结果
  5. Order节点: 排序并结块
  6. Order节点-> 组织Anchor节点(主节点): 广播节点

fabric 分析

events: 事件监听机制

gossip: 最终一致性:用于组织内部进行区块同步

images: docker镜像打包

msp:member service provider: 成员服务管理

  • 读取证书 ,签名,验签等

order : 排序节点入口

peer : peer节点入口

proposals: 新功能提案: 因为fabric 开源,他人的feature都会在这

protos : 提供了几乎所有的数据结构和数据服务

  • 通过grpc: protobuffer+rpc

账本存储

  • 源码在: core/ledger

区块存储

  • 区块以文件块的形式存储(blockFile_xx)
    • 文件块大小:默认为64M
    • 账本总大小: 64M* 区块编号的最大值默认为1000000)(既一条链码的最大值)

区块索引:

  • 作用: 快速定位区块
  • 索引键: 区块高度/区块hash/交易hash
  • 索引值: 区块编号+文件内偏移量+区块数据长度

区块提交(当anchor节点收到order节点的区块)

  1. 保存区块文件(追加)|新起一个文件块
  2. 更新世界状态
  3. 更新历史状态(可选)

数据存储问题

  • 数据隔离问题: 可能不同的channel有相同的key,

    • 解决方法: 形成组合键()
  • 历史数据如何实现:

    • 利用levelDB的前缀匹配功能,拆分对应的区块交易集合
    • 基于区块文件存储,找到对应的交易,
    • 如 /ns/key/blocknum/trannum ,这样只需要到固定的channel->文件

智能合约(链码)

  • 链码

    • 是fabric的应用层基石(中间件)
    • 需要独立的Docker执行环境
    • endorser节点之间通过grpc通信(只有endorser peer节点才会绑定智能合约
  • 生命周期:

    • 打包
    • 安装
    • 实例化:
    • 升级
    • 交互(查询|写入)
  • 链码的交互流程: 图在本地

  • 系统链码:

    • LSCC(Lifecycle System Chaincode) : 管理链码的生命周期
    • CSCC(Configuration System Chaincode): 用于管理系统配置:如允新的节点加入某一个链
    • QSCC(Query System Chaincode): 用于账本存储的查询服务
    • ESCC(Endorsement System Chaincode): 将交易模拟执行后的结果进行封装和签名
    • VSCC(alidation System Chaincode) : 交易验证,一笔交易的是否有效,需要通过这个
  • 链码的编程接口

  • 核心接口是Chaincode:

type Chaincode interface {
Init(stub ChaincodeStubInterface) pb.Response // 链码初始化
Invoke(stub ChaincodeStubInterface) pb.Response // 应用程序与链码交互的入口
}

  • 链码SDK接口:
    • 参数解析接口: 解析参数
    • 交易信息接口: 只有一个方法,获取交易的ID
    • 状态操作接口: CRUD
    • 链码互操作接口: 跨链功能的体现,现在只支持跨链查询
    • 事件发送接口: 当链码完成后,对客户端发送相应的事件,客户端根据相应的事件做相应的操作,不过前提是这个操作是有效的操作
  • 链码编程禁忌
    • 首先需要认知,链码的执行是在分布式系统中执行的,多个节点之间隔离执行,一个交易在区块链网络中会执行很多次,客户端会对返回的所有结果进行匹配,如果不一样就不会给order进行排序,所以当挂在多个endorser的时候要确保相同的交易结果一致
      • 导致执行结果不一致的情况:
        • 随机函数
        • 系统时间(分布式系统时间可能不一样)
        • 不稳定的外部依赖

网络搭建

  • 关注点:

    • 注入系统配置到容器中
      • 通过environment,如,注意都要大写

        enviroment:
        - ORDER_GENERAL_LOGLEVEL=debug 会被映射为general.loglevel=debug
        - ORDER_GENERAL_LISENADDRESS=0.0.0.0 服务暴露地址
        - ORDER_GENERAL_GENESISFILE=/etc/hyperledger/config/genesis.block 注入创始区块
        - ORDER_GENERAL_LOCALMSPID=orderMSP msp的名称
        - ORDER_GENERAL_LOCALMSPDIR=/etc/hyperledger/order/msp 证书的位置

    • 端口的映射关系: 通过ports

    ports:
    - - 7050:7050 本机的7050映射到order服务的7050端口
    - 文件的映射:通过 volumes 在环境变量中,如上述的msp证书地址,用的都是容器中的地址,
    volumes:
    - - ./config:/etc/hyperledger/config 既将本地的./config 映射到了容器中的/etc/hyperledger/config 内容

    • peer节点的配置:

链码编写的套路都是固定的:

  1. 检查参数的个数
  2. 验证参数的正确性

SDK的模块

  • 第一步:(也可以认为是全局的) 先初始化一个sdk ,可以用GoLang也可以用Java|Node.js
// Initialize the SDK with the configuration file
	sdk, err := fabsdk.New(config.FromFile(setup.ConfigFile))
	if err != nil {
		return errors.WithMessage(err, "failed to create SDK")
	}

区块链管理

  • 通道的创建&加入
  • 链码的install,instance,upgrade
  • 可能用到的用户: admin|云服务提供商
在这个模块中,使用的是sdk.Context
// 注意,这个是名字,不是域名之类的
	context := sdk.Context(fabsdk.WithOrg(setup.OrgName), fabsdk.WithUser(setup.UserName))

  • 区块链管理都在resourcemanagement这个包下,既resmgmt

区块链账本查询

  • 功能:
    • 区块相关查询
    • 交易信息的查询
在这个模块中,使用的是sdk.ChannelContext 
	context := sdk.ChannelContext(setup.ChannelID, fabsdk.WithOrg(setup.OrgName), fabsdk.WithUser(setup.UserName))
  • 账本查询都在ledger包下:
context := sdk.ChannelContext(setup.ChannelID, fabsdk.WithUser(setup.UserName), fabsdk.WithOrg(setup.OrgName))
	client, _ := ledger.New(context)

区块链交互

  • 发起交易 调用函数:invoke
在这个模块中,使用的是sdk.ChannelContext 
	context := sdk.ChannelContext(setup.ChannelID, fabsdk.WithOrg(setup.OrgName), fabsdk.WithUser(setup.UserName))
  • 交易代码都在channel下
context := sdk.ChannelContext(setup.ChannelID, fabsdk.WithUser(setup.UserName), fabsdk.WithOrg(setup.OrgName))
	client, _ := channel.New(context)
	client.Execute(channel.Request{})
	client.Query(channel.Request{})
  • 其中Execute 和Query 可以与SQL对应
    • Execute 对应 insert/delete/update
    • Query对应Select

事件监听

  • 分为2方面内容
    • 业务事件 :通过SDK的SendEvent实现
    • 系统事件: 区块生成,或者是事务提交了
在这个模块中,使用的是sdk.ChannelContext 
	context := sdk.ChannelContext(setup.ChannelID, fabsdk.WithOrg(setup.OrgName), fabsdk.WithUser(setup.UserName))
  • 事件代码都在event包下
  • 通常都是与区块交互一起使用的
在这个模块中,使用的是sdk.ChannelContext 
	context := sdk.ChannelContext(setup.ChannelID, fabsdk.WithOrg(setup.OrgName), fabsdk.WithUser(setup.UserName))

// 系统事件
response, err := setup.client.Execute(channel.Request{
		ChaincodeID:  setup.ChainCodeID,
		Fcn:          args[0],
		Args:         [][]byte{[]byte(args[1])},
		TransientMap: transientDataMap})
	if err != nil {
		return result, fmt.Errorf("failed to find : %v", err)
	}

	context := setup.sdk.ChannelContext(setup.ChannelID, fabsdk.WithUser(setup.UserName), fabsdk.WithOrg(setup.OrgName))
	client, _ := event.New(context)
	registration, events, _ := client.RegisterTxStatusEvent(string(response.TransactionID))
	defer client.Unregister(registration)
	for {
		select {
		case eve := <-events:
			fmt.Println(eve)
		case <-time.After(20 * time.Second):
			fmt.Println("time out ")
		}
	}
	
// 业务事件, 需要在ChainCode实现类中的Invoke方法,通过SetEvent实现: 
stub.SetEvent("aaa",[]byte(""))

Config.yaml 解析

version: 1.0.0
client:
  organization: org1    # 表示这个client是属于哪个组织的
  logging:
    level: debug    # 日志打印级别
  eventService:
    type: eventhub
  cryptoconfig: # 指定msp的根目录
    path: ${GOPATH}/src/github.com/hyperledger/fabric/imocc/deploy/crypto-config
  credentialStore:
    path: "/tmp/state-store"
    cryptoStore:
      path: /tmp/msp
  BCCSP:    # 密码学相关的配置,默认即可
    security:
     enabled: true
     default:
      provider: "SW"
     hashAlgorithm: "SHA2"
     softVerify: true
     level: 256
  tlsCerts: # tls 配置 
    systemCertPool: true
    client:
      key:
        path: ${GOPATH}/src/github.com/hyperledger/fabric-sdk-go/test/fixtures/config/mutual_tls/client_sdk_go-key.pem
      cert:
        path: ${GOPATH}/src/github.com/hyperledger/fabric-sdk-go/test/fixtures/config/mutual_tls/client_sdk_go.pem
channels: # 核心配置,这个配置可以认为是全局声明,具体的是在下面配置的
  assetschannel:    # channel 名称
    orderers:  # order order节点配置 既排序节点
      - orderer.imocc.com
    peers:
      peer0.org1.imocc.com:
        endorsingPeer: true
        chaincodeQuery: true
        ledgerQuery: true
        eventSource: true
      peer1.org1.imocc.com:
        endorsingPeer: true
        chaincodeQuery: true
        ledgerQuery: true
        eventSource: true
    policies:
      queryChannelConfig:
        minResponses: 1
        maxTargets: 1
        retryOpts:
          attempts: 5
          initialBackoff: 500ms
          maxBackoff: 5s
          backoffFactor: 2.0
organizations: # 组织信息的配置
  org1:
    mspid: Org1MSP 
    cryptoPath:  peerOrganizations/org1.imocc.com/users/{username}@org1.imocc.com/msp   # 指定证书的位置,是一个相对路径
    peers:  # 指定组织下边有多少个peer
      - peer0.org1.imocc.com
    certificateAuthorities:
  ordererorg:   # 配置order节点的信息
      mspID: "OrdererMSP"
      cryptoPath: ordererOrganizations/imocc.com/users/{username}@imocc.com/msp
      
orderers:
  orderer.imocc.com:
    url: 127.0.0.1:7050
    grpcOptions:
      ssl-target-name-override: orderer.imocc.com
      keep-alive-time: 0s
      keep-alive-timeout: 20s
      keep-alive-permit: false
      fail-fast: false
      allow-insecure: true # 非tls连接
    tlsCACerts:
      path: ${GOPATH}/src/github.com/hyperledger/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem
peers:
  peer0.org1.imocc.com:
    url: 127.0.0.1:27051
    eventUrl: 127.0.0.1:27053
    grpcOptions:
      ssl-target-name-override: peer0.org1.imocc.com
      keep-alive-time: 0s
      keep-alive-timeout: 20s
      keep-alive-permit: false
      fail-fast: false
      allow-insecure: true
    tlsCACerts:
      path: ${GOPATH}/src/github.com/hyperledger/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/peerOrganizations/org1.example.com/tlsca/tlsca.org1.example.com-cert.pem



疑惑点

  • 如何配置多个CC
  • 可以通过交易id获取交易信息吗
  • order是什么
  • 链码监听如何编写(是否跟常规编写相同)

豁然开朗点

  • 链码是在分布式系统中执行的,当链码挂断在多个endorser节点的时候,一个交易会被执行多次

你可能感兴趣的:(Go,区块链)