注册监听事件文档
如何使用事件监听方法
探寻SDK包
在寻找能接收event的SDK中的方法时,我们寻找到了很多可能解,也排除了很多情况。
我们曾经探究过能否使用event包下的RegisterTxStatusEvent,RegisterBlockEvent等方法,而由于我们需要的是执行智能合约时进行使用,而TxStatus只能查询一笔交易的情况,RegisterTxStatusEvent方法被排除了。而对于RegisterBlockEvent方法,由于并不是只有提交模型的信息被作为block上传,其中会包含有很多冗余信息需要处理,因此也遭到了排除。
最终我们选择了RegisterChaincodeEvent()方法。这个方法可以通过传入的eventFilter参数(一个字符串,传入的是正则表达式)来挑选符合条件的setevent释放出的信息。
问题解决
最终,我们的解决方式如下:
以官方示例的Release2.2中的fabcar为例,进行监听信息的模拟
首先在智能合约的CreateCar函数进行如下修改:
func (s *SmartContract) CreateCar(ctx contractapi.TransactionContextInterface, carNumber string, make string, model string, colour string, owner string) (string, error) {
car := Car{
Make: make,
Model: model,
Colour: colour,
Owner: owner,
}
carAsBytes, _ := json.Marshal(car)
err := ctx.GetStub().PutState(carNumber, carAsBytes)
if err != nil {
return "", err
}
successResult := "Set the event successfully"
err = ctx.GetStub().SetEvent("CreateCar", []byte(successResult))
if err != nil {
return "", err
}
return successResult, nil
}
此次修改加入了SetEvent方法,方便等下在SDK中进行监听
然后进入fabcar文件,运行脚本./startFabric.sh
等待运行结束后,进入go文件夹,修改fabcar.go文件,修改为如下内容:
/*
Copyright 2020 IBM All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"errors"
"fmt"
"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"
"github.com/hyperledger/fabric-sdk-go/pkg/gateway"
"io/ioutil"
"os"
"path/filepath"
"time"
)
func main() {
os.Setenv("DISCOVERY_AS_LOCALHOST", "true")
wallet, err := gateway.NewFileSystemWallet("wallet")
if err != nil {
fmt.Printf("Failed to create wallet: %s\n", err)
os.Exit(1)
}
if !wallet.Exists("appUser") {
err = populateWallet(wallet)
if err != nil {
fmt.Printf("Failed to populate wallet contents: %s\n", err)
os.Exit(1)
}
}
ccpPath := filepath.Join(
"..",
"..",
"test-network",
"organizations",
"peerOrganizations",
"org1.example.com",
"connection-org1.yaml",
)
gw, err := gateway.Connect(
gateway.WithConfig(config.FromFile(filepath.Clean(ccpPath))),
gateway.WithIdentity(wallet, "appUser"),
)
if err != nil {
fmt.Printf("Failed to connect to gateway: %s\n", err)
os.Exit(1)
}
defer gw.Close()
network, err := gw.GetNetwork("mychannel")
if err != nil {
fmt.Printf("Failed to get network: %s\n", err)
os.Exit(1)
}
contract := network.GetContract("fabcar")
//sdk, err := fabsdk.New(config.FromFile(filepath.Clean(ccpPath)))
//if err != nil {
// panic(err)
//} else {
// fmt.Printf("sdk initialized successfully!\n")
//}
//failed to create identity manager provider: failed to initialize identity manager
//for organization: org1: Either a cryptopath or an embedded list of users is required
//need to add a cryptopath in config.yaml, all the errors can be fixed through make the
//yaml file detail.
//ccp := sdk.ChannelContext("mychannel", fabsdk.WithUser("Admin"))
//if err != nil {
// panic(err)
//}
//cc, err := event.New(ccp)
reg, channel, err := contract.RegisterEvent(".*")
if err != nil {
panic(err)
}
reg, channel, err := contract.RegisterEvent("fabcar", ".*")
if err != nil {
panic(err)
} else {
fmt.Printf("channel initialized successfully!\n")
}
defer contract.Unregister(reg)
go func() {
select {
case value := <-channel:
{
fmt.Printf("Get something from the channel, %v", value)
}
case <-time.After(20 * time.Second):
fmt.Printf("timeout while waiting for chaincode event\n")
}
}()
result, err := contract.EvaluateTransaction("queryAllCars")
if err != nil {
fmt.Printf("Failed to evaluate transaction: %s\n", err)
os.Exit(1)
}
fmt.Println(string(result))
result, err = contract.SubmitTransaction("createCar", "CAR10", "VW", "Polo", "Grey", "Mary")
if err != nil {
fmt.Printf("Failed to submit transaction: %s\n", err)
os.Exit(1)
}
fmt.Println(string(result))
result, err = contract.EvaluateTransaction("queryCar", "CAR10")
if err != nil {
fmt.Printf("Failed to evaluate transaction: %s\n", err)
os.Exit(1)
}
fmt.Println(string(result))
_, err = contract.SubmitTransaction("changeCarOwner", "CAR10", "Archie")
if err != nil {
fmt.Printf("Failed to submit transaction: %s\n", err)
os.Exit(1)
}
result, err = contract.EvaluateTransaction("queryCar", "CAR10")
if err != nil {
fmt.Printf("Failed to evaluate transaction: %s\n", err)
os.Exit(1)
}
fmt.Println(string(result))
}
func populateWallet(wallet *gateway.Wallet) error {
credPath := filepath.Join(
"..",
"..",
"test-network",
"organizations",
"peerOrganizations",
"org1.example.com",
"users",
"User1@org1.example.com",
"msp",
)
certPath := filepath.Join(credPath, "signcerts", "cert.pem")
// read the certificate pem
cert, err := ioutil.ReadFile(filepath.Clean(certPath))
if err != nil {
return err
}
keyDir := filepath.Join(credPath, "keystore")
// there's a single file in this dir containing the private key
files, err := ioutil.ReadDir(keyDir)
if err != nil {
return err
}
if len(files) != 1 {
return errors.New("keystore folder should have contain one file")
}
keyPath := filepath.Join(keyDir, files[0].Name())
key, err := ioutil.ReadFile(filepath.Clean(keyPath))
if err != nil {
return err
}
identity := gateway.NewX509Identity("Org1MSP", string(cert), string(key))
err = wallet.Put("appUser", identity)
if err != nil {
return err
}
return nil
}
注:其中sdk注释内容是event包下的方法,此时则需要修改对应的配置文件才可使用。如若只想进行体验则直接使用未注释的contract包下的RegisterEvent即可。