Skip to content

Commit

Permalink
jsonrpc: move getBadBlocks to debug api (#13547)
Browse files Browse the repository at this point in the history
See #8171
and Previous PR which put this into `eth_` api -
#11888
  • Loading branch information
somnathb1 committed Jan 28, 2025
1 parent 9c74446 commit 956ce32
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 112 deletions.
2 changes: 1 addition & 1 deletion tests/execution-spec-tests
4 changes: 0 additions & 4 deletions turbo/jsonrpc/corner_cases_support_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,4 @@ func TestNotFoundMustReturnNil(t *testing.T) {
j, err := api.GetBlockTransactionCountByNumber(ctx, 10_000)
require.Nil(j)
require.Nil(err)

k, err := api.GetBadBlocks(ctx)
require.Nil(k)
require.Nil(err)
}
81 changes: 81 additions & 0 deletions turbo/jsonrpc/debug_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"

"github.com/erigontech/erigon-lib/common/hexutil"
"github.com/erigontech/erigon-lib/log/v3"

jsoniter "github.com/json-iterator/go"

Expand Down Expand Up @@ -43,6 +44,8 @@ type PrivateDebugAPI interface {
AccountAt(ctx context.Context, blockHash common.Hash, txIndex uint64, account common.Address) (*AccountResult, error)
GetRawHeader(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (hexutility.Bytes, error)
GetRawBlock(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (hexutility.Bytes, error)
GetRawReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]hexutility.Bytes, error)
GetBadBlocks(ctx context.Context) ([]map[string]interface{}, error)
}

// PrivateDebugAPIImpl is implementation of the PrivateDebugAPI interface based on remote Db access
Expand Down Expand Up @@ -404,3 +407,81 @@ func (api *PrivateDebugAPIImpl) GetRawBlock(ctx context.Context, blockNrOrHash r
}
return rlp.EncodeToBytes(block)
}

// GetRawReceipts retrieves the binary-encoded receipts of a single block.
func (api *PrivateDebugAPIImpl) GetRawReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]hexutility.Bytes, error) {
tx, err := api.db.BeginRo(ctx)
if err != nil {
return nil, err
}
defer tx.Rollback()

blockNum, blockHash, _, err := rpchelper.GetBlockNumber(blockNrOrHash, tx, api.filters)
if err != nil {
return nil, err
}
block, err := api.blockWithSenders(ctx, tx, blockHash, blockNum)
if err != nil {
return nil, err
}
if block == nil {
return nil, nil
}
receipts, err := api.getReceipts(ctx, tx, block, nil)
if err != nil {
return nil, fmt.Errorf("getReceipts error: %w", err)
}
chainConfig, err := api.chainConfig(ctx, tx)
if err != nil {
return nil, err
}
if chainConfig.Bor != nil {
return nil, nil
}

result := make([]hexutility.Bytes, len(receipts))
for i, receipt := range receipts {
b, err := rlp.EncodeToBytes(receipt)
if err != nil {
return nil, err
}
result[i] = b
}
return result, nil
}

func (api *PrivateDebugAPIImpl) GetBadBlocks(ctx context.Context) ([]map[string]interface{}, error) {
tx, err := api.db.BeginRo(ctx)
if err != nil {
return nil, err
}
defer tx.Rollback()

blocks, err := rawdb.GetLatestBadBlocks(tx)
if err != nil || len(blocks) == 0 {
return nil, err
}

results := make([]map[string]interface{}, 0, len(blocks))
for _, block := range blocks {
var blockRlp string
if rlpBytes, err := rlp.EncodeToBytes(block); err != nil {
blockRlp = err.Error() // hack
} else {
blockRlp = fmt.Sprintf("%#x", rlpBytes)
}

blockJson, err := ethapi.RPCMarshalBlock(block, true, true, nil)
if err != nil {
log.Error("Failed to marshal block", "err", err)
blockJson = map[string]interface{}{}
}
results = append(results, map[string]interface{}{
"hash": block.Hash(),
"block": blockRlp,
"rlp": blockJson,
})
}

return results, nil
}
72 changes: 72 additions & 0 deletions turbo/jsonrpc/debug_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package jsonrpc

