跳到主要内容

订阅事件日志

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

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

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

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

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

logs := make(chan types.Log)

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

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

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

for {
select {
case err := <-sub.Err():
log.Fatal(err)
case vLog := <-logs:
fmt.Println(vLog) // pointer to event log
}
}

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


完整代码

Commands

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

Store.sol

pragma solidity ^0.4.24;

contract Store {
event ItemSet(bytes32 key, bytes32 value);

string public version;
mapping (bytes32 => bytes32) public items;

constructor(string _version) public {
version = _version;
}

function setItem(bytes32 key, bytes32 value) external {
items[key] = value;
emit ItemSet(key, value);
}
}

event_subscribe.go

package main

import (
"context"
"fmt"
"log"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
)

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

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

logs := make(chan types.Log)
sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
if err != nil {
log.Fatal(err)
}

for {
select {
case err := <-sub.Err():
log.Fatal(err)
case vLog := <-logs:
fmt.Println(vLog) // pointer to event log
}
}
}
$ solc --version
0.4.24+commit.e67f0147.Emscripten.clang

title: 监听事件日志 description: "这本迷你书的本意是给任何想用Go进行以太坊开发的同学一个概括的介绍。本意是如果你已经对以太坊和Go有一些熟悉,但是对于怎么把两者结合起来还有些无从下手,那这本书就是一个好的起点。" image: "https://ipfs.decert.me/QmfZm4ZahZBcpLNoMwNBX5kNLNaQ6PsPRV7oiJXTudvYWy" sidebar_label: "监听事件日志"

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

订阅事件日志

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

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

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

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

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

logs := make(chan types.Log)

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

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

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

for {
select {
case err := <-sub.Err():
log.Fatal(err)
case vLog := <-logs:
fmt.Println(vLog) // pointer to event log
}
}

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


完整代码

Commands

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

Store.sol

pragma solidity ^0.4.24;

contract Store {
event ItemSet(bytes32 key, bytes32 value);

string public version;
mapping (bytes32 => bytes32) public items;

constructor(string _version) public {
version = _version;
}

function setItem(bytes32 key, bytes32 value) external {
items[key] = value;
emit ItemSet(key, value);
}
}

event_subscribe.go

package main

import (
"context"
"fmt"
"log"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
)

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

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

logs := make(chan types.Log)
sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
if err != nil {
log.Fatal(err)
}

for {
select {
case err := <-sub.Err():
log.Fatal(err)
case vLog := <-logs:
fmt.Println(vLog) // pointer to event log
}
}
}
$ solc --version
0.4.24+commit.e67f0147.Emscripten.clang