1、fabric链码版本区别
Fabric链码分成了两个大版本,1.x和2.x版本,两者主要区别为:
1、导入包的不同
1.x导入的包为:
"[github.com/hyperledger/fabric/core/chaincode/shim](http://github.com/hyperledger/fabric/core/chaincode/shim)"
pb "[github.com/hyperledger/fabric/protos/peer](http://github.com/hyperledger/fabric/protos/peer)"
2.0导入的包为:
"[github.com/hyperledger/fabric-contract-api-go/contractapi](http://github.com/hyperledger/fabric-contract-api-go/contractapi)"
2、方法结构不同
Fabric2.0链码中不需要invoke和init方法
3、方法中调用形式参数类型、返回值不同
1.x方法为:
createCar1(stub shim.ChaincodeStubInterface, args []string) pb.Response { }
2.x方法为:
Create(ctx contractapi.TransactionContextInterface,key string,value string)error { }
2、contractapi包简单分析
从官方的fabric-samples提供的各种简单的Go链码中可以看到,一般我们链码方法都是自定义一个SmartContract struct, 里面包含了comtractapi包中的Contract struct。Contract struct实现了ContractInterface 接口,自定义的结构体通过水平组合Contract可以快速帮助我自定义的结构体实现ContractInterface接口。
type SimpleChaincode struct {
contractapi.Contract
}
type Contract struct {
Name string
Info metadata.InfoMetadata
UnknownTransaction interface{}
BeforeTransaction interface{}
AfterTransaction interface{}
TransactionContextHandler SettableTransactionContextInterface
}
ContractInterface 定义了有效合约应具有的功能。链码中使用的合约必须实现此接口。因此应用链码会直接将contractapi.Contract嵌套在链码结构体中,以实现ContractInterface接口。
type ContractInterface interface {
//获取当前描述智能合约的元数据
GetInfo() metadata.InfoMetadata
//在合约向链码转化的时候,获取合约中的未知的交易集合
GetUnknownTransaction() interface{}
//获取before transaction 集合
GetBeforeTransaction() interface{}
//获取after transaction 集合
GetAfterTransaction() interface{}
//GetName 返回合约的名称。当合约用于创建新链码时,该函数将被调用,返回的名称将用于在初始化/调用时识别链码中的合约。
GetName() string
//GetTransactionContextHandler返回约定函数使用的SettableTransactionContextInterface。
//合约向链码转化时,将调用此函数并存储返回的事务上下文。
//当通过init/Invoke调用链代码时,如果函数需要其参数列表中的上下文,则会创建存储类型的事务上下文,并将其作为参数发送给命名合约的函数(after,before和未知函数)。
//如果采用事务上下文的函数采用接口作为上下文,则此函数返回的事务上下文必须满足该接口
GetTransactionContextHandler() SettableTransactionContextInterface
}
除正常链码之外,contractapi包也提供了很多正常链码的扩展功能:
IgnoreContractInterface 扩展了ContractInterface, 并提供了其他功能,可用于标记哪些函数不应通过调用/查询链码来访问;
EvaluationContractInterface扩展了ContractInterface,标示这些function应该被query(查询)而不是被invoke(调用)
从上面图可以看出来我们定义的应用结构体,通过入参NewChaincode(contracts...ContractInterface)(*ContractChainCode,error)函数,可以转换为ContractChaincode结构体,NewChaincode基本逻辑就是该函数解析每个传递的函数,并存储链码要使用的组成细节,合约的公共函数存储在链代码中,并且可以调用。同时系统合约被添加到链码中,它提供了获取链码元数据的功能。生成的元数据是一个JSON格式的MetadataContractChaincode,包含每个合约的名称以及他们接受/返回的公共函数和类型的详细信息。它还概述了合同和链码的版本详细信息。
同时ContractChaincode实现了Chaincode接口,该接口是fabric每一个链码都必须实现的接口,里面提供了Invoke和Init方法,这就是fabric1.x链码的交互接口,fabric2.x链码实现就是对fabric1.x进行封装,便于开发人员链码编写。
3、shim包简单分析
3.1 shim包结构内容
在contractapi包中发现,contractapi包仅仅是为了方便交互,对shim进行了一个封装,调用的接口还是需要获取shim包中的ChaincodeStub
func (t *SimpleChaincode) InitLedger(ctx contractapi.TransactionContextInterface) error {
key := "assetGlobal"
exist, err := ctx.GetStub().GetState(key)
type TransactionContextInterface interface {
// GetStub should provide a way to access the stub set by Init/Invoke
GetStub() shim.ChaincodeStubInterface
// GetClientIdentity should provide a way to access the client identity set by Init/Invoke
GetClientIdentity() cid.ClientIdentity
}
// ChaincodeStub is an object passed to chaincode for shim side handling of
// APIs.
type ChaincodeStub struct {
TxID string
ChannelID string
chaincodeEvent *pb.ChaincodeEvent
args [][]byte
handler *Handler
signedProposal *pb.SignedProposal
proposal *pb.Proposal
validationParameterMetakey string
// Additional fields extracted from the signedProposal
creator []byte
transient map[string][]byte
binding []byte
decorations map[string][]byte
}
`
shim里面的handler.go是链码服务和peer服务通信的功能代码,目前主要关注提供了哪些与账本交互的API接口,方便学习编写链码。从interface.go看出,链码的与账本交互API主要由ChaincodeStubInterface来提供,剩下的三个Iterator都是账本富查询的迭代器接口。
ChaincodeStubInterface由ChaincodeStub来实现,了解ChaincodeStub结构体的方法,我们基本上就掌握了fabric链码的编写方法了,官方API文档和fabric-sample中的链码示例中也可以学到。
2、API功能分类
链码最最最(重点说三遍)主要的功能就是对账本进行操作,加上一些msp身份认证等的附加功能,目的也是更安全的对账本进行操作。
辅助功能:例如参数获取,交易获取,网络信息获取等。
- 参数获取:这类方法在链码2.x中已经不需要了,contractapi包中的NewChaincode方法已经帮我们把参数进行了填充,让我们可以和编写常规方法一样去编写链码方法。
-- 获取信息类型的函数:GetTxID()、GetChannel()、GetCreator()、GetSignedProposal()、GetTxTimestamp() - 状态操作:对账本的K-V进行操作
1.读写: PutState、DelState、GetStateByRange、GetStateByRangeWithPagination、GetHistoryForKey
2.复合键:SplitCompositeKey、CreateCompositeKey、GetStateByPartialCompositeKey、GetStateByPartialCompositeKeyWithPagination
3.对此Key的背书策略设置:SetStateValidationParameter、GetStateValidationParameter - 私有数据库操作:
1.读写:GetPrivateData、GetPrivateDataHash(方便非私有成员对交易进行验证,仅可读取数据的Hash)、PutPrivateData、DelPrivateData、PurgePrivateData、GetPrivateDataByRange
2.Key级别的背书策略设置:SetPrivateDataValidationParameter、GetPrivateDataValidationParameter
3.复合键:GetPrivateDataByPartialCompositeKey - 富查询:GetQueryResult、GetPrivateDataQueryResult
- 暂态数据:GetTransient(暂态数据主要是为了保护数据,字面意思,通过暂态数据传递进来的数据不会永久存储,会有专门的数据对其进行暂存,目前只能用于传递结构体数据)
- 事件设置:SetEvent(主要绑定在专门的函数执行完后出发所设定的事件,一个方法中最多只能设置一个Event,如果设置两个Event,则首个Event会被第二个Event覆盖)
- GetBinding:返回事务绑定,该绑定用于强制应用程序数据(如上文中的暂态字段中存储的数据)与提案本身之间的链接。有助于避免可能得重放攻击。
- GetDecorations:返回关于源自对等方的提案的附加数据(如果适用)。这些数据是由对等端的装饰器设置的,这些装饰器附加或变异传递给链代码的链代码输入。
原文链接:
https://blog.csdn.net/weixin_43274469/article/details/129643800