core, eth, internal: Added debug_getBadBlocks() method (#3654)

* core,eth,internal: Added `debug_getBadBlocks()` method

When bad blocks are discovered, these are stored within geth.
An RPC-endpoint makes them availablewithin the `debug`
namespace. This feature makes it easier to discover network forks.

```

* core, api: go format + docs

* core/blockchain: Documentation, fix minor nitpick

* core: fix failing blockchain test
This commit is contained in:
Martin Holst Swende 2017-02-13 21:44:06 +01:00 committed by Jeffrey Wilcke
parent 4ece9c6cb0
commit 72dcd3c58b
4 changed files with 42 additions and 2 deletions

View File

@ -60,6 +60,7 @@ const (
// must be bumped when consensus algorithm is changed, this forces the upgradedb // must be bumped when consensus algorithm is changed, this forces the upgradedb
// command to be run (forces the blocks to be imported again using the new algorithm) // command to be run (forces the blocks to be imported again using the new algorithm)
BlockChainVersion = 3 BlockChainVersion = 3
badBlockLimit = 10
) )
// BlockChain represents the canonical chain given a database with a genesis // BlockChain represents the canonical chain given a database with a genesis
@ -108,6 +109,8 @@ type BlockChain struct {
processor Processor // block processor interface processor Processor // block processor interface
validator Validator // block and state validator interface validator Validator // block and state validator interface
vmConfig vm.Config vmConfig vm.Config
badBlocks *lru.Cache // Bad block cache
} }
// NewBlockChain returns a fully initialised block chain using information // NewBlockChain returns a fully initialised block chain using information
@ -118,6 +121,7 @@ func NewBlockChain(chainDb ethdb.Database, config *params.ChainConfig, pow pow.P
bodyRLPCache, _ := lru.New(bodyCacheLimit) bodyRLPCache, _ := lru.New(bodyCacheLimit)
blockCache, _ := lru.New(blockCacheLimit) blockCache, _ := lru.New(blockCacheLimit)
futureBlocks, _ := lru.New(maxFutureBlocks) futureBlocks, _ := lru.New(maxFutureBlocks)
badBlocks, _ := lru.New(badBlockLimit)
bc := &BlockChain{ bc := &BlockChain{
config: config, config: config,
@ -130,6 +134,7 @@ func NewBlockChain(chainDb ethdb.Database, config *params.ChainConfig, pow pow.P
futureBlocks: futureBlocks, futureBlocks: futureBlocks,
pow: pow, pow: pow,
vmConfig: vmConfig, vmConfig: vmConfig,
badBlocks: badBlocks,
} }
bc.SetValidator(NewBlockValidator(config, bc, pow)) bc.SetValidator(NewBlockValidator(config, bc, pow))
bc.SetProcessor(NewStateProcessor(config, bc)) bc.SetProcessor(NewStateProcessor(config, bc))
@ -893,7 +898,6 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
glog.V(logger.Debug).Infoln("Premature abort during block chain processing") glog.V(logger.Debug).Infoln("Premature abort during block chain processing")
break break
} }
bstart := time.Now() bstart := time.Now()
// Wait for block i's nonce to be verified before processing // Wait for block i's nonce to be verified before processing
// its state transition. // its state transition.
@ -1242,8 +1246,32 @@ func (self *BlockChain) update() {
} }
} }
// BadBlockArgs represents the entries in the list returned when bad blocks are queried.
type BadBlockArgs struct {
Hash common.Hash `json:"hash"`
Header *types.Header `json:"header"`
}
// BadBlocks returns a list of the last 'bad blocks' that the client has seen on the network
func (bc *BlockChain) BadBlocks() ([]BadBlockArgs, error) {
headers := make([]BadBlockArgs, 0, bc.badBlocks.Len())
for _, hash := range bc.badBlocks.Keys() {
if hdr, exist := bc.badBlocks.Peek(hash); exist {
header := hdr.(*types.Header)
headers = append(headers, BadBlockArgs{header.Hash(), header})
}
}
return headers, nil
}
// addBadBlock adds a bad block to the bad-block LRU cache
func (bc *BlockChain) addBadBlock(block *types.Block) {
bc.badBlocks.Add(block.Header().Hash(), block.Header())
}
// 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) {
bc.addBadBlock(block)
if glog.V(logger.Error) { if glog.V(logger.Error) {
var receiptString string var receiptString string
for _, receipt := range receipts { for _, receipt := range receipts {

View File

@ -485,6 +485,7 @@ func chm(genesis *types.Block, db ethdb.Database) *BlockChain {
bc.bodyRLPCache, _ = lru.New(100) bc.bodyRLPCache, _ = lru.New(100)
bc.blockCache, _ = lru.New(100) bc.blockCache, _ = lru.New(100)
bc.futureBlocks, _ = lru.New(100) bc.futureBlocks, _ = lru.New(100)
bc.badBlocks, _ = lru.New(10)
bc.SetValidator(bproc{}) bc.SetValidator(bproc{})
bc.SetProcessor(bproc{}) bc.SetProcessor(bproc{})
bc.ResetWithGenesisBlock(genesis) bc.ResetWithGenesisBlock(genesis)

View File

@ -566,3 +566,9 @@ func (api *PrivateDebugAPI) Preimage(ctx context.Context, hash common.Hash) (hex
db := core.PreimageTable(api.eth.ChainDb()) db := core.PreimageTable(api.eth.ChainDb())
return db.Get(hash.Bytes()) return db.Get(hash.Bytes())
} }
// GetBadBLocks returns a list of the last 'bad blocks' that the client has seen on the network
// and returns them as a JSON list of block-hashes
func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]core.BadBlockArgs, error) {
return api.eth.BlockChain().BadBlocks()
}

View File

@ -294,7 +294,12 @@ web3._extend({
call: 'debug_preimage', call: 'debug_preimage',
params: 1, params: 1,
inputFormatter: [null] inputFormatter: [null]
}) }),
new web3._extend.Method({
name: 'getBadBlocks',
call: 'debug_getBadBlocks',
params: 0,
}),
], ],
properties: [] properties: []
}); });