forked from cerc-io/plugeth
core: improved bad block error reporting (#3320)
This commit is contained in:
parent
e05d35e6e0
commit
c04c8f10f0
@ -93,14 +93,14 @@ func (v *BlockValidator) ValidateBlock(block *types.Block) error {
|
|||||||
// Verify UncleHash before running other uncle validations
|
// Verify UncleHash before running other uncle validations
|
||||||
unclesSha := types.CalcUncleHash(block.Uncles())
|
unclesSha := types.CalcUncleHash(block.Uncles())
|
||||||
if unclesSha != header.UncleHash {
|
if unclesSha != header.UncleHash {
|
||||||
return fmt.Errorf("invalid uncles root hash. received=%x calculated=%x", header.UncleHash, unclesSha)
|
return fmt.Errorf("invalid uncles root hash (remote: %x local: %x)", header.UncleHash, unclesSha)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The transactions Trie's root (R = (Tr [[i, RLP(T1)], [i, RLP(T2)], ... [n, RLP(Tn)]]))
|
// The transactions Trie's root (R = (Tr [[i, RLP(T1)], [i, RLP(T2)], ... [n, RLP(Tn)]]))
|
||||||
// can be used by light clients to make sure they've received the correct Txs
|
// can be used by light clients to make sure they've received the correct Txs
|
||||||
txSha := types.DeriveSha(block.Transactions())
|
txSha := types.DeriveSha(block.Transactions())
|
||||||
if txSha != header.TxHash {
|
if txSha != header.TxHash {
|
||||||
return fmt.Errorf("invalid transaction root hash. received=%x calculated=%x", header.TxHash, txSha)
|
return fmt.Errorf("invalid transaction root hash (remote: %x local: %x)", header.TxHash, txSha)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -113,23 +113,23 @@ func (v *BlockValidator) ValidateBlock(block *types.Block) error {
|
|||||||
func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas *big.Int) (err error) {
|
func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas *big.Int) (err error) {
|
||||||
header := block.Header()
|
header := block.Header()
|
||||||
if block.GasUsed().Cmp(usedGas) != 0 {
|
if block.GasUsed().Cmp(usedGas) != 0 {
|
||||||
return ValidationError(fmt.Sprintf("gas used error (%v / %v)", block.GasUsed(), usedGas))
|
return ValidationError(fmt.Sprintf("invalid gas used (remote: %v local: %v)", block.GasUsed(), usedGas))
|
||||||
}
|
}
|
||||||
// Validate the received block's bloom with the one derived from the generated receipts.
|
// Validate the received block's bloom with the one derived from the generated receipts.
|
||||||
// For valid blocks this should always validate to true.
|
// For valid blocks this should always validate to true.
|
||||||
rbloom := types.CreateBloom(receipts)
|
rbloom := types.CreateBloom(receipts)
|
||||||
if rbloom != header.Bloom {
|
if rbloom != header.Bloom {
|
||||||
return fmt.Errorf("unable to replicate block's bloom=%x vs calculated bloom=%x", header.Bloom, rbloom)
|
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom)
|
||||||
}
|
}
|
||||||
// Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]]))
|
// Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]]))
|
||||||
receiptSha := types.DeriveSha(receipts)
|
receiptSha := types.DeriveSha(receipts)
|
||||||
if receiptSha != header.ReceiptHash {
|
if receiptSha != header.ReceiptHash {
|
||||||
return fmt.Errorf("invalid receipt root hash. received=%x calculated=%x", header.ReceiptHash, receiptSha)
|
return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha)
|
||||||
}
|
}
|
||||||
// Validate the state root against the received state root and throw
|
// Validate the state root against the received state root and throw
|
||||||
// an error if they don't match.
|
// an error if they don't match.
|
||||||
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
|
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
|
||||||
return fmt.Errorf("invalid merkle root: header=%x computed=%x", header.Root, root)
|
return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -223,7 +223,7 @@ func ValidateHeader(config *params.ChainConfig, pow pow.PoW, header *types.Heade
|
|||||||
|
|
||||||
expd := CalcDifficulty(config, header.Time.Uint64(), parent.Time.Uint64(), parent.Number, parent.Difficulty)
|
expd := CalcDifficulty(config, header.Time.Uint64(), parent.Time.Uint64(), parent.Number, parent.Difficulty)
|
||||||
if expd.Cmp(header.Difficulty) != 0 {
|
if expd.Cmp(header.Difficulty) != 0 {
|
||||||
return fmt.Errorf("Difficulty check failed for header %v, %v", header.Difficulty, expd)
|
return fmt.Errorf("Difficulty check failed for header (remote: %v local: %v)", header.Difficulty, expd)
|
||||||
}
|
}
|
||||||
|
|
||||||
a := new(big.Int).Set(parent.GasLimit)
|
a := new(big.Int).Set(parent.GasLimit)
|
||||||
@ -232,7 +232,7 @@ func ValidateHeader(config *params.ChainConfig, pow pow.PoW, header *types.Heade
|
|||||||
b := new(big.Int).Set(parent.GasLimit)
|
b := new(big.Int).Set(parent.GasLimit)
|
||||||
b = b.Div(b, params.GasLimitBoundDivisor)
|
b = b.Div(b, params.GasLimitBoundDivisor)
|
||||||
if !(a.Cmp(b) < 0) || (header.GasLimit.Cmp(params.MinGasLimit) == -1) {
|
if !(a.Cmp(b) < 0) || (header.GasLimit.Cmp(params.MinGasLimit) == -1) {
|
||||||
return fmt.Errorf("GasLimit check failed for header %v (%v > %v)", header.GasLimit, a, b)
|
return fmt.Errorf("GasLimit check failed for header (remote: %v local_max: %v)", header.GasLimit, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
num := new(big.Int).Set(parent.Number)
|
num := new(big.Int).Set(parent.Number)
|
||||||
|
@ -878,7 +878,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
|||||||
|
|
||||||
if BadHashes[block.Hash()] {
|
if BadHashes[block.Hash()] {
|
||||||
err := BadHashError(block.Hash())
|
err := BadHashError(block.Hash())
|
||||||
reportBlock(block, err)
|
self.reportBlock(block, nil, err)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
// Stage 1 validation of the block using the chain's validator
|
// Stage 1 validation of the block using the chain's validator
|
||||||
@ -910,7 +910,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
reportBlock(block, err)
|
self.reportBlock(block, nil, err)
|
||||||
|
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
@ -924,19 +924,19 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
|||||||
err = self.stateCache.Reset(chain[i-1].Root())
|
err = self.stateCache.Reset(chain[i-1].Root())
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
reportBlock(block, err)
|
self.reportBlock(block, nil, err)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
// Process block using the parent state as reference point.
|
// Process block using the parent state as reference point.
|
||||||
receipts, logs, usedGas, err := self.processor.Process(block, self.stateCache, vm.Config{})
|
receipts, logs, usedGas, err := self.processor.Process(block, self.stateCache, vm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
reportBlock(block, err)
|
self.reportBlock(block, receipts, err)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
// Validate the state using the default validator
|
// Validate the state using the default validator
|
||||||
err = self.Validator().ValidateState(block, self.GetBlock(block.ParentHash(), block.NumberU64()-1), self.stateCache, receipts, usedGas)
|
err = self.Validator().ValidateState(block, self.GetBlock(block.ParentHash(), block.NumberU64()-1), self.stateCache, receipts, usedGas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
reportBlock(block, err)
|
self.reportBlock(block, receipts, err)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
// Write state changes to database
|
// Write state changes to database
|
||||||
@ -1207,10 +1207,23 @@ func (self *BlockChain) update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// reportBlock logs a bad block error.
|
// reportBlock logs a bad block error.
|
||||||
func reportBlock(block *types.Block, err error) {
|
func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error) {
|
||||||
if glog.V(logger.Error) {
|
if glog.V(logger.Error) {
|
||||||
glog.Errorf("Bad block #%v (%s)\n", block.Number(), block.Hash().Hex())
|
var receiptString string
|
||||||
glog.Errorf(" %v", err)
|
for _, receipt := range receipts {
|
||||||
|
receiptString += fmt.Sprintf("\t%v\n", receipt)
|
||||||
|
}
|
||||||
|
glog.Errorf(`
|
||||||
|
########## BAD BLOCK #########
|
||||||
|
Chain config: %v
|
||||||
|
|
||||||
|
Number: %v
|
||||||
|
Hash: 0x%x
|
||||||
|
%v
|
||||||
|
|
||||||
|
Error: %v
|
||||||
|
##############################
|
||||||
|
`, bc.config, block.Number(), block.Hash(), receiptString, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,12 +143,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 {
|
||||||
reportBlock(block, err)
|
blockchain.reportBlock(block, receipts, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = blockchain.Validator().ValidateState(block, blockchain.GetBlockByHash(block.ParentHash()), statedb, receipts, usedGas)
|
err = blockchain.Validator().ValidateState(block, blockchain.GetBlockByHash(block.ParentHash()), statedb, receipts, usedGas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
reportBlock(block, err)
|
blockchain.reportBlock(block, receipts, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
blockchain.mu.Lock()
|
blockchain.mu.Lock()
|
||||||
|
@ -218,6 +218,8 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
|||||||
|
|
||||||
eth.chainConfig = config.ChainConfig
|
eth.chainConfig = config.ChainConfig
|
||||||
|
|
||||||
|
glog.V(logger.Info).Infoln("Chain config:", eth.chainConfig)
|
||||||
|
|
||||||
eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.EventMux())
|
eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.EventMux())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == core.ErrNoGenesis {
|
if err == core.ErrNoGenesis {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package params
|
package params
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
@ -66,6 +67,19 @@ type ChainConfig struct {
|
|||||||
EIP158Block *big.Int `json:"eip158Block"` // EIP158 HF block
|
EIP158Block *big.Int `json:"eip158Block"` // EIP158 HF block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String implements the Stringer interface.
|
||||||
|
func (c *ChainConfig) String() string {
|
||||||
|
return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v}",
|
||||||
|
c.ChainId,
|
||||||
|
c.HomesteadBlock,
|
||||||
|
c.DAOForkBlock,
|
||||||
|
c.DAOForkSupport,
|
||||||
|
c.EIP150Block,
|
||||||
|
c.EIP155Block,
|
||||||
|
c.EIP158Block,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
TestChainConfig = &ChainConfig{big.NewInt(1), new(big.Int), new(big.Int), true, new(big.Int), common.Hash{}, new(big.Int), new(big.Int)}
|
TestChainConfig = &ChainConfig{big.NewInt(1), new(big.Int), new(big.Int), true, new(big.Int), common.Hash{}, new(big.Int), new(big.Int)}
|
||||||
TestRules = TestChainConfig.Rules(new(big.Int))
|
TestRules = TestChainConfig.Rules(new(big.Int))
|
||||||
|
Loading…
Reference in New Issue
Block a user