From f46920b4071dbb9b16898d15ef0ebbe133fe7bed Mon Sep 17 00:00:00 2001 From: Daniel Liu <139250065@qq.com> Date: Fri, 26 Sep 2025 19:02:13 +0800 Subject: [PATCH] core, eth, internal: improve getBadBlocks to return full block rlp #16902 (#1595) --- core/blockchain.go | 22 ++++++++-------------- eth/api.go | 29 +++++++++++++++++++++++++++-- internal/ethapi/api.go | 29 +++++++++++++++++++---------- 3 files changed, 54 insertions(+), 26 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index c2c42b4b98..7a86e21ddd 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -197,7 +197,7 @@ type BlockChain struct { resultProcess *lru.Cache[common.Hash, *ResultProcessBlock] // Cache for processed blocks calculatingBlock *lru.Cache[common.Hash, *CalculatedBlock] // Cache for processing blocks downloadingBlock *lru.Cache[common.Hash, struct{}] // Cache for downloading blocks (avoid duplication from fetcher) - badBlocks *lru.Cache[common.Hash, *types.Header] // Bad block cache + badBlocks *lru.Cache[common.Hash, *types.Block] // Bad block cache // future blocks are blocks added for later processing futureBlocks *lru.Cache[common.Hash, *types.Block] @@ -262,7 +262,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par engine: engine, vmConfig: vmConfig, logger: vmConfig.Tracer, - badBlocks: lru.NewCache[common.Hash, *types.Header](badBlockLimit), + badBlocks: lru.NewCache[common.Hash, *types.Block](badBlockLimit), blocksHashCache: lru.NewCache[uint64, []common.Hash](blocksHashCacheLimit), resultTrade: lru.NewCache[common.Hash, interface{}](tradingstate.OrderCacheLimit), rejectedOrders: lru.NewCache[common.Hash, interface{}](tradingstate.OrderCacheLimit), @@ -2574,26 +2574,20 @@ func (bc *BlockChain) futureBlocksLoop() { } } -// 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()) +func (bc *BlockChain) BadBlocks() []*types.Block { + blocks := make([]*types.Block, 0, bc.badBlocks.Len()) for _, hash := range bc.badBlocks.Keys() { - if header, exist := bc.badBlocks.Peek(hash); exist { - headers = append(headers, BadBlockArgs{header.Hash(), header}) + if blk, exist := bc.badBlocks.Peek(hash); exist { + blocks = append(blocks, blk) } } - return headers, nil + return blocks } // 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()) + bc.badBlocks.Add(block.Hash(), block) } // reportBlock logs a bad block error. diff --git a/eth/api.go b/eth/api.go index bbe038a850..5e2ad4b31a 100644 --- a/eth/api.go +++ b/eth/api.go @@ -32,6 +32,7 @@ import ( "github.com/XinFinOrg/XDPoSChain/core/rawdb" "github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/types" + "github.com/XinFinOrg/XDPoSChain/internal/ethapi" "github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/miner" "github.com/XinFinOrg/XDPoSChain/params" @@ -325,10 +326,34 @@ func (api *DebugAPI) Preimage(ctx context.Context, hash common.Hash) (hexutil.By 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 *DebugAPI) GetBadBlocks(ctx context.Context) ([]core.BadBlockArgs, error) { - return api.eth.BlockChain().BadBlocks() +func (api *DebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, error) { + 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 rlpBytes, err := rlp.EncodeToBytes(block); err != nil { + results[i].RLP = err.Error() // Hacky, but hey, it works + } else { + results[i].RLP = fmt.Sprintf("0x%x", rlpBytes) + } + if results[i].Block, err = ethapi.RPCMarshalBlock(block, true, true); err != nil { + results[i].Block = map[string]interface{}{"error": err.Error()} + } + } + return results, nil } // AccountRangeMaxResults is the maximum number of results to be returned per call diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 36dda2f30b..50d3ad558c 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -382,7 +382,7 @@ func (s *BlockChainAPI) GetTransactionAndReceiptProof(ctx context.Context, hash func (s *BlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { block, err := s.b.BlockByNumber(ctx, blockNr) if block != nil { - response, err := s.rpcOutputBlock(block, true, fullTx, ctx) + response, err := s.rpcOutputBlock(block, true, fullTx) if err == nil && blockNr == rpc.PendingBlockNumber { // Pending blocks need to nil out a few fields for _, field := range []string{"hash", "nonce", "miner"} { @@ -399,7 +399,7 @@ func (s *BlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr rpc.BlockN func (s *BlockChainAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (map[string]interface{}, error) { block, err := s.b.GetBlock(ctx, blockHash) if block != nil { - return s.rpcOutputBlock(block, true, fullTx, ctx) + return s.rpcOutputBlock(block, true, fullTx) } return nil, err } @@ -415,7 +415,7 @@ func (s *BlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, block return nil, nil } block = types.NewBlockWithHeader(uncles[index]) - return s.rpcOutputBlock(block, false, false, ctx) + return s.rpcOutputBlock(block, false, false) } return nil, err } @@ -432,7 +432,7 @@ func (s *BlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHa return nil, nil } block = types.NewBlockWithHeader(uncles[index]) - return s.rpcOutputBlock(block, false, false, ctx) + return s.rpcOutputBlock(block, false, false) } return nil, err } @@ -1411,29 +1411,26 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} { return result } -// 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 *BlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool, ctx context.Context) (map[string]interface{}, error) { +func RPCMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { fields := RPCMarshalHeader(b.Header()) fields["size"] = hexutil.Uint64(b.Size()) - fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(context.Background(), b.Hash())) if inclTx { 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 } @@ -1447,9 +1444,21 @@ func (s *BlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool, uncleHashes[i] = uncle.Hash() } fields["uncles"] = uncleHashes + return fields, nil } +// rpcOutputBlock uses the generalized output filler, then adds the total difficulty field, which requires +// a `BlockChainAPI`. +func (s *BlockChainAPI) 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(context.Background(), b.Hash())) + return fields, err +} + // findNearestSignedBlock finds the nearest checkpoint from input block func (s *BlockChainAPI) findNearestSignedBlock(ctx context.Context, b *types.Block) *types.Block { if b.Number().Int64() <= 0 {