mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
core: don't mark bad for block with inconsistent body
This commit is contained in:
parent
3bb6815fc1
commit
5e01efbb2f
5 changed files with 72 additions and 11 deletions
|
|
@ -59,10 +59,10 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
|
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 {
|
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.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
|
||||||
if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) {
|
if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) {
|
||||||
|
|
|
||||||
|
|
@ -1572,11 +1572,19 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
|
||||||
// If there are any still remaining, mark as ignored
|
// If there are any still remaining, mark as ignored
|
||||||
return it.index, err
|
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
|
// Some other error occurred, abort
|
||||||
case err != nil:
|
case err != nil:
|
||||||
bc.futureBlocks.Remove(block.Hash())
|
bc.futureBlocks.Remove(block.Hash())
|
||||||
stats.ignored += len(it.chain)
|
stats.ignored += len(it.chain)
|
||||||
bc.reportBlock(block, nil, err)
|
bc.reportBlock(block, nil, err, true)
|
||||||
return it.index, err
|
return it.index, err
|
||||||
}
|
}
|
||||||
// No validation errors for the first block (or chain prefix skipped)
|
// 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 the header is a banned one, straight out abort
|
||||||
if BadHashes[block.Hash()] {
|
if BadHashes[block.Hash()] {
|
||||||
bc.reportBlock(block, nil, ErrBlacklistedHash)
|
bc.reportBlock(block, nil, ErrBlacklistedHash, true)
|
||||||
return it.index, ErrBlacklistedHash
|
return it.index, ErrBlacklistedHash
|
||||||
}
|
}
|
||||||
// If the block is known (in the middle of the chain), it's a special case for
|
// 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()
|
substart := time.Now()
|
||||||
receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig)
|
receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bc.reportBlock(block, receipts, err)
|
bc.reportBlock(block, receipts, err, true)
|
||||||
atomic.StoreUint32(&followupInterrupt, 1)
|
atomic.StoreUint32(&followupInterrupt, 1)
|
||||||
return it.index, err
|
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
|
// Validate the state using the default validator
|
||||||
substart = time.Now()
|
substart = time.Now()
|
||||||
if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil {
|
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)
|
atomic.StoreUint32(&followupInterrupt, 1)
|
||||||
return it.index, err
|
return it.index, err
|
||||||
}
|
}
|
||||||
|
|
@ -2065,9 +2073,10 @@ func (bc *BlockChain) addBadBlock(block *types.Block) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// reportBlock logs a bad block error.
|
// reportBlock logs a bad block error.
|
||||||
func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error) {
|
func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error, markBad bool) {
|
||||||
|
if markBad {
|
||||||
bc.addBadBlock(block)
|
bc.addBadBlock(block)
|
||||||
|
}
|
||||||
var receiptString string
|
var receiptString string
|
||||||
for i, receipt := range receipts {
|
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",
|
receiptString += fmt.Sprintf("\t %d: cumulative: %v gas: %v contract: %v status: %v tx: %v logs: %v bloom: %x state: %x\n",
|
||||||
|
|
|
||||||
|
|
@ -150,12 +150,12 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
|
||||||
}
|
}
|
||||||
receipts, _, usedGas, err := blockchain.processor.Process(block, statedb, vm.Config{})
|
receipts, _, usedGas, err := blockchain.processor.Process(block, statedb, vm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
blockchain.reportBlock(block, receipts, err)
|
blockchain.reportBlock(block, receipts, err, true)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas)
|
err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
blockchain.reportBlock(block, receipts, err)
|
blockchain.reportBlock(block, receipts, err, true)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
blockchain.chainmu.Lock()
|
blockchain.chainmu.Lock()
|
||||||
|
|
@ -2362,3 +2362,50 @@ func TestDeleteCreateRevert(t *testing.T) {
|
||||||
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,4 +35,8 @@ var (
|
||||||
|
|
||||||
// ErrNoGenesis is returned when there is no Genesis Block.
|
// ErrNoGenesis is returned when there is no Genesis Block.
|
||||||
ErrNoGenesis = errors.New("genesis not found in chain")
|
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
1
go.sum
|
|
@ -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/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 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA=
|
||||||
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
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/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 h1:F/iKcka0K2LgnKy/fgSBf235AETtm1n1TvBzqu40LE0=
|
||||||
github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue