Go-Ethereum and JSON-RPC – How to Access the Event Log by Knowing the Contract Address (Golang)

eventsgo-ethereumgolangjson-rpclogs

At the moment I develope dapps that use smart contract as storage for specific data. I use abigen to generate specific go binding to my contract. If someone try change state of the contract I use event for logging this action. But I am stuck, because I do not realy understand how can I view log history of specific event using go ethereum.

How can I use json rpc call of eth_getlogs method and get all the logs that are stored in this contract address with go ?

I will be appreciated for a snippet of code.

Thanks in advance!

Best Answer

Typically you would first create a new filter (eth_newFilter + eth_getFilterLogs) and reuse that filter to perform the same query many times as well as listen for changes. However, you can also install an ad-hoc filter with eth_getLogs, referencing the topics you wish to search over.

A topic is a piece of data you are searching. For example, if you have the following event:

Transfer(address to, address from)

The following filter would search for all logs going to 0xb3904758c0d3bfc25746c47caa45b01da8930e19:

[0x000000000000000000000000b3904758c0d3bfc25746c47caa45b01da8930e19, null]

This filter would search for all logs coming from 0xb3904758c0d3bfc25746c47caa45b01da8930e19:

[null, 0x000000000000000000000000b3904758c0d3bfc25746c47caa45b01da8930e19]

And this filter would search for all logs going to 0xb3904758c0d3bfc25746c47caa45b01da8930e19 from 0x8cc19c7b50857abbfbeeed31c302319a075d4a9b:

[0x000000000000000000000000b3904758c0d3bfc25746c47caa45b01da8930e19, 0x0000000000000000000000008cc19c7b50857abbfbeeed31c302319a075d4a9b

A full golang wrapper for RPC requests would look something like this:

// This needs to be instantiated
type EthereumClient struct {
  URL string
}

// Basic RPC repsonse format
type JSONRPCRequest struct {
  JSONRPC string        `json:"jsonrpc"`
  Method  string        `json:"method"`
  ID      int64         `json:"id"`
  Params  []interface{} `json:"params"`
}

// Base struct
type ResponseBase struct {
  JSONRPC string `json:"jsonrpc"`
  ID      int64  `json:"id"`
}

// Response struct based on below RPC methods
type Response struct {
  ResponseBase
  Result string `json:"result"`
}

// ToJSON marshals a JSONRPCRequest into JSON
func (req *JSONRPCRequest) ToJSON() ([]byte, error) {
  s, err := json.Marshal(req)
  if err != nil {
    return nil, err
  }
  return s, nil
}

// Get logs given an array of topics
func (client *EthereumClient) Eth_getLogs(topics string[]) (string, error) {
  reqBody := JSONRPCRequest{
    JSONRPC: "2.0",
    ID:      1,
    Method:  "eth_sendRawTransaction",
    Params:  []interface{}{topics},
  }
  res, err := client.issueRequest(&reqBody)
  if err != nil {
    return "", err
  }

  var clientResp Response
  err = json.Unmarshal(res, &clientResp)
  if err != nil {
    return "", err
  }
  return clientResp.Result, nil
}

The EthereumClient can be instantiated in a different package by something like this:

// Global client connection
var client = EthereumClient{}

// provider = e.g. 'localhost:8545'
func ConnectToRPC(provider string) {
  client = EthereumClient{provider}
}

This client can now be used to start a new filter and get the logs from that filter.

I don't have a specific example for this use case, but please see this for some examples of making RPC requests in Go.

Related Topic