Retrieving the From Field in Ethereum Transactions with Go-Ethereum

·

go-ethereum version: v1.12.2

Ethereum's continuous evolution brings protocol upgrades, impacting how developers interact with the blockchain. If you've consulted resources like "Ethereum Development with Go", you may notice that older code snippets for retrieving the sender (From) field in transactions no longer work. This guide demonstrates the updated approach for the latest go-ethereum client.

Prerequisites


Step 1: Fetching a Block

To access transactions, start by retrieving a block object:

package main
import (
  "context"
  "fmt"
  "github.com/ethereum/go-ethereum/ethclient"
  "log"
  "math/big"
)
func main() {
  ethereumNodeEndpoint := "https://cloudflare-eth.com"
  client, err := ethclient.Dial(ethereumNodeEndpoint)
  if err != nil {
    log.Fatalf("Failed to connect to Ethereum node [%s]: %s", ethereumNodeEndpoint, err)
  }
  ctx := context.TODO()
  latestBlockNumber, err := client.BlockNumber(ctx)
  if err != nil {
    log.Fatal("Failed to fetch latest block number: ", err)
  }
  fmt.Println("Latest block height:", latestBlockNumber)
  block, err := client.BlockByNumber(ctx, big.NewInt(int64(latestBlockNumber)))
  if err != nil {
    log.Fatal("Failed to fetch block: ", err)
  }
  fmt.Println("Block hash:", block.Hash().Hex())
  fmt.Println("Transaction count:", len(block.Transactions()))
}

Output:

Latest block height: 18054718
Block hash: 0xe1122f17b2d7e9f717bdedb7062cf0a2f44b3199e702754b97f9a5832622a87a
Transaction count: 226

Step 2: Extracting Transactions

Once you have the block, inspect its transactions:

tx := block.Transactions()[1]
fmt.Println("Transaction hash:", tx.Hash().Hex())
fmt.Println("Value:", tx.Value().String(), "wei")
fmt.Println("Gas limit:", tx.Gas())
fmt.Println("Gas price:", tx.GasPrice().Uint64())
fmt.Println("Recipient address:", tx.To().Hex())

Output:

Transaction hash: 0xb9ac9b6a4eb857cfd410d0f3dc5604c5e52382e490acd00a14f9cf69c59391b0
Value: 10000000000000000 wei
Gas limit: 274920
Gas price: 59204457483
Recipient address: 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D

Step 3: Deriving the Sender (From) Field

The From field isn't stored directly in the transaction—it’s derived from the signature. Use a signer to decode it:

signer := types.MakeSigner(params.MainnetChainConfig, block.Number(), block.Time())
from, err := signer.Sender(tx)
if err != nil {
  log.Fatal("Failed to derive sender: ", err)
}
fmt.Println("Sender address:", from.Hex())

Output:

Sender address: 0xCe1a934f373fb7355aFa2895d411A80e38384703

Key Notes:


Complete Code Example

package main
import (
  "context"
  "fmt"
  "github.com/ethereum/go-ethereum/core/types"
  "github.com/ethereum/go-ethereum/ethclient"
  "github.com/ethereum/go-ethereum/params"
  "log"
  "math/big"
)
func main() {
  ethereumNodeEndpoint := "https://cloudflare-eth.com"
  client, err := ethclient.Dial(ethereumNodeEndpoint)
  if err != nil {
    log.Fatalf("Connection error: %s", err)
  }
  ctx := context.TODO()
  latestBlockNumber, err := client.BlockNumber(ctx)
  if err != nil {
    log.Fatal("Block number error: ", err)
  }
  block, err := client.BlockByNumber(ctx, big.NewInt(int64(latestBlockNumber)))
  if err != nil {
    log.Fatal("Block fetch error: ", err)
  }
  tx := block.Transactions()[1]
  fmt.Println("Transaction details:")
  fmt.Println("Hash:", tx.Hash().Hex())
  fmt.Println("Value:", tx.Value().String(), "wei")
  fmt.Println("Recipient:", tx.To().Hex())
  signer := types.MakeSigner(params.MainnetChainConfig, block.Number(), block.Time())
  from, err := signer.Sender(tx)
  if err != nil {
    log.Fatal("Sender derivation error:", err)
  }
  fmt.Println("Sender:", from.Hex())
}

FAQ

Q1: Why isn’t the From field stored directly in Ethereum transactions?

A1: Storing From explicitly would bloat the blockchain. Instead, it’s computed from the signature to save space.

Q2: Can I use this method for testnets like Sepolia?

A2: Yes! Replace params.MainnetChainConfig with the testnet’s configuration (e.g., params.SepoliaChainConfig).

Q3: What if my transaction lacks a To address?

A3: A missing To field indicates a contract creation transaction.


Advanced Topics

👉 Explore Ethereum’s transaction lifecycle
👉 Deep dive into EIP-1559 fee mechanics

For further reading:


Conclusion