core: don't mark bad for block with inconsistent body

This commit is contained in:
rjl493456442 2019-12-31 17:09:48 +08:00
parent 3bb6815fc1
commit 5e01efbb2f
5 changed files with 72 additions and 11 deletions

View file

@ -59,10 +59,10 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
return err
}
if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
return fmt.Errorf("uncle root hash mismatch: have %x, want %x", hash, header.UncleHash)
return ErrInconsistentBody
}
if hash := types.DeriveSha(block.Transactions()); hash != header.TxHash {
return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash)
return ErrInconsistentBody
}
if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) {

View file

@ -1572,11 +1572,19 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
// If there are any still remaining, mark as ignored
return it.index, err
case err == ErrInconsistentBody:
// If the body is inconsistent with header, don't mark the
// whole block hash as invalid. We may receive a block with
// invalid body but valid header.
stats.ignored += len(it.chain)
bc.reportBlock(block, nil, err, false)
return it.index, err
// Some other error occurred, abort
case err != nil:
bc.futureBlocks.Remove(block.Hash())
stats.ignored += len(it.chain)
bc.reportBlock(block, nil, err)
bc.reportBlock(block, nil, err, true)
return it.index, err
}
// No validation errors for the first block (or chain prefix skipped)
@ -1588,7 +1596,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
}
// If the header is a banned one, straight out abort
if BadHashes[block.Hash()] {
bc.reportBlock(block, nil, ErrBlacklistedHash)
bc.reportBlock(block, nil, ErrBlacklistedHash, true)
return it.index, ErrBlacklistedHash
}
// If the block is known (in the middle of the chain), it's a special case for
@ -1647,7 +1655,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
substart := time.Now()
receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig)
if err != nil {
bc.reportBlock(block, receipts, err)
bc.reportBlock(block, receipts, err, true)
atomic.StoreUint32(&followupInterrupt, 1)
return it.index, err
}
@ -1666,7 +1674,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
// Validate the state using the default validator
substart = time.Now()
if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil {
bc.reportBlock(block, receipts, err)
bc.reportBlock(block, receipts, err, true)
atomic.StoreUint32(&followupInterrupt, 1)
return it.index, err
}
@ -2065,9 +2073,10 @@ func (bc *BlockChain) addBadBlock(block *types.Block) {
}
// reportBlock logs a bad block error.
func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error) {
bc.addBadBlock(block)
func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error, markBad bool) {
if markBad {
bc.addBadBlock(block)
}
var receiptString string
for i, receipt := range receipts {
receiptString += fmt.Sprintf("\t %d: cumulative: %v gas: %v contract: %v status: %v tx: %v logs: %v bloom: %x state: %x\n",

View file

@ -150,12 +150,12 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
}
receipts, _, usedGas, err := blockchain.processor.Process(block, statedb, vm.Config{})
if err != nil {
blockchain.reportBlock(block, receipts, err)
blockchain.reportBlock(block, receipts, err, true)
return err
}
err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas)
if err != nil {
blockchain.reportBlock(block, receipts, err)
blockchain.reportBlock(block, receipts, err, true)
return err
}
blockchain.chainmu.Lock()
@ -2362,3 +2362,50 @@ func TestDeleteCreateRevert(t *testing.T) {
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
}
}
func TestInconsistentBlockImport(t *testing.T) {
var (
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
gspec = &Genesis{
Config: params.TestChainConfig,
Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}},
}
signer = types.NewEIP155Signer(gspec.Config.ChainID)
)
engine := ethash.NewFaker()
db := rawdb.NewMemoryDatabase()
genesis, _ := gspec.Commit(db)
// Generate inconsistent blocks
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 32, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{1})
tx, err := types.SignTx(types.NewContractCreation(b.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), nil), signer, key1)
if err != nil {
t.Fatalf("failed to create tx: %v", err)
}
b.AddTx(tx)
})
badBlocks := make([]*types.Block, len(blocks))
copy(badBlocks, blocks)
badBlocks[0] = types.NewBlockWithHeader(badBlocks[0].Header()) // Modify the block, wipe body.
// Import the canonical chain
diskdb := rawdb.NewMemoryDatabase()
gspec.Commit(diskdb)
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
if err != nil {
t.Fatalf("failed to create tester chain: %v", err)
}
n, err := chain.InsertChain(badBlocks)
if err == nil || n != 0 {
t.Fatal("expect error")
}
// Ensure the hash is not recorded as BAD
if chain.badBlocks.Contains(badBlocks[0].Hash()) {
t.Fatal("expect no recording")
}
if _, err := chain.InsertChain(blocks); err != nil {
t.Fatal("expect successfully insertion")
}
}

View file

@ -35,4 +35,8 @@ var (
// ErrNoGenesis is returned when there is no Genesis Block.
ErrNoGenesis = errors.New("genesis not found in chain")
// ErrInconsistentBody is returned if the block body is inconsistent with its
// corresponding header.
ErrInconsistentBody = errors.New("body is inconsistent with header")
)

1
go.sum
View file

@ -101,6 +101,7 @@ github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883 h1:FSeK4fZCo
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA=
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21 h1:F/iKcka0K2LgnKy/fgSBf235AETtm1n1TvBzqu40LE0=
github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=