Understanding block data structures is fundamental to grasping blockchain systems. In Ethereum’s go-ethereum implementation, the core block types are defined in core/types/block.go.
The Block Structure The main block structure encapsulates all components of a block:
type Block struct {
header *Header
uncles []*Header
transactions Transactions
withdrawals Withdrawals
hash atomic.Value
size atomic.Value
ReceivedAt time.Time
ReceivedFrom interface{}
}
This declaration follows Go’s syntax: field names come first, followed by types. Let’s examine each component:
| Field | Description |
|---|---|
header |
Pointer to the block header containing metadata |
uncles |
List of uncle block headers |
transactions |
Ordered list of transactions included in the block |
withdrawals |
List of withdrawal requests processed in this block |
hash |
Cached instance for the block’s Keccak256 hash |
size |
Cached serialized size (RLP-encoded bytes) |
ReceivedAt |
Timestamp of when the node first received the block |
ReceivedFrom |
Network peer or source from which the block originated |
The Header Structure The block header is the metadata anchor, containing references to merkle roots and consensus parameters:
type Header struct {
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
Coinbase common.Address `json:"miner"`
Root common.Hash `json:"stateRoot" gencodec:"required"`
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
Bloom Bloom `json:"logsBloom" gencodec:"required"`
Difficulty *big.Int `json:"difficulty" gencodec:"required"`
Number *big.Int `json:"number" gencodec:"required"`
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
Time uint64 `json:"timestamp" gencodec:"required"`
Extra []byte `json:"extraData" gencodec:"required"`
MixDigest common.Hash `json:"mixHash"`
Nonce BlockNonce `json:"nonce"`
BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"`
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
BlobGasUsed *uint64 `json:"blobGasUsed" rlp:"optional"`
ExcessBlobGas *uint64 `json:"excessBlobGas" rlp:"optional"`
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
}
| Field | Description |
|---|---|
ParentHash |
Keccak hash of the previous block’s header |
UncleHash |
Keccak hash of the OM merkle root for uncles |
Coinbase |
Beneficiary address of block rewards |
Root |
State trie root hash |
TxHash |
Transactions trie root |
ReceiptHash |
Receipts trie root |
Bloom |
Bloom filter for log event indexing |
Difficulty |
PoW difficultytarget; zero post-merge |
Number |
Block height (chain index) |
GasLimit |
Maximum gas allowed in the block |
GasUsed |
Total gas consumed by transactions |
Time |
Unix timestamp of block production |
Extra |
Arbitrary metadata (often contains miner signature) |
MixDigest |
PoW mix hash (used with nonce for verification) |
Nonce |
64-bit proof-of-work nonce |
BaseFee |
EIP-1559 base fee per gas; ignored pre-London |
WithdrawalsHash |
EIP-4895 withdrawal root; post-Shanghai |
BlobGasUsed |
EIP-4844 blob gas consumed; post-Cancun |
ExcessBlobGas |
Cumulative blob gas limit for fee calculasions |
ParentBeaconRoot |
EIP-4788 parent beacon block root; post-Consensus Layer sync |
The Body and extblock Structures The body separates the block contents from the header:
type Body struct {
Transactions []*Transaction
Uncles []*Header
Withdrawals []*Withdrawal `rlp:"optional"`
}
For external API or JSON exposure, Ethereum uses extblock to group components:
type extblock struct {
Header *Header
Txs []*Transaction
Uncles []*Header
Withdrawals []*Withdrawal `rlp:"optional"`
}
Non-Canonical Header Marshaling To support JSON serialization, headerMarshaling provides a readable format:
type headerMarshaling struct {
Difficulty *hexutil.Big
Number *hexutil.Big
GasLimit hexutil.Uint64
GasUsed hexutil.Uint64
Time hexutil.Uint64
Extra hexutil.Bytes
BaseFee *hexutil.Big
Hash common.Hash `json:"hash"`
BlobGasUsed *hexutil.Uint64
ExcessBlobGas *hexutil.Uint64
}
This enables clean encoding/decoding over HTTP APIs, converting raw types to human-readable hex notation.
BlockNonce and Nonce Handling Ase nonce is defined:
type BlockNonce [8]byte
Supporting conversion and encoding:
func (n BlockNonce) Uint64() uint64 {
return binary.BigEndian.Uint64(n[:])
}
For fullhearted compatibility with JSON and RLP, custom marshaling methods are implemented:
func (n BlockNonce) MarshalText() ([]byte, error) {
return []byte(`0x` + hex.EncodeToString(n[:])), nil
}
func (n *BlockNonce) UnmarshalText(input []byte) error {
_, err := hex.Decode(n[:], input[2:]) // skip "0x"
return err
}
Block Construction and Deep Copy Utility functions construct blocks from inputs and ensure immutability:
func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt, hasher TrieHasher) *Block {
b := &Block{header: CopyHeader(header)}
if len(txs) == 0 {
b.header.TxHash = EmptyTxsHash
} else {
b.header.TxHash = DeriveSha(Transactions(txs), hasher)
b.transactions = make(Transactions, len(txs))
copy(b.transactions, txs)
}
if len(receipts) == 0 {
b.header.ReceiptHash = EmptyReceiptsHash
} else {
b.header.ReceiptHash = DeriveSha(Receipts(receipts), hasher)
b.header.Bloom = CreateBloom(receipts)
}
if len(uncles) == 0 {
b.header.UncleHash = EmptyUncleHash
} else {
b.header.UncleHash = CalcUncleHash(uncles)
b.uncles = make([]*Header, len(uncles))
for i := range uncles {
b.uncles[i] = CopyHeader(uncles[i])
}
}
return b
}
The CopyHeader function recursively duplicates large value types like *big.Int, slices, and nested pointers:
func CopyHeader(h *Header) *Header {
cpy := *h
if h.Difficulty != nil {
cpy.Difficulty = new(big.Int).Set(h.Difficulty)
}
if h.Number != nil {
cpy.Number = new(big.Int).Set(h.Number)
}
if h.BaseFee != nil {
cpy.BaseFee = new(big.Int).Set(h.BaseFee)
}
if len(h.Extra) > 0 {
cpy.Extra = make([]byte, len(h.Extra))
copy(cpy.Extra, h.Extra)
}
if h.WithdrawalsHash != nil {
cpy.WithdrawalsHash = new(common.Hash)
*cpy.WithdrawalsHash = *h.WithdrawalsHash
}
// ... similar deep copies for optional EIP fields
return &cpy
}
Additional Methods and Utilities Key convenience functions include:
| Function | Behavior |
|---|---|
EncodeNonce(uint64) BlockNonce |
Converts a uint64 to big-endian BlockNonce |
BlockNonce.Uint64() |
Parses the BlockNonce as uint64 |
Header.Hash() |
Computes the Keccak256 digest of the header |
Header.Size() |
Estimates memory footprint in bytes |
Header.SanityCheck() |
Validates字段 consistency and ranges |
Block.EncodeRLP()/DecodeRLP() |
Implements RLP serialization for network transport |