-
Notifications
You must be signed in to change notification settings - Fork 20.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
core: improve getBadBlocks to return full block rlp #16902
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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), | ||
}) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might be a bit cleaner as: blocks := api.eth.BlockChain().BadBlocks()
results := make([]*BadBlockArgs, len(blocks))
var err error
for i, block := range blocks {
results[i] = &BadBlockArgs{
Hash: block.Hash(),
})
if results[i].RLP, err = rlp.EncodeToBytes(block); err != nil {
results[i].RLP = err.Error() // Hacky, but hey, it works
}
if results[i].Block, err = ethapi.RPCMarshalBlock(block, true, true); err != nil {
results[i].Block = map[string]interface{}{"error": err.Error()}
}
}
return results, nil Note, your code would have crashed on marshal errors because the |
||
return responseBlocks, nil | ||
} | ||
|
||
// StorageRangeResult is the result of a debug_storageRangeAt API call. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please capitalize RPC, that's usually the canonical way for public abbreviations. |
||
// 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"` | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it make sense to do this for rlp.Encode errors too?