- fabric的事件
fabric支持四类事件:
- BlockEvent(filter ...fab.BlockFilter)
- FilteredBlockEvent()
- ChaincodeEvent(chaincodeID string, eventNameFilter string)
- TxStatusEvent(txID string)
几点注释
- BlockEvent和FilteredBlockEvent是针对block的,即当生成一个block的时候就出发一个事件;两者的区别是是否包含block的payload数据(FilteredBlockEvent不含有payload,只包含block的metadata信息)。
- 我不知道TxStatusEvent这个干什么用,用户怎么知道txID是什么呢?能想到的只有一种情况,即采用异步调用的时候,fabric首先返回txID,然后异步查询transaction的状态。
- ChaincodeEvent:这个名字取得不好,让人误解,以为是chaincode相关的事件,其实这个是用户event,就是用户在chaincode里面显式的抛出的事件,我觉得这个事件最有用。
下面举一个ChaincodeEvent的例子
- ChaincodeEvent例子
2.1. chaincode抛出事件
func (e *ChaincodeImpl) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
...
err = stub.PutState(mykey, myvalue)
if err != nil {
return shim.Error(fmt.Sprintf("unable put state (%s), error: %v", key, err))
}
err = stub.SetEvent("<eventName>", myvalue)
if err != nil {
return shim.Error(fmt.Sprintf("unable set event, error: %v", err))
}
return shim.Success(nil)
}
在chaincode invoke函数的最后return之前,通过调用stub.SetEven(name string, payload []byte)来抛出ChaincodeEvent。
包含两个参数eventName,和eventPayload。
2.2. 监听chaincode事件
下面是一个由fabric sdk实现的ChaincodeEvent的例子:
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/hyperledger/fabric-sdk-go/pkg/client/event"
"github.com/hyperledger/fabric-sdk-go/pkg/core/config"
"github.com/hyperledger/fabric-sdk-go/pkg/fabsdk"
)
const (
channelID = "<channelID>"
chaincodeID = "<chaincodeID>"
eventID = "<eventName>"
mspID = "<mspid>"
userID = "<userid>"
)
func main() {
configOpt := config.FromFile("./profile.yaml")
sdk, err := fabsdk.New(configOpt)
if err != nil {
log.Fatalf("Failed to create new SDK: %v\n", err)
return
}
defer sdk.Close()
clientChannelContext := sdk.ChannelContext(channelID, fabsdk.WithUser(userID), fabsdk.WithOrg(mspID))
eventClient, err := event.New(clientChannelContext, event.WithBlockEvents())
//eventClient, err := event.New(clientChannelContext) // if this, you will not get payload data
if err != nil {
log.Fatalf("Failed to create event client: %v\n", err)
return
}
reg, eventCh, err := eventClient.RegisterChaincodeEvent(chaincodeID, eventID)
if err != nil {
log.Fatalf("Failed to regitser block event: %v\n", err)
return
}
defer eventClient.Unregister(reg)
timeoutctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
for {
select {
case evtdata := <-eventCh:
fmt.Printf("received a block: %s\n", evtdata.Payload)
case <-timeoutctx.Done():
fmt.Println("event timeout, exit!")
return
}
}
log.Printf("done\n")
}
需要匹配这里的eventID和chaincode里面stub.SetEvent(<eventName>,...),两个必须匹配。
可见ChaincodeEvent是比较常用的场景,用户只关注需要关注的内容,包括事件payload都是自定义的,而抛弃复杂的统一格式事件内容。










网友评论