import (
"bytes"
"context"
"encoding/json"
"math/big"
"reflect"
"testing"

Expand All @@ -11,14 +13,19 @@ import (
jsoniter "github.com/json-iterator/go"
"github.com/stretchr/testify/require"

"github.com/erigontech/erigon/common/u256"
"github.com/erigontech/erigon/crypto"

"github.com/erigontech/erigon-lib/common"
"github.com/erigontech/erigon-lib/kv"
"github.com/erigontech/erigon-lib/kv/iter"
"github.com/erigontech/erigon-lib/kv/kvcache"
"github.com/erigontech/erigon-lib/kv/order"
"github.com/erigontech/erigon/cmd/rpcdaemon/rpcdaemontest"
"github.com/erigontech/erigon/core/rawdb"
"github.com/erigontech/erigon/core/types"
"github.com/erigontech/erigon/eth/tracers"
"github.com/erigontech/erigon/params"
"github.com/erigontech/erigon/rpc"
"github.com/erigontech/erigon/rpc/rpccfg"
"github.com/erigontech/erigon/turbo/adapter/ethapi"
Expand Down Expand Up @@ -504,3 +511,68 @@ func TestAccountAt(t *testing.T) {
require.Equal(0, int(results.Nonce))
})
}

func TestGetBadBlocks(t *testing.T) {
m, _, _ := rpcdaemontest.CreateTestSentry(t)
api := NewPrivateDebugAPI(newBaseApiForTest(m), m.DB, 5000000)
ctx := context.Background()

require := require.New(t)
var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)

mustSign := func(tx types.Transaction, s types.Signer) types.Transaction {
r, err := types.SignTx(tx, s, testKey)
require.NoError(err)
return r
}

tx, err := m.DB.BeginRw(ctx)
if err != nil {
t.Errorf("could not begin read write transaction: %s", err)
}

putBlock := func(number uint64) common.Hash {
// prepare db so it works with our test
signer1 := types.MakeSigner(params.MainnetChainConfig, number, number-1)
body := &types.Body{
Transactions: []types.Transaction{
mustSign(types.NewTransaction(number, testAddr, u256.Num1, 1, u256.Num1, nil), *signer1),
mustSign(types.NewTransaction(number+1, testAddr, u256.Num1, 2, u256.Num1, nil), *signer1),
},
Uncles: []*types.Header{{Extra: []byte("test header")}},
}

header := &types.Header{Number: big.NewInt(int64(number))}
require.NoError(rawdb.WriteCanonicalHash(tx, header.Hash(), number))
require.NoError(rawdb.WriteHeader(tx, header))
require.NoError(rawdb.WriteBody(tx, header.Hash(), number, body))

return header.Hash()
}

number := *rawdb.ReadCurrentBlockNumber(tx)

// put some blocks
i := number
for i <= number+6 {
putBlock(i)
i++
}
hash1 := putBlock(i)
hash2 := putBlock(i + 1)
hash3 := putBlock(i + 2)
hash4 := putBlock(i + 3)
require.NoError(rawdb.TruncateCanonicalHash(tx, i, true)) // trim since i

tx.Commit()

data, err := api.GetBadBlocks(ctx)
require.NoError(err)

require.Len(data, 4)
require.Equal(data[0]["hash"], hash4)
require.Equal(data[1]["hash"], hash3)
require.Equal(data[2]["hash"], hash2)
require.Equal(data[3]["hash"], hash1)
}
1 change: 0 additions & 1 deletion turbo/jsonrpc/eth_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ type EthAPI interface {
// Block related (proposed file: ./eth_blocks.go)
GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error)
GetBlockByHash(ctx context.Context, hash rpc.BlockNumberOrHash, fullTx bool) (map[string]interface{}, error)
GetBadBlocks(ctx context.Context) ([]map[string]interface{}, error)
GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*hexutil.Uint, error)
GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) (*hexutil.Uint, error)

Expand Down
38 changes: 1 addition & 37 deletions turbo/jsonrpc/eth_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/erigontech/erigon-lib/common/hexutil"
"github.com/erigontech/erigon-lib/common/hexutility"
"github.com/erigontech/erigon-lib/kv"

