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:
TheSignTx
function is located in thetypes
package, notcrypto
. EIP155 signers adjust thev
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.