diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 07798aa710..f98493c57f 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -156,7 +156,11 @@ func NewXDCSimulatedBackend(alloc types.GenesisAlloc, gasLimit uint64, chainConf backend.events = filters.NewEventSystem(backend.filterSystem, false) blockchain.Client = backend - backend.rollback(blockchain.CurrentBlock()) + + header := backend.blockchain.CurrentBlock() + block := backend.blockchain.GetBlock(header.Hash(), header.Number.Uint64()) + + backend.rollback(block) return backend } @@ -179,7 +183,10 @@ func NewSimulatedBackend(alloc types.GenesisAlloc, gasLimit uint64) *SimulatedBa backend.filterSystem = filters.NewFilterSystem(filterBackend, filters.Config{}) backend.events = filters.NewEventSystem(backend.filterSystem, false) - backend.rollback(blockchain.CurrentBlock()) + header := backend.blockchain.CurrentBlock() + block := backend.blockchain.GetBlock(header.Hash(), header.Number.Uint64()) + + backend.rollback(block) return backend } @@ -212,7 +219,10 @@ func (b *SimulatedBackend) Rollback() { b.mu.Lock() defer b.mu.Unlock() - b.rollback(b.blockchain.CurrentBlock()) + header := b.blockchain.CurrentBlock() + block := b.blockchain.GetBlock(header.Hash(), header.Number.Uint64()) + + b.rollback(block) } func (b *SimulatedBackend) rollback(parent *types.Block) { @@ -252,7 +262,7 @@ func (b *SimulatedBackend) Fork(ctx context.Context, parent common.Hash) error { // stateByBlockNumber retrieves a state by a given blocknumber. func (b *SimulatedBackend) stateByBlockNumber(ctx context.Context, blockNumber *big.Int) (*state.StateDB, error) { - if blockNumber == nil || blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) == 0 { + if blockNumber == nil || blockNumber.Cmp(b.blockchain.CurrentBlock().Number) == 0 { return b.blockchain.State() } block, err := b.blockByNumber(ctx, blockNumber) @@ -334,7 +344,7 @@ func (b *SimulatedBackend) ForEachStorageAt(ctx context.Context, contract common b.mu.Lock() defer b.mu.Unlock() - if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { + if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number) != 0 { return errBlockNumberUnsupported } stateDB, _ := b.blockchain.State() @@ -408,7 +418,7 @@ func (b *SimulatedBackend) BlockByNumber(ctx context.Context, number *big.Int) ( // (associated with its hash) if found without Lock. func (b *SimulatedBackend) blockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { if number == nil || number.Cmp(b.pendingBlock.Number()) == 0 { - return b.blockchain.CurrentBlock(), nil + return b.blockByHash(ctx, b.blockchain.CurrentBlock().Hash()) } block := b.blockchain.GetBlockByNumber(uint64(number.Int64())) @@ -540,7 +550,7 @@ func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallM b.mu.Lock() defer b.mu.Unlock() - if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { + if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number) != 0 { return nil, errBlockNumberUnsupported } return b.callContractAtHead(ctx, call) @@ -563,7 +573,8 @@ func (b *SimulatedBackend) callContractAtHead(ctx context.Context, call ethereum if err != nil { return nil, err } - res, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), stateDB) + header := b.blockchain.CurrentBlock() + res, err := b.callContract(ctx, call, header, stateDB) if err != nil { return nil, err } @@ -580,7 +591,7 @@ func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call ethereu defer b.mu.Unlock() defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot()) - res, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState) + res, err := b.callContract(ctx, call, b.pendingBlock.Header(), b.pendingState) if err != nil { return nil, err } @@ -642,7 +653,7 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs call.Gas = gas snapshot := b.pendingState.Snapshot() - res, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState) + res, err := b.callContract(ctx, call, b.pendingBlock.Header(), b.pendingState) b.pendingState.RevertToSnapshot(snapshot) if err != nil { @@ -692,7 +703,7 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs // callContract implements common code between normal and pending contract calls. // state is modified during execution, make sure to copy it if necessary. -func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, stateDB *state.StateDB) (*core.ExecutionResult, error) { +func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Header, stateDB *state.StateDB) (*core.ExecutionResult, error) { // Gas prices post 1559 need to be initialized if call.GasPrice != nil && (call.GasFeeCap != nil || call.GasTipCap != nil) { return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") @@ -763,7 +774,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. txContext := core.NewEVMTxContext(msg) - evmContext := core.NewEVMBlockContext(block.Header(), b.blockchain, nil) + evmContext := core.NewEVMBlockContext(block, b.blockchain, nil) // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. vmenv := vm.NewEVM(evmContext, txContext, stateDB, nil, b.config, vm.Config{NoBaseFee: true}) @@ -958,7 +969,7 @@ func (fb *filterBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNum if fb.bc.Config().XDPoS == nil { return nil, errors.New("only XDPoS v2 supports committed block lookup") } - current := fb.bc.CurrentBlock().Header() + current := fb.bc.CurrentBlock() if fb.bc.Config().XDPoS.BlockConsensusVersion(current.Number) == params.ConsensusEngineVersion2 { confirmedHash := fb.bc.Engine().(*XDPoS.XDPoS).EngineV2.GetLatestCommittedBlockInfo().Hash return fb.bc.GetHeaderByHash(confirmedHash), nil diff --git a/accounts/abi/bind/backends/simulated_test.go b/accounts/abi/bind/backends/simulated_test.go index 24b2c4ef0f..ce0f480d24 100644 --- a/accounts/abi/bind/backends/simulated_test.go +++ b/accounts/abi/bind/backends/simulated_test.go @@ -1254,7 +1254,7 @@ func TestFork(t *testing.T) { sim.Commit() } // 3. - if sim.blockchain.CurrentBlock().NumberU64() != uint64(n) { + if sim.blockchain.CurrentBlock().Number.Uint64() != uint64(n) { t.Error("wrong chain length") } // 4. @@ -1264,7 +1264,7 @@ func TestFork(t *testing.T) { sim.Commit() } // 6. - if sim.blockchain.CurrentBlock().NumberU64() != uint64(n+1) { + if sim.blockchain.CurrentBlock().Number.Uint64() != uint64(n+1) { t.Error("wrong chain length") } } @@ -1421,7 +1421,7 @@ func TestCommitReturnValue(t *testing.T) { sim := simTestBackend(testAddr) defer sim.Close() - startBlockHeight := sim.blockchain.CurrentBlock().NumberU64() + startBlockHeight := sim.blockchain.CurrentBlock().Number.Uint64() // Test if Commit returns the correct block hash h1 := sim.Commit() diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index ceb86453ba..017a6dcc16 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -190,7 +190,7 @@ func missingBlocks(chain *core.BlockChain, blocks []*types.Block) []*types.Block head := chain.CurrentBlock() for i, block := range blocks { // If we're behind the chain head, only check block, state is available at head - if head.NumberU64() > block.NumberU64() { + if head.Number.Uint64() > block.NumberU64() { if !chain.HasBlock(block.Hash(), block.NumberU64()) { return blocks[i:] } diff --git a/consensus/XDPoS/XDPoS.go b/consensus/XDPoS/XDPoS.go index 09dfec9f5b..6d3cad19f9 100644 --- a/consensus/XDPoS/XDPoS.go +++ b/consensus/XDPoS/XDPoS.go @@ -491,17 +491,15 @@ func (x *XDPoS) GetAuthorisedSignersFromSnapshot(chain consensus.ChainReader, he } } -func (x *XDPoS) FindParentBlockToAssign(chain consensus.ChainReader, currentBlock *types.Block) *types.Block { - switch x.config.BlockConsensusVersion(currentBlock.Number()) { - case params.ConsensusEngineVersion2: - block := x.EngineV2.FindParentBlockToAssign(chain) - if block == nil { - return currentBlock - } - return block - default: // Default "v1" - return currentBlock +func (x *XDPoS) FindParentBlockToAssign(chain consensus.ChainReader, currentBlock *types.Header) *types.Block { + var parent *types.Block = nil + if x.config.BlockConsensusVersion(currentBlock.Number) == params.ConsensusEngineVersion2 { + parent = x.EngineV2.FindParentBlockToAssign(chain) } + if parent == nil { + parent = chain.GetBlock(currentBlock.Hash(), currentBlock.Number.Uint64()) + } + return parent } /** diff --git a/consensus/tests/engine_v1_tests/block_signer_test.go b/consensus/tests/engine_v1_tests/block_signer_test.go index a6f3368378..0c1d22eff5 100644 --- a/consensus/tests/engine_v1_tests/block_signer_test.go +++ b/consensus/tests/engine_v1_tests/block_signer_test.go @@ -205,7 +205,7 @@ func TestCallUpdateM1WithSmartContractTranscation(t *testing.T) { func TestCallUpdateM1WhenForkedBlockBackToMainChain(t *testing.T) { blockchain, backend, currentBlock, signer, signFn := PrepareXDCTestBlockChain(t, GAP-1, params.TestXDPoSMockChainConfig) // Check initial signer, by default, acc3 is in the signerList - signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header()) + signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock()) if err != nil { t.Fatal(err) } @@ -337,7 +337,7 @@ func TestCallUpdateM1WhenForkedBlockBackToMainChain(t *testing.T) { t.Fatalf("acc1,3should NOT sit in the signer list") } - signers, err = GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header()) + signers, err = GetSnapshotSigner(blockchain, blockchain.CurrentBlock()) if err != nil { t.Fatal(err) } @@ -360,7 +360,7 @@ func TestStatesShouldBeUpdatedWhenForkedBlockBecameMainChainAtGapBlock(t *testin } t.Logf("Account %v have balance of: %v", acc1Addr.String(), state.GetBalance(acc1Addr)) // Check initial signer - signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header()) + signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock()) if err != nil { t.Fatal(err) } @@ -493,7 +493,7 @@ func TestStatesShouldBeUpdatedWhenForkedBlockBecameMainChainAtGapBlock(t *testin t.Fatalf("account 2 should sit in the signer list") } - signers, err = GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header()) + signers, err = GetSnapshotSigner(blockchain, blockchain.CurrentBlock()) if err != nil { t.Fatal(err) } @@ -516,7 +516,7 @@ func TestStatesShouldBeUpdatedWhenForkedBlockBecameMainChainAtGapBlock(t *testin func TestVoteShouldNotBeAffectedByFork(t *testing.T) { blockchain, backend, parentBlock, signer, signFn := PrepareXDCTestBlockChain(t, GAP-1, params.TestXDPoSMockChainConfig) // Check initial signer, by default, acc3 is in the signerList - signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header()) + signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock()) if err != nil { t.Fatal(err) } diff --git a/consensus/tests/engine_v1_tests/blockchain_race_condition_test.go b/consensus/tests/engine_v1_tests/blockchain_race_condition_test.go index 5db266c413..b1d6e318c7 100644 --- a/consensus/tests/engine_v1_tests/blockchain_race_condition_test.go +++ b/consensus/tests/engine_v1_tests/blockchain_race_condition_test.go @@ -19,7 +19,7 @@ func TestRaceConditionOnBlockchainReadAndWrite(t *testing.T) { } t.Logf("Account %v have balance of: %v", acc1Addr.String(), state.GetBalance(acc1Addr)) // Check initial signer - signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header()) + signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock()) if err != nil { t.Fatal(err) } @@ -157,7 +157,7 @@ func TestRaceConditionOnBlockchainReadAndWrite(t *testing.T) { t.Fatalf("account 2 should sit in the signer list") } - signers, err = GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header()) + signers, err = GetSnapshotSigner(blockchain, blockchain.CurrentBlock()) if err != nil { t.Fatal(err) } diff --git a/consensus/tests/engine_v2_tests/adaptor_test.go b/consensus/tests/engine_v2_tests/adaptor_test.go index 46f56485e3..449b2c0e61 100644 --- a/consensus/tests/engine_v2_tests/adaptor_test.go +++ b/consensus/tests/engine_v2_tests/adaptor_test.go @@ -241,11 +241,12 @@ func TestGetParentBlock(t *testing.T) { adaptor := blockchain.Engine().(*XDPoS.XDPoS) // V1 - block := adaptor.FindParentBlockToAssign(blockchain, block900) - assert.Equal(t, block, block900) + block := adaptor.FindParentBlockToAssign(blockchain, block900.Header()) + assert.Equal(t, block.Number(), block900.Number()) + assert.Equal(t, block.Hash(), block900.Hash()) // Initialise - err := adaptor.EngineV2.Initial(blockchain, block.Header()) + err := adaptor.EngineV2.Initial(blockchain, block900.Header()) assert.Nil(t, err) // V2 @@ -260,7 +261,7 @@ func TestGetParentBlock(t *testing.T) { block902 := CreateBlock(blockchain, params.TestXDPoSMockChainConfig, block901, blockNum, 1, blockCoinBase, signer, signFn, nil, nil, "") err = blockchain.InsertBlock(block902) assert.Nil(t, err) - block = adaptor.FindParentBlockToAssign(blockchain, block902) - - assert.Equal(t, block900.Hash(), block.Hash()) + block = adaptor.FindParentBlockToAssign(blockchain, block902.Header()) + assert.Equal(t, block.Number(), block900.Number()) + assert.Equal(t, block.Hash(), block900.Hash()) } diff --git a/core/blockchain.go b/core/blockchain.go index fab8628e7c..ce80ad56c0 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -187,8 +187,8 @@ type BlockChain struct { // Readers don't need to take it, they can just read the database. chainmu *syncx.ClosableMutex - currentBlock atomic.Value // Current head of the block chain - currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!) + currentBlock atomic.Pointer[types.Header] // Current head of the chain + currentSnapBlock atomic.Pointer[types.Header] // Current head of snap-sync bodyCache *lru.Cache[common.Hash, *types.Body] // Cache for the most recent block bodies bodyRLPCache *lru.Cache[common.Hash, rlp.RawValue] // Cache for the most recent block bodies in RLP encoded format @@ -289,9 +289,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par return nil, ErrNoGenesis } - var nilBlock *types.Block - bc.currentBlock.Store(nilBlock) - bc.currentFastBlock.Store(nilBlock) + bc.currentBlock.Store(nil) + bc.currentSnapBlock.Store(nil) // Update chain info data metrics chainInfoGauge.Update(metrics.GaugeInfoValue{"chain_id": bc.chainConfig.ChainID.String()}) @@ -319,16 +318,18 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par } if bc.logger != nil && bc.logger.OnGenesisBlock != nil { - if block := bc.CurrentBlock(); block.NumberU64() == 0 { + block := bc.CurrentBlock() + if block == nil { + return nil, errors.New("live blockchain tracer requires current block to be set") + } + if block.Number != nil && block.Number.Sign() == 0 { alloc, err := getGenesisState(bc.db, block.Hash()) if err != nil { return nil, fmt.Errorf("failed to get genesis state: %w", err) } - if alloc == nil { return nil, fmt.Errorf("live blockchain tracer requires genesis alloc to be set") } - bc.logger.OnGenesisBlock(bc.genesisBlock, alloc) } } @@ -339,7 +340,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par return bc, nil } - // NewBlockChainEx extend old blockchain, add order state db func NewBlockChainEx(db ethdb.Database, XDCxDb ethdb.XDCxDatabase, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config) (*BlockChain, error) { blockchain, err := NewBlockChain(db, cacheConfig, chainConfig, engine, vmConfig) @@ -367,24 +367,24 @@ func (bc *BlockChain) loadLastState() error { return bc.Reset() } // Make sure the entire head block is available - currentBlock := bc.GetBlockByHash(head) - if currentBlock == nil { + headBlock := bc.GetBlockByHash(head) + if headBlock == nil { // Corrupt or empty database, init from scratch log.Warn("Head block missing, resetting chain", "hash", head) return bc.Reset() } // Make sure the state associated with the block is available repair := false - if !bc.HasState(currentBlock.Root()) { + if !bc.HasState(headBlock.Root()) { repair = true } else { engine, ok := bc.Engine().(*XDPoS.XDPoS) if ok { tradingService := engine.GetXDCXService() lendingService := engine.GetLendingService() - if bc.Config().IsTIPXDCX(currentBlock.Number()) && bc.chainConfig.XDPoS != nil && currentBlock.NumberU64() > bc.chainConfig.XDPoS.Epoch && tradingService != nil && lendingService != nil { - author, _ := bc.Engine().Author(currentBlock.Header()) - tradingRoot, err := tradingService.GetTradingStateRoot(currentBlock, author) + if bc.Config().IsTIPXDCX(headBlock.Number()) && bc.chainConfig.XDPoS != nil && headBlock.NumberU64() > bc.chainConfig.XDPoS.Epoch && tradingService != nil && lendingService != nil { + author, _ := bc.Engine().Author(headBlock.Header()) + tradingRoot, err := tradingService.GetTradingStateRoot(headBlock, author) if err != nil { repair = true } else { @@ -397,7 +397,7 @@ func (bc *BlockChain) loadLastState() error { } if !repair { - lendingRoot, err := lendingService.GetLendingStateRoot(currentBlock, author) + lendingRoot, err := lendingService.GetLendingStateRoot(headBlock, author) if err != nil { repair = true } else { @@ -414,45 +414,50 @@ func (bc *BlockChain) loadLastState() error { } if repair { // Dangling block without a state associated, init from scratch - log.Warn("Head state missing, repairing chain", "number", currentBlock.Number(), "hash", currentBlock.Hash()) - if err := bc.repair(¤tBlock); err != nil { + log.Warn("Head state missing, repairing chain", "number", headBlock.Number(), "hash", headBlock.Hash()) + if err := bc.repair(&headBlock); err != nil { return err } } // Everything seems to be fine, set as the head block - bc.currentBlock.Store(currentBlock) - headBlockGauge.Update(int64(currentBlock.NumberU64())) + bc.currentBlock.Store(headBlock.Header()) + headBlockGauge.Update(int64(headBlock.NumberU64())) // Restore the last known head header - currentHeader := currentBlock.Header() + headHeader := headBlock.Header() if head := rawdb.ReadHeadHeaderHash(bc.db); head != (common.Hash{}) { if header := bc.GetHeaderByHash(head); header != nil { - currentHeader = header + headHeader = header } } - bc.hc.SetCurrentHeader(currentHeader) + bc.hc.SetCurrentHeader(headHeader) // Restore the last known head fast block - bc.currentFastBlock.Store(currentBlock) - headFastBlockGauge.Update(int64(currentBlock.NumberU64())) + bc.currentSnapBlock.Store(headBlock.Header()) + headFastBlockGauge.Update(int64(headBlock.NumberU64())) if head := rawdb.ReadHeadFastBlockHash(bc.db); head != (common.Hash{}) { if block := bc.GetBlockByHash(head); block != nil { - bc.currentFastBlock.Store(block) + bc.currentSnapBlock.Store(block.Header()) headFastBlockGauge.Update(int64(block.NumberU64())) } } // Issue a status log for the user - currentFastBlock := bc.CurrentFastBlock() + var ( + currentSnapBlock = bc.CurrentSnapBlock() - headerTd := bc.GetTd(currentHeader.Hash(), currentHeader.Number.Uint64()) - blockTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64()) - fastTd := bc.GetTd(currentFastBlock.Hash(), currentFastBlock.NumberU64()) - - log.Info("Loaded most recent local header", "number", currentHeader.Number, "hash", currentHeader.Hash(), "td", headerTd, "age", common.PrettyAge(time.Unix(int64(currentHeader.Time), 0))) - log.Info("Loaded most recent local full block", "number", currentBlock.Number(), "hash", currentBlock.Hash(), "td", blockTd, "age", common.PrettyAge(time.Unix(int64(currentBlock.Time()), 0))) - log.Info("Loaded most recent local fast block", "number", currentFastBlock.Number(), "hash", currentFastBlock.Hash(), "td", fastTd, "age", common.PrettyAge(time.Unix(int64(currentFastBlock.Time()), 0))) + headerTd = bc.GetTd(headHeader.Hash(), headHeader.Number.Uint64()) + blockTd = bc.GetTd(headBlock.Hash(), headBlock.NumberU64()) + ) + if headHeader.Hash() != headBlock.Hash() { + log.Info("Loaded most recent local header", "number", headHeader.Number, "hash", headHeader.Hash(), "td", headerTd, "age", common.PrettyAge(time.Unix(int64(headHeader.Time), 0))) + } + log.Info("Loaded most recent local block", "number", headBlock.Number(), "hash", headBlock.Hash(), "td", blockTd, "age", common.PrettyAge(time.Unix(int64(headBlock.Time()), 0))) + if headBlock.Hash() != currentSnapBlock.Hash() { + fastTd := bc.GetTd(currentSnapBlock.Hash(), currentSnapBlock.Number.Uint64()) + log.Info("Loaded most recent local snap block", "number", currentSnapBlock.Number, "hash", currentSnapBlock.Hash(), "td", fastTd, "age", common.PrettyAge(time.Unix(int64(currentSnapBlock.Time), 0))) + } return nil } @@ -465,7 +470,16 @@ func (bc *BlockChain) SetHead(head uint64) error { return err } // Send chain head event to update the transaction pool - bc.chainHeadFeed.Send(ChainHeadEvent{Block: bc.CurrentBlock()}) + header := bc.CurrentBlock() + block := bc.GetBlock(header.Hash(), header.Number.Uint64()) + if block == nil { + // This should never happen. In practice, previously currentBlock + // contained the entire block whereas now only a "marker", so there + // is an ever so slight chance for a race we should handle. + log.Error("Current block not found in database", "block", header.Number, "hash", header.Hash()) + return fmt.Errorf("current block missing: #%d [%x..]", header.Number, header.Hash().Bytes()[:4]) + } + bc.chainHeadFeed.Send(ChainHeadEvent{Block: block}) return nil } @@ -483,7 +497,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64) error { updateFn := func(db ethdb.KeyValueWriter, header *types.Header) { // Rewind the block chain, ensuring we don't end up with a stateless head block - if currentBlock := bc.CurrentBlock(); currentBlock != nil && header.Number.Uint64() < currentBlock.NumberU64() { + if currentBlock := bc.CurrentBlock(); currentBlock != nil && header.Number.Uint64() < currentBlock.Number.Uint64() { newHeadBlock := bc.GetBlock(header.Hash(), header.Number.Uint64()) if newHeadBlock == nil { newHeadBlock = bc.genesisBlock @@ -499,25 +513,25 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64) error { // In theory we should update all in-memory markers in the // last step, however the direction of SetHead is from high // to low, so it's safe the update in-memory markers directly. - bc.currentBlock.Store(newHeadBlock) + bc.currentBlock.Store(newHeadBlock.Header()) headBlockGauge.Update(int64(newHeadBlock.NumberU64())) } // Rewind the fast block in a simpleton way to the target head - if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock != nil && header.Number.Uint64() < currentFastBlock.NumberU64() { - newHeadFastBlock := bc.GetBlock(header.Hash(), header.Number.Uint64()) + if currentSnapBlock := bc.CurrentSnapBlock(); currentSnapBlock != nil && header.Number.Uint64() < currentSnapBlock.Number.Uint64() { + newHeadSnapBlock := bc.GetBlock(header.Hash(), header.Number.Uint64()) // If either blocks reached nil, reset to the genesis state - if newHeadFastBlock == nil { - newHeadFastBlock = bc.genesisBlock + if newHeadSnapBlock == nil { + newHeadSnapBlock = bc.genesisBlock } - rawdb.WriteHeadFastBlockHash(db, newHeadFastBlock.Hash()) + rawdb.WriteHeadFastBlockHash(db, newHeadSnapBlock.Hash()) // Degrade the chain markers if they are explicitly reverted. // In theory we should update all in-memory markers in the // last step, however the direction of SetHead is from high // to low, so it's safe the update in-memory markers directly. - bc.currentFastBlock.Store(newHeadFastBlock) - headFastBlockGauge.Update(int64(newHeadFastBlock.NumberU64())) + bc.currentSnapBlock.Store(newHeadSnapBlock.Header()) + headFastBlockGauge.Update(int64(newHeadSnapBlock.NumberU64())) } } @@ -572,7 +586,7 @@ func (bc *BlockChain) FastSyncCommitHead(hash common.Hash) error { if !bc.chainmu.TryLock() { return errChainStopped } - bc.currentBlock.Store(block) + bc.currentBlock.Store(block.Header()) headBlockGauge.Update(int64(block.NumberU64())) bc.chainmu.Unlock() @@ -652,11 +666,11 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error { // Last update all in-memory chain markers bc.genesisBlock = genesis - bc.currentBlock.Store(bc.genesisBlock) + bc.currentBlock.Store(bc.genesisBlock.Header()) headBlockGauge.Update(int64(bc.genesisBlock.NumberU64())) bc.hc.SetGenesis(bc.genesisBlock.Header()) bc.hc.SetCurrentHeader(bc.genesisBlock.Header()) - bc.currentFastBlock.Store(bc.genesisBlock) + bc.currentSnapBlock.Store(bc.genesisBlock.Header()) headFastBlockGauge.Update(int64(bc.genesisBlock.NumberU64())) return nil } @@ -713,7 +727,7 @@ func (bc *BlockChain) repair(head **types.Block) error { // Export writes the active chain to the given writer. func (bc *BlockChain) Export(w io.Writer) error { - return bc.ExportN(w, uint64(0), bc.CurrentBlock().NumberU64()) + return bc.ExportN(w, uint64(0), bc.CurrentBlock().Number.Uint64()) } // ExportN writes a subset of the active chain to the given writer. @@ -775,10 +789,10 @@ func (bc *BlockChain) writeHeadBlock(block *types.Block, writeBlock bool) { // Update all in-memory chain markers in the last step bc.hc.SetCurrentHeader(block.Header()) - bc.currentFastBlock.Store(block) + bc.currentSnapBlock.Store(block.Header()) headFastBlockGauge.Update(int64(blockNumberU64)) - bc.currentBlock.Store(block) + bc.currentBlock.Store(block.Header()) headBlockGauge.Update(int64(block.NumberU64())) // save cache BlockSigners @@ -855,7 +869,7 @@ func (bc *BlockChain) saveData() { var lendingService utils.LendingService triedb := bc.triedb engine, _ := bc.Engine().(*XDPoS.XDPoS) - if bc.Config().IsTIPXDCX(bc.CurrentBlock().Number()) && bc.chainConfig.XDPoS != nil && bc.CurrentBlock().NumberU64() > bc.chainConfig.XDPoS.Epoch && engine != nil { + if bc.Config().IsTIPXDCX(bc.CurrentBlock().Number) && bc.chainConfig.XDPoS != nil && bc.CurrentBlock().Number.Uint64() > bc.chainConfig.XDPoS.Epoch && engine != nil { tradingService = engine.GetXDCXService() if tradingService != nil && tradingService.GetStateCache() != nil { tradingTriedb = tradingService.GetStateCache().TrieDB() @@ -866,7 +880,7 @@ func (bc *BlockChain) saveData() { } } for _, offset := range []uint64{0, 1, triesInMemory - 1} { - if number := bc.CurrentBlock().NumberU64(); number > offset { + if number := bc.CurrentBlock().Number.Uint64(); number > offset { recent := bc.GetBlockByNumber(number - offset) log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root()) @@ -1028,16 +1042,24 @@ func (bc *BlockChain) Rollback(chain []common.Hash) { rawdb.WriteHeadHeaderHash(batch, currentHeader.ParentHash) bc.hc.SetCurrentHeader(newHeadHeader) } - if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock.Hash() == hash { - newFastBlock := bc.GetBlock(currentFastBlock.ParentHash(), currentFastBlock.NumberU64()-1) - rawdb.WriteHeadFastBlockHash(batch, currentFastBlock.ParentHash()) - bc.currentFastBlock.Store(newFastBlock) + if currentSnapBlock := bc.CurrentSnapBlock(); currentSnapBlock.Hash() == hash { + newFastBlock := bc.GetBlock(currentSnapBlock.ParentHash, currentSnapBlock.Number.Uint64()-1) + if newFastBlock == nil { + log.Error("Rollback failed", "number", currentSnapBlock.Number.Uint64()-1, "hash", currentSnapBlock.ParentHash.Hex()) + return + } + rawdb.WriteHeadFastBlockHash(batch, currentSnapBlock.ParentHash) + bc.currentSnapBlock.Store(newFastBlock.Header()) headFastBlockGauge.Update(int64(newFastBlock.NumberU64())) } if currentBlock := bc.CurrentBlock(); currentBlock.Hash() == hash { - newBlock := bc.GetBlock(currentBlock.ParentHash(), currentBlock.NumberU64()-1) - rawdb.WriteHeadBlockHash(batch, currentBlock.ParentHash()) - bc.currentBlock.Store(newBlock) + newBlock := bc.GetBlock(currentBlock.ParentHash, currentBlock.Number.Uint64()-1) + if newBlock == nil { + log.Error("Rollback failed", "number", currentBlock.Number.Uint64()-1, "hash", currentBlock.ParentHash.Hex()) + return + } + rawdb.WriteHeadBlockHash(batch, currentBlock.ParentHash) + bc.currentBlock.Store(newBlock.Header()) headBlockGauge.Update(int64(newBlock.NumberU64())) } } @@ -1129,10 +1151,10 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ } head := blockChain[len(blockChain)-1] if td := bc.GetTd(head.Hash(), head.NumberU64()); td != nil { // Rewind may have occurred, skip in that case - currentFastBlock := bc.CurrentFastBlock() - if bc.GetTd(currentFastBlock.Hash(), currentFastBlock.NumberU64()).Cmp(td) < 0 { + currentSnapBlock := bc.CurrentSnapBlock() + if bc.GetTd(currentSnapBlock.Hash(), currentSnapBlock.Number.Uint64()).Cmp(td) < 0 { rawdb.WriteHeadFastBlockHash(bc.db, head.Hash()) - bc.currentFastBlock.Store(head) + bc.currentSnapBlock.Store(head.Header()) headFastBlockGauge.Update(int64(head.NumberU64())) } } @@ -1193,7 +1215,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. } // Make sure no inconsistent state is leaked during insertion currentBlock := bc.CurrentBlock() - localTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64()) + localTd := bc.GetTd(currentBlock.Hash(), currentBlock.Number.Uint64()) externTd := new(big.Int).Add(block.Difficulty(), ptd) // Irrelevant of the canonical status, write the block itself to the database. @@ -1360,12 +1382,12 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. currentBlock = bc.CurrentBlock() if !reorg && externTd.Cmp(localTd) == 0 { // Split same-difficulty blocks by number - reorg = block.NumberU64() > currentBlock.NumberU64() + reorg = block.NumberU64() > currentBlock.Number.Uint64() } if reorg { // Reorganise the chain if the parent is not the head block if block.ParentHash() != currentBlock.Hash() { - if err := bc.reorg(currentBlock.Header(), block.Header()); err != nil { + if err := bc.reorg(currentBlock, block.Header()); err != nil { return NonStatTy, err } } @@ -1514,7 +1536,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, [] // from the canonical chain, which has not been verified. case err == ErrKnownBlock: // Skip all known blocks that behind us - current := bc.CurrentBlock().NumberU64() + current := bc.CurrentBlock().Number.Uint64() for block != nil && err == ErrKnownBlock && current >= block.NumberU64() { stats.ignored++ @@ -1742,7 +1764,7 @@ func (bc *BlockChain) processBlock(block *types.Block, parent *types.Header, sta func (bc *BlockChain) insertSidechain(block *types.Block, it *insertIterator) (int, []interface{}, []*types.Log, error) { var ( externTd *big.Int - current = bc.CurrentBlock().NumberU64() + current = bc.CurrentBlock().Number.Uint64() ) // The first sidechain block error is already verified to be ErrPrunedAncestor. // Since we don't import them here, we expect ErrUnknownAncestor for the remaining @@ -1913,14 +1935,14 @@ func (bc *BlockChain) getResultBlock(block *types.Block, verifiedM2 bool) (*Resu case err == ErrKnownBlock: // Block and state both already known. However if the current block is below // this number we did a rollback and we should reimport it nonetheless. - if bc.CurrentBlock().NumberU64() >= block.NumberU64() { + if bc.CurrentBlock().Number.Uint64() >= block.NumberU64() { return nil, ErrKnownBlock } case err == consensus.ErrPrunedAncestor: // Block competing with the canonical chain, store in the db, but don't process // until the competitor TD goes above the canonical TD currentBlock := bc.CurrentBlock() - localTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64()) + localTd := bc.GetTd(currentBlock.Hash(), currentBlock.Number.Uint64()) externTd := new(big.Int).Add(bc.GetTd(block.ParentHash(), block.NumberU64()-1), block.Difficulty()) if localTd.Cmp(externTd) > 0 { return nil, err diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index c761b80d13..7e92a1f50b 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -37,16 +37,16 @@ func (bc *BlockChain) CurrentHeader() *types.Header { return bc.hc.CurrentHeader() } -// 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) +// CurrentBlock retrieves the current head header of the canonical chain. The +// header is retrieved from the blockchain's internal cache. +func (bc *BlockChain) CurrentBlock() *types.Header { + return bc.currentBlock.Load() } -// 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) +// CurrentSnapBlock retrieves the current snap-sync head header of the canonical +// chain. The header is retrieved from the blockchain's internal cache. +func (bc *BlockChain) CurrentSnapBlock() *types.Header { + return bc.currentSnapBlock.Load() } // HasHeader checks if a block header is present in the database or not, caching @@ -282,7 +282,7 @@ func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) { // State returns a new mutable state based on the current HEAD block. func (bc *BlockChain) State() (*state.StateDB, error) { - return bc.StateAt(bc.CurrentBlock().Root()) + return bc.StateAt(bc.CurrentBlock().Root) } // StateAt returns a new mutable state based on a particular point in time. @@ -313,7 +313,7 @@ func (bc *BlockChain) StateCache() state.Database { // GasLimit returns the gas limit of the current HEAD block. func (bc *BlockChain) GasLimit() uint64 { - return bc.CurrentBlock().GasLimit() + return bc.CurrentBlock().GasLimit } // Genesis retrieves the chain's genesis block. diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 46d09e4656..8768281f93 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -98,7 +98,7 @@ func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, compara headerChainB []*types.Header ) if full { - blockChainB = makeBlockChain(blockchain2.CurrentBlock(), n, ethash.NewFaker(), db, forkSeed) + blockChainB = makeBlockChain(blockchain2.GetBlockByHash(blockchain2.CurrentBlock().Hash()), n, ethash.NewFaker(), db, forkSeed) if _, err := blockchain2.InsertChain(blockChainB); err != nil { t.Fatalf("failed to insert forking chain: %v", err) } @@ -129,7 +129,7 @@ func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, compara } func printChain(bc *BlockChain) { - for i := bc.CurrentBlock().Number().Uint64(); i > 0; i-- { + for i := bc.CurrentBlock().Number.Uint64(); i > 0; i-- { b := bc.GetBlockByNumber(i) fmt.Printf("\t%x %v\n", b.Hash(), b.Difficulty()) } @@ -205,7 +205,7 @@ func TestLastBlock(t *testing.T) { } defer blockchain.Stop() - blocks := makeBlockChain(blockchain.CurrentBlock(), 1, ethash.NewFullFaker(), blockchain.db, 0) + blocks := makeBlockChain(blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), 1, ethash.NewFullFaker(), blockchain.db, 0) if _, err := blockchain.InsertChain(blocks); err != nil { t.Fatalf("Failed to insert block: %v", err) } @@ -346,7 +346,7 @@ func testBrokenChain(t *testing.T, full bool) { // Create a forked chain, and try to insert with a missing link if full { - chain := makeBlockChain(blockchain.CurrentBlock(), 5, ethash.NewFaker(), db, forkSeed)[1:] + chain := makeBlockChain(blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), 5, ethash.NewFaker(), db, forkSeed)[1:] if err := testBlockChainImport(chain, blockchain); err == nil { t.Errorf("broken block chain not reported") } @@ -400,10 +400,10 @@ func testReorg(t *testing.T, first, second []int64, td int64, full bool) { defer blockchain.Stop() // Insert an easy and a difficult chain afterwards - easyBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.CurrentBlock(), ethash.NewFaker(), db, len(first), func(i int, b *BlockGen) { + easyBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), ethash.NewFaker(), db, len(first), func(i int, b *BlockGen) { b.OffsetTime(first[i]) }) - diffBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.CurrentBlock(), ethash.NewFaker(), db, len(second), func(i int, b *BlockGen) { + diffBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), ethash.NewFaker(), db, len(second), func(i int, b *BlockGen) { b.OffsetTime(second[i]) }) if full { @@ -432,9 +432,9 @@ func testReorg(t *testing.T, first, second []int64, td int64, full bool) { // Check that the chain is valid number and link wise if full { prev := blockchain.CurrentBlock() - for block := blockchain.GetBlockByNumber(blockchain.CurrentBlock().NumberU64() - 1); block.NumberU64() != 0; prev, block = block, blockchain.GetBlockByNumber(block.NumberU64()-1) { - if prev.ParentHash() != block.Hash() { - t.Errorf("parent block hash mismatch: have %x, want %x", prev.ParentHash(), block.Hash()) + for block := blockchain.GetBlockByNumber(blockchain.CurrentBlock().Number.Uint64() - 1); block.NumberU64() != 0; prev, block = block.Header(), blockchain.GetBlockByNumber(block.NumberU64()-1) { + if prev.ParentHash != block.Hash() { + t.Errorf("parent block hash mismatch: have %x, want %x", prev.ParentHash, block.Hash()) } } } else { @@ -461,7 +461,7 @@ func testBadHashes(t *testing.T, full bool) { // Create a chain, ban a hash and try to import if full { - blocks := makeBlockChain(blockchain.CurrentBlock(), 3, ethash.NewFaker(), db, 10) + blocks := makeBlockChain(blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), 3, ethash.NewFaker(), db, 10) BadHashes[blocks[2].Header().Hash()] = true defer func() { delete(BadHashes, blocks[2].Header().Hash()) }() @@ -493,7 +493,7 @@ func testReorgBadHashes(t *testing.T, full bool) { } // Create a chain, import and ban afterwards headers := makeHeaderChain(blockchain.CurrentHeader(), 4, ethash.NewFaker(), db, 10) - blocks := makeBlockChain(blockchain.CurrentBlock(), 4, ethash.NewFaker(), db, 10) + blocks := makeBlockChain(blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), 4, ethash.NewFaker(), db, 10) if full { if _, err = blockchain.InsertChain(blocks); err != nil { @@ -697,10 +697,10 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { } // Create a small assertion method to check the three heads assert := func(t *testing.T, kind string, chain *BlockChain, header uint64, fast uint64, block uint64) { - if num := chain.CurrentBlock().NumberU64(); num != block { + if num := chain.CurrentBlock().Number.Uint64(); num != block { t.Errorf("%s head block mismatch: have #%v, want #%v", kind, num, block) } - if num := chain.CurrentFastBlock().NumberU64(); num != fast { + if num := chain.CurrentSnapBlock().Number.Uint64(); num != fast { t.Errorf("%s head fast-block mismatch: have #%v, want #%v", kind, num, fast) } if num := chain.CurrentHeader().Number.Uint64(); num != header { @@ -1258,13 +1258,13 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { t.Fatalf("block %d: failed to insert into chain: %v", i, err) } if chain.CurrentBlock().Hash() != chain.CurrentHeader().Hash() { - t.Errorf("block %d: current block/header mismatch: block #%d [%x..], header #%d [%x..]", i, chain.CurrentBlock().Number(), chain.CurrentBlock().Hash().Bytes()[:4], chain.CurrentHeader().Number, chain.CurrentHeader().Hash().Bytes()[:4]) + t.Errorf("block %d: current block/header mismatch: block #%d [%x..], header #%d [%x..]", i, chain.CurrentBlock().Number, chain.CurrentBlock().Hash().Bytes()[:4], chain.CurrentHeader().Number, chain.CurrentHeader().Hash().Bytes()[:4]) } if _, err := chain.InsertChain(forks[i : i+1]); err != nil { t.Fatalf(" fork %d: failed to insert into chain: %v", i, err) } if chain.CurrentBlock().Hash() != chain.CurrentHeader().Hash() { - t.Errorf(" fork %d: current block/header mismatch: block #%d [%x..], header #%d [%x..]", i, chain.CurrentBlock().Number(), chain.CurrentBlock().Hash().Bytes()[:4], chain.CurrentHeader().Number, chain.CurrentHeader().Hash().Bytes()[:4]) + t.Errorf(" fork %d: current block/header mismatch: block #%d [%x..], header #%d [%x..]", i, chain.CurrentBlock().Number, chain.CurrentBlock().Hash().Bytes()[:4], chain.CurrentHeader().Number, chain.CurrentHeader().Hash().Bytes()[:4]) } } } @@ -1433,7 +1433,8 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in b.Fatalf("failed to insert shared chain: %v", err) } b.StopTimer() - if got := chain.CurrentBlock().Transactions().Len(); got != numTxs*numBlocks { + block := chain.GetBlockByHash(chain.CurrentBlock().Hash()) + if got := block.Transactions().Len(); got != numTxs*numBlocks { b.Fatalf("Transactions were not included, expected %d, got %d", (numTxs * numBlocks), got) } } @@ -1516,7 +1517,7 @@ func TestBlocksHashCacheUpdate(t *testing.T) { }) t.Run("Expect BlocksHashCache has 4 cached keys after concat a 4-length-chain", func(t *testing.T) { - concatedChain := makeBlockChain(chain.CurrentBlock(), 4, ethash.NewFullFaker(), chain.db, 0) + concatedChain := makeBlockChain(chain.GetBlockByHash(chain.CurrentBlock().Hash()), 4, ethash.NewFullFaker(), chain.db, 0) if _, err := chain.InsertChain(concatedChain); err != nil { t.Fatalf("failed to insert shared chain: %v", err) } @@ -1540,7 +1541,7 @@ func TestBlocksHashCacheUpdate(t *testing.T) { t.Run("Expect BlocksHashCache caches when inserting block on syncing", func(t *testing.T) { currentCachedLength := len(chain.blocksHashCache.Keys()) - singleBlockChain := makeBlockChain(chain.CurrentBlock(), 1, ethash.NewFaker(), chain.db, 0) + singleBlockChain := makeBlockChain(chain.GetBlockByHash(chain.CurrentBlock().Hash()), 1, ethash.NewFaker(), chain.db, 0) chain.insertBlock(singleBlockChain[0]) if len(chain.blocksHashCache.Keys()) != currentCachedLength+1 { diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index d419f03b7c..7e62bd9ff4 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -87,7 +87,7 @@ func ExampleGenerateChain() { } state, _ := blockchain.State() - fmt.Printf("last block: #%d\n", blockchain.CurrentBlock().Number()) + fmt.Printf("last block: #%d\n", blockchain.CurrentBlock().Number) fmt.Println("balance of addr1:", state.GetBalance(addr1)) fmt.Println("balance of addr2:", state.GetBalance(addr2)) fmt.Println("balance of addr3:", state.GetBalance(addr3)) diff --git a/core/dao_test.go b/core/dao_test.go index 0fbbd7153d..8bb3bfa55f 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -43,21 +43,17 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Create the concurrent, conflicting two nodes proDb := rawdb.NewMemoryDatabase() gspec.MustCommit(proDb) - proConf := *params.TestChainConfig proConf.DAOForkBlock = forkBlock proConf.DAOForkSupport = true - proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}) defer proBc.Stop() conDb := rawdb.NewMemoryDatabase() gspec.MustCommit(conDb) - conConf := *params.TestChainConfig conConf.DAOForkBlock = forkBlock conConf.DAOForkSupport = false - conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}) defer conBc.Stop() @@ -73,9 +69,8 @@ func TestDAOForkRangeExtradata(t *testing.T) { db = rawdb.NewMemoryDatabase() gspec.MustCommit(db) bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}) - defer bc.Stop() - blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) + blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64())) for j := 0; j < len(blocks)/2; j++ { blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j] } @@ -85,12 +80,13 @@ func TestDAOForkRangeExtradata(t *testing.T) { if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil { t.Fatalf("failed to commit contra-fork head for expansion: %v", err) } - blocks, _ = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) + bc.Stop() + blocks, _ = GenerateChain(&proConf, conBc.GetBlockByHash(conBc.CurrentBlock().Hash()), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) if _, err := conBc.InsertChain(blocks); err == nil { t.Fatalf("contra-fork chain accepted pro-fork block: %v", blocks[0]) } // Create a proper no-fork block for the contra-forker - blocks, _ = GenerateChain(&conConf, conBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) + blocks, _ = GenerateChain(&conConf, conBc.GetBlockByHash(conBc.CurrentBlock().Hash()), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) if _, err := conBc.InsertChain(blocks); err != nil { t.Fatalf("contra-fork chain didn't accepted no-fork block: %v", err) } @@ -98,9 +94,8 @@ func TestDAOForkRangeExtradata(t *testing.T) { db = rawdb.NewMemoryDatabase() gspec.MustCommit(db) bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}) - defer bc.Stop() - blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) + blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64())) for j := 0; j < len(blocks)/2; j++ { blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j] } @@ -110,12 +105,13 @@ func TestDAOForkRangeExtradata(t *testing.T) { if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil { t.Fatalf("failed to commit pro-fork head for expansion: %v", err) } - blocks, _ = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) + bc.Stop() + blocks, _ = GenerateChain(&conConf, proBc.GetBlockByHash(proBc.CurrentBlock().Hash()), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) if _, err := proBc.InsertChain(blocks); err == nil { t.Fatalf("pro-fork chain accepted contra-fork block: %v", blocks[0]) } // Create a proper pro-fork block for the pro-forker - blocks, _ = GenerateChain(&proConf, proBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) + blocks, _ = GenerateChain(&proConf, proBc.GetBlockByHash(proBc.CurrentBlock().Hash()), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) if _, err := proBc.InsertChain(blocks); err != nil { t.Fatalf("pro-fork chain didn't accepted pro-fork block: %v", err) } @@ -126,7 +122,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}) defer bc.Stop() - blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) + blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64())) for j := 0; j < len(blocks)/2; j++ { blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j] } @@ -136,7 +132,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil { t.Fatalf("failed to commit contra-fork head for expansion: %v", err) } - blocks, _ = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) + blocks, _ = GenerateChain(&proConf, conBc.GetBlockByHash(conBc.CurrentBlock().Hash()), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) if _, err := conBc.InsertChain(blocks); err != nil { t.Fatalf("contra-fork chain didn't accept pro-fork block post-fork: %v", err) } @@ -146,7 +142,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}) defer bc.Stop() - blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) + blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64())) for j := 0; j < len(blocks)/2; j++ { blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j] } @@ -156,7 +152,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil { t.Fatalf("failed to commit pro-fork head for expansion: %v", err) } - blocks, _ = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) + blocks, _ = GenerateChain(&conConf, proBc.GetBlockByHash(proBc.CurrentBlock().Hash()), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) if _, err := proBc.InsertChain(blocks); err != nil { t.Fatalf("pro-fork chain didn't accept contra-fork block post-fork: %v", err) } diff --git a/core/state_processor_test.go b/core/state_processor_test.go index c2d31c8512..266324855c 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -402,7 +402,7 @@ func TestApplyTransactionWithEVMTracer(t *testing.T) { blockNumber := big.NewInt(1) blockHash := genesis.Hash() - vmContext := NewEVMBlockContext(blockchain.CurrentBlock().Header(), blockchain, nil) + vmContext := NewEVMBlockContext(blockchain.CurrentBlock(), blockchain, nil) evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, nil, blockchain.Config(), vmConfig) // Apply transaction diff --git a/core/txpool/lending_pool.go b/core/txpool/lending_pool.go index 9fdf39ec77..62c6b02838 100644 --- a/core/txpool/lending_pool.go +++ b/core/txpool/lending_pool.go @@ -72,7 +72,7 @@ type LendingPoolConfig struct { // blockChain_XDCx add order state type blockChainLending interface { - CurrentBlock() *types.Block + CurrentBlock() *types.Header GetBlock(hash common.Hash, number uint64) *types.Block LendingStateAt(block *types.Block) (*lendingstate.LendingStateDB, error) StateAt(root common.Hash) (*state.StateDB, error) @@ -151,7 +151,7 @@ type LendingPool struct { func NewLendingPool(chainconfig *params.ChainConfig, chain blockChainLending) *LendingPool { // Sanitize the input to ensure no vulnerable gas prices are set config := (&DefaultLendingPoolConfig).sanitize() - log.Debug("NewLendingPool start...", "current block", chain.CurrentBlock().Header().Number) + log.Debug("NewLendingPool start...", "current block", chain.CurrentBlock().Number) // Create the transaction pool with its initial settings pool := &LendingPool{ config: config, @@ -165,7 +165,7 @@ func NewLendingPool(chainconfig *params.ChainConfig, chain blockChainLending) *L chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), } pool.locals = newLendingAccountSet(pool.signer) - pool.reset(nil, chain.CurrentBlock()) + pool.reset(chain.CurrentBlock()) // If local transactions and journaling is enabled, load from disk if !config.NoLocals && config.Journal != "" { @@ -216,9 +216,13 @@ func (pool *LendingPool) loop() { if pool.chainconfig.IsHomestead(ev.Block.Number()) { pool.homestead = true } - log.Debug("LendingPool new chain header reset pool", "old", head.Header().Number, "new", ev.Block.Header().Number) - pool.reset(head, ev.Block) - head = ev.Block + if head != nil { + log.Debug("LendingPool new chain header reset pool", "old", head.Number, "new", ev.Block.Header().Number) + } else { + log.Debug("LendingPool new chain header reset pool", "old", "nil", "new", ev.Block.Header().Number) + } + pool.reset(ev.Block.Header()) + head = ev.Block.Header() pool.mu.Unlock() } @@ -268,19 +272,23 @@ func (pool *LendingPool) loop() { // reset retrieves the current state of the blockchain and ensures the content // of the transaction pool is valid with regard to the chain state. -func (pool *LendingPool) reset(oldHead, newblock *types.Block) { - if !pool.chainconfig.IsTIPXDCXReceiver(pool.chain.CurrentBlock().Number()) || pool.chain.Config().XDPoS == nil || pool.chain.CurrentBlock().NumberU64() <= pool.chain.Config().XDPoS.Epoch { +func (pool *LendingPool) reset(newHead *types.Header) { + if !pool.chainconfig.IsTIPXDCXReceiver(pool.chain.CurrentBlock().Number) || pool.chain.Config().XDPoS == nil || pool.chain.CurrentBlock().Number.Uint64() <= pool.chain.Config().XDPoS.Epoch { return } // If we're reorging an old state, reinject all dropped transactions var reinject types.LendingTransactions // Initialize the internal state to the current head - if newblock == nil { - newblock = pool.chain.CurrentBlock() + if newHead == nil { + newHead = pool.chain.CurrentBlock() } - newHead := newblock.Header() - lendingState, err := pool.chain.LendingStateAt(newblock) + newBlock := pool.chain.GetBlock(newHead.Hash(), newHead.Number.Uint64()) + if newBlock == nil { + log.Error("Not find block to reset LendingPool state", "number", newHead.Number, "hash", newHead.Hash()) + return + } + lendingState, err := pool.chain.LendingStateAt(newBlock) if err != nil { log.Error("Failed to reset LendingPool state", "err", err) return @@ -527,7 +535,12 @@ func (pool *LendingPool) validateBalance(cloneStateDb *state.StateDB, cloneLendi if err != nil { return err } - tradingStateDb, err := XDCXServ.GetTradingState(pool.chain.CurrentBlock(), author) + newHead := pool.chain.CurrentBlock() + newBlock := pool.chain.GetBlock(newHead.Hash(), newHead.Number.Uint64()) + if newBlock == nil { + return fmt.Errorf("not find block to validate balance, number: %d, hash: %s", newHead.Number, newHead.Hash().Hex()) + } + tradingStateDb, err := XDCXServ.GetTradingState(newBlock, author) if err != nil { return fmt.Errorf("validateLending: failed to get tradingStateDb. Error: %v", err) } @@ -808,7 +821,7 @@ func (pool *LendingPool) AddRemotes(txs []*types.LendingTransaction) []error { // addTx enqueues a single transaction into the pool if it is valid. func (pool *LendingPool) addTx(tx *types.LendingTransaction, local bool) error { - if !pool.chainconfig.IsTIPXDCXReceiver(pool.chain.CurrentBlock().Number()) { + if !pool.chainconfig.IsTIPXDCXReceiver(pool.chain.CurrentBlock().Number) { return nil } tx.CacheHash() diff --git a/core/txpool/order_pool.go b/core/txpool/order_pool.go index f9a624fa72..a95fdcc481 100644 --- a/core/txpool/order_pool.go +++ b/core/txpool/order_pool.go @@ -81,7 +81,7 @@ type OrderPoolConfig struct { // blockChain_XDCx add order state type blockChainXDCx interface { - CurrentBlock() *types.Block + CurrentBlock() *types.Header GetBlock(hash common.Hash, number uint64) *types.Block OrderStateAt(block *types.Block) (*tradingstate.TradingStateDB, error) StateAt(root common.Hash) (*state.StateDB, error) @@ -160,7 +160,7 @@ type OrderPool struct { func NewOrderPool(chainconfig *params.ChainConfig, chain blockChainXDCx) *OrderPool { // Sanitize the input to ensure no vulnerable gas prices are set config := (&DefaultOrderPoolConfig).sanitize() - log.Debug("NewOrderPool start...", "current block", chain.CurrentBlock().Header().Number) + log.Debug("NewOrderPool start...", "current block", chain.CurrentBlock().Number) // Create the transaction pool with its initial settings pool := &OrderPool{ config: config, @@ -174,7 +174,7 @@ func NewOrderPool(chainconfig *params.ChainConfig, chain blockChainXDCx) *OrderP chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), } pool.locals = newOrderAccountSet(pool.signer) - pool.reset(nil, chain.CurrentBlock()) + pool.reset(chain.CurrentBlock()) // If local transactions and journaling is enabled, load from disk if !config.NoLocals && config.Journal != "" { @@ -224,9 +224,13 @@ func (pool *OrderPool) loop() { if pool.chainconfig.IsHomestead(ev.Block.Number()) { pool.homestead = true } - log.Debug("OrderPool new chain header reset pool", "old", head.Header().Number, "new", ev.Block.Header().Number) - pool.reset(head, ev.Block) - head = ev.Block + if head != nil { + log.Debug("OrderPool new chain header reset pool", "old", head.Number, "new", ev.Block.Header().Number) + } else { + log.Debug("OrderPool new chain header reset pool", "old", "nil", "new", ev.Block.Header().Number) + } + pool.reset(ev.Block.Header()) + head = ev.Block.Header() pool.mu.Unlock() } @@ -274,19 +278,23 @@ func (pool *OrderPool) loop() { // reset retrieves the current state of the blockchain and ensures the content // of the transaction pool is valid with regard to the chain state. -func (pool *OrderPool) reset(oldHead, newblock *types.Block) { - if !pool.chainconfig.IsTIPXDCXReceiver(pool.chain.CurrentBlock().Number()) || pool.chain.Config().XDPoS == nil || pool.chain.CurrentBlock().NumberU64() <= pool.chain.Config().XDPoS.Epoch { +func (pool *OrderPool) reset(newHead *types.Header) { + if !pool.chainconfig.IsTIPXDCXReceiver(pool.chain.CurrentBlock().Number) || pool.chain.Config().XDPoS == nil || pool.chain.CurrentBlock().Number.Uint64() <= pool.chain.Config().XDPoS.Epoch { return } // If we're reorging an old state, reinject all dropped transactions var reinject types.OrderTransactions // Initialize the internal state to the current head - if newblock == nil { - newblock = pool.chain.CurrentBlock() + if newHead == nil { + newHead = pool.chain.CurrentBlock() } - newHead := newblock.Header() - orderstate, err := pool.chain.OrderStateAt(newblock) + newBlock := pool.chain.GetBlock(newHead.Hash(), newHead.Number.Uint64()) + if newBlock == nil { + log.Error("Not find block to reset OrderPool state", "number", newHead.Number, "hash", newHead.Hash()) + return + } + orderstate, err := pool.chain.OrderStateAt(newBlock) if err != nil { log.Error("Failed to reset OrderPool state", "err", err) return @@ -722,7 +730,7 @@ func (pool *OrderPool) AddRemotes(txs []*types.OrderTransaction) []error { // addTx enqueues a single transaction into the pool if it is valid. func (pool *OrderPool) addTx(tx *types.OrderTransaction, local bool) error { - if !pool.chainconfig.IsTIPXDCXReceiver(pool.chain.CurrentBlock().Number()) { + if !pool.chainconfig.IsTIPXDCXReceiver(pool.chain.CurrentBlock().Number) { return nil } tx.CacheHash() diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 5ad28d58a7..eb031c02be 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -162,7 +162,7 @@ const ( // blockChain provides the state of blockchain and current gas limit to do // some pre checks in tx pool and event subscribers. type blockChain interface { - CurrentBlock() *types.Block + CurrentBlock() *types.Header GetBlock(hash common.Hash, number uint64) *types.Block StateAt(root common.Hash) (*state.StateDB, error) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription @@ -339,7 +339,7 @@ func NewTxPool(config Config, chainconfig *params.ChainConfig, chain blockChain) pool.locals.add(addr) } pool.priced = newPricedList(pool.all) - pool.reset(nil, chain.CurrentBlock().Header()) + pool.reset(nil, chain.CurrentBlock()) // Start the reorg loop early so it can handle requests generated during journal loading. pool.wg.Go(pool.scheduleReorgLoop) @@ -387,8 +387,8 @@ func (pool *TxPool) loop() { // Handle ChainHeadEvent case ev := <-pool.chainHeadCh: if ev.Block != nil { - pool.requestReset(head.Header(), ev.Block.Header()) - head = ev.Block + pool.requestReset(head, ev.Block.Header()) + head = ev.Block.Header() } // System shutdown. @@ -1506,7 +1506,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { } // Initialize the internal state to the current head if newHead == nil { - newHead = pool.chain.CurrentBlock().Header() // Special case during testing + newHead = pool.chain.CurrentBlock() // Special case during testing } statedb, err := pool.chain.StateAt(newHead.Root) if err != nil { diff --git a/core/txpool/txpool_test.go b/core/txpool/txpool_test.go index d8e7145c1c..7d6be9f626 100644 --- a/core/txpool/txpool_test.go +++ b/core/txpool/txpool_test.go @@ -83,15 +83,16 @@ func (bc *testBlockChain) Config() *params.ChainConfig { return nil } -func (bc *testBlockChain) CurrentBlock() *types.Block { - return types.NewBlock(&types.Header{ +func (bc *testBlockChain) CurrentBlock() *types.Header { + return &types.Header{ Root: types.EmptyRootHash, + Number: new(big.Int), GasLimit: atomic.LoadUint64(&bc.gasLimit), - }, nil, nil, trie.NewStackTrie(nil)) + } } func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { - return bc.CurrentBlock() + return types.NewBlock(bc.CurrentBlock(), nil, nil, trie.NewStackTrie(nil)) } func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { diff --git a/core/types/block.go b/core/types/block.go index edc1184012..b9b4b56d62 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -411,7 +411,7 @@ func (b *Block) HashNoValidator() common.Hash { } // Size returns the true RLP encoded storage size of the block, either by encoding -// and returning it, or returning a previsouly cached value. +// and returning it, or returning a previously cached value. func (b *Block) Size() uint64 { if size := b.size.Load(); size > 0 { return size diff --git a/core/types/lending_transaction.go b/core/types/lending_transaction.go index 03cd1a9420..8b075e475a 100644 --- a/core/types/lending_transaction.go +++ b/core/types/lending_transaction.go @@ -242,7 +242,7 @@ func (tx *LendingTransaction) CacheHash() { } // Size returns the true RLP encoded storage size of the transaction, either by -// encoding and returning it, or returning a previsouly cached value. +// encoding and returning it, or returning a previously cached value. func (tx *LendingTransaction) Size() common.StorageSize { if size := tx.size.Load(); size != nil { return size.(common.StorageSize) diff --git a/core/types/order_transaction.go b/core/types/order_transaction.go index 471bea5dcf..9c4b17516a 100644 --- a/core/types/order_transaction.go +++ b/core/types/order_transaction.go @@ -185,7 +185,7 @@ func (tx *OrderTransaction) CacheHash() { } // Size returns the true RLP encoded storage size of the transaction, either by -// encoding and returning it, or returning a previsouly cached value. +// encoding and returning it, or returning a previously cached value. func (tx *OrderTransaction) Size() common.StorageSize { if size := tx.size.Load(); size != nil { return size.(common.StorageSize) diff --git a/eth/api.go b/eth/api.go index 98335b21a3..df2a6cf73a 100644 --- a/eth/api.go +++ b/eth/api.go @@ -57,7 +57,7 @@ func (api *EthereumAPI) Mining() bool { func (api *EthereumAPI) ChainId() hexutil.Uint64 { chainID := new(big.Int) - if config := api.e.chainConfig; config.IsEIP155(api.e.blockchain.CurrentBlock().Number()) { + if config := api.e.chainConfig; config.IsEIP155(api.e.blockchain.CurrentBlock().Number) { chainID = config.ChainID } return (hexutil.Uint64)(chainID.Uint64()) diff --git a/eth/api_backend.go b/eth/api_backend.go index 35b3be4d1e..fde60d3035 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -68,7 +68,7 @@ func (b *EthAPIBackend) ChainConfig() *params.ChainConfig { return b.eth.chainConfig } -func (b *EthAPIBackend) CurrentBlock() *types.Block { +func (b *EthAPIBackend) CurrentBlock() *types.Header { return b.eth.blockchain.CurrentBlock() } @@ -84,13 +84,13 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb } // Otherwise resolve and return the block if number == rpc.LatestBlockNumber { - return b.eth.blockchain.CurrentBlock().Header(), nil + return b.eth.blockchain.CurrentBlock(), nil } if number == rpc.FinalizedBlockNumber { if b.eth.chainConfig.XDPoS == nil { return nil, errors.New("PoW does not support confirmed block lookup") } - current := b.eth.blockchain.CurrentBlock().Header() + current := b.eth.blockchain.CurrentBlock() if b.eth.blockchain.Config().XDPoS.BlockConsensusVersion(current.Number) == params.ConsensusEngineVersion2 { // TO CHECK: why calling config in XDPoS is blocked (not field and method) confirmedHash := b.XDPoS.EngineV2.GetLatestCommittedBlockInfo().Hash @@ -136,13 +136,17 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe } // Otherwise resolve and return the block if number == rpc.LatestBlockNumber { - return b.eth.blockchain.CurrentBlock(), nil + header := b.eth.blockchain.CurrentBlock() + return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil } if number == rpc.FinalizedBlockNumber { if b.eth.chainConfig.XDPoS == nil { return nil, errors.New("PoW does not support confirmed block lookup") } - current := b.eth.blockchain.CurrentBlock().Header() + current := b.eth.blockchain.CurrentBlock() + if current == nil { + return nil, errors.New("current block is nil") + } if b.eth.blockchain.Config().XDPoS.BlockConsensusVersion(current.Number) == params.ConsensusEngineVersion2 { // TO CHECK: why calling config in XDPoS is blocked (not field and method) confirmedHash := b.XDPoS.EngineV2.GetLatestCommittedBlockInfo().Hash @@ -465,19 +469,19 @@ func (b *EthAPIBackend) GetRewardByHash(hash common.Hash) map[string]map[string] // 4. Calculate voters's rewards for input masternode func (b *EthAPIBackend) GetVotersRewards(masternodeAddr common.Address) map[common.Address]*big.Int { chain := b.eth.blockchain - block := chain.CurrentBlock() - number := block.Number().Uint64() + header := chain.CurrentBlock() + number := header.Number.Uint64() engine := b.Engine().(*XDPoS.XDPoS) foundationWalletAddr := chain.Config().XDPoS.FoudationWalletAddr // calculate for 2 epochs ago - currentCheckpointNumber, _, err := engine.GetCurrentEpochSwitchBlock(chain, block.Number()) + currentCheckpointNumber, _, err := engine.GetCurrentEpochSwitchBlock(chain, header.Number) if err != nil { - log.Error("[GetVotersRewards] Fail to get GetCurrentEpochSwitchBlock for current checkpoint block", "block", block.Number(), "err", err) + log.Error("[GetVotersRewards] Fail to get GetCurrentEpochSwitchBlock for current checkpoint block", "block", header.Number, "err", err) } lastCheckpointNumber, _, err := engine.GetCurrentEpochSwitchBlock(chain, big.NewInt(int64(currentCheckpointNumber-1))) if err != nil { - log.Error("[GetVotersRewards] Fail to get GetCurrentEpochSwitchBlock for last checkpoint block", "block", block.Number(), "err", err) + log.Error("[GetVotersRewards] Fail to get GetCurrentEpochSwitchBlock for last checkpoint block", "block", header.Number, "err", err) } lastCheckpointBlock := chain.GetBlockByNumber(lastCheckpointNumber) @@ -567,8 +571,8 @@ func (b *EthAPIBackend) GetVotersCap(checkpoint *big.Int, masterAddr common.Addr // ie 30min for each epoch func (b *EthAPIBackend) GetEpochDuration() *big.Int { chain := b.eth.blockchain - block := chain.CurrentBlock() - number := block.Number().Uint64() + header := chain.CurrentBlock() + number := header.Number.Uint64() lastCheckpointNumber := number - (number % b.ChainConfig().XDPoS.Epoch) lastCheckpointBlockTime := chain.GetBlockByNumber(lastCheckpointNumber).Time() secondToLastCheckpointNumber := lastCheckpointNumber - b.ChainConfig().XDPoS.Epoch diff --git a/eth/api_debug.go b/eth/api_debug.go index 103a158389..9a8ae3d519 100644 --- a/eth/api_debug.go +++ b/eth/api_debug.go @@ -55,16 +55,20 @@ func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) { if blockNr == rpc.PendingBlockNumber { blockNr = rpc.LatestBlockNumber } - var block *types.Block + var header *types.Header if blockNr == rpc.LatestBlockNumber { - block = api.eth.blockchain.CurrentBlock() + header = api.eth.blockchain.CurrentBlock() } else { - block = api.eth.blockchain.GetBlockByNumber(uint64(blockNr)) + block := api.eth.blockchain.GetBlockByNumber(uint64(blockNr)) + if block == nil { + return state.Dump{}, fmt.Errorf("block #%d not found", blockNr) + } + header = block.Header() } - if block == nil { + if header == nil { return state.Dump{}, fmt.Errorf("block #%d not found", blockNr) } - stateDb, err := api.eth.BlockChain().StateAt(block.Root()) + stateDb, err := api.eth.BlockChain().StateAt(header.Root) if err != nil { return state.Dump{}, err } @@ -128,16 +132,20 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start []b // the miner and operate on those _, stateDb = api.eth.miner.Pending() } else { - var block *types.Block + var header *types.Header if number == rpc.LatestBlockNumber { - block = api.eth.blockchain.CurrentBlock() + header = api.eth.blockchain.CurrentBlock() } else { - block = api.eth.blockchain.GetBlockByNumber(uint64(number)) + block := api.eth.blockchain.GetBlockByNumber(uint64(number)) + if block == nil { + return state.IteratorDump{}, fmt.Errorf("block #%d not found", number) + } + header = block.Header() } - if block == nil { + if header == nil { return state.IteratorDump{}, fmt.Errorf("block #%d not found", number) } - stateDb, err = api.eth.BlockChain().StateAt(block.Root()) + stateDb, err = api.eth.BlockChain().StateAt(header.Root) if err != nil { return state.IteratorDump{}, err } diff --git a/eth/backend.go b/eth/backend.go index a6a22edd3a..6095b816b3 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -235,7 +235,7 @@ func New(stack *node.Node, config *ethconfig.Config, XDCXServ *XDCx.XDCX, lendin if currentBlock == nil { return nil, fmt.Errorf("not find current block when rollback to %d", common.RollbackNumber) } - currentNumber := currentBlock.NumberU64() + currentNumber := currentBlock.Number.Uint64() if target > currentNumber { return nil, fmt.Errorf("can't rollback to %d which is greater than current %d", target, currentNumber) } diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index f523420191..14be27b196 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -189,11 +189,11 @@ type BlockChain interface { // GetBlockByHash retrieves a block from the local chain. GetBlockByHash(common.Hash) *types.Block - // CurrentBlock retrieves the head block from the local chain. - CurrentBlock() *types.Block + // CurrentBlock retrieves the header of the head block from the local chain. + CurrentBlock() *types.Header - // CurrentFastBlock retrieves the head fast block from the local chain. - CurrentFastBlock() *types.Block + // CurrentSnapBlock retrieves the header of the head snap block from the local chain. + CurrentSnapBlock() *types.Header // FastSyncCommitHead directly commits the head block to a certain entity. FastSyncCommitHead(common.Hash) error @@ -264,9 +264,9 @@ func (d *Downloader) Progress() XDPoSChain.SyncProgress { mode := d.getMode() switch { case d.blockchain != nil && mode == FullSync: - current = d.blockchain.CurrentBlock().NumberU64() + current = d.blockchain.CurrentBlock().Number.Uint64() case d.blockchain != nil && mode == FastSync: - current = d.blockchain.CurrentFastBlock().NumberU64() + current = d.blockchain.CurrentSnapBlock().Number.Uint64() case d.lightchain != nil: current = d.lightchain.CurrentHeader().Number.Uint64() default: @@ -671,9 +671,9 @@ func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header) mode := d.getMode() switch mode { case FullSync: - localHeight = d.blockchain.CurrentBlock().NumberU64() + localHeight = d.blockchain.CurrentBlock().Number.Uint64() case FastSync: - localHeight = d.blockchain.CurrentFastBlock().NumberU64() + localHeight = d.blockchain.CurrentSnapBlock().Number.Uint64() default: localHeight = d.lightchain.CurrentHeader().Number.Uint64() } @@ -943,8 +943,8 @@ func (d *Downloader) fetchHeaders(p *peerConnection, from uint64, pivot uint64) if mode == LightSync { head = d.lightchain.CurrentHeader().Number.Uint64() } else { - head = d.blockchain.CurrentFastBlock().NumberU64() - if full := d.blockchain.CurrentBlock().NumberU64(); head < full { + head = d.blockchain.CurrentSnapBlock().Number.Uint64() + if full := d.blockchain.CurrentBlock().Number.Uint64(); head < full { head = full } } @@ -1311,14 +1311,14 @@ func (d *Downloader) processHeaders(origin uint64, pivot uint64, td *big.Int) er } lastHeader, lastFastBlock, lastBlock := d.lightchain.CurrentHeader().Number, common.Big0, common.Big0 if mode != LightSync { - lastFastBlock = d.blockchain.CurrentFastBlock().Number() - lastBlock = d.blockchain.CurrentBlock().Number() + lastFastBlock = d.blockchain.CurrentSnapBlock().Number + lastBlock = d.blockchain.CurrentBlock().Number } d.lightchain.Rollback(hashes) curFastBlock, curBlock := common.Big0, common.Big0 if mode != LightSync { - curFastBlock = d.blockchain.CurrentFastBlock().Number() - curBlock = d.blockchain.CurrentBlock().Number() + curFastBlock = d.blockchain.CurrentSnapBlock().Number + curBlock = d.blockchain.CurrentBlock().Number } log.Warn("Rolled back headers", "count", len(hashes), "header", fmt.Sprintf("%d->%d", lastHeader, d.lightchain.CurrentHeader().Number), @@ -1360,7 +1360,7 @@ func (d *Downloader) processHeaders(origin uint64, pivot uint64, td *big.Int) er // R: Nothing to give if mode != LightSync { head := d.blockchain.CurrentBlock() - if !gotHeaders && td.Cmp(d.blockchain.GetTd(head.Hash(), head.NumberU64())) > 0 { + if !gotHeaders && td.Cmp(d.blockchain.GetTd(head.Hash(), head.Number.Uint64())) > 0 { return errStallingPeer } } diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 9cee05d056..09b0277ffa 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -168,31 +168,31 @@ func (dl *downloadTester) CurrentHeader() *types.Header { } // CurrentBlock retrieves the current head block from the canonical chain. -func (dl *downloadTester) CurrentBlock() *types.Block { +func (dl *downloadTester) CurrentBlock() *types.Header { dl.lock.RLock() defer dl.lock.RUnlock() for i := len(dl.ownHashes) - 1; i >= 0; i-- { if block := dl.ownBlocks[dl.ownHashes[i]]; block != nil { if _, err := dl.stateDb.Get(block.Root().Bytes()); err == nil { - return block + return block.Header() } } } - return dl.genesis + return dl.genesis.Header() } // CurrentFastBlock retrieves the current head fast-sync block from the canonical chain. -func (dl *downloadTester) CurrentFastBlock() *types.Block { +func (dl *downloadTester) CurrentSnapBlock() *types.Header { dl.lock.RLock() defer dl.lock.RUnlock() for i := len(dl.ownHashes) - 1; i >= 0; i-- { if block := dl.ownBlocks[dl.ownHashes[i]]; block != nil { - return block + return block.Header() } } - return dl.genesis + return dl.genesis.Header() } // FastSyncCommitHead manually sets the head block to a given hash. @@ -1002,7 +1002,7 @@ func testInvalidHeaderRollback(t *testing.T, protocol int, mode SyncMode) { t.Errorf("rollback head mismatch: have %v, want at most %v", head, 2*fsHeaderSafetyNet+MaxHeaderFetch) } if mode == FastSync { - if head := tester.CurrentBlock().NumberU64(); head != 0 { + if head := tester.CurrentBlock().Number.Uint64(); head != 0 { t.Errorf("fast sync pivot block #%d not rolled back", head) } } @@ -1025,7 +1025,7 @@ func testInvalidHeaderRollback(t *testing.T, protocol int, mode SyncMode) { t.Errorf("rollback head mismatch: have %v, want at most %v", head, 2*fsHeaderSafetyNet+MaxHeaderFetch) } if mode == FastSync { - if head := tester.CurrentBlock().NumberU64(); head != 0 { + if head := tester.CurrentBlock().Number.Uint64(); head != 0 { t.Errorf("fast sync pivot block #%d not rolled back", head) } } diff --git a/eth/downloader/statesync.go b/eth/downloader/statesync.go index a3898d2847..6d52f3374d 100644 --- a/eth/downloader/statesync.go +++ b/eth/downloader/statesync.go @@ -140,7 +140,7 @@ func (d *Downloader) runStateSync(s *stateSync) *stateSync { // Handle incoming state packs: case pack := <-d.stateCh: - // Discard any data not requested (or previsouly timed out) + // Discard any data not requested (or previously timed out) req := active[pack.PeerId()] if req == nil { log.Debug("Unrequested node data", "peer", pack.PeerId(), "len", pack.Items()) diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index 62661c3058..da4d4329a0 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -49,7 +49,7 @@ func (b *testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber number = 0 } if number == rpc.FinalizedBlockNumber { - return b.chain.CurrentBlock().Header(), nil + return b.chain.CurrentBlock(), nil } if number == rpc.LatestBlockNumber { number = testHead @@ -72,7 +72,7 @@ func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) number = 0 } if number == rpc.FinalizedBlockNumber { - return b.chain.CurrentBlock(), nil + number = rpc.BlockNumber(b.chain.CurrentBlock().Number.Uint64()) } if number == rpc.LatestBlockNumber { number = testHead diff --git a/eth/handler.go b/eth/handler.go index b00e2eb5c7..a99e4a433e 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -68,7 +68,7 @@ func errResp(code errCode, format string, v ...interface{}) error { type ProtocolManager struct { networkId uint64 - fastSync uint32 // Flag whether fast sync is enabled (gets disabled if we already have blocks) + snapSync uint32 // Flag whether snap sync is enabled (gets disabled if we already have blocks) acceptTxs uint32 // Flag whether we're considered synchronised (enables transaction processing) txpool txPool @@ -151,12 +151,12 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne lendingTxSub: nil, } // Figure out whether to allow fast sync or not - if mode == downloader.FastSync && blockchain.CurrentBlock().NumberU64() > 0 { + if mode == downloader.FastSync && blockchain.CurrentBlock().Number.Uint64() > 0 { log.Warn("Blockchain not empty, fast sync disabled") mode = downloader.FullSync } if mode == downloader.FastSync { - manager.fastSync = uint32(1) + manager.snapSync = uint32(1) } // Initiate a sub-protocol for every implemented version we can handle manager.SubProtocols = make([]p2p.Protocol, 0, len(ProtocolVersions)) @@ -215,12 +215,12 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne } heighter := func() uint64 { - return blockchain.CurrentBlock().NumberU64() + return blockchain.CurrentBlock().Number.Uint64() } inserter := func(block *types.Block) error { // If fast sync is running, deny importing weird blocks - if atomic.LoadUint32(&manager.fastSync) == 1 { + if atomic.LoadUint32(&manager.snapSync) == 1 { log.Warn("Discarded bad propagated block", "number", block.Number(), "hash", block.Hash()) return nil } @@ -230,7 +230,7 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne prepare := func(block *types.Block) error { // If fast sync is running, deny importing weird blocks - if atomic.LoadUint32(&manager.fastSync) == 1 { + if atomic.LoadUint32(&manager.snapSync) == 1 { log.Warn("Discarded bad propagated block", "number", block.Number(), "hash", block.Hash()) return nil } @@ -751,7 +751,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { // a singe block (as the true TD is below the propagated block), however this // scenario should easily be covered by the fetcher. currentBlock := pm.blockchain.CurrentBlock() - if trueTD.Cmp(pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64())) > 0 { + if trueTD.Cmp(pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.Number.Uint64())) > 0 { go pm.synchronise(p) } } @@ -1096,7 +1096,7 @@ func (pm *ProtocolManager) NodeInfo() *NodeInfo { currentBlock := pm.blockchain.CurrentBlock() return &NodeInfo{ Network: pm.networkId, - Difficulty: pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64()), + Difficulty: pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.Number.Uint64()), Genesis: pm.blockchain.Genesis().Hash(), Config: pm.blockchain.Config(), Head: currentBlock.Hash(), diff --git a/eth/handler_test.go b/eth/handler_test.go index 651a33a28c..3e74b6ad1e 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -132,20 +132,20 @@ func testGetBlockHeaders(t *testing.T, protocol int) { &getBlockHeadersData{Origin: hashOrNumber{Number: 0}, Amount: 1}, []common.Hash{pm.blockchain.GetBlockByNumber(0).Hash()}, }, { - &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64()}, Amount: 1}, + &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().Number.Uint64()}, Amount: 1}, []common.Hash{pm.blockchain.CurrentBlock().Hash()}, }, // Ensure protocol limits are honored { - &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 1}, Amount: limit + 10, Reverse: true}, + &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().Number.Uint64() - 1}, Amount: limit + 10, Reverse: true}, pm.blockchain.GetBlockHashesFromHash(pm.blockchain.CurrentBlock().Hash(), limit), }, // Check that requesting more than available is handled gracefully { - &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 3, Amount: 3}, + &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().Number.Uint64() - 4}, Skip: 3, Amount: 3}, []common.Hash{ - pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(), - pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64()).Hash(), + pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().Number.Uint64() - 4).Hash(), + pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().Number.Uint64()).Hash(), }, }, { &getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 3, Amount: 3, Reverse: true}, @@ -156,10 +156,10 @@ func testGetBlockHeaders(t *testing.T, protocol int) { }, // Check that requesting more than available is handled gracefully, even if mid skip { - &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 2, Amount: 3}, + &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().Number.Uint64() - 4}, Skip: 2, Amount: 3}, []common.Hash{ - pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(), - pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 1).Hash(), + pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().Number.Uint64() - 4).Hash(), + pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().Number.Uint64() - 1).Hash(), }, }, { &getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 2, Amount: 3, Reverse: true}, @@ -196,7 +196,7 @@ func testGetBlockHeaders(t *testing.T, protocol int) { &getBlockHeadersData{Origin: hashOrNumber{Hash: unknown}, Amount: 1}, []common.Hash{}, }, { - &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() + 1}, Amount: 1}, + &getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().Number.Uint64() + 1}, Amount: 1}, []common.Hash{}, }, } @@ -270,7 +270,7 @@ func testGetBlockBodies(t *testing.T, protocol int) { for j := 0; j < tt.random; j++ { for { - num := rand.Int63n(int64(pm.blockchain.CurrentBlock().NumberU64())) + num := rand.Int63n(int64(pm.blockchain.CurrentBlock().Number.Uint64())) if !seen[num] { seen[num] = true @@ -374,7 +374,7 @@ func testGetNodeData(t *testing.T, protocol int) { statedb.Put(hashes[i].Bytes(), data[i]) } accounts := []common.Address{testBank, acc1Addr, acc2Addr} - for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ { + for i := uint64(0); i <= pm.blockchain.CurrentBlock().Number.Uint64(); i++ { trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), state.NewDatabase(statedb)) for j, acc := range accounts { @@ -438,7 +438,7 @@ func testGetReceipt(t *testing.T, protocol int) { // Collect the hashes to request, and the response to expect hashes, receipts := []common.Hash{}, []types.Receipts{} - for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ { + for i := uint64(0); i <= pm.blockchain.CurrentBlock().Number.Uint64(); i++ { block := pm.blockchain.GetBlockByNumber(i) hashes = append(hashes, block.Hash()) diff --git a/eth/sync.go b/eth/sync.go index 85ff3a0815..f816af2d7f 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -170,29 +170,29 @@ func (pm *ProtocolManager) synchronise(peer *peer) { } // Make sure the peer's TD is higher than our own currentBlock := pm.blockchain.CurrentBlock() - td := pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64()) + td := pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.Number.Uint64()) pHead, pTd := peer.Head() if pTd.Cmp(td) <= 0 { return } // Otherwise try to sync with the downloader mode := downloader.FullSync - if atomic.LoadUint32(&pm.fastSync) == 1 { + if atomic.LoadUint32(&pm.snapSync) == 1 { // Fast sync was explicitly requested, and explicitly granted mode = downloader.FastSync - } else if currentBlock.NumberU64() == 0 && pm.blockchain.CurrentFastBlock().NumberU64() > 0 { + } else if currentBlock.Number.Uint64() == 0 && pm.blockchain.CurrentSnapBlock().Number.Uint64() > 0 { // The database seems empty as the current block is the genesis. Yet the fast // block is ahead, so fast sync was enabled for this node at a certain point. // The only scenario where this can happen is if the user manually (or via a // bad block) rolled back a fast sync node below the sync point. In this case // however it's safe to reenable fast sync. - atomic.StoreUint32(&pm.fastSync, 1) + atomic.StoreUint32(&pm.snapSync, 1) mode = downloader.FastSync } if mode == downloader.FastSync { // Make sure the peer's total difficulty we are synchronizing is higher. - if pm.blockchain.GetTdByHash(pm.blockchain.CurrentFastBlock().Hash()).Cmp(pTd) >= 0 { + if pm.blockchain.GetTdByHash(pm.blockchain.CurrentSnapBlock().Hash()).Cmp(pTd) >= 0 { return } } @@ -201,9 +201,9 @@ func (pm *ProtocolManager) synchronise(peer *peer) { if err := pm.downloader.Synchronise(peer.id, pHead, pTd, mode); err != nil { return } - if atomic.LoadUint32(&pm.fastSync) == 1 { + if atomic.LoadUint32(&pm.snapSync) == 1 { log.Info("Fast sync complete, auto disabling") - atomic.StoreUint32(&pm.fastSync, 0) + atomic.StoreUint32(&pm.snapSync, 0) } atomic.StoreUint32(&pm.acceptTxs, 1) // Mark initial sync done //if head := pm.blockchain.CurrentBlock(); head.NumberU64() > 0 { diff --git a/eth/sync_test.go b/eth/sync_test.go index cd5b85e941..3880e18572 100644 --- a/eth/sync_test.go +++ b/eth/sync_test.go @@ -31,13 +31,13 @@ import ( func TestFastSyncDisabling(t *testing.T) { // Create a pristine protocol manager, check that fast sync is left enabled pmEmpty, _ := newTestProtocolManagerMust(t, downloader.FastSync, 0, nil, nil) - if atomic.LoadUint32(&pmEmpty.fastSync) == 0 { - t.Fatalf("fast sync disabled on pristine blockchain") + if atomic.LoadUint32(&pmEmpty.snapSync) == 0 { + t.Fatalf("snap sync disabled on pristine blockchain") } - // Create a full protocol manager, check that fast sync gets disabled + // Create a full protocol manager, check that snap sync gets disabled pmFull, _ := newTestProtocolManagerMust(t, downloader.FastSync, 1024, nil, nil) - if atomic.LoadUint32(&pmFull.fastSync) == 1 { - t.Fatalf("fast sync not disabled on non-empty blockchain") + if atomic.LoadUint32(&pmFull.snapSync) == 1 { + t.Fatalf("snap sync not disabled on non-empty blockchain") } // Sync up the two peers io1, io2 := p2p.MsgPipe() @@ -48,8 +48,8 @@ func TestFastSyncDisabling(t *testing.T) { time.Sleep(250 * time.Millisecond) pmEmpty.synchronise(pmEmpty.peers.BestPeer()) - // Check that fast sync was disabled - if atomic.LoadUint32(&pmEmpty.fastSync) == 1 { - t.Fatalf("fast sync not disabled after successful synchronisation") + // Check that snap sync was disabled + if atomic.LoadUint32(&pmEmpty.snapSync) == 1 { + t.Fatalf("snap sync not disabled after successful synchronisation") } } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 0bafbe03e4..e91502e808 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -112,7 +112,7 @@ func (b *testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { if number == rpc.PendingBlockNumber || number == rpc.LatestBlockNumber { - return b.chain.CurrentBlock(), nil + return b.chain.GetBlockByNumber(b.chain.CurrentBlock().Number.Uint64()), nil } return b.chain.GetBlockByNumber(uint64(number)), nil } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 602ab19e70..c03e16a17c 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -773,7 +773,7 @@ func (api *BlockChainAPI) GetMasternodes(ctx context.Context, b *types.Block) ([ if b.Number().Int64() >= 0 { curBlockNumber := b.Number().Uint64() prevBlockNumber := curBlockNumber + (common.MergeSignRange - (curBlockNumber % common.MergeSignRange)) - latestBlockNumber := api.b.CurrentBlock().Number().Uint64() + latestBlockNumber := api.b.CurrentBlock().Number.Uint64() if prevBlockNumber >= latestBlockNumber || !api.b.ChainConfig().IsTIP2019(b.Number()) { prevBlockNumber = curBlockNumber } @@ -1122,7 +1122,7 @@ func (api *BlockChainAPI) GetCheckpointFromEpoch(ctx context.Context, epochNum r epoch := api.b.ChainConfig().XDPoS.Epoch if epochNum == rpc.LatestEpochNumber { - blockNumer := api.b.CurrentBlock().Number() + blockNumer := api.b.CurrentBlock().Number if engine, ok := api.b.Engine().(*XDPoS.XDPoS); ok { var err error var currentEpoch uint64 @@ -1512,7 +1512,7 @@ func (api *BlockChainAPI) findNearestSignedBlock(ctx context.Context, b *types.B blockNumber := b.Number().Uint64() signedBlockNumber := blockNumber + (common.MergeSignRange - (blockNumber % common.MergeSignRange)) - latestBlockNumber := api.b.CurrentBlock().Number() + latestBlockNumber := api.b.CurrentBlock().Number if signedBlockNumber >= latestBlockNumber.Uint64() || !api.b.ChainConfig().IsTIPSigning(b.Number()) { signedBlockNumber = blockNumber @@ -2083,7 +2083,7 @@ func (s *TransactionAPI) sign(addr common.Address, tx *types.Transaction) (*type } // Request the wallet to sign the transaction var chainID *big.Int - if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) { + if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number) { chainID = config.ChainID } return wallet.SignTx(account, tx, chainID) @@ -2109,7 +2109,7 @@ func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (c } // Print a log with full tx details for manual investigations and interventions - signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number()) + signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number) from, err := types.Sender(signer, tx) if err != nil { return common.Hash{}, err @@ -2150,7 +2150,7 @@ func (s *TransactionAPI) SendTransaction(ctx context.Context, args TransactionAr tx := args.ToTransaction(types.LegacyTxType) var chainID *big.Int - if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) { + if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number) { chainID = config.ChainID } signed, err := wallet.SignTx(account, tx, chainID) @@ -2522,7 +2522,7 @@ func GetSignersFromBlocks(b Backend, blockNumber uint64, blockHash common.Hash, signer := types.MakeSigner(b.ChainConfig(), new(big.Int).SetUint64(blockNumber)) if engine, ok := b.Engine().(*XDPoS.XDPoS); ok { limitNumber := blockNumber + common.LimitTimeFinality - currentNumber := b.CurrentBlock().NumberU64() + currentNumber := b.CurrentBlock().Number.Uint64() if limitNumber > currentNumber { limitNumber = currentNumber } @@ -2564,7 +2564,7 @@ func GetSignersFromBlocks(b Backend, blockNumber uint64, blockHash common.Hash, // // ROI = average_latest_epoch_reward_for_voters*number_of_epoch_per_year/latest_total_cap*100 func (api *BlockChainAPI) GetStakerROI() float64 { - blockNumber := api.b.CurrentBlock().Number().Uint64() + blockNumber := api.b.CurrentBlock().Number.Uint64() lastCheckpointNumber := blockNumber - (blockNumber % api.b.ChainConfig().XDPoS.Epoch) - api.b.ChainConfig().XDPoS.Epoch // calculate for 2 epochs ago totalCap := new(big.Int).SetUint64(0) @@ -2603,7 +2603,7 @@ func (api *BlockChainAPI) GetStakerROIMasternode(masternode common.Address) floa masternodeReward.Add(masternodeReward, reward) } - blockNumber := api.b.CurrentBlock().Number().Uint64() + blockNumber := api.b.CurrentBlock().Number.Uint64() lastCheckpointNumber := blockNumber - blockNumber%api.b.ChainConfig().XDPoS.Epoch totalCap := new(big.Int).SetUint64(0) votersCap := api.b.GetVotersCap(new(big.Int).SetUint64(lastCheckpointNumber), masternode, voters) diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 7850b232bc..9f720c912d 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -92,7 +92,7 @@ type Backend interface { ChainConfig() *params.ChainConfig Engine() consensus.Engine - CurrentBlock() *types.Block + CurrentBlock() *types.Header GetIPCClient() (bind.ContractBackend, error) GetRewardByHash(hash common.Hash) map[string]map[string]map[string]*big.Int diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index a8ad17931b..71ace1fd1c 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -317,7 +317,7 @@ func (b *backendMock) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rp return nil, nil } -func (b *backendMock) CurrentBlock() *types.Block { return nil } +func (b *backendMock) CurrentBlock() *types.Header { return nil } func (b *backendMock) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { return nil, nil diff --git a/miner/worker.go b/miner/worker.go index 6e126cd014..c8c4a2fe0e 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -393,10 +393,18 @@ func (w *worker) getHashrate() int64 { } func getResetTime(chain *core.BlockChain, minePeriod int) time.Duration { - minePeriodDuration := time.Duration(minePeriod) * time.Second - currentBlockTime := int64(chain.CurrentBlock().Time()) - nowTime := time.Now().UnixMilli() - resetTime := time.Duration(currentBlockTime)*time.Second + minePeriodDuration - time.Duration(nowTime)*time.Millisecond + var ( + currentBlockTime int64 = 0 + nowTime int64 = 0 + resetTime time.Duration = 0 + minePeriodDuration time.Duration = time.Duration(minePeriod) * time.Second + header *types.Header = chain.CurrentBlock() + ) + if header != nil { + currentBlockTime = int64(header.Time) + nowTime = time.Now().UnixMilli() + resetTime = time.Duration(currentBlockTime)*time.Second + minePeriodDuration - time.Duration(nowTime)*time.Millisecond + } // in case the current block time is not very accurate if resetTime > minePeriodDuration || resetTime <= 0 { resetTime = minePeriodDuration @@ -622,6 +630,8 @@ func (w *worker) makeCurrent(parent *types.Block, header *types.Header) error { return nil } +// checkPreCommitWithLock checks whether a new work commit is needed with locks, +// returns the parent block and shouldReturn. func (w *worker) checkPreCommitWithLock() (*types.Block, bool) { w.mu.Lock() defer w.mu.Unlock() @@ -633,15 +643,24 @@ func (w *worker) checkPreCommitWithLock() (*types.Block, bool) { return w.checkPreCommit() } +// checkPreCommit checks whether a new work commit is needed, +// returns the parent block and shouldReturn. func (w *worker) checkPreCommit() (*types.Block, bool) { c := w.engine.(*XDPoS.XDPoS) var parent *types.Block - if c != nil { - parent = c.FindParentBlockToAssign(w.chain, w.chain.CurrentBlock()) - } else { - parent = w.chain.CurrentBlock() + currentHeader := w.chain.CurrentBlock() + // Guard against nil header (early startup or uninitialised chain). + if currentHeader == nil { + return nil, true + } + if c != nil { + parent = c.FindParentBlockToAssign(w.chain, currentHeader) + } else { + parent = w.chain.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64()) + } + if parent == nil { + return nil, true } - if parent.Hash().Hex() == w.lastParentBlockCommit { return parent, true } @@ -670,7 +689,7 @@ func (w *worker) checkPreCommit() (*types.Block, bool) { func (w *worker) commitNewWork() { parent, shouldReturn := w.checkPreCommitWithLock() - if shouldReturn { + if parent == nil || shouldReturn { return } tstart := time.Now() @@ -693,7 +712,7 @@ func (w *worker) commitNewWork() { defer w.currentMu.Unlock() parent, shouldReturn = w.checkPreCommit() - if shouldReturn { + if parent == nil || shouldReturn { return } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index a4c1b50a91..37af5a3073 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -286,8 +286,8 @@ func (t *BlockTest) validateImportedHeaders(cm *core.BlockChain, validBlocks []b // block-by-block, so we can only validate imported headers after // all blocks have been processed by BlockChain, as they may not // be part of the longest chain until last block is imported. - for b := cm.CurrentBlock(); b != nil && b.NumberU64() != 0; b = cm.GetBlockByHash(b.Header().ParentHash) { - if err := validateHeader(bmap[b.Hash()].BlockHeader, b.Header()); err != nil { + for b := cm.CurrentBlock(); b != nil && b.Number.Uint64() != 0; b = cm.GetHeaderByHash(b.ParentHash) { + if err := validateHeader(bmap[b.Hash()].BlockHeader, b); err != nil { return fmt.Errorf("imported block header validation failed: %v", err) } }