9.3 内置的系统链码

链码分为两种类型。

·系统链码:系统内置的链码,用来完成一些系统功能等。

·普通链码:实现应用业务逻辑的链码。

系统链码和普通链码的几个不同点,如表9-4所示。

表9-4 系统链码和普通链码的不同点

image.png

下面是系统链码的属性定义。


 

type SystemChaincode struct {
    //system chaincode名称(唯一)
    Name string
    //system chaincode路径(暂未使用)
    Path string
    //system chaincode初始化参数
    InitArgs [][]byte
    // chaincode object实体对象
    Chaincode shim.Chaincode
    // 用于追踪是否通过发送提案给Peer节点来完成对system chaincode调用
    InvokableExternal bool
    // 用于追踪是否可以通过chaincode-to-chaincode的调用方式调用system chaincode
    InvokableCC2CC bool
    // 用于开启/禁用 system chaincode的便捷开关,无须删除importsysccs.go的条目
    Enabled bool
}


以下是内置的系统链码及其属性列表,如表9-5所示。

表9-5 内置的系统链码及其属性列表

image.png

下面就来详细说明一下每个系统链码的功能。

9.3.1 生命周期管理系统链码

生命周期管理系统链码(Lifecycle System Chaincode,LSCC),主要功能是管理部署在背书节点上的链码,并不是全生周期的管理。

1.链码的安装

链码安装接收的参数如下。


 

type ChaincodeDeploymentSpec struct {
    // 链码描述规范
    ChaincodeSpec *ChaincodeSpec
    // 控制链码可用事件,预留字段
    EffectiveDate *google_protobuf1.Timestamp
    // 打包好的链码源代码
    CodePackage   []byte
    // 运行环境:系统进程或者Docker
    ExecEnv       ChaincodeDeploymentSpec_ExecutionEnvironment
}


其中,CodePackage是已经打包好的链码源代码,会在源码基础上添加所需要的库文件,比如和背书节点通信 的github.com/hyperledger/fabric/core/chaincode/shim。链码描述规范ChaincodeSpec约定 链码部署或者调用的一些参数,定义如下。


 

type ChaincodeSpec struct {
    // 链码类型:Golang、Node.js、Java、Car(Chaincode Archive),目前只支持Golang
    Type        ChaincodeSpec_Type
    // 链码的路径、名称和版本信息
    ChaincodeId *ChaincodeID
    // 链码的输入参数
    Input       *ChaincodeInput
    // 超时时间,预留字段
    Timeout     int32
}

type ChaincodeID struct {
    // 链码路径
    Path string
    // 链码名称
    Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"`
    // 链码版本
    Version string `protobuf:"bytes,3,opt,name=version" json:"version,omitempty"`
}

type ChaincodeInput struct {
    // 链码输入参数数组
    Args [][]byte
}


在调用LSCC的时候,ChaincodeDeploymentSpec是ChaincodeInput的第2个参数,第1个参数是固定的“install”。就是说外层还有一层封装,封装在ChaincodeInvocationSpec中。


 

type ChaincodeInvocationSpec struct {
    // 链码描述规范
    ChaincodeSpec *ChaincodeSpec
    // 可包含指定用户ID的生成算法,通过此方法来生成ID。
    // 若不指定(或留空),将使用sha256base64算法。算法主要包含两部分:
    //  1, hash函数;2, 将用户的(字符串)输入进行字节解码
    // 目前,支持带BASE64的SHA256(例如: idGenerationAlg='sha256base64')
    IdGenerationAlg string
}


其中,ChaincodeInvocationSpec中的ChaincodeSpec指定的ChaincodeId.Name是固定的“lscc”,消息结构图如图9-7所示。

image.png

图9-7 链码安装结构图

再加上必需的消息头,链码安装提交的Proposal逻辑结构如下。


 

