diff --git a/core/blockchain.go b/core/blockchain.go index b63730a319..946fb78c40 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -3236,67 +3236,6 @@ func (bc *BlockChain) GetTrustedDiffLayer(blockHash common.Hash) *types.DiffLaye return diff } -// GenerateDiffLayer generates DiffLayer of a specified block by replaying the block's transactions. -// If the block is an empty block, no DiffLayer will be generated. -// The generated DiffLayer whose Receipts are empty, whose DiffAccounts' storage root is empty. -func (bc *BlockChain) GenerateDiffLayer(blockHash common.Hash) (*types.DiffLayer, error) { - if bc.snaps == nil { - return nil, fmt.Errorf("snapshot disabled, can't generate difflayer") - } - - block := bc.GetBlockByHash(blockHash) - if block == nil { - return nil, fmt.Errorf("block not found, block number: %d, blockhash: %v", block.NumberU64(), blockHash) - } - - parent := bc.GetBlockByHash(block.ParentHash()) - if parent == nil { - return nil, fmt.Errorf("block not found, block number: %d, blockhash: %v", block.NumberU64()-1, block.ParentHash()) - } - statedb, err := bc.StateAt(parent.Root()) - if err != nil { - return nil, fmt.Errorf("state not found for block number (%d): %v", parent.NumberU64(), err) - } - - // Empty block, no DiffLayer would be generated. - if block.Header().TxHash == types.EmptyRootHash { - return nil, nil - } - - // Replay transactions. - signer := types.MakeSigner(bc.Config(), block.Number()) - for _, tx := range block.Transactions() { - msg, _ := tx.AsMessage(signer) - txContext := NewEVMTxContext(msg) - context := NewEVMBlockContext(block.Header(), bc, nil) - vmenv := vm.NewEVM(context, txContext, statedb, bc.Config(), vm.Config{}) - - if posa, ok := bc.Engine().(consensus.PoSA); ok { - if isSystem, _ := posa.IsSystemTransaction(tx, block.Header()); isSystem { - balance := statedb.GetBalance(consensus.SystemAddress) - if balance.Cmp(common.Big0) > 0 { - statedb.SetBalance(consensus.SystemAddress, big.NewInt(0)) - statedb.AddBalance(block.Header().Coinbase, balance) - } - } - } - - if _, err := ApplyMessage(vmenv, msg, new(GasPool).AddGas(tx.Gas())); err != nil { - return nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) - } - statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) - } - - diffLayer := statedb.GenerateDiffLayer() - if diffLayer != nil { - diffLayer.BlockHash = blockHash - diffLayer.Number = block.NumberU64() - bc.cacheDiffLayer(diffLayer, true) - } - - return diffLayer, nil -} - func CalculateDiffHash(d *types.DiffLayer) (common.Hash, error) { if d == nil { return common.Hash{}, fmt.Errorf("nil diff layer") diff --git a/core/blockchain_diff_test.go b/core/blockchain_diff_test.go index c245d71883..fad8fe353a 100644 --- a/core/blockchain_diff_test.go +++ b/core/blockchain_diff_test.go @@ -27,8 +27,6 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/consensus/clique" - "golang.org/x/crypto/sha3" "github.com/ethereum/go-ethereum/common" @@ -647,118 +645,3 @@ func TestGetRootByDiffHash(t *testing.T) { testGetRootByDiffHash(t, chain1, chain2, 24, types.StatusBlockNewer) testGetRootByDiffHash(t, chain1, chain2, 35, types.StatusBlockTooNew) } - -func newBlockChainWithCliqueEngine(blocks int) *BlockChain { - signer := types.HomesteadSigner{} - db := rawdb.NewMemoryDatabase() - engine := clique.New(params.AllCliqueProtocolChanges.Clique, db) - genspec := &Genesis{ - //Config: params.TestChainConfig, - ExtraData: make([]byte, 32+common.AddressLength+65), - Alloc: GenesisAlloc{testAddr: {Balance: big.NewInt(100000000000000000)}}, - } - copy(genspec.ExtraData[32:], testAddr[:]) - genesis := genspec.MustCommit(db) - - chain, _ := NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil, EnableBlockValidator(params.AllCliqueProtocolChanges, engine, 0 /*LocalVerify*/, nil)) - generator := func(i int, block *BlockGen) { - // The chain maker doesn't have access to a chain, so the difficulty will be - // lets unset (nil). Set it here to the correct value. - // block.SetCoinbase(testAddr) - block.SetDifficulty(big.NewInt(2)) - - for idx, testBlock := range testBlocks { - // Specific block setting, the index in this generator has 1 diff from specified blockNr. - if i+1 == testBlock.blockNr { - for _, testTransaction := range testBlock.txs { - var transaction *types.Transaction - if testTransaction.to == nil { - transaction = types.NewContractCreation(block.TxNonce(testAddr), - testTransaction.value, uint64(commonGas), nil, testTransaction.data) - } else { - transaction = types.NewTransaction(block.TxNonce(testAddr), *testTransaction.to, - testTransaction.value, uint64(commonGas), nil, testTransaction.data) - } - tx, err := types.SignTx(transaction, signer, testKey) - if err != nil { - panic(err) - } - block.AddTxWithChain(chain, tx) - } - break - } - - // Default block setting. - if idx == len(testBlocks)-1 { - // We want to simulate an empty middle block, having the same state as the - // first one. The last is needs a state change again to force a reorg. - for _, testTransaction := range testBlocks[0].txs { - tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), *testTransaction.to, - testTransaction.value, uint64(commonGas), nil, testTransaction.data), signer, testKey) - if err != nil { - panic(err) - } - block.AddTxWithChain(chain, tx) - } - } - } - - } - bs, _ := GenerateChain(params.AllCliqueProtocolChanges, genesis, engine, db, blocks, generator) - for i, block := range bs { - header := block.Header() - if i > 0 { - header.ParentHash = bs[i-1].Hash() - } - header.Extra = make([]byte, 32+65) - header.Difficulty = big.NewInt(2) - - sig, _ := crypto.Sign(clique.SealHash(header).Bytes(), testKey) - copy(header.Extra[len(header.Extra)-65:], sig) - bs[i] = block.WithSeal(header) - } - - if _, err := chain.InsertChain(bs); err != nil { - panic(err) - } - - return chain -} - -func TestGenerateDiffLayer(t *testing.T) { - blockNum := 32 - chain := newBlockChainWithCliqueEngine(blockNum) - defer chain.Stop() - - for blockNr := 1; blockNr <= blockNum; blockNr++ { - block := chain.GetBlockByNumber(uint64(blockNr)) - if block == nil { - t.Fatal("block should not be nil") - } - - expDiffLayer := chain.GetTrustedDiffLayer(block.Hash()) - if expDiffLayer == nil { - // Skip empty block. - if blockNr == 15 { - continue - } - t.Fatalf("unexpected nil diff layer, block number: %v, block hash: %v", blockNr, block.Hash()) - } - expDiffHash, err := CalculateDiffHash(expDiffLayer) - if err != nil { - t.Fatalf("compute diff hash failed: %v", err) - } - - diffLayer, err := chain.GenerateDiffLayer(block.Hash()) - if err != nil || diffLayer == nil { - t.Fatalf("generate diff layer failed: %v", err) - } - diffHash, err := CalculateDiffHash(diffLayer) - if err != nil { - t.Fatalf("compute diff hash failed: %v", err) - } - if expDiffHash != diffHash { - t.Fatalf("generated wrong diff layer for block: %d, expected hash: %v, real hash: %v", blockNr, expDiffHash, diffHash) - } - } -} diff --git a/core/remote_state_verifier.go b/core/remote_state_verifier.go index c9e137f300..ee567d359e 100644 --- a/core/remote_state_verifier.go +++ b/core/remote_state_verifier.go @@ -71,14 +71,26 @@ func NewVerifyManager(blockchain *BlockChain, peers verifyPeers, allowInsecure b if oldBlock == nil { return nil, fmt.Errorf("block is nil, number: %d", number) } - blockHash := oldBlock.Hash() - _, err := blockchain.GenerateDiffLayer(blockHash) - if err != nil { - return nil, err + + // rewind to last non verified block + blockchain.SetHead(oldBlock.NumberU64()) + block = oldBlock + break + } + + number = block.Number() + for i := maxForkHeight; i >= 0; i-- { + if new(big.Int).Sub(number, big.NewInt(int64(i))).Cmp(common.Big0) <= 0 { + continue + } + oldBlock := blockchain.GetBlockByNumber(number.Uint64() - uint64(i)) + if oldBlock == nil { + return nil, fmt.Errorf("block is nil, number: %d", number) } - diffLayerCh := make(chan struct{}) - close(diffLayerCh) - blockchain.diffLayerChanCache.Store(blockHash, diffLayerCh) + // When inserting a block, + // the block before 11 blocks will be verified, + // so the parent block of 11-22 will directly write the verification information. + verifiedCache.Add(oldBlock.Hash(), true) } vm := &remoteVerifyManager{