概述: 用Go订阅智能合约事件日志的教程。

订阅事件日志

为了订阅事件日志,我们需要做的第一件事就是拨打启用websocket的以太坊客户端。 幸运的是,Infura支持websockets。

  1. client, err := ethclient.Dial("wss://rinkeby.infura.io/ws")
  2. if err != nil {
  3. log.Fatal(err)
  4. }

下一步是创建筛选查询。 在这个例子中,我们将阅读来自我们在之前课程中创建的示例合约中的所有事件。

  1. contractAddress := common.HexToAddress("0x147B8eb97fD247D06C4006D269c90C1908Fb5D54")
  2. query := ethereum.FilterQuery{
  3. Addresses: []common.Address{contractAddress},
  4. }

我们接收事件的方式是通过Go channel。 让我们从go-ethereumcore/types包创建一个类型为Log的channel。

  1. logs := make(chan types.Log)

现在我们所要做的就是通过从客户端调用SubscribeFilterLogs来订阅,它接收查询选项和输出通道。 这将返回包含unsubscribe和error方法的订阅结构。

  1. sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
  2. if err != nil {
  3. log.Fatal(err)
  4. }

最后,我们要做的就是使用select语句设置一个连续循环来读入新的日志事件或订阅错误。

  1. for {
  2. select {
  3. case err := <-sub.Err():
  4. log.Fatal(err)
  5. case vLog := <-logs:
  6. fmt.Println(vLog) // pointer to event log
  7. }
  8. }

我们会在下个章节介绍如何解析日志。

完整代码

Commands

  1. solc --abi Store.sol
  2. solc --bin Store.sol
  3. abigen --bin=Store_sol_Store.bin --abi=Store_sol_Store.abi --pkg=store --out=Store.go

Store.sol

  1. pragma solidity ^0.4.24;
  2. contract Store {
  3. event ItemSet(bytes32 key, bytes32 value);
  4. string public version;
  5. mapping (bytes32 => bytes32) public items;
  6. constructor(string _version) public {
  7. version = _version;
  8. }
  9. function setItem(bytes32 key, bytes32 value) external {
  10. items[key] = value;
  11. emit ItemSet(key, value);
  12. }
  13. }

event_subscribe.go

  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "log"
  6. "github.com/ethereum/go-ethereum"
  7. "github.com/ethereum/go-ethereum/common"
  8. "github.com/ethereum/go-ethereum/core/types"
  9. "github.com/ethereum/go-ethereum/ethclient"
  10. )
  11. func main() {
  12. client, err := ethclient.Dial("wss://rinkeby.infura.io/ws")
  13. if err != nil {
  14. log.Fatal(err)
  15. }
  16. contractAddress := common.HexToAddress("0x147B8eb97fD247D06C4006D269c90C1908Fb5D54")
  17. query := ethereum.FilterQuery{
  18. Addresses: []common.Address{contractAddress},
  19. }
  20. logs := make(chan types.Log)
  21. sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
  22. if err != nil {
  23. log.Fatal(err)
  24. }
  25. for {
  26. select {
  27. case err := <-sub.Err():
  28. log.Fatal(err)
  29. case vLog := <-logs:
  30. fmt.Println(vLog) // pointer to event log
  31. }
  32. }
  33. }
  1. $ solc --version
  2. 0.4.24+commit.e67f0147.Emscripten.clang