From 904e9033929145adf4b4698149544c180960a14f Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 6 Jun 2018 22:23:41 +0200 Subject: [PATCH] core, eth, ethapi: changes to getBadBlocks formatting --- core/blockchain.go | 26 ++++---------------------- eth/api.go | 34 ++++++++++++++++++++++++++++++++-- internal/ethapi/api.go | 20 ++++++++++++++------ 3 files changed, 50 insertions(+), 30 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 50bcf3c2c7..63e3e03ab0 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1385,34 +1385,16 @@ func (bc *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"` - BlockRLP string `json:"blockrlp"` -} - // BadBlocks returns a list of the last 'bad blocks' that the client has seen on the network -func (bc *BlockChain) BadBlocks() ([]BadBlockArgs, error) { - blocks := make([]BadBlockArgs, 0, bc.badBlocks.Len()) - var ( - err error - rlpData []byte - ) +func (bc *BlockChain) BadBlocks() []*types.Block { + blocks := make([]*types.Block, 0, bc.badBlocks.Len()) for _, hash := range bc.badBlocks.Keys() { if blk, exist := bc.badBlocks.Peek(hash); exist { block := blk.(*types.Block) - rlpData, err = rlp.EncodeToBytes(block) - if err != nil { - break - } - blocks = append(blocks, BadBlockArgs{ - Hash: block.Hash(), - Header: block.Header(), - BlockRLP: fmt.Sprintf("%x", rlpData)}) + blocks = append(blocks, block) } } - return blocks, err + return blocks } // addBadBlock adds a bad block to the bad-block LRU cache diff --git a/eth/api.go b/eth/api.go index 247ca7485c..fce8c551c9 100644 --- a/eth/api.go +++ b/eth/api.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/params" @@ -351,10 +352,39 @@ func (api *PrivateDebugAPI) Preimage(ctx context.Context, hash common.Hash) (hex return nil, errors.New("unknown preimage") } +// BadBlockArgs represents the entries in the list returned when bad blocks are queried. +type BadBlockArgs struct { + Hash common.Hash `json:"hash"` + Block map[string]interface{} `json:"block"` + RLP string `json:"rlp"` +} + // 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() +func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]BadBlockArgs, error) { + blocks := api.eth.BlockChain().BadBlocks() + responseBlocks := make([]BadBlockArgs, 0, len(blocks)) + for _, block := range blocks { + rlpData, err := rlp.EncodeToBytes(block) + if err != nil { + return responseBlocks, err + } + var ( + blockdata map[string]interface{} + berr error + ) + // A bad block may be so malformed that it the expanded format fails to generate + // correctly. If so, provide the caller with error message and RLP anyway + if blockdata, berr = ethapi.RpcMarshalBlock(block, true, true); berr != nil { + blockdata["error"] = berr.Error() + } + responseBlocks = append(responseBlocks, BadBlockArgs{ + Hash: block.Hash(), + Block: blockdata, + RLP: fmt.Sprintf("%x", rlpData), + }) + } + return responseBlocks, nil } // StorageRangeResult is the result of a debug_storageRangeAt API call. diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index a524dbadd8..bb7673ad29 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -792,10 +792,10 @@ func FormatLogs(logs []vm.StructLog) []StructLogRes { return formatted } -// rpcOutputBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are +// RpcMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are // returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain // transaction hashes. -func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { +func RpcMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { head := b.Header() // copies the header once fields := map[string]interface{}{ "number": (*hexutil.Big)(head.Number), @@ -808,7 +808,6 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx "stateRoot": head.Root, "miner": head.Coinbase, "difficulty": (*hexutil.Big)(head.Difficulty), - "totalDifficulty": (*hexutil.Big)(s.b.GetTd(b.Hash())), "extraData": hexutil.Bytes(head.Extra), "size": hexutil.Uint64(b.Size()), "gasLimit": hexutil.Uint64(head.GasLimit), @@ -822,17 +821,15 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx formatTx := func(tx *types.Transaction) (interface{}, error) { return tx.Hash(), nil } - if fullTx { formatTx = func(tx *types.Transaction) (interface{}, error) { return newRPCTransactionFromBlockHash(b, tx.Hash()), nil } } - txs := b.Transactions() transactions := make([]interface{}, len(txs)) var err error - for i, tx := range b.Transactions() { + for i, tx := range txs { if transactions[i], err = formatTx(tx); err != nil { return nil, err } @@ -850,6 +847,17 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx return fields, nil } +// rpcOutputBlock uses the generalized output filler, then adds the total difficulty field, which requires +// a `PublicBlockchainAPI`. +func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { + fields, err := RpcMarshalBlock(b, inclTx, fullTx) + if err != nil { + return nil, err + } + fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(b.Hash())) + return fields, err +} + // RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction type RPCTransaction struct { BlockHash common.Hash `json:"blockHash"`