Package core/types contains the consensus-layer data structures used throughout go-ethereum. You will interact with these types whenever you read from the chain or construct transactions.
import "github.com/ethereum/go-ethereum/core/types"
Block
Block is immutable after construction. Header data is returned as a copy to protect internal caches.
type Block struct { /* unexported */ }
Accessor methods:
func (b *Block) Number() *big.Int // block number
func (b *Block) Hash() common.Hash // keccak256 of the RLP-encoded header
func (b *Block) Time() uint64 // Unix timestamp
func (b *Block) GasLimit() uint64 // maximum gas per block
func (b *Block) GasUsed() uint64 // gas consumed by all transactions
func (b *Block) BaseFee() *big.Int // EIP-1559 base fee (nil for pre-London blocks)
func (b *Block) Difficulty() *big.Int // PoW difficulty (zero post-merge)
func (b *Block) Coinbase() common.Address // fee recipient
func (b *Block) Root() common.Hash // state trie root
func (b *Block) TxHash() common.Hash // transactions trie root
func (b *Block) ReceiptHash() common.Hash // receipts trie root
func (b *Block) ParentHash() common.Hash // hash of the parent block
func (b *Block) Extra() []byte // extra data field
func (b *Block) Transactions() Transactions // ordered list of transactions
func (b *Block) Uncles() []*Header // uncle headers (PoW era)
func (b *Block) Withdrawals() Withdrawals // EIP-4895 validator withdrawals
func (b *Block) Header() *Header // copy of the header
func (b *Block) Body() *Body // transactions, uncles, withdrawals
func (b *Block) NumberU64() uint64 // block number as uint64
Iterating transactions in a block
block, err := client.BlockByNumber(ctx, nil) // latest
for _, tx := range block.Transactions() {
fmt.Printf("%s gas=%d\n", tx.Hash().Hex(), tx.Gas())
}
Header holds all block metadata and is cheaper to fetch than a full Block.
type Header struct {
ParentHash common.Hash
UncleHash common.Hash
Coinbase common.Address
Root common.Hash // state root
TxHash common.Hash // transactions root
ReceiptHash common.Hash // receipts root
Bloom Bloom
Difficulty *big.Int
Number *big.Int
GasLimit uint64
GasUsed uint64
Time uint64
Extra []byte
MixDigest common.Hash
Nonce BlockNonce
// EIP-1559 (London)
BaseFee *big.Int
// EIP-4895 (Shanghai)
WithdrawalsHash *common.Hash
// EIP-4844 (Cancun)
BlobGasUsed *uint64
ExcessBlobGas *uint64
// EIP-4788 (Cancun)
ParentBeaconRoot *common.Hash
// EIP-7685 (Prague)
RequestsHash *common.Hash
}
func (h *Header) Hash() common.Hash
Transaction
Transaction types
| Constant | Type ID | EIP | Description |
|---|
LegacyTxType | 0x00 | pre-EIP-2718 | gasPrice-based |
AccessListTxType | 0x01 | EIP-2930 | adds accessList |
DynamicFeeTxType | 0x02 | EIP-1559 | maxFeePerGas + maxPriorityFeePerGas |
BlobTxType | 0x03 | EIP-4844 | blob-carrying transactions |
SetCodeTxType | 0x04 | EIP-7702 | code delegation |
Creating transactions
EIP-1559 (recommended)
EIP-2930 (access list)
Legacy
tx := types.NewTx(&types.DynamicFeeTx{
ChainID: chainID,
Nonce: nonce,
GasTipCap: tip, // maxPriorityFeePerGas
GasFeeCap: feeCap, // maxFeePerGas
Gas: 21000,
To: &recipient,
Value: big.NewInt(1e18),
Data: nil,
})
tx := types.NewTx(&types.AccessListTx{
ChainID: chainID,
Nonce: nonce,
GasPrice: gasPrice,
Gas: gasLimit,
To: &recipient,
Value: value,
Data: data,
AccessList: accessList,
})
// NewTransaction is the legacy constructor
tx := types.NewTransaction(
nonce,
recipient, // common.Address
amount, // *big.Int (wei)
gasLimit, // uint64
gasPrice, // *big.Int
data, // []byte
)
Signing a transaction
func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, error)
Use types.LatestSignerForChainID when you know the chain ID but not the specific fork:
signer := types.LatestSignerForChainID(chainID)
signedTx, err := types.SignTx(tx, signer, privateKey)
Or use types.MakeSigner when you have both the chain config and current block number.
Transaction accessor methods
func (tx *Transaction) Hash() common.Hash // transaction hash
func (tx *Transaction) Type() uint8 // LegacyTxType, DynamicFeeTxType, etc.
func (tx *Transaction) To() *common.Address // nil for contract-creation transactions
func (tx *Transaction) Value() *big.Int // wei amount
func (tx *Transaction) Gas() uint64 // gas limit
func (tx *Transaction) GasPrice() *big.Int // legacy gas price
func (tx *Transaction) GasFeeCap() *big.Int // EIP-1559 maxFeePerGas
func (tx *Transaction) GasTipCap() *big.Int // EIP-1559 maxPriorityFeePerGas
func (tx *Transaction) Data() []byte // input data / calldata
func (tx *Transaction) Nonce() uint64 // sender nonce
func (tx *Transaction) ChainId() *big.Int // EIP-155 chain ID
func (tx *Transaction) AccessList() AccessList
func (tx *Transaction) Cost() *big.Int // gas*gasPrice + blobGas*blobGasPrice + value
Receipt
A receipt is created after a transaction is mined and records its outcome.
type Receipt struct {
// Consensus fields
Type uint8 // transaction type
PostState []byte // pre-Byzantium: state root after the tx
Status uint64 // 1 = success, 0 = failure (post-Byzantium)
CumulativeGasUsed uint64 // gas used up to and including this tx in the block
Bloom Bloom // logs bloom filter
Logs []*Log // events emitted by this transaction
// Implementation fields (added by the node)
TxHash common.Hash // transaction hash
ContractAddress common.Address // non-zero for contract-creation transactions
GasUsed uint64 // gas used by this transaction alone
EffectiveGasPrice *big.Int // actual gas price paid
BlobGasUsed uint64 // EIP-4844
BlobGasPrice *big.Int // EIP-4844
// Inclusion metadata
BlockHash common.Hash
BlockNumber *big.Int
TransactionIndex uint
}
const (
ReceiptStatusFailed = uint64(0)
ReceiptStatusSuccessful = uint64(1)
)
receipt, err := client.TransactionReceipt(ctx, txHash)
if err != nil {
log.Fatal(err)
}
if receipt.Status == types.ReceiptStatusSuccessful {
fmt.Println("transaction succeeded, gas used:", receipt.GasUsed)
} else {
fmt.Println("transaction reverted")
}
// Contract address (if this was a deployment)
if receipt.ContractAddress != (common.Address{}) {
fmt.Println("deployed to:", receipt.ContractAddress.Hex())
}
Log
Logs are produced by the EVM LOG opcode (Solidity emit).
type Log struct {
// Consensus fields
Address common.Address // contract that emitted the log
Topics []common.Hash // indexed parameters (first topic = event ID)
Data []byte // ABI-encoded non-indexed parameters
// Derived fields (not part of consensus)
BlockNumber uint64
TxHash common.Hash
TxIndex uint
BlockHash common.Hash
BlockTimestamp uint64
Index uint // log index within the block
// Removed is true when the log was part of a re-orged-out block
Removed bool
}
Always check log.Removed when receiving logs via a subscription. A true value means the log was reverted by a chain reorganisation and should be treated as if it never happened.
Reading logs
query := ethereum.FilterQuery{
Addresses: []common.Address{contractAddress},
Topics: [][]common.Hash{
{transferEventID}, // first topic = event selector
},
FromBlock: big.NewInt(20_000_000),
ToBlock: nil, // latest
}
logs, err := client.FilterLogs(ctx, query)
for _, l := range logs {
if l.Removed {
continue
}
fmt.Printf("block %d tx %s topics: %v\n",
l.BlockNumber, l.TxHash.Hex(), l.Topics)
}