SignedProposal: {
   ProposalBytes(Proposal): {
       Header: {
           ChannelHeader: {
               Type: "HeaderType_ENDORSER_TRANSACTION",
               TxId: TxId,
               Timestamp: Timestamp,
               Extension(ChaincodeHeaderExtension): {
                   PayloadVisibility: PayloadVisibility,
                   ChaincodeId: {
                       Path: Path,
                       Name: Name,
                       Version: Version
                   }
               },
               Epoch: Epoch
           },
           SignatureHeader: {
               Creator: Creator,
               Nonce: Nonce
           }
       },
       Payload: {
           ChaincodeProposalPayload: {
               Input(ChaincodeInvocationSpec): {
                   ChaincodeSpec: {
                       Type: "Golang",
                       ChaincodeId: {
                           Name: "lscc"
                       },
                       Input(ChaincodeInput): {
                           "install",
                           ChaincodeDeploymentSpec: {
                               ChaincodeSpec: {
                                   Type: Type,
                                   ChaincodeId: {
                                       Path: Path,
                                       Name: Name,
                                       Version: Version
                                   },
                                   Input(ChaincodeInput): Args,
                                   Timeout: Timeout
                               },
                               EffectiveDate: EffectiveDate,
                               CodePackage: CodePackage,
                               ExecEnv: "Docker"
                           }
                       }
                   }
               },
               TransientMap: TransientMap
           }
       }
   },
   Signature: Signature
}


其中,有"()"的地方,比如ProposalBytes(Proposal)中,ProposalBytes代 表字段名称,Proposal代表实际的类型。有""的是请求固定的内容,其他的变量会根据实际的请求发生变化。TxId是交易号,是在客户端构建 Proposal的时候生成的,生成规则是:


 

TxID = HASH(Nonce + Creator)


其中,Nonce是随机数,Creator是创建请求的用户身份信息,独立生成的交易号出现冲突的可能性是比较小 的。Creator还有别的用处,背书节点接收到请求以后LSCC会根据这个信息验证是否有权限安装链码或者其他的操作。Signature是 Creator对整个Proposal的签名,能验证消息的完整性,起到防抵赖的作用。

TransientMap是应用程序提交给背书节点处理但不记录到账本中的数据,链码可以通过 GetTransient接口获取到,用来传输一些敏感信息。比如,链码传递的参数Input里的内容都是加密的,密钥通过TransientMap传递 给链码,链码可以解密调用参数的内容,最后记录到账本里的只有加密的参数,TransientMap的内容在ESCC签名背书的时候是会删掉的。

LSCC直接处理的是ChaincodeDeploymentSpec结构,首先会根据签名信息验证权限,然后会检查链码的名称和版本是否合法。链码名称和版本的命名都是有内置规范的,如表9-6所示。

表9-6 链码名称和版本的命名规范

image.png

最后把ChaincodeDeploymentSpec存储在背书节点文件中安装过程就结束了,并不会在多个节点直接同步。如果想要安装到多个节点,就需要客户端向不同的节点发起多次安装链码的请求。存储的文件名称是:


 

fileSystemPath/chaincodes/chaincodeName:chaincodeVersion


其中,fileSystemPath是环境变量CORE_PEER_FILESYSTEMPATH或者 core.yaml文件配置的peer.fileSystemPath定义的,chaincodes是固定的子目录。从上面的目录结构可以看出,链码存储 的时候并没有区分不同链的命名空间,实际多链是共享链码的。在链码部署和调用的时候会根据背书节点本地存储的链码构建链码镜像,启动链码容器。

2.链码的部署

链码部署提交的Proposal逻辑结构与安装的逻辑结构基本相同,区别在于Chaincode InvocationSpec.ChaincodeSpec.Input内容不一样。


 

Input(ChaincodeInvocationSpec): {
   "deploy",
   ChaincodeDeploymentSpec: {
       ChaincodeSpec: {
           Type: Type,
           ChaincodeId: {
               Path: Path,
               Name: Name,
               Version: Version
           },
           Input(ChaincodeInput): Args,
           Timeout: Timeout
       },
       EffectiveDate: EffectiveDate,
       CodePackage: CodePackage,
       ExecEnv: "Docker"
   },
   chainID,
   policy(SignaturePolicyEnvelope): {
       Version: Version,
       Rule(SignaturePolicy): {
           Type: SignedBy/NOutOf
       },
       Identities(common1.MSPPrincipal): [
           PrincipalClassification: PrincipalClassification,
           Principal: Principal
       ]
   },
   "escc",
   "vscc"
}


