一、链码开发模板
链码开发实现Chaincode接口,Chaincode接口里面只有两个方法,一个是Init()方法(链码初始化),另一个是Invoke()方法(链码调用主要逻辑),Chaincode接口如下:
/*
所有链码必须实现Chaincode接口的Init()和Invoke()方法,
并且fabric需要调用这两个方法来执行交易逻辑
*/
type Chaincode interface {
// Init is called during Instantiate transaction after the chaincode container
// has been established for the first time, allowing the chaincode to
// initialize its internal data
/*
Init()方法在首次建立链码容器后负责实例化,并初始化数据
*/
Init(stub ChaincodeStubInterface) pb.Response
// Invoke is called to update or query the ledger in a proposal transaction.
// Updated state variables are not committed to the ledger until the
// transaction is committed.
/*
一次交易提案会通过调用Invoke()方法执行,包括查询或者更新账本
交易成功提交后,更新的状态变量才会提交到账本中
*/
Invoke(stub ChaincodeStubInterface) pb.Response
}
在链码开发的过程中,主要涉及到ChaincodeStubInterface的以下方法,可以直接使用,方法列表如下:
type ChaincodeStubInterface interface {
//获取参数,返回Invoke()方法名称,以及参数列表
GetFunctionAndParameters() (string, []string)
//获取TxID,也就是每次调用的提案ID
GetTxID() string
//获取KV键值Value
GetState(key string) ([]byte, error)
//更新KV键值
PutState(key string, value []byte) error
//删除KV键值
DelState(key string) error
//根据字典序获取KV键值集合
GetStateByRange(startKey, endKey string) (StateQueryIteratorInterface, error)
//获取联合索引KV键值
GetStateByPartialCompositeKey(objectType string, keys []string) (StateQueryIteratorInterface, error)
//创建联合索引
CreateCompositeKey(objectType string, attributes []string) (string, error)
//分割联合索引
SplitCompositeKey(compositeKey string) (string, []string, error)
//获取KV键值结合
GetQueryResult(query string) (StateQueryIteratorInterface, error)
//获取对应Key下的历史更新记录
GetHistoryForKey(key string) (HistoryQueryIteratorInterface, error)
}
二、链码启动流程
- 初始化:读取默认配置,创建到Peer节点的gRPC的连接;
- 创建有限状态机结构(FSM):FSM会根据收到的消息和当前的状态来触发状态转移,并执行提前设置的操作;同时Peer节点也有类似的FSM结构来管理消息响应;
- 发送注册gRPC消息:利用创建好的gPRC连接向Peer发送自身的注册消息;
- 消息处理循环:注册成功之后,等待接收来自Peer的消息以及自身的状态迁移(nextState)消息;
三、链码容器与Peer节点通信过程
-
链码容器与Peer节点建立通信
- 链码容器向Peer节点发送自己的注册信息ChaincodeMessage_REGISTER;
- Peer节点接收到之后注册到本地的一个Handle结构,返回ChaincodeMessage_REGISTERED消息给链码容器,状态更新为established;
- 链码容器收到之后,什么也不做,只把状态更新为established;
- Peer节点继续发送ChaincodeMessage_READY消息给链码容器,状态更新为READY;
- 链码容器收到之后,还是什么也不做,状态继续更新为READY;
-
链码容器初始化
- Peer节点继续发送ChaincodeMessage_INIT消息给链码容器;
- 链码容器收到之后,调用Handler.handleInit()方法进行初始化。主要是初始化所需的ChaincodeStub结构,调用链码代码中的Init()方法;
- 链码容器初始化成功之后,返回ChaincodeMessage_COMPLETED消息给Peer节点。此时,链码容器进入可被调用(Invoke)状态;
-
链码容器的Invoke()方法被Peer节点调用
- Peer节点如果要调用链码,发送ChaincodeMessage_TRANSACTION消息给链码容器;
- 链码容器收到,调用**Invoke()**方法,根据用户在Invoke()方法的具体实现逻辑,可以返回如下几类的响应消息给Peer节点:
- ChaincodeMessage_GET_HISTORY_FOR_KEY
- ChaincodeMessage_GET_QUERY_RESULT
- ChaincodeMessage_GET_STATE
- ChaincodeMessage_GET_STATE_BY_RANGE
- ChaincodeMessage_QUERY_STATE_CLOSE
- ChaincodeMessage_QUERY_STATE_NEXT
- ChaincodeMessage_INVOKE_CHAINCODE
- Peer节点收到消息,进行处理,并返回ChaincodeMessage_RESPONSR消息给链码容器;
- 链码容器收到消息,返回ChaincodeMessage_COMPLETE消息给Peer节点,代表链码的一次Invoke()方法调用成功结束;