Ethereum Block Structure and Core Types

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

Tags: ether eip Blockchain Golang merkle-tree

Posted on Tue, 20 Oct 2026 16:57:35 +0000 by sometimes