|
51 | 51 | headHeaderGauge = metrics.NewRegisteredGauge("chain/head/header", nil)
|
52 | 52 | headFastBlockGauge = metrics.NewRegisteredGauge("chain/head/receipt", nil)
|
53 | 53 | headFinalizedBlockGauge = metrics.NewRegisteredGauge("chain/head/finalized", nil)
|
| 54 | + headSafeBlockGauge = metrics.NewRegisteredGauge("chain/head/safe", nil) |
54 | 55 |
|
55 | 56 | accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil)
|
56 | 57 | accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil)
|
@@ -191,6 +192,7 @@ type BlockChain struct {
|
191 | 192 | currentBlock atomic.Value // Current head of the block chain
|
192 | 193 | currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!)
|
193 | 194 | currentFinalizedBlock atomic.Value // Current finalized head
|
| 195 | + currentSafeBlock atomic.Value // Current safe head |
194 | 196 |
|
195 | 197 | stateCache state.Database // State database to reuse between imports (contains state cache)
|
196 | 198 | bodyCache *lru.Cache // Cache for the most recent block bodies
|
@@ -267,6 +269,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
|
267 | 269 | bc.currentBlock.Store(nilBlock)
|
268 | 270 | bc.currentFastBlock.Store(nilBlock)
|
269 | 271 | bc.currentFinalizedBlock.Store(nilBlock)
|
| 272 | + bc.currentSafeBlock.Store(nilBlock) |
270 | 273 |
|
271 | 274 | // Initialize the chain with ancient data if it isn't empty.
|
272 | 275 | var txIndexBlock uint64
|
@@ -464,11 +467,15 @@ func (bc *BlockChain) loadLastState() error {
|
464 | 467 | }
|
465 | 468 | }
|
466 | 469 |
|
467 |
| - // Restore the last known finalized block |
| 470 | + // Restore the last known finalized block and safe block |
| 471 | + // Note: the safe block is not stored on disk and it is set to the last |
| 472 | + // known finalized block on startup |
468 | 473 | if head := rawdb.ReadFinalizedBlockHash(bc.db); head != (common.Hash{}) {
|
469 | 474 | if block := bc.GetBlockByHash(head); block != nil {
|
470 | 475 | bc.currentFinalizedBlock.Store(block)
|
471 | 476 | headFinalizedBlockGauge.Update(int64(block.NumberU64()))
|
| 477 | + bc.currentSafeBlock.Store(block) |
| 478 | + headSafeBlockGauge.Update(int64(block.NumberU64())) |
472 | 479 | }
|
473 | 480 | }
|
474 | 481 | // Issue a status log for the user
|
@@ -504,8 +511,23 @@ func (bc *BlockChain) SetHead(head uint64) error {
|
504 | 511 | // SetFinalized sets the finalized block.
|
505 | 512 | func (bc *BlockChain) SetFinalized(block *types.Block) {
|
506 | 513 | bc.currentFinalizedBlock.Store(block)
|
507 |
| - rawdb.WriteFinalizedBlockHash(bc.db, block.Hash()) |
508 |
| - headFinalizedBlockGauge.Update(int64(block.NumberU64())) |
| 514 | + if block != nil { |
| 515 | + rawdb.WriteFinalizedBlockHash(bc.db, block.Hash()) |
| 516 | + headFinalizedBlockGauge.Update(int64(block.NumberU64())) |
| 517 | + } else { |
| 518 | + rawdb.WriteFinalizedBlockHash(bc.db, common.Hash{}) |
| 519 | + headFinalizedBlockGauge.Update(0) |
| 520 | + } |
| 521 | +} |
| 522 | + |
| 523 | +// SetSafe sets the safe block. |
| 524 | +func (bc *BlockChain) SetSafe(block *types.Block) { |
| 525 | + bc.currentSafeBlock.Store(block) |
| 526 | + if block != nil { |
| 527 | + headSafeBlockGauge.Update(int64(block.NumberU64())) |
| 528 | + } else { |
| 529 | + headSafeBlockGauge.Update(0) |
| 530 | + } |
509 | 531 | }
|
510 | 532 |
|
511 | 533 | // setHeadBeyondRoot rewinds the local chain to a new head with the extra condition
|
@@ -663,6 +685,16 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, root common.Hash, repair bo
|
663 | 685 | bc.txLookupCache.Purge()
|
664 | 686 | bc.futureBlocks.Purge()
|
665 | 687 |
|
| 688 | + // Clear safe block, finalized block if needed |
| 689 | + if safe := bc.CurrentSafeBlock(); safe != nil && head < safe.NumberU64() { |
| 690 | + log.Warn("SetHead invalidated safe block") |
| 691 | + bc.SetSafe(nil) |
| 692 | + } |
| 693 | + if finalized := bc.CurrentFinalizedBlock(); finalized != nil && head < finalized.NumberU64() { |
| 694 | + log.Error("SetHead invalidated finalized block") |
| 695 | + bc.SetFinalized(nil) |
| 696 | + } |
| 697 | + |
666 | 698 | return rootNumber, bc.loadLastState()
|
667 | 699 | }
|
668 | 700 |
|
|
0 commit comments