其中,第1个参数是"deploy",后面增加了几个参数,"escc"和"vscc"默认是内置的系统链码,也可以自行实现替换。SignaturePolicyEnvelope的详细介绍参考成员管理章节的内容。

部署的时候会检查实例化策略,默认的实例化策略是管理员权限。最后会记录ChaincodeData到链上。


 

type ChaincodeData struct {
   // 链码名称
   Name string
   // 链码版本
   Version string
   // 链码的ESCC,默认是内置的escc
   Escc string
   // 链码的VSCC,默认是内置的vscc
   Vscc string
   // 链码的背书策略
   Policy []byte
   // 链码源代码哈希和元数据哈希组成的CDSData
   Data []byte
   // 链码编号,预留字段
   Id []byte
   // 链码实例化策略
   InstantiationPolicy
}

type CDSData struct {
   // 链码源代码哈希=hash(chaincode)
   CodeHash []byte
   // 链码元数据哈希=hash(chaincodeName+chaincodeVersion)
   MetaDataHash []byte
}


实例化只能调用执行一次,实例化的时候检查链上有ChaincodeData就说明已经实例化过了。

背书节点在调用LSCC执行完部署的工作后,还会继续执行实例化的操作。这种情况只有链码是LSCC,并且调用是部署(deploy)和升级(upgrade)的时候才执行。就是说,只有LSCC的Proposal里的ChaincodeInvocationSpec才会有嵌套ChaincodeDeploymentSpec的结构。

链码的安装是和具体的链没有关系的,并不会记录数据到账本里,同一个链码是可以多个链共享的,实例化的时候才会记录到不同链的账本数据里,不同链的数据是独立隔离的。

3.链码的升级

链码的升级和部署比较类似,也需要先安装链码,再执行链码的升级。链码升级需要保证链码的名称和升级之前的一样, 否则会被当成另外一个链码。由于链码的版本可以是符合命名规范的字符串,并不是严格意义的递增关系,是以提交的先后顺序为准的,链码升级的时候会比较升级 的版本是否和最新版本的版本号一致。与链码部署不同的地方在于,链码升级的时候会检查链码最新版本的实例化策略,再执行链码的更新,更新的过程中也会执行 实例化的操作。

链码升级并不会删除老版本的链码,多个版本是可以并存的,需要手工维护应用程序和链码之间的对应关系,避免调用出现错误。链码升级的操作过程参考前面介绍的内容。

4.链码信息的查询

可以查询如下几个接口的信息,如表9-7所示。

表9-7 链码信息查询的接口列表

image.png

9.3.2 配置管理系统链码

配置管理系统链码(CSCC)的全称是Configuration System Chaincode,主要功能是管理记账节点上的配置信息。

1.记账节点加入链

记账节点加入链的Proposal请求的ChaincodeInput不再是多层的嵌套了,结构如下。


 

SignedProposal: {
   ProposalBytes(Proposal): {
       Header: {
           ChannelHeader: {
               Type: "HeaderType_CONFIG",
               TxId: TxId,
               Timestamp: Timestamp,
               Extension(ChaincodeHeaderExtension): {
                   PayloadVisibility: PayloadVisibility,
                   ChaincodeId: {
                       Path: Path,
                       Name: Name,
                       Version: Version
                   }
               },
               Epoch: Epoch
           },
           SignatureHeader: {
               Creator: Creator,
               Nonce: Nonce
           }
       },
       Payload: {
           ChaincodeProposalPayload: {
               Input(ChaincodeInvocationSpec): {
                   ChaincodeSpec: {
                       Type: "Golang",
                       ChaincodeId: {
                           Name: "cscc"
                       },
                       Input(ChaincodeInput): {
                           "JoinChain",
                           genesisBlock
                       }
                   }
               },
               TransientMap: TransientMap
           }
       }
   },
   Signature: Signature
}


其中,genesisBlock是创建通道时生成的创世区块。

其中,区块的有效性验证主要包括如下几个方面。

·类型检查:查看区块类型是否是HeaderType_CONFIG。

·配置检查:查看配置区块里是否包含Application信息。

·权限检查:是否满足提交策略,比如是否和节点同一个MSP。

本地创建账本的时候有两个操作,先是在本地链的数据库idStore里添加记录,然后再把创世区块写到本地文件系 统里。Peer节点加入链的时间是不一样的,需要通过Gossip服务同步数据,根据节点的配置是主节点还是参加主节点选举,若是主节点则会主动跟排序服 务节点连接,否则从组织内其他节点处同步数据。本地创建链会从创世区块里读取链配置相关的信息,记录到本地链的映射表里。

Peer节点加入链完成以后,利用Golang的通道机制发送一个事件,接收到事件的协程异步发送给注册监听的客户端。详细内容参考前面事件相关的内容。

2.链相关信息查询

通过CSCC可以查询如下几个接口的信息,如表9-8所示。

表9-8 链信息查询的接口列表

image.png

9.3.3 查询管理系统链码

查询管理系统链码(QSCC)的全称是Query System Chaincode,主要功能是提供查询记账节点的账本数据,包括区块和交易数据、区块链信息等,如表9-9所示。

表9-9 账本信息查询的接口列表

image.png

从索引数据库查询通用的过程是根据查询项从索引数据库查询出FLP(File Location Pointer),再根据FLP在区块中定位获取所需内容。索引相关的内容参考前面已经介绍过的章节。

9.3.4 交易背书系统链码

交易背书系统链码(ESCC)的全称是Endorsement System Chaincode,主要功能是对交易进行结果的结构转换和签名背书。

ESCC是背书节点模拟执行完链码后,对执行的结果Response进行转换,去掉里面的Transient信息,再添加签名背书,最后封装成ProposalResponse,结构如下。


 

ProposalResponse: {
   Version: Version,
   Timestamp: Timestamp,
   Response: {
       Status: Status,
       Message: Message,
       Payload: Payload
   },
   Payload(ProposalResponsePayload): {
       ProposalHash: ProposalHash,
       Extension(ChaincodeAction): {
           Results(TxRwSet): {
               NsRwSets(NsRwSet): [
                   NameSpace: NameSpace,
                   KvRwSet: {
                       Reads(KVRead): [
                           Key: Key,
                           Version: {
                               BlockNum: BlockNum,
                               TxNum: TxNum
                           }
                       ],
                       RangeQueriesInfo(RangeQueryInfo): [
                           StartKey: StartKey,
                           EndKey: EndKey,
                           ItrExhausted: ItrExhausted,
                           ReadsInfo: ReadsInfo
                       ],
                       Writes(KVWrite): [
                           Key: Key,
                           IsDelete: IsDelete,
                           Value: Value
                       ]
                   }
               ]
           },
           Events(ChaincodeEvent): {
               ChaincodeId: ChaincodeId,
               TxId: TxId,
               EventName: EventName,
               Payload: Payload
           }
           Response: {
               Status: Status,
               Message: Message,
               Payload: Payload
           },
           ChaincodeId: ChaincodeId
       }
   },
   Endorsement: {
       Endorser: Endorser,
       Signature: Signature
   }
}


其中,Endorsement就是背书的内容,包含背书节点的签名证书Endorser和背书节点对ProposalResponsePayload+Endorser的签名,即:


 

Signature=Endorser.Sign(ProposalResponsePayload+Endorser)


背书代表背书节点用自己的身份对模拟执行结果进行担保,通过证书和签名就可以验证背书是否是有效的。

9.3.5 交易验证系统链码

交易验证系统链码(VSCC)的全称是Validation System Chaincode,主要功能是记账前对区块和交易进行验证。ESCC是背书节点独立对模拟执行结果的背书,VSCC是对多个背书验证是否符合背书策略。VSCC验证交易背书的过程参考第3章的交易背书策略部分。

来源:我是码农,转载请保留出处和链接!

本文链接:http://www.54manong.com/?id=1056

'); (window.slotbydup = window.slotbydup || []).push({ id: "u3646208", container: s }); })();
'); (window.slotbydup = window.slotbydup || []).push({ id: "u3646147", container: s }); })();
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值