@@ -130,6 +130,7 @@ func (hc *HeaderChain) GetBlockNumber(hash common.Hash) *uint64 {
130130}
131131
132132type headerWriteResult struct {
133+ status WriteStatus
133134 ignored int
134135 imported int
135136 lastHash common.Hash
@@ -145,7 +146,7 @@ type headerWriteResult struct {
145146// without the real blocks. Hence, writing headers directly should only be done
146147// in two scenarios: pure-header mode of operation (light clients), or properly
147148// separated header/block phases (non-archive clients).
148- func (hc * HeaderChain ) writeHeaders (headers []* types.Header , postWriteFn PostWriteCallback ) (result * headerWriteResult , err error ) {
149+ func (hc * HeaderChain ) writeHeaders (headers []* types.Header ) (result * headerWriteResult , err error ) {
149150 if len (headers ) == 0 {
150151 return & headerWriteResult {}, nil
151152 }
@@ -154,39 +155,25 @@ func (hc *HeaderChain) writeHeaders(headers []*types.Header, postWriteFn PostWri
154155 return & headerWriteResult {}, consensus .ErrUnknownAncestor
155156 }
156157 var (
157- lastHeader * types.Header // Last successfully imported header
158- lastNumber uint64 // Last successfully imported number
159- lastHash common.Hash
160- externTd * big.Int // TD of successfully imported chain
158+ lastNumber = headers [0 ].Number .Uint64 () - 1 // Last successfully imported number
159+ lastHash = headers [0 ].ParentHash // Last imported header hash
160+ newTD = new (big.Int ).Set (ptd ) // Total difficulty of inserted chain
161+
162+ lastHeader * types.Header
161163 inserted []numberHash // Ephemeral lookup of number/hash for the chain
162164 firstInserted = - 1 // Index of the first non-ignored header
163165 )
164- lastHash , lastNumber = headers [ 0 ]. ParentHash , headers [ 0 ]. Number . Uint64 () - 1 // Already validated above
166+
165167 batch := hc .chainDb .NewBatch ()
166168 for i , header := range headers {
167- // Short circuit insertion if shutting down
168- if hc .procInterrupt () {
169- log .Debug ("Premature abort during headers import" )
170- // if we haven't done anything yet, we can return
171- if i == 0 {
172- return & headerWriteResult {}, errors .New ("aborted" )
173- }
174- // We only 'break' here - since we want to try and keep the
175- // db consistent
176- break
177- }
178169 hash , number := header .Hash (), header .Number .Uint64 ()
179- if header .ParentHash != lastHash {
180- log .Warn ("Non-contiguous header insertion" , "parent" , header .ParentHash , "expected" , lastHash , "number" , number )
181- break
182- }
183- externTd = new (big.Int ).Add (header .Difficulty , ptd )
170+ newTD .Add (newTD , header .Difficulty )
184171
185172 // If the header is already known, skip it, otherwise store
186173 if ! hc .HasHeader (hash , number ) {
187- // Irrelevant of the canonical status, write the td and header to the database
188- rawdb .WriteTd (batch , hash , number , externTd )
189- hc .tdCache .Add (hash , new (big.Int ).Set (externTd ))
174+ // Irrelevant of the canonical status, write the TD and header to the database.
175+ rawdb .WriteTd (batch , hash , number , newTD )
176+ hc .tdCache .Add (hash , new (big.Int ).Set (newTD ))
190177
191178 rawdb .WriteHeader (batch , header )
192179 inserted = append (inserted , numberHash {number , hash })
@@ -196,22 +183,30 @@ func (hc *HeaderChain) writeHeaders(headers []*types.Header, postWriteFn PostWri
196183 firstInserted = i
197184 }
198185 }
199- lastHeader , lastHash , lastNumber , ptd = header , hash , number , externTd
186+ lastHeader , lastHash , lastNumber = header , hash , number
187+ }
188+
189+ // Skip the slow disk write of all headers if interrupted.
190+ if hc .procInterrupt () {
191+ log .Debug ("Premature abort during headers import" )
192+ return & headerWriteResult {}, errors .New ("aborted" )
200193 }
194+ // Commit to disk!
201195 if err := batch .Write (); err != nil {
202196 log .Crit ("Failed to write headers" , "error" , err )
203197 }
204198 batch .Reset ()
199+
205200 var (
206201 head = hc .CurrentHeader ().Number .Uint64 ()
207- localTd = hc .GetTd (hc .currentHeaderHash , head )
202+ localTD = hc .GetTd (hc .currentHeaderHash , head )
208203 status = SideStatTy
209204 )
210205 // If the total difficulty is higher than our known, add it to the canonical chain
211206 // Second clause in the if statement reduces the vulnerability to selfish mining.
212207 // Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
213- reorg := externTd .Cmp (localTd ) > 0
214- if ! reorg && externTd .Cmp (localTd ) == 0 {
208+ reorg := newTD .Cmp (localTD ) > 0
209+ if ! reorg && newTD .Cmp (localTD ) == 0 {
215210 if lastNumber < head {
216211 reorg = true
217212 } else if lastNumber == head {
@@ -275,31 +270,23 @@ func (hc *HeaderChain) writeHeaders(headers []*types.Header, postWriteFn PostWri
275270 hc .currentHeader .Store (types .CopyHeader (lastHeader ))
276271 headHeaderGauge .Update (lastHeader .Number .Int64 ())
277272
273+ // Chain status is canonical since this insert was a reorg.
274+ // Note that all inserts which have higher TD than existing are 'reorg'.
278275 status = CanonStatTy
279276 }
280- // Execute any post-write callback function
281- // - unless we're exiting
282- // - and unless we ignored everything
283- if postWriteFn != nil && ! hc .procInterrupt () && len (inserted ) > 0 {
284- // The postwrite function is called only for the last imported header.
285- // It is only used for lightchain event aggregation.
286- postWriteFn (lastHeader , status )
277+
278+ if len (inserted ) == 0 {
279+ status = NonStatTy
287280 }
288281 return & headerWriteResult {
282+ status : status ,
289283 ignored : len (headers ) - len (inserted ),
290284 imported : len (inserted ),
291285 lastHash : lastHash ,
292286 lastHeader : lastHeader ,
293287 }, nil
294288}
295289
296- // PostWriteCallback is a callback function for inserting headers,
297- // which is called once, with the last successfully imported header in the batch.
298- // The reason for having it is:
299- // In light-chain mode, status should be processed and light chain events sent,
300- // whereas in a non-light mode this is not necessary since chain events are sent after inserting blocks.
301- type PostWriteCallback func (header * types.Header , status WriteStatus )
302-
303290func (hc * HeaderChain ) ValidateHeaderChain (chain []* types.Header , checkFreq int ) (int , error ) {
304291 // Do a sanity check that the provided chain is actually ordered and linked
305292 for i := 1 ; i < len (chain ); i ++ {
@@ -351,14 +338,22 @@ func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header, checkFreq int)
351338 return 0 , nil
352339}
353340
354- // InsertHeaderChain inserts the given headers, and returns the
355- // index at which something went wrong, and the error (if any)
356- // The caller should hold applicable mutexes
357- func (hc * HeaderChain ) InsertHeaderChain (chain []* types.Header , postWriteFn PostWriteCallback , start time.Time ) (int , error ) {
341+ // InsertHeaderChain inserts the given headers.
342+ //
343+ // The validity of the headers is NOT CHECKED by this method, i.e. they need to be
344+ // validated by ValidateHeaderChain before calling InsertHeaderChain.
345+ //
346+ // This insert is all-or-nothing. If this returns an error, no headers were written,
347+ // otherwise they were all processed successfully.
348+ //
349+ // The returned 'write status' says if the inserted headers are part of the canonical chain
350+ // or a side chain.
351+ func (hc * HeaderChain ) InsertHeaderChain (chain []* types.Header , start time.Time ) (WriteStatus , error ) {
358352 if hc .procInterrupt () {
359353 return 0 , errors .New ("aborted" )
360354 }
361- res , err := hc .writeHeaders (chain , postWriteFn )
355+ res , err := hc .writeHeaders (chain )
356+
362357 // Report some public statistics so the user has a clue what's going on
363358 context := []interface {}{
364359 "count" , res .imported ,
@@ -377,7 +372,7 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, postWriteFn Post
377372 context = append (context , []interface {}{"ignored" , res .ignored }... )
378373 }
379374 log .Info ("Imported new block headers" , context ... )
380- return 0 , err
375+ return res . status , err
381376}
382377
383378// GetBlockHashesFromHash retrieves a number of block hashes starting at a given
0 commit comments