Go-Ethereum

目前將事件發送到使用 go-ethereum 的 Go 應用程序的最佳方式是什麼?

  • November 27, 2017

我已經生成並使用Go 綁定來部署一些合約並且效果很好,但是我看到事件還沒有實現。這項工作是否在某處討論過?

我想了解 Go 中的伺服器端應用程序有哪些選項可以觀看已部署的智能合約上的事件?

我知道事件是圍繞 EVM 日誌操作的包裝器,並作為交易收據中的條目存在。此外,觀察事件是按契約實例完成的(而不是按類)。

我想避免手動解析事件,我可以使用輪詢 JSON RPC log changesRPC pub/sub for logs 來完成

Go中目前建議的方式是什麼?請在程式碼中顯示一個範例。謝謝!

更新

為 go-ethereum 打開了一個問題,為 Go 綁定添加事件,所以請 +1。:)

abigen將生成程式碼以通過合約介面訪問事件之前,您應該使用Client.SubscribeFilterLogs方法。這很不言自明。您必須提供一個由日誌提供的通道。另外,不要忘記收聽Subscription.Err()

查看 consensys 文章:乙太坊中事件和日誌的技術介紹,了解有關在乙太坊中處理日誌的資訊。

例子:

query := ethereum.FilterQuery{
   FromBlock: nil,
   ToBlock:   nil,
   // Topics [][]common.Hash
   Addresses: []common.Address{myContractAddress}}
var logs = make(chan types.Log, 2)
s, err := client.SubscribeFilterLogs(context.TODO(), query, logs)
// check err
errChan := s.Err()
for {
   select {
   case err := <-errChan:
       logger.Error("Logs subscription error", err)
       break
   case l := <-logs:
       logger.Info("new log", log15.Spew(l))
   }
}

這是一個例子

package main

import (
   "context"
   "fmt"
   "github.com/ethereum/go-ethereum"
   "github.com/ethereum/go-ethereum/accounts/abi/bind"
   "github.com/ethereum/go-ethereum/common"
   "github.com/ethereum/go-ethereum/core/types"
   "github.com/ethereum/go-ethereum/crypto"
   "github.com/ethereum/go-ethereum/ethclient"
   "github.com/miguelmota/go-web3-example/greeter"
   "log"
)

func main() {
   client, err := ethclient.Dial("wss://rinkeby.infura.io/ws")

   if err != nil {
       log.Fatal(err)
   }

   greeterAddress := "a7b2eb1b9fff7c9625373a6a6d180e36b552fc4c"
   priv := "abcdbcf6bdc3a8e57f311a2b4f513c25b20e3ad4606486d7a927d8074872cefg"

   key, err := crypto.HexToECDSA(priv)

   contractAddress := common.HexToAddress(greeterAddress)
   greeterClient, err := greeter.NewGreeter(contractAddress, client)

   if err != nil {
       log.Fatal(err)
   }

   auth := bind.NewKeyedTransactor(key)

   // not sure why I have to set this when using testrpc
   // var nonce int64 = 0
   // auth.Nonce = big.NewInt(nonce)

   tx, err := greeterClient.Greet(auth, "hello")

   if err != nil {
       log.Fatal(err)
   }

   fmt.Printf("Pending TX: 0x%x\n", tx.Hash())

   query := ethereum.FilterQuery{
       Addresses: []common.Address{contractAddress},
   }

   var ch = make(chan types.Log)
   ctx := context.Background()

   sub, err := client.SubscribeFilterLogs(ctx, query, ch)

   if err != nil {
       log.Println("Subscribe:", err)
       return
   }

   for {
       select {
       case err := <-sub.Err():
           log.Fatal(err)
       case log := <-ch:
           fmt.Println("Log:", log)
       }
   }

}

使用的範例契約

pragma solidity ^0.4.9;

contract Greeter {
 event _Greet(string name);

 function greet(string name) public {
   _Greet(name);
 }
}

引用自:https://ethereum.stackexchange.com/questions/6933