So dekodieren Sie Log.Data in Go

Ich hole die Protokolle mit client.SubscribeFilterLogs. Die Ereignisparameter sind in codiert types.Log.Data. Wie kann ich es entschlüsseln go?

Ja, das Paket go-ethereum (die Geth-Bibliotheken) hat den Beitrag zum Hinzufügen von Event-Entpacken erhalten. Ich werde mehr darüber in der Antwort unten schreiben.

Antworten (4)

Das go-ethereum abi- Paket hat im Oktober 2017 das Update zum Entpacken der Ereignisausgabe erhalten. Anfangs war es nur möglich, die Methodenausgabe zu entpacken.

Alle Funktionen werden über das abi.ABIObjekt bereitgestellt. Um es zu verwenden, benötigen Sie Event ABI (JSON-String). Verwenden Sie dann func (abi *ABI) UnmarshalJSON , um das ABIObjekt zu erstellen. Von dort aus können Sie die UnpackMethode using Dataaus Ihrem Protokollobjekt verwenden.

Denken Sie daran, dass indizierte Attribute Topiceher in log als in Data.

Für weitere Nutzungsdetails können Sie diesen Beispielen folgen:

HINWEIS: In der aktuellen Implementierung (2017-11-29) gibt es einen Fehler mit indizierten Attributen. Ich habe dafür eine PR eingereicht und warte immer noch auf die endgültige Genehmigung.

Hier ist ein vollständiges Codebeispiel für alle, die immer noch verwirrt sind (dank der Antwort von @Robert Zaremba).

package main

import (
    "context"

    "log"
    "math/big"
    "strings"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/accounts/abi"
    "github.com/ethereum/go-ethereum/common"

    "github.com/myorg/myrepo/go-contracts/token"
    "github.com/ethereum/go-ethereum/core/types"
)


func main() {
    contractAddress := common.HexToAddress("0x0d8775f648430679a709e98d2b0cb6250d2887ef")

    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.Fatal(err)
    }

    tokenAbi, err := abi.JSON(strings.NewReader(string(token.TokenABI)))

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

    for {
        select {
        case err := <-sub.Err():
            log.Fatal(err)
        case eventLog := <-ch:
            var transferEvent struct {
                From  common.Address
                To    common.Address
                Value *big.Int
            }

            err = tokenAbi.Unpack(&transferEvent, "Transfer", eventLog.Data)

            if err != nil {
                log.Println("Failed to unpack")
                continue
            }

            transferEvent.From = common.BytesToAddress(eventLog.Topics[1].Bytes())
            transferEvent.To = common.BytesToAddress(eventLog.Topics[2].Bytes())

            log.Println("From", transferEvent.From.Hex())
            log.Println("To", transferEvent.To.Hex())
            log.Println("Value", transferEvent.Value)
        }
    }
}
Eine Frage: Woher wissen Sie, ob die Daten ein Übertragungsereignis oder ein Genehmigungsereignis enthalten??? Denn Sie können beides empfangen, oder Sie können sogar andere Ereignisse empfangen, wie burnoder mint, woher wissen Sie also im Voraus, welche Art von Ereignis Sie entpacken müssen?
@Nulik tolle Frage; Thema[0] ist also die Ereignissignatur . keccak256(eventName(arg1,arg2))Wenn es sich also um ein Übertragungsereignis handelt, ist Thema[0] keccak256(Transfer(address,address,uint256))=> ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. Kurz gesagt: Sie kennen den Ereignistyp, indem Sie nach Thema[0] filtern, das der Hash der Ereignissignatur ist. Sehen Sie sich diese Ethereum-Entwicklung mit Go-Leitfaden für Beispiele an goethereumbook.org
@Nulik hier ist ein Beispielereignisprotokoll eines Übertragungsereignisses etherscan.io/tx/… . Wie Sie sehen können, ist topic[0] keccak256(Transfer(address,address,uint256))=>ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
@Nulik hier ist ein Beispielereignisprotokoll eines Genehmigungsereignisses etherscan.io/tx/… . Wie Sie sehen können, ist topic[0] keccak256(Approval(address,address,uint256))=>8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925
Danke, jetzt habe ich es. Übrigens, kennst du noch andere Standard-Events? Transfer() und Approval() sind die üblichen, aber viele Token fügen Präge- oder Brennereignisse hinzu. Kennen Sie andere Ereignisse, die auch für erc20-Token zum Standard werden?
@Nulik nicht sicher, sehen Sie sich die beliebten EIPS von Ethereum auf github.com/ethereum/EIPs/issues an
Darf ich fragen, welche gethVersion mit diesem Code verwendet wurde?
@NulikVersion: 1.8.10-stable
Danke. Dies erklärt, warum mein 1.7.2 nicht funktioniert. abi.Unpack() verwaltet noch keine Events. Ich denke, diese Funktion wurde ab 1.8 hinzugefügt

So habe ich es mit dem ABI gemacht:

path, _ := filepath.Abs("./resources/etherdelta.abi")
file, err := ioutil.ReadFile(path)
if err != nil {
    fmt.Println("Failed to read file:", err)
}
edabi, err := abi.JSON(strings.NewReader(string(file)))
if err != nil {
    fmt.Println("Invalid abi:", err)
}
var orderStruct struct {
    TokenGet   common.Address
    AmountGet  *big.Int
    TokenGive  common.Address
    AmountGive *big.Int
    Expires    *big.Int
    Nonce      *big.Int
    User       common.Address
}
err = edabi.Unpack(&orderStruct, "Order", log.Data)
if err != nil {
    fmt.Println("Failed to unpack:", err)
}
fmt.Println("TokenGet:", orderStruct.TokenGet.Hex())
fmt.Println("AmountGet:", orderStruct.AmountGet.Hex())
data := common.TrimLeftZeroes(log.Data)
hex := common.Bytes2Hex(data)
hex = TrimLeftZeroes(hex)
if hex != "" {
    erc20Amount, err := hexutil.DecodeBig("0x" + hex)
}



func TrimLeftZeroes(hex string) string {
    idx := 0
    for ; idx < len(hex); idx++ {
        if hex[idx] != '0' {
            break
        }
    }
    return hex[idx:]
}
Erklären Sie Ihren Code.
Das ist die Antwort auf die Frage, verarsch mich nicht.