Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Panic when resetting the chain after a crash #481

Open
endale98 opened this issue Nov 22, 2024 · 0 comments
Open

Panic when resetting the chain after a crash #481

endale98 opened this issue Nov 22, 2024 · 0 comments

Comments

@endale98
Copy link

endale98 commented Nov 22, 2024

When restarting a node that previously crashed at a certain point, the loadLastState function may encounter a situation where head := GetHeadBlockHash(bc.db) is nil (head == (common.Hash{})) or currentBlock := bc.GetBlockByHash(head) is nil. This leads to an empty database or a missing head block, triggering a chain reset. However, during the reset process, specifically at if err := bc.SetHead(0); err != nil { ... } in the ResetWithGenesisBlock function in blockchain.go, causes a panic due to an unhandled nil return type:

panic: interface conversion: interface {} is nil, not *types.Block 

After investigate, this panic error from :

// CurrentBlock retrieves the current head block of the canonical chain. The
// block is retrieved from the blockchain's internal cache.
func (bc *BlockChain) CurrentBlock() *types.Block {
	return bc.currentBlock.Load().(*types.Block)
}

// CurrentFastBlock retrieves the current fast-sync head block of the canonical
// chain. The block is retrieved from the blockchain's internal cache.
func (bc *BlockChain) CurrentFastBlock() *types.Block {
	return bc.currentFastBlock.Load().(*types.Block)
}

Issue Description

Summary

func (bc *BlockChain) SetHead(head uint64) error {
	log.Warn("Rewinding blockchain", "target", head)

	bc.mu.Lock()
	defer bc.mu.Unlock()
...

	// Rewind the block chain, ensuring we don't end up with a stateless head block
	if currentBlock := bc.CurrentBlock(); currentBlock != nil && currentHeader.Number.Uint64() < currentBlock.NumberU64() {
		bc.currentBlock.Store(bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64()))
	}
...

When invoking the SetHead() method in blockchain.go , the application encounters a panic due to an unsafe type assertion in the CurrentBlock() method. Specifically, currentBlock.Load() returns nil, and the subsequent assertion to *types.Block fails, cause the panic.

Suggested Fix

Add a nil check for CurrentBlock() && CurrentFastBlock() in the blockchain.go to handle the nil return type gracefully and avoid the panic.

func (bc *BlockChain) CurrentBlock() *types.Block {
	currentBlockInterface := bc.currentBlock.Load()
	if currentBlockInterface == nil {
		return nil
	}
	currentBlock, ok := currentBlockInterface.(*types.Block)
	if !ok {
		return nil
	}
	return currentBlock
}

func (bc *BlockChain) CurrentFastBlock() *types.Block {
	currentFastBlockInterface := bc.currentFastBlock.Load()
	if currentFastBlockInterface == nil {
		return nil
	}
	currentFastBlock, ok := currentFastBlockInterface.(*types.Block)
	if !ok {
		return nil
	}
	return currentFastBlock
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant