概述: 用Go构建以太坊原始交易的教程。

构建原始交易(Raw Transaction)

如果你看过上个章节, 那么你知道如何加载你的私钥来签名交易。 我们现在假设你知道如何做到这一点,现在你想让原始交易数据能够在以后广播它。

首先构造事务对象并对其进行签名,例如:

  1. tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, data)
  2. signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
  3. if err != nil {
  4. log.Fatal(err)
  5. }

现在,在我们以原始字节格式获取事务之前,我们需要初始化一个types.Transactions类型,并将签名后的交易作为第一个值。

  1. ts := types.Transactions{signedTx}

这样做的原因是因为Transactions类型提供了一个GetRlp方法,用于以RLP编码格式返回事务。 RLP是以太坊用于序列化对象的特殊编码方法。 结果是原始字节。

  1. rawTxBytes := ts.GetRlp(0)

最后,我们可以非常轻松地将原始字节转换为十六进制字符串。

  1. rawTxHex := hex.EncodeToString(rawTxBytes)
  2. fmt.Printf(rawTxHex)
  3. // f86d8202b38477359400825208944592d8f8d7b001e72cb26a73e4fa1806a51ac79d880de0b6b3a7640000802ba0699ff162205967ccbabae13e07cdd4284258d46ec1051a70a51be51ec2bc69f3a04e6944d508244ea54a62ebf9a72683eeadacb73ad7c373ee542f1998147b220e

接下来,你就可以广播原始交易数据。在下一章 我们将学习如何广播一个原始交易。

完整代码

transaction_raw_create.go

  1. package main
  2. import (
  3. "context"
  4. "crypto/ecdsa"
  5. "encoding/hex"
  6. "fmt"
  7. "log"
  8. "math/big"
  9. "github.com/ethereum/go-ethereum/common"
  10. "github.com/ethereum/go-ethereum/core/types"
  11. "github.com/ethereum/go-ethereum/crypto"
  12. "github.com/ethereum/go-ethereum/ethclient"
  13. )
  14. func main() {
  15. client, err := ethclient.Dial("https://rinkeby.infura.io")
  16. if err != nil {
  17. log.Fatal(err)
  18. }
  19. privateKey, err := crypto.HexToECDSA("fad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19")
  20. if err != nil {
  21. log.Fatal(err)
  22. }
  23. publicKey := privateKey.Public()
  24. publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
  25. if !ok {
  26. log.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey")
  27. }
  28. fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
  29. nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
  30. if err != nil {
  31. log.Fatal(err)
  32. }
  33. value := big.NewInt(1000000000000000000) // in wei (1 eth)
  34. gasLimit := uint64(21000) // in units
  35. gasPrice, err := client.SuggestGasPrice(context.Background())
  36. if err != nil {
  37. log.Fatal(err)
  38. }
  39. toAddress := common.HexToAddress("0x4592d8f8d7b001e72cb26a73e4fa1806a51ac79d")
  40. var data []byte
  41. tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, data)
  42. chainID, err := client.NetworkID(context.Background())
  43. if err != nil {
  44. log.Fatal(err)
  45. }
  46. signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
  47. if err != nil {
  48. log.Fatal(err)
  49. }
  50. ts := types.Transactions{signedTx}
  51. rawTxBytes := ts.GetRlp(0)
  52. rawTxHex := hex.EncodeToString(rawTxBytes)
  53. fmt.Printf(rawTxHex) // f86...772
  54. }