@@ -32,6 +32,10 @@ type UpdateLatestResult struct {
3232 UpdatedSegment * ChainSegment
3333}
3434
35+ // capNumPollBlocks is a pipeline function
36+ // that restricts the number of blocks to be
37+ // polled, e.g. during filling gaps between
38+ // two chain-segments.
3539func capNumPollBlocks (num int ) int {
3640 if num > MaxNumPollBlocks {
3741 return MaxNumPollBlocks
@@ -45,8 +49,6 @@ type ChainSegment struct {
4549 chain []* types.Header
4650}
4751
48- // assumes reverse order, and that it is
49- // a connected chain-segment.
5052func NewChainSegment (chain ... * types.Header ) * ChainSegment {
5153 bc := & ChainSegment {
5254 chain : chain ,
@@ -91,16 +93,31 @@ func (bc *ChainSegment) Copy() *ChainSegment {
9193 return NewChainSegment (bc .chain ... )
9294}
9395
96+ // UpdateLatest incorporates a new chainsegment `update` into it's existing
97+ // chain-segment.
98+ // For this it backtracks the new chain-segment until it finds the common ancestor
99+ // with it's current chain-segment. If there is no ancestor because of a block-number
100+ // gap between the old segments "latest" block and the new segments "earliest" block,
101+ // it will incrementally batch-augment the 'update' chain-segment with blocks older than
102+ // it's "earliest" block, and call the UpdateLatest latest method recursively
103+ // until the algorithm finds a common ancestor.
104+ // The outcome of this process is an `UpdateLatestResult`, which
105+ // communicates to the caller what part of the previous chain-segment had to be removed,
106+ // and what part of the `update` chain-segment was appended to the previous chain-segment
107+ // after removal of out-of-date blocks, in addition to the full newly updated chain-segment.
108+ // This is a pointer method that updates the internal state of it's chain-segment!
94109func (bc * ChainSegment ) UpdateLatest (ctx context.Context , c client.Sync , update * ChainSegment ) (UpdateLatestResult , error ) {
95110 update = update .Copy ()
96111 if bc .Len () == 0 {
112+ // We can't compare anything - instead of silently absorbing the
113+ // whole new segment, communicate this to the caller with a specific error.
97114 return UpdateLatestResult {}, ErrEmpty
98115 }
99116
100117 if bc .Earliest ().Number .Cmp (update .Earliest ().Number ) == 1 {
101- // We don't reach so far in the past.
102- // This only happens when the cache of used blocks in
103- // doesn't reach so far .
118+ // We don't reach so far in the past for the old chain-segment .
119+ // This happens when there is a large reorg, while the chain-segment
120+ // of the cache is still small .
104121 return UpdateLatestResult {}, fmt .Errorf (
105122 "segment earliest=%d, update earliest=%d: %w" ,
106123 bc .Earliest ().Number .Int64 (), update .Earliest ().Number .Int64 (),
@@ -143,12 +160,22 @@ func (bc *ChainSegment) UpdateLatest(ctx context.Context, c client.Sync, update
143160 return bc .UpdateLatest (ctx , c , update )
144161 }
145162 // implicit case - overlap > 0:
163+ // now we can compare the segments and find the common ancestor
164+ // Return the segment of the overlap from the current segment
165+ // and compute the diff of the whole new update segment.
146166 removed , updated := bc .GetLatest (overlap ).DiffLeftAligned (update )
167+ // don't copy, but use the method's struct,
168+ // that way we modify in-place
147169 full := bc
148170 if removed != nil {
171+ // cut the reorged section that has to be removed
172+ // so that we only have the "left" section up until the
173+ // common ancestor
149174 full = full .GetEarliest (full .Len () - removed .Len ())
150175 }
151176 if updated != nil {
177+ // and now append the update section
178+ // to the right, effectively removing the reorged section
152179 full .AddRight (updated )
153180 }
154181 return UpdateLatestResult {
@@ -158,11 +185,28 @@ func (bc *ChainSegment) UpdateLatest(ctx context.Context, c client.Sync, update
158185 }, nil
159186}
160187
188+ // AddRight adds the `add` chain-segment to the "right" of the
189+ // original chain-segment, and thus assumes that the `add` segments
190+ // Earliest() block is the child-block of the original segments
191+ // Latest() block. This condition is *not* checked,
192+ // so callers have to guarantee for it.
161193func (bc * ChainSegment ) AddRight (add * ChainSegment ) * ChainSegment {
162194 bc .chain = append (bc .chain , add .chain ... )
163195 return bc
164196}
165197
198+ // DiffLeftAligned compares the ChainSegment to another chain-segment that
199+ // starts at the same Earliest() block-number.
200+ // It walks both segments from earliest to latest header simultaneously
201+ // and compares the block-hashes. As soon as there is a mismatch
202+ // in block-hashes, a consecutive difference from that point on is assumed.
203+ // All diff blocks from the `other` chain-segment will be appended to the returned `update`
204+ // chain-segment, and all diff blocks from the original chain-segment
205+ // will be appended to the `remove` chain-segment.
206+ // If there is no overlap in the diff, but the `other` chain-segment is longer than
207+ // the original segment, the `remove` segment will be nil, and the `update` segment
208+ // will consist of the non-overlapping blocks of the `other` segment.
209+ // If both segments are identical, both `update` and `remove` segments will be nil.
166210func (bc * ChainSegment ) DiffLeftAligned (other * ChainSegment ) (remove , update * ChainSegment ) {
167211 // 1) assumes both segments start at the same block height (earliest block at index 0 with same blocknum)
168212 // 2) assumes the other.Len() >= bc.Len()
0 commit comments