Signieren einer Rohtransaktion in Go

Ich muss eine Offline-Transaktion in Golang unterzeichnen. Ich habe Folgendes, was eine leichte Modifikation dieser Antwort auf eine ähnliche Frage ist:

import "github.com/ethereum/go-ethereum/core/types"
import "github.com/ethereum/go-ethereum/common"
import "github.com/ethereum/go-ethereum/crypto"

type GethTxn struct {
  To   string     `json:"to"`
  From string     `json:"from"`
  Gas string      `json:"gas"`
  GasPrice string `json:"gasPrice"`
  Value string    `json:"value"`
  Data string     `json:"input"`
}

func SignTxn(from string, _to string, data []byte, nonce uint64, value int64, gas *big.Int, gasPrice *big.Int, privkey *ecdsa.PrivateKey) (*GethTxn, error) {

  var parsed_tx = new(GethTxn)
  var amount = big.NewInt(value)
  var bytesto [20]byte
  _bytesto, _ := hex.DecodeString(_to[2:])
  copy(bytesto[:], _bytesto)
  to := common.Address([20]byte(bytesto))

  signer := types.NewEIP155Signer(nil)
  tx := types.NewTransaction(nonce, to, amount, gas, gasPrice, data)
  signature, _ := crypto.Sign(tx.SigHash(signer).Bytes(), privkey)
  signed_tx, _ := tx.WithSignature(signer, signature)

  json_tx, _ := signed_tx.MarshalJSON()
  _ = json.Unmarshal(json_tx, parsed_tx)
  parsed_tx.From = from
  fmt.Println("data", parsed_tx.Data)
  return parsed_tx, nil
}

Was ich will, ist die rohe Transaktionsnutzlast, aber was ich bekomme, ist falsch. Ich glaube, ich will parsed_data.Data, aber ich bin mir nicht sicher. Was ich suche, ist ein Go-Analog zur folgenden JS-Funktion:

var Tx = require('ethereumjs-tx');

var privateKey = new Buffer(pkey, 'hex')
var tx = new Tx(txn);
tx.sign(privateKey);
var serializedTx = tx.serialize().toString('hex')

Wo serializedTxist eine Zeichenfolge (die gewünschte Nutzlast).

Ich bin ein Golang-Noob, also vermute ich, dass ich Geth nur missbrauche, aber jede Hilfe wäre sehr willkommen. Ich habe ziemlich lange mit diesem Problem verbracht.

Antworten (3)

Sie können zwei Methoden verwenden, um das Rohtransaktions-RLP zu erhalten

  1. Rufen Sie die String()der signierten Transaktion ab. Sie können es direkt aufrufen oder es die fmtBibliothek für Sie erledigen lassen:

    my_string_var = signed_tx.String()
    

    oder

    my_string_var = fmt.Sprintf("%v", signed_tx)
    

Das Problem ist, dass Sie die Ausgabe analysieren müssen, die so etwas wie sein wird

    TX(57c9544749f223acdff0be77876a4a45125cef360530caa97a92c359e4d7a6ce)
    Contract: false
    From:     1600da1bcbef5599e09532f230ced99db0619b95
    To:       1737b4e8e4101334b1b1965d3d739c41cc54f096
    Nonce:    0
    GasPrice: 0x1bc16d674ec80000
    GasLimit  0x186a0
    Value:    0x0
    Data:     0xdeaa59df000000000000000000000000cbfdfb9fb838b9090a7fe1976ed98017632b44f1
    V:        0x78
    R:        0xa484a59015d08e736f59edf07ffb32f73151fddec52885b1f29cbcfd7aac203
    S:        0x842a3a63c2fb1771cd0495b93a4db94692d4733baa9e96c559ddc4ff600422
    Hex:      f88b80881bc16d674ec80000830186a0941737b4e8e4101334b1b1965d3d739c41cc54f09680a4deaa59df000000000000000000000000cbfdfb9fb838b9090a7fe1976ed98017632b44f178a00a484a59015d08e736f59edf07ffb32f73151fddec52885b1f29cbcfd7aac2039f842a3a63c2fb1771cd0495b93a4db94692d4733baa9e96c559ddc4ff600422
  1. Verwenden Sie stattdessen die Methode GetRlp()der Struktur Transactions(Plural, mit einem s).

    Wir erstellen eine Variable tsund füllen sie mit dieser signierten Transaktion

    ts := types.Transactions{signed_tx}
    

    Dann rufen wir einfach auf

    my_string_var = fmt.Sprintf("%x", ts.getRlp(0))
    

    Welche die gewünschte rohe Transaktionszeichenfolge enthalten wird

    f88b80881bc16d674ec80000830186a0941737b4e8e4101334b1b1965d3d739c41cc54f09680a4deaa59df000000000000000000000000cbfdfb9fb838b9090a7fe1976ed98017632b44f178a00a484a59015d08e736f59edf07ffb32f73151fddec52885b1f29cbcfd7aac2039f842a3a63c2fb1771cd0495b93a4db94692d4733baa9e96c559ddc4ff600422
    
Diese Antwort ist richtig, aber ich möchte nur eine nicht offensichtliche Bemerkung hinzufügen. Wenn Sie Ihre Transaktion bilden, müssen Sie Ihr dataFeld in einen der Geth-Typen umwandeln: common.FromHex(string(data)), wo my dataist []byte.
Ich habe ein Plus für diese Antwort gegeben, aber darf ich fragen, warum Sie die Rohtransaktion benötigen würden?
@Cyberience Es ist sicherer, auf App-Ebene als auf Knotenebene zu signieren. Auf diese Weise müssen Sie die privaten Schlüssel nicht auf dem Knoten speichern und Ihr Konto nicht entsperren. Einige Angriffe nutzen die Freischaltzeit, um zu versuchen, Ether zu stehlen, oder zielen auf Server ab, die Knoten halten, um private Schlüssel zu stehlen

Erstellen Sie eine Rohtransaktion:

package main

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

    "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"
)

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(1000000000000000000) // in wei (1 eth)
    gasLimit := uint64(21000)                // in units
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    toAddress := common.HexToAddress("0x4592d8f8d7b001e72cb26a73e4fa1806a51ac79d")
    var data []byte
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, data)

    chainID, err := client.NetworkID(context.Background())
    if err != nil {
        log.Fatal(err)
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    ts := types.Transactions{signedTx}
    rawTx := hex.EncodeToString(ts.GetRlp(0))

    fmt.Printf(rawTx) // f86...772
}

Senden der Rohtransaktion:

package main

import (
    "context"
    "encoding/hex"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/ethclient"
    "github.com/ethereum/go-ethereum/rlp"
)

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

    rawTx := "f86d8202b28477359400825208944592d8f8d7b001e72cb26a73e4fa1806a51ac79d880de0b6b3a7640000802ca05924bde7ef10aa88db9c66dd4f5fb16b46dff2319b9968be983118b57bb50562a001b24b31010004f13d9a26b320845257a6cfc2bf819a3d55e3fc86263c5f0772"

    var tx *types.Transaction

    rawTxBytes, err := hex.DecodeString(rawTx)
    rlp.DecodeBytes(rawTxBytes, &tx)

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

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

„Erstellen von Offline-/Rohtransaktionen mit Go-Ethereum“ @akshay_111meher https://medium.com/@akshay_111meher/creating-offline-raw-transactions-with-go-ethereum-8d6cc8174c5d