Die Go-Bindungen haben einen Typ namens Log
mit den folgenden Feldern
type Log struct {
// Consensus fields:
// address of the contract that generated the event
Address common.Address `json:"address" gencodec:"required"`
// list of topics provided by the contract.
Topics []common.Hash `json:"topics" gencodec:"required"`
// supplied by the contract, usually ABI-encoded
Data []byte `json:"data" gencodec:"required"`
[...]
}
Nehmen wir an, ich habe eine Veranstaltung wie dieseevent SomethingHappened(uint256 indexed id, address indexed participant1, address indexed participant2, uint256 value1, uint256 value2);
Es gibt 4 Themen und sie sind wie folgt gefüllt, sie sind vom Typ common.Hash
:
SHA3("SomethingHappened(uint256,address,address,uint256,uint256)")
uint256
, die mit der großen Bibliothek gelesen werden kann:new(big.Int).SetBytes(log.Topics[1].Bytes())
common.Hash
es 32 Bytes lang common.Address
ist und 20 Bytes beträgt, können Sie die Adresse wie folgt erhalten: common.BytesToAddress(log.Topics[2].Bytes()[12:32])
.Nun, das ist nicht so bequem, aber es ist immer noch möglich. Wenn wir jedoch versuchen, auf die letzten beiden Argumente zuzugreifen, verliere ich mich. Sie sind irgendwie im Data []byte
Feld der Struktur codiert common.Log
. Die Dokumentation erwähnt, dass sie "ABI-kodiert" sind, bietet aber keine Möglichkeit, etwas mit diesen Daten zu tun. abigen hat auch keine Unterstützung für Ereignisvariablen, daher bin ich wirklich verloren, wie ich auf diese Werte zugreifen kann.
Das Data
Feld Protokolltyp enthält die Argumente des nicht indizierten Ereignisprotokolls, sodass Sie sie nur in Go-Typen decodieren müssen.
Hier ist zum Beispiel ein einfacher Smart Contract, der nicht indizierte Protokolleinträge ausgibt:
pragma solidity ^0.4.24;
contract Store {
event ItemSet(bytes32 key, bytes32 value);
mapping (bytes32 => bytes32) public items;
function setItem(bytes32 key, bytes32 value) external {
items[key] = value;
emit ItemSet(key, value);
}
}
Dann rufen Sie in Ihrem Code nach dem Abrufen der Ereignisprotokolle die Unpack
Methode aus der Smart-Contract-Go-Bindung auf und übergeben ihr die Struktur mit den Ereigniseigenschaften, dem Namen des Smart-Contract-Protokollereignisses und schließlich den eigentlichen Protokolldaten.
for _, vLog := range logs {
event := struct {
Key [32]byte
Value [32]byte
}{}
err := contractAbi.Unpack(&event, "ItemSet", vLog.Data)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(event.Key[:])) // foo
fmt.Println(string(event.Value[:])) // bar
}
Hier ist das vollständige Beispiel für das Abfragen und Decodieren der nicht indizierten Protokolle des Beispiel-Smart-Vertrags.
package main
import (
"context"
"fmt"
"log"
"math/big"
"strings"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
store "./contracts" // for demo
)
func main() {
client, err := ethclient.Dial("wss://rinkeby.infura.io/ws")
if err != nil {
log.Fatal(err)
}
contractAddress := common.HexToAddress("0x147B8eb97fD247D06C4006D269c90C1908Fb5D54")
query := ethereum.FilterQuery{
FromBlock: big.NewInt(2394201),
ToBlock: big.NewInt(2394201),
Addresses: []common.Address{
contractAddress,
},
}
logs, err := client.FilterLogs(context.Background(), query)
if err != nil {
log.Fatal(err)
}
contractAbi, err := abi.JSON(strings.NewReader(string(store.StoreABI)))
if err != nil {
log.Fatal(err)
}
for _, vLog := range logs {
event := struct {
Key [32]byte
Value [32]byte
}{}
err := contractAbi.Unpack(&event, "ItemSet", vLog.Data)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(event.Key[:])) // foo
fmt.Println(string(event.Value[:])) // bar
var topics [4]string
for i := range vLog.Topics {
topics[i] = vLog.Topics[i].Hex()
}
fmt.Println(topics[0]) // 0xe79e73da417710ae99aa2088575580a60415d359acfad9cdd3382d59c80281d4
}
eventSignature := []byte("ItemSet(bytes32,bytes32)")
hash := crypto.Keccak256Hash(eventSignature)
fmt.Println(hash.Hex()) // 0xe79e73da417710ae99aa2088575580a60415d359acfad9cdd3382d59c80281d4
}
Für indizierte Protokolle verwenden Sie einfach log.Topics
. Das erste Thema ist immer die Methoden-ID, die ein Hash der Signatur der Ereignisprotokollfunktion ist (Methodenname und Argumenttypen).
Weitere Beispiele finden Sie im Handbuch Ethereum Development with Go .