Interacting with Ethereum Blockchain Using Go (Part 2)

·

Introduction

In the previous article, we explored how to connect to the Ethereum blockchain using Go, retrieve the latest block number, and submit transactions (with private keys stored on the node). This follow-up article delves into generating private keys with go-ethereum, signing transactions, and broadcasting them to the Ethereum blockchain (via clients like geth or parity).

Note:

  • Connection setup is not covered here; refer to Part 1 for details.
  • Go development environment setup is assumed; consult external resources if needed.

Generating Private Keys

Private keys can be restored from existing strings or generated anew.

Restoring from a Hex String

privKey, err := crypto.HexToECDSA("your_private_key_hex")
if err != nil {
    fmt.Println(err)
} else {
    // Proceed with the private key
}

Generating a New Key

privKey, err := crypto.GenerateKey()
if err != nil {
    fmt.Println(err)
} else {
    // Extract public key and Ethereum address
    publicKey := privKey.PublicKey
    address := crypto.PubkeyToAddress(publicKey).Hex()
}

Signing Transactions

Step 1: Create a Transaction Object

amount := big.NewInt(1)
gasLimit := uint64(90000)
gasPrice := big.NewInt(0)
data := []byte{}
tx := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data)

Step 2: Initialize a Signer

signer := types.HomesteadSigner{} // For mainnet-like networks
// OR for EIP155-compatible chains (e.g., Rinkeby):
// signer := types.NewEIP155Signer(big.NewInt(4))

Step 3: Sign the Transaction

signedTx, err := types.SignTx(tx, signer, privKey)
if err != nil {
    fmt.Println("Signing failed:", err)
}
Tip:
The SignTx function is located in the types package, not crypto. EIP155 signers adjust the v value to include chain-specific data.

Broadcasting Transactions

Using SendTransaction (Default)

err := ec.SendTransaction(context.TODO(), signedTx)
if err != nil {
    fmt.Println("Broadcast failed:", err)
}

Custom SendRawTransaction (To Retrieve TX Hash)

func (ec *Client) SendRawTransaction(ctx context.Context, tx *types.Transaction) (common.Hash, error) {
    var txHash common.Hash
    data, err := rlp.EncodeToBytes(tx)
    if err != nil {
        return txHash, err
    }
    err = ec.rpcClient.CallContext(ctx, &txHash, "eth_sendRawTransaction", common.ToHex(data))
    return txHash, err
}

Calculating Transaction Hash Manually

txHash := crypto.Keccak256Hash(rlpEncodedTx)

Practical Example (Rinkeby Testnet)

Transaction Parameters

amount := big.NewInt(100000000000) // 0.0001 Ether
gasLimit := uint64(90000)
gasPrice := big.NewInt(1000000000) // 1 Gwei
data := []byte("send from sc0vu")

Signing and Broadcasting

tx := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data)
signer := types.NewEIP155Signer(big.NewInt(4)) // Rinkeby chainId = 4
signedTx, _ := types.SignTx(tx, signer, privKey)
txHash, err := client.SendRawTransaction(context.TODO(), signedTx)
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println("Transaction hash:", txHash)
}
Note:
Monitor the transaction on Rinkeby Etherscan. Chain IDs for other networks are listed in EIP155.

Conclusion

This guide demonstrated how to generate private keys, sign transactions, and broadcast them to Ethereum using Go. For the complete code, visit the GitHub repository. Feedback and issues are welcome!

👉 Explore more Ethereum developer tools


FAQ

Q1: Why use EIP155 signers?
A1: EIP155 prevents replay attacks across different chains by incorporating the chain ID into the signature.

Q2: How do I set the nonce?
A2: Fetch the latest count using PendingNonceAt from the Ethereum client.

Q3: What’s the difference between HomesteadSigner and EIP155Signer?
A3: HomesteadSigner is legacy, while EIP155Signer supports post-Spurious Dragon hard forks.

Q4: Can I use this for smart contract interactions?
A4: Yes! Replace the data field with the contract’s ABI-encoded function call.

Q5: How do I estimate gas limits accurately?
A5: Use EstimateGas method on the client with a simulated call.

Q6: Is there a way to speed up a stuck transaction?
A6: Resubmit with a higher gas price (replace-by-fee) or cancel it by sending a zero-ETH transaction with the same nonce.