"github.com/erigontech/erigon/cl/clparams"
"github.com/erigontech/erigon/common/math"
"github.com/erigontech/erigon/core"
Expand All @@ -22,7 +23,6 @@ import (
"github.com/erigontech/erigon/crypto/cryptopool"
"github.com/erigontech/erigon/polygon/bor/borcfg"
bortypes "github.com/erigontech/erigon/polygon/bor/types"
"github.com/erigontech/erigon/rlp"
"github.com/erigontech/erigon/rpc"
"github.com/erigontech/erigon/turbo/adapter/ethapi"
"github.com/erigontech/erigon/turbo/rpchelper"
Expand Down Expand Up @@ -313,42 +313,6 @@ func (api *APIImpl) GetBlockByHash(ctx context.Context, numberOrHash rpc.BlockNu
return response, err
}

func (api *APIImpl) GetBadBlocks(ctx context.Context) ([]map[string]interface{}, error) {
tx, err := api.db.BeginRo(ctx)
if err != nil {
return nil, err
}
defer tx.Rollback()

blocks, err := rawdb.GetLatestBadBlocks(tx)
if err != nil || len(blocks) == 0 {
return nil, err
}

results := make([]map[string]interface{}, 0, len(blocks))
for _, block := range blocks {
var blockRlp string
if rlpBytes, err := rlp.EncodeToBytes(block); err != nil {
blockRlp = err.Error() // hack
} else {
blockRlp = fmt.Sprintf("%#x", rlpBytes)
}

blockJson, err := ethapi.RPCMarshalBlock(block, true, true, nil)
if err != nil {
log.Error("Failed to marshal block", "err", err)
blockJson = map[string]interface{}{}
}
results = append(results, map[string]interface{}{
"hash": block.Hash(),
"block": blockRlp,
"rlp": blockJson,
})
}

return results, nil
}

// GetBlockTransactionCountByNumber implements eth_getBlockTransactionCountByNumber. Returns the number of transactions in a block given the block's block number.
func (api *APIImpl) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*hexutil.Uint, error) {
tx, err := api.db.BeginRo(ctx)
Expand Down
69 changes: 0 additions & 69 deletions turbo/jsonrpc/eth_block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/erigontech/erigon-lib/common/hexutil"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/erigontech/erigon-lib/common"
"github.com/erigontech/erigon-lib/gointerfaces/txpool"
Expand All @@ -17,11 +16,8 @@ import (
"github.com/erigontech/erigon-lib/log/v3"

"github.com/erigontech/erigon/cmd/rpcdaemon/rpcdaemontest"
"github.com/erigontech/erigon/common/u256"
"github.com/erigontech/erigon/core/rawdb"
"github.com/erigontech/erigon/core/types"
"github.com/erigontech/erigon/crypto"
"github.com/erigontech/erigon/params"
"github.com/erigontech/erigon/rlp"
"github.com/erigontech/erigon/rpc"
"github.com/erigontech/erigon/rpc/rpccfg"
Expand Down Expand Up @@ -308,68 +304,3 @@ func TestGetBlockTransactionCountByNumber_ZeroTx(t *testing.T) {

assert.Equal(t, expectedAmount, *txAmount)
}

func TestGetBadBlocks(t *testing.T) {
m, _, _ := rpcdaemontest.CreateTestSentry(t)
api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 1e18, 100_000, false, 100_000, 128, log.New())
ctx := context.Background()

require := require.New(t)
var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)

mustSign := func(tx types.Transaction, s types.Signer) types.Transaction {
r, err := types.SignTx(tx, s, testKey)
require.NoError(err)
return r
}

tx, err := m.DB.BeginRw(ctx)
if err != nil {
t.Errorf("could not begin read write transaction: %s", err)
}

putBlock := func(number uint64) common.Hash {
// prepare db so it works with our test
signer1 := types.MakeSigner(params.MainnetChainConfig, number, number-1)
body := &types.Body{
Transactions: []types.Transaction{
mustSign(types.NewTransaction(number, testAddr, u256.Num1, 1, u256.Num1, nil), *signer1),
mustSign(types.NewTransaction(number+1, testAddr, u256.Num1, 2, u256.Num1, nil), *signer1),
},
Uncles: []*types.Header{{Extra: []byte("test header")}},
}

header := &types.Header{Number: big.NewInt(int64(number))}
require.NoError(rawdb.WriteCanonicalHash(tx, header.Hash(), number))
require.NoError(rawdb.WriteHeader(tx, header))
require.NoError(rawdb.WriteBody(tx, header.Hash(), number, body))

return header.Hash()
}

number := *rawdb.ReadCurrentBlockNumber(tx)

// put some blocks
i := number
for i <= number+6 {
putBlock(i)
i++
}
hash1 := putBlock(i)
hash2 := putBlock(i + 1)
hash3 := putBlock(i + 2)
hash4 := putBlock(i + 3)
require.NoError(rawdb.TruncateCanonicalHash(tx, i, true)) // trim since i

tx.Commit()

data, err := api.GetBadBlocks(ctx)
require.NoError(err)

require.Len(data, 4)
require.Equal(data[0]["hash"], hash4)
require.Equal(data[1]["hash"], hash3)
require.Equal(data[2]["hash"], hash2)
require.Equal(data[3]["hash"], hash1)
}

0 comments on commit 956ce32

Please sign in to comment.