@@ -22,7 +22,6 @@ import (
2222 "fmt"
2323 "iter"
2424 "maps"
25- "math"
2625 "slices"
2726 "sort"
2827 "time"
@@ -202,17 +201,6 @@ func (h *trienodeHistory) encode() ([]byte, []byte, []byte, error) {
202201 binary .Write (& headerSection , binary .BigEndian , h .meta .block ) // 8 byte
203202
204203 for _ , owner := range h .owners {
205- // Fill the header section with offsets at key and value section
206- headerSection .Write (owner .Bytes ()) // 32 bytes
207- binary .Write (& headerSection , binary .BigEndian , uint32 (keySection .Len ())) // 4 bytes
208-
209- // The offset to the value section is theoretically unnecessary, since the
210- // individual value offset is already tracked in the key section. However,
211- // we still keep it here for two reasons:
212- // - It's cheap to store (only 4 bytes for each trie).
213- // - It can be useful for decoding the trie data when key is not required (e.g., in hash mode).
214- binary .Write (& headerSection , binary .BigEndian , uint32 (valueSection .Len ())) // 4 bytes
215-
216204 // Fill the key section with node index
217205 var (
218206 prevKey []byte
@@ -266,6 +254,21 @@ func (h *trienodeHistory) encode() ([]byte, []byte, []byte, error) {
266254 if _ , err := keySection .Write (trailer ); err != nil {
267255 return nil , nil , nil , err
268256 }
257+
258+ // Fill the header section with the offsets of the key and value sections.
259+ // Note that the key/value offsets are intentionally tracked *after* encoding
260+ // them into their respective sections, ensuring each offset refers to the end
261+ // position. For n trie chunks, n offset pairs are sufficient to uniquely locate
262+ // the corresponding data.
263+ headerSection .Write (owner .Bytes ()) // 32 bytes
264+ binary .Write (& headerSection , binary .BigEndian , uint32 (keySection .Len ())) // 4 bytes
265+
266+ // The offset to the value section is theoretically unnecessary, since the
267+ // individual value offset is already tracked in the key section. However,
268+ // we still keep it here for two reasons:
269+ // - It's cheap to store (only 4 bytes for each trie).
270+ // - It can be useful for decoding the trie data when key is not required (e.g., in hash mode).
271+ binary .Write (& headerSection , binary .BigEndian , uint32 (valueSection .Len ())) // 4 bytes
269272 }
270273 return headerSection .Bytes (), keySection .Bytes (), valueSection .Bytes (), nil
271274}
@@ -475,22 +478,22 @@ func (h *trienodeHistory) decode(header []byte, keySection []byte, valueSection
475478
476479 for i := range len (owners ) {
477480 // Resolve the boundary of key section
478- keyStart := keyOffsets [i ]
479- keyLimit := len (keySection )
480- if i != len (owners )- 1 {
481- keyLimit = int (keyOffsets [i + 1 ])
481+ var keyStart , keyLimit uint32
482+ if i != 0 {
483+ keyStart = keyOffsets [i - 1 ]
482484 }
483- if int (keyStart ) > len (keySection ) || keyLimit > len (keySection ) {
485+ keyLimit = keyOffsets [i ]
486+ if int (keyStart ) > len (keySection ) || int (keyLimit ) > len (keySection ) {
484487 return fmt .Errorf ("invalid key offsets: keyStart: %d, keyLimit: %d, size: %d" , keyStart , keyLimit , len (keySection ))
485488 }
486489
487490 // Resolve the boundary of value section
488- valStart := valueOffsets [i ]
489- valLimit := len (valueSection )
490- if i != len (owners )- 1 {
491- valLimit = int (valueOffsets [i + 1 ])
491+ var valStart , valLimit uint32
492+ if i != 0 {
493+ valStart = valueOffsets [i - 1 ]
492494 }
493- if int (valStart ) > len (valueSection ) || valLimit > len (valueSection ) {
495+ valLimit = valueOffsets [i ]
496+ if int (valStart ) > len (valueSection ) || int (valLimit ) > len (valueSection ) {
494497 return fmt .Errorf ("invalid value offsets: valueStart: %d, valueLimit: %d, size: %d" , valStart , valLimit , len (valueSection ))
495498 }
496499
@@ -510,33 +513,27 @@ type iRange struct {
510513 limit uint32
511514}
512515
516+ func (ir iRange ) len () uint32 {
517+ return ir .limit - ir .start
518+ }
519+
513520// singleTrienodeHistoryReader provides read access to a single trie within the
514521// trienode history. It stores an offset to the trie's position in the history,
515522// along with a set of per-node offsets that can be resolved on demand.
516523type singleTrienodeHistoryReader struct {
517524 id uint64
518525 reader ethdb.AncientReader
519- valueRange iRange // value range within the total value section
526+ valueRange iRange // value range within the global value section
520527 valueInternalOffsets map [string ]iRange // value offset within the single trie data
521528}
522529
523530func newSingleTrienodeHistoryReader (id uint64 , reader ethdb.AncientReader , keyRange iRange , valueRange iRange ) (* singleTrienodeHistoryReader , error ) {
524- // TODO(rjl493456442) partial freezer read should be supported
525- keyData , err := rawdb .ReadTrienodeHistoryKeySection (reader , id )
531+ keyData , err := rawdb .ReadTrienodeHistoryKeySection (reader , id , uint64 (keyRange .start ), uint64 (keyRange .len ()))
526532 if err != nil {
527533 return nil , err
528534 }
529- keyStart := int (keyRange .start )
530- keyLimit := int (keyRange .limit )
531- if keyRange .limit == math .MaxUint32 {
532- keyLimit = len (keyData )
533- }
534- if len (keyData ) < keyStart || len (keyData ) < keyLimit {
535- return nil , fmt .Errorf ("key section too short, start: %d, limit: %d, size: %d" , keyStart , keyLimit , len (keyData ))
536- }
537-
538535 valueOffsets := make (map [string ]iRange )
539- _ , err = decodeSingle (keyData [ keyStart : keyLimit ] , func (key []byte , start int , limit int ) error {
536+ _ , err = decodeSingle (keyData , func (key []byte , start int , limit int ) error {
540537 valueOffsets [string (key )] = iRange {
541538 start : uint32 (start ),
542539 limit : uint32 (limit ),
@@ -560,20 +557,7 @@ func (sr *singleTrienodeHistoryReader) read(path string) ([]byte, error) {
560557 if ! exists {
561558 return nil , fmt .Errorf ("trienode %v not found" , []byte (path ))
562559 }
563- // TODO(rjl493456442) partial freezer read should be supported
564- valueData , err := rawdb .ReadTrienodeHistoryValueSection (sr .reader , sr .id )
565- if err != nil {
566- return nil , err
567- }
568- if len (valueData ) < int (sr .valueRange .start ) {
569- return nil , fmt .Errorf ("value section too short, start: %d, size: %d" , sr .valueRange .start , len (valueData ))
570- }
571- entryStart := sr .valueRange .start + offset .start
572- entryLimit := sr .valueRange .start + offset .limit
573- if len (valueData ) < int (entryStart ) || len (valueData ) < int (entryLimit ) {
574- return nil , fmt .Errorf ("value section too short, start: %d, limit: %d, size: %d" , entryStart , entryLimit , len (valueData ))
575- }
576- return valueData [int (entryStart ):int (entryLimit )], nil
560+ return rawdb .ReadTrienodeHistoryValueSection (sr .reader , sr .id , uint64 (sr .valueRange .start + offset .start ), uint64 (offset .len ()))
577561}
578562
579563// trienodeHistoryReader provides read access to node data in the trie node history.
@@ -614,27 +598,23 @@ func (r *trienodeHistoryReader) decodeHeader() error {
614598 }
615599 for i , owner := range owners {
616600 // Decode the key range for this trie chunk
617- var keyLimit uint32
618- if i == len (owners )- 1 {
619- keyLimit = math .MaxUint32
620- } else {
621- keyLimit = keyOffsets [i + 1 ]
601+ var keyStart uint32
602+ if i != 0 {
603+ keyStart = keyOffsets [i - 1 ]
622604 }
623605 r .keyRanges [owner ] = iRange {
624- start : keyOffsets [ i ] ,
625- limit : keyLimit ,
606+ start : keyStart ,
607+ limit : keyOffsets [ i ] ,
626608 }
627609
628610 // Decode the value range for this trie chunk
629- var valLimit uint32
630- if i == len (owners )- 1 {
631- valLimit = math .MaxUint32
632- } else {
633- valLimit = valOffsets [i + 1 ]
611+ var valStart uint32
612+ if i != 0 {
613+ valStart = valOffsets [i - 1 ]
634614 }
635615 r .valRanges [owner ] = iRange {
636- start : valOffsets [ i ] ,
637- limit : valLimit ,
616+ start : valStart ,
617+ limit : valOffsets [ i ] ,
638618 }
639619 }
640620 return nil
0 commit comments