Skip to content

Commit 60dbb64

Browse files
committed
triedb/pathdb: include metadata in header section
1 parent 0dbd835 commit 60dbb64

File tree

2 files changed

+151
-64
lines changed

2 files changed

+151
-64
lines changed

triedb/pathdb/history_trienode.go

Lines changed: 76 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,20 @@ import (
3838
//
3939
// # Header
4040
// The header records metadata, including:
41-
// - the history version
41+
//
42+
// - the history version (1 byte)
43+
// - the parent state root (32 bytes)
44+
// - the current state root (32 bytes)
45+
// - block number (8 bytes)
46+
//
4247
// - a lexicographically sorted list of trie IDs
4348
// - the corresponding offsets into the key and value sections for each trie data chunk
4449
//
50+
// Although some fields (e.g., parent state root, block number) are duplicated
51+
// between the state history and the trienode history, these two histories
52+
// operate independently. To ensure each remains self-contained and self-descriptive,
53+
// we have chosen to maintain these duplicate fields.
54+
//
4555
// # Key section
4656
// The key section stores trie node keys (paths) in a compressed format.
4757
// It also contains relative offsets into the value section for resolving
@@ -60,7 +70,7 @@ import (
6070
// Header section:
6171
//
6272
// +----------+------------------+---------------------+---------------------+-------+------------------+---------------------+---------------------|
63-
// | ver (1B) | TrieID(32 bytes) | key offset(4 bytes) | val offset(4 bytes) | ... | TrieID(32 bytes) | key offset(4 bytes) | val offset(4 bytes) |
73+
// | metadata | TrieID(32 bytes) | key offset(4 bytes) | val offset(4 bytes) | ... | TrieID(32 bytes) | key offset(4 bytes) | val offset(4 bytes) |
6474
// +----------+------------------+---------------------+---------------------+-------+------------------+---------------------+---------------------|
6575
//
6676
//
@@ -103,30 +113,45 @@ import (
103113
// NOTE: All fixed-length integer are big-endian.
104114

105115
const (
106-
trienodeHistoryV0 = uint8(0) // initial version of node history structure
107-
trienodeHistoryVersion = trienodeHistoryV0 // the default node history version
108-
trienodeVersionSize = 1 // the size of version tag in the history
109-
trienodeTrieHeaderSize = 8 + common.HashLength // the size of a single trie header in history
110-
trienodeDataBlockRestartLen = 16 // The restart interval length of trie node block
116+
trienodeHistoryV0 = uint8(0) // initial version of node history structure
117+
trienodeHistoryVersion = trienodeHistoryV0 // the default node history version
118+
trienodeMetadataSize = 1 + 2*common.HashLength + 8 // the size of metadata in the history
119+
trienodeTrieHeaderSize = 8 + common.HashLength // the size of a single trie header in history
120+
trienodeDataBlockRestartLen = 16 // The restart interval length of trie node block
111121
)
112122

123+
// trienodeMetadata describes the meta data of trienode history.
124+
type trienodeMetadata struct {
125+
version uint8 // version tag of history object
126+
parent common.Hash // prev-state root before the state transition
127+
root common.Hash // post-state root after the state transition
128+
block uint64 // associated block number
129+
}
130+
113131
// trienodeHistory represents a set of trie node changes resulting from a state
114132
// transition across the main account trie and all associated storage tries.
115133
type trienodeHistory struct {
134+
meta *trienodeMetadata // Metadata of the history
116135
owners []common.Hash // List of trie identifier sorted lexicographically
117136
nodeList map[common.Hash][]string // Set of node paths sorted lexicographically
118137
nodes map[common.Hash]map[string][]byte // Set of original value of trie nodes before state transition
119138
}
120139

121140
// newTrienodeHistory constructs a trienode history with the provided trie nodes.
122-
func newTrienodeHistory(nodes map[common.Hash]map[string][]byte) *trienodeHistory {
141+
func newTrienodeHistory(root common.Hash, parent common.Hash, block uint64, nodes map[common.Hash]map[string][]byte) *trienodeHistory {
123142
nodeList := make(map[common.Hash][]string)
124143
for owner, subset := range nodes {
125144
keys := sort.StringSlice(slices.Collect(maps.Keys(subset)))
126145
keys.Sort()
127146
nodeList[owner] = keys
128147
}
129148
return &trienodeHistory{
149+
meta: &trienodeMetadata{
150+
version: trienodeHistoryVersion,
151+
parent: parent,
152+
root: root,
153+
block: block,
154+
},
130155
owners: slices.SortedFunc(maps.Keys(nodes), common.Hash.Cmp),
131156
nodeList: nodeList,
132157
nodes: nodes,
@@ -174,7 +199,10 @@ func (h *trienodeHistory) encode() ([]byte, []byte, []byte, error) {
174199
keySection bytes.Buffer
175200
valueSection bytes.Buffer
176201
)
177-
binary.Write(&headerSection, binary.BigEndian, trienodeHistoryVersion) // 1 byte
202+
binary.Write(&headerSection, binary.BigEndian, h.meta.version) // 1 byte
203+
headerSection.Write(h.meta.parent.Bytes()) // 32 bytes
204+
headerSection.Write(h.meta.root.Bytes()) // 32 bytes
205+
binary.Write(&headerSection, binary.BigEndian, h.meta.block) // 8 byte
178206

179207
for _, owner := range h.owners {
180208
// Fill the header section with offsets at key and value section
@@ -246,17 +274,21 @@ func (h *trienodeHistory) encode() ([]byte, []byte, []byte, error) {
246274

247275
// decodeHeader resolves the metadata from the header section. An error
248276
// should be returned if the header section is corrupted.
249-
func decodeHeader(data []byte) ([]common.Hash, []uint32, []uint32, error) {
250-
if len(data) < trienodeVersionSize {
251-
return nil, nil, nil, fmt.Errorf("trienode history is too small, index size: %d", len(data))
277+
func decodeHeader(data []byte) (*trienodeMetadata, []common.Hash, []uint32, []uint32, error) {
278+
if len(data) < trienodeMetadataSize {
279+
return nil, nil, nil, nil, fmt.Errorf("trienode history is too small, index size: %d", len(data))
252280
}
253281
version := data[0]
254282
if version != trienodeHistoryVersion {
255-
return nil, nil, nil, fmt.Errorf("unregonized trienode history version: %d", version)
283+
return nil, nil, nil, nil, fmt.Errorf("unregonized trienode history version: %d", version)
256284
}
257-
size := len(data) - trienodeVersionSize
285+
parent := common.BytesToHash(data[1 : common.HashLength+1]) // 32 bytes
286+
root := common.BytesToHash(data[common.HashLength+1 : common.HashLength*2+1]) // 32 bytes
287+
block := binary.BigEndian.Uint64(data[common.HashLength*2+1 : trienodeMetadataSize]) // 8 bytes
288+
289+
size := len(data) - trienodeMetadataSize
258290
if size%trienodeTrieHeaderSize != 0 {
259-
return nil, nil, nil, fmt.Errorf("truncated trienode history data, size %d", len(data))
291+
return nil, nil, nil, nil, fmt.Errorf("truncated trienode history data, size %d", len(data))
260292
}
261293
count := size / trienodeTrieHeaderSize
262294

@@ -266,17 +298,17 @@ func decodeHeader(data []byte) ([]common.Hash, []uint32, []uint32, error) {
266298
valOffsets = make([]uint32, 0, count)
267299
)
268300
for i := 0; i < count; i++ {
269-
n := trienodeVersionSize + trienodeTrieHeaderSize*i
301+
n := trienodeMetadataSize + trienodeTrieHeaderSize*i
270302
owner := common.BytesToHash(data[n : n+common.HashLength])
271303
if i != 0 && bytes.Compare(owner.Bytes(), owners[i-1].Bytes()) <= 0 {
272-
return nil, nil, nil, fmt.Errorf("trienode owners are out of order, prev: %v, cur: %v", owners[i-1], owner)
304+
return nil, nil, nil, nil, fmt.Errorf("trienode owners are out of order, prev: %v, cur: %v", owners[i-1], owner)
273305
}
274306
owners = append(owners, owner)
275307

276308
// Decode the offset to the key section
277309
keyOffset := binary.BigEndian.Uint32(data[n+common.HashLength : n+common.HashLength+4])
278310
if i != 0 && keyOffset <= keyOffsets[i-1] {
279-
return nil, nil, nil, fmt.Errorf("key offset is out of order, prev: %v, cur: %v", keyOffsets[i-1], keyOffset)
311+
return nil, nil, nil, nil, fmt.Errorf("key offset is out of order, prev: %v, cur: %v", keyOffsets[i-1], keyOffset)
280312
}
281313
keyOffsets = append(keyOffsets, keyOffset)
282314

@@ -285,11 +317,16 @@ func decodeHeader(data []byte) ([]common.Hash, []uint32, []uint32, error) {
285317
// a trie deletion).
286318
valOffset := binary.BigEndian.Uint32(data[n+common.HashLength+4 : n+common.HashLength+8])
287319
if i != 0 && valOffset < valOffsets[i-1] {
288-
return nil, nil, nil, fmt.Errorf("value offset is out of order, prev: %v, cur: %v", valOffsets[i-1], valOffset)
320+
return nil, nil, nil, nil, fmt.Errorf("value offset is out of order, prev: %v, cur: %v", valOffsets[i-1], valOffset)
289321
}
290322
valOffsets = append(valOffsets, valOffset)
291323
}
292-
return owners, keyOffsets, valOffsets, nil
324+
return &trienodeMetadata{
325+
version: version,
326+
parent: parent,
327+
root: root,
328+
block: block,
329+
}, owners, keyOffsets, valOffsets, nil
293330
}
294331

295332
func decodeSingle(keySection []byte, onValue func([]byte, int, int) error) ([]string, error) {
@@ -425,10 +462,11 @@ func decodeSingleWithValue(keySection []byte, valueSection []byte) ([]string, ma
425462

426463
// decode deserializes the contained trie nodes from the provided bytes.
427464
func (h *trienodeHistory) decode(header []byte, keySection []byte, valueSection []byte) error {
428-
owners, keyOffsets, valueOffsets, err := decodeHeader(header)
465+
metadata, owners, keyOffsets, valueOffsets, err := decodeHeader(header)
429466
if err != nil {
430467
return err
431468
}
469+
h.meta = metadata
432470
h.owners = owners
433471
h.nodeList = make(map[common.Hash][]string)
434472
h.nodes = make(map[common.Hash]map[string][]byte)
@@ -562,13 +600,13 @@ func newTrienodeHistoryReader(id uint64, reader ethdb.AncientReader) (*trienodeH
562600
return r, nil
563601
}
564602

565-
// decodeHeader decodes the metadata of trienode history from the header section.
603+
// decodeHeader decodes the header section of trienode history.
566604
func (r *trienodeHistoryReader) decodeHeader() error {
567605
header, err := rawdb.ReadTrienodeHistoryHeader(r.reader, r.id)
568606
if err != nil {
569607
return err
570608
}
571-
owners, keyOffsets, valOffsets, err := decodeHeader(header)
609+
_, owners, keyOffsets, valOffsets, err := decodeHeader(header)
572610
if err != nil {
573611
return err
574612
}
@@ -626,7 +664,7 @@ func (r *trienodeHistoryReader) read(owner common.Hash, path string) ([]byte, er
626664
// nolint:unused
627665
func writeTrienodeHistory(writer ethdb.AncientWriter, dl *diffLayer) error {
628666
start := time.Now()
629-
h := newTrienodeHistory(dl.nodes.nodeOrigin)
667+
h := newTrienodeHistory(dl.rootHash(), dl.parent.rootHash(), dl.block, dl.nodes.nodeOrigin)
630668
header, keySection, valueSection, err := h.encode()
631669
if err != nil {
632670
return err
@@ -649,6 +687,20 @@ func writeTrienodeHistory(writer ethdb.AncientWriter, dl *diffLayer) error {
649687
return nil
650688
}
651689

690+
// readTrienodeMetadata resolves the metadata of the specified trienode history.
691+
// nolint:unused
692+
func readTrienodeMetadata(reader ethdb.AncientReader, id uint64) (*trienodeMetadata, error) {
693+
header, err := rawdb.ReadTrienodeHistoryHeader(reader, id)
694+
if err != nil {
695+
return nil, err
696+
}
697+
metadata, _, _, _, err := decodeHeader(header)
698+
if err != nil {
699+
return nil, err
700+
}
701+
return metadata, nil
702+
}
703+
652704
// readTrienodeHistory resolves a single trienode history object with specific id.
653705
func readTrienodeHistory(reader ethdb.AncientReader, id uint64) (*trienodeHistory, error) {
654706
header, keySection, valueSection, err := rawdb.ReadTrienodeHistory(reader, id)

0 commit comments

Comments
 (0)