Rohtransaktionsdaten in Go

Ich möchte Rohtransaktionen ohne golangBindung generieren gound frage mich, ob es eine Bibliothek gibt, mit der ich meinen Argumentparameter dynamisch codieren kann .go

https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI

Mit dieser Ressource sieht es so aus, als wäre es eine Menge Arbeit, jeden Parameter manuell für jeden verfügbaren Datentyp dynamisch zu codieren.

Gibt es eine Möglichkeit, dies zu tun?

Auch hier suche ich nicht nach Ethereum Go-Bindungen , da ich die rohen unsignierten Transaktionsdaten zurückgeben muss.

Antworten (2)

Das Go-Ethereum-Paket bietet eine common.LeftPadBytesFunktion für linke Füllwerte für die Solidität. Sie würden dies verwenden, um auf 32 Bytes aufzufüllen, was die Wortgröße ist, die der EVM verwendet.

Hier ist ein vollständiges Beispiel für die manuelle Erstellung der Transaktionsdaten für die Übertragung eines ERC-20-Tokens, das Ihnen eine gute Vorstellung geben sollte (aus dem Buch Ethereum Development with Go ).

package main

import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "math/big"

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

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

    privateKey, err := crypto.HexToECDSA("fad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.Public()
    publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
    if !ok {
        log.Fatal("error casting public key to ECDSA")
    }

    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }

    value := big.NewInt(0)      // in wei (0 eth)
    gasLimit := uint64(2000000) // in units
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x4592d8f8d7b001e72cb26a73e4fa1806a51ac79d")
    tokenAddress := common.HexToAddress("0x28b149020d2152179873ec60bed6bf7cd705775d")

    transferFnSignature := []byte("transfer(address,uint256)")
    hash := sha3.NewKeccak256()
    hash.Write(transferFnSignature)
    methodID := hash.Sum(nil)[:4]
    fmt.Println(hexutil.Encode(methodID)) // 0xa9059cbb

    paddedAddress := common.LeftPadBytes(toAddress.Bytes(), 32)
    fmt.Println(hexutil.Encode(paddedAddress)) // 0x0000000000000000000000004592d8f8d7b001e72cb26a73e4fa1806a51ac79d

    amount := new(big.Int)
    amount.SetString("1000000000000000000000", 10) // 1000 tokens
    paddedAmount := common.LeftPadBytes(amount.Bytes(), 32)
    fmt.Println(hexutil.Encode(paddedAmount)) // 0x00000000000000000000000000000000000000000000003635c9adc5dea00000

    var data []byte
    data = append(data, methodID...)
    data = append(data, paddedAddress...)
    data = append(data, paddedAmount...)

    tx := types.NewTransaction(nonce, tokenAddress, value, gasLimit, gasPrice, data)
    signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, privateKey)
    if err != nil {
        log.Fatal(err)
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("tx sent: %s", signedTx.Hash().Hex()) // tx sent: 0xa56316b637a94c4cc0331c73ef26389d6c097506d581073f927275e7a6ece0bc
}

Ein Ausgangspunkt wäre NewTransaction()in transaction.go. Dies ist Teil des typesPakets.

// NewTransaction creates a new transaction with the given properties.
func NewTransaction(nonce int64, to *Address, amount, gasLimit, gasPrice *BigInt, data []byte) *Transaction {
    return &Transaction{types.NewTransaction(uint64(nonce), to.address, amount.bigint, gasLimit.bigint, gasPrice.bigint, data)}
}

Es gibt unzählige Stellen im Code, die Beispiele dafür enthalten, wie die Funktion getestet werden kann, mit oder ohne den Schritt, der das Signieren durchführt.