diff --git a/eth/api.go b/eth/api.go index f81dfa922b..f571a57507 100644 --- a/eth/api.go +++ b/eth/api.go @@ -343,7 +343,8 @@ func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, } else { blockRlp = fmt.Sprintf("0x%x", rlpBytes) } - if blockJSON, err = ethapi.RPCMarshalBlock(block, true, true, api.eth.APIBackend.ChainConfig()); err != nil { + + if blockJSON, err = ethapi.RPCMarshalBlock(block, true, true, api.eth.APIBackend.ChainConfig(), api.eth.chainDb); err != nil { blockJSON = map[string]interface{}{"error": err.Error()} } results = append(results, &BadBlockArgs{ diff --git a/eth/tracers/api_bor.go b/eth/tracers/api_bor.go index 6ab1a4290a..f42c7a27f7 100644 --- a/eth/tracers/api_bor.go +++ b/eth/tracers/api_bor.go @@ -43,7 +43,7 @@ func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *T } // block object cannot be converted to JSON since much of the fields are non-public - blockFields, err := ethapi.RPCMarshalBlock(block, true, true, api.backend.ChainConfig()) + blockFields, err := ethapi.RPCMarshalBlock(block, true, true, api.backend.ChainConfig(), api.backend.ChainDb()) if err != nil { return nil, err } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 91d88ec815..a71ec3bd87 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -44,6 +44,7 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/tracers/logger" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" @@ -1332,7 +1333,7 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} { // 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 RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *params.ChainConfig) (map[string]interface{}, error) { +func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *params.ChainConfig, db ethdb.Database) (map[string]interface{}, error) { fields := RPCMarshalHeader(block.Header()) fields["size"] = hexutil.Uint64(block.Size()) @@ -1342,7 +1343,7 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param } if fullTx { formatTx = func(tx *types.Transaction) (interface{}, error) { - return newRPCTransactionFromBlockHash(block, tx.Hash(), config), nil + return newRPCTransactionFromBlockHash(block, tx.Hash(), config, db), nil } } txs := block.Transactions() @@ -1376,7 +1377,7 @@ func (s *PublicBlockChainAPI) rpcMarshalHeader(ctx context.Context, header *type // rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field, which requires // a `PublicBlockchainAPI`. func (s *PublicBlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { - fields, err := RPCMarshalBlock(b, inclTx, fullTx, s.b.ChainConfig()) + fields, err := RPCMarshalBlock(b, inclTx, fullTx, s.b.ChainConfig(), s.b.ChainDb()) if err != nil { return nil, err } @@ -1469,8 +1470,18 @@ func newRPCPendingTransaction(tx *types.Transaction, current *types.Header, conf } // newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation. -func newRPCTransactionFromBlockIndex(b *types.Block, index uint64, config *params.ChainConfig) *RPCTransaction { +func newRPCTransactionFromBlockIndex(b *types.Block, index uint64, config *params.ChainConfig, db ethdb.Database) *RPCTransaction { txs := b.Transactions() + + borReceipt := rawdb.ReadBorReceipt(db, b.Hash(), b.NumberU64()) + if borReceipt != nil { + tx, _, _, _ := rawdb.ReadBorTransaction(db, borReceipt.TxHash) + + if tx != nil { + txs = append(txs, tx) + } + } + if index >= uint64(len(txs)) { return nil } @@ -1488,10 +1499,10 @@ func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.By } // newRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation. -func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash, config *params.ChainConfig) *RPCTransaction { +func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash, config *params.ChainConfig, db ethdb.Database) *RPCTransaction { for idx, tx := range b.Transactions() { if tx.Hash() == hash { - return newRPCTransactionFromBlockIndex(b, uint64(idx), config) + return newRPCTransactionFromBlockIndex(b, uint64(idx), config, db) } } return nil @@ -1633,7 +1644,7 @@ func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Co // GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { - return newRPCTransactionFromBlockIndex(block, uint64(index), s.b.ChainConfig()) + return newRPCTransactionFromBlockIndex(block, uint64(index), s.b.ChainConfig(), s.b.ChainDb()) } return nil } @@ -1641,7 +1652,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx conte // GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction { if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { - return newRPCTransactionFromBlockIndex(block, uint64(index), s.b.ChainConfig()) + return newRPCTransactionFromBlockIndex(block, uint64(index), s.b.ChainConfig(), s.b.ChainDb()) } return nil } diff --git a/tests/bor/bor_api_test.go b/tests/bor/bor_api_test.go index b0e627bd54..63d2c8f3d5 100644 --- a/tests/bor/bor_api_test.go +++ b/tests/bor/bor_api_test.go @@ -1,3 +1,5 @@ +//go:build integration + package bor import ( @@ -13,6 +15,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" @@ -20,6 +23,19 @@ import ( "github.com/stretchr/testify/assert" ) +var ( + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addrr = crypto.PubkeyToAddress(key1.PublicKey) + stack, _ = node.New(&node.DefaultConfig) + backend, _ = eth.New(stack, ðconfig.Defaults) + db = backend.ChainDb() + hash1 = common.BytesToHash([]byte("topic1")) + hash2 = common.BytesToHash([]byte("topic2")) + hash3 = common.BytesToHash([]byte("topic3")) + hash4 = common.BytesToHash([]byte("topic4")) + hash5 = common.BytesToHash([]byte("topic5")) +) + func duplicateInArray(arr []common.Hash) bool { visited := make(map[common.Hash]bool, 0) for i := 0; i < len(arr); i++ { @@ -45,21 +61,75 @@ func areDifferentHashes(receipts []map[string]interface{}) bool { return true } -func TestGetTransactionReceiptsByBlock(t *testing.T) { - t.Parallel() - - var ( - key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - addr = crypto.PubkeyToAddress(key1.PublicKey) - stack, _ = node.New(&node.DefaultConfig) - backend, _ = eth.New(stack, ðconfig.Defaults) - db = backend.ChainDb() - hash1 = common.BytesToHash([]byte("topic1")) - hash2 = common.BytesToHash([]byte("topic2")) - hash3 = common.BytesToHash([]byte("topic3")) - hash4 = common.BytesToHash([]byte("topic4")) - hash5 = common.BytesToHash([]byte("topic5")) - ) +// Test for GetTransactionReceiptsByBlock +func testGetTransactionReceiptsByBlock(t *testing.T, publicBlockchainAPI *ethapi.PublicBlockChainAPI) { + // check 1 : zero transactions + receiptsOut, err := publicBlockchainAPI.GetTransactionReceiptsByBlock(context.Background(), rpc.BlockNumberOrHashWithNumber(1)) + if err != nil { + t.Error(err) + } + + assert.Equal(t, 0, len(receiptsOut)) + + // check 2 : one transactions ( normal ) + receiptsOut, err = publicBlockchainAPI.GetTransactionReceiptsByBlock(context.Background(), rpc.BlockNumberOrHashWithNumber(2)) + if err != nil { + t.Error(err) + } + + assert.Equal(t, 1, len(receiptsOut)) + assert.True(t, areDifferentHashes(receiptsOut)) + + // check 3 : two transactions ( both normal ) + receiptsOut, err = publicBlockchainAPI.GetTransactionReceiptsByBlock(context.Background(), rpc.BlockNumberOrHashWithNumber(3)) + if err != nil { + t.Error(err) + } + + assert.Equal(t, 2, len(receiptsOut)) + assert.True(t, areDifferentHashes(receiptsOut)) + + // check 4 : two transactions ( one normal + one state-sync) + receiptsOut, err = publicBlockchainAPI.GetTransactionReceiptsByBlock(context.Background(), rpc.BlockNumberOrHashWithNumber(4)) + if err != nil { + t.Error(err) + } + + assert.Equal(t, 2, len(receiptsOut)) + assert.True(t, areDifferentHashes(receiptsOut)) + +} + +// Test for GetTransactionByBlockNumberAndIndex +func testGetTransactionByBlockNumberAndIndex(t *testing.T, publicTransactionPoolAPI *ethapi.PublicTransactionPoolAPI) { + // check 1 : False ( no transaction ) + tx := publicTransactionPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(1), 0) + assert.Nil(t, tx) + + // check 2 : Normal Transaction + tx = publicTransactionPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(2), 0) + assert.Equal(t, common.HexToAddress("0x24"), *tx.To) + + // check 3 : Normal Transaction + tx = publicTransactionPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(3), 0) + assert.Equal(t, common.HexToAddress("0x992"), *tx.To) + + // check 4 : Normal Transaction + tx = publicTransactionPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(3), 1) + assert.Equal(t, common.HexToAddress("0x993"), *tx.To) + + // check 5 : Normal Transaction + tx = publicTransactionPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(4), 0) + assert.Equal(t, common.HexToAddress("0x1000"), *tx.To) + + // check 5 : Normal Transaction + tx = publicTransactionPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(4), 1) + assert.Equal(t, common.HexToAddress("0x0"), *tx.To) +} + +// This Testcase tests functions for RPC API calls. +// NOTE : Changes to this function might affect the child testcases. +func TestAPIs(t *testing.T) { defer func() { if err := stack.Close(); err != nil { @@ -67,7 +137,7 @@ func TestGetTransactionReceiptsByBlock(t *testing.T) { } }() - genesis := core.GenesisBlockForTesting(db, addr, big.NewInt(1000000)) + genesis := core.GenesisBlockForTesting(db, addrr, big.NewInt(1000000)) sprint := params.TestChainConfig.Bor.Sprint chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 6, func(i int, gen *core.BlockGen) { @@ -77,7 +147,7 @@ func TestGetTransactionReceiptsByBlock(t *testing.T) { receipt := types.NewReceipt(nil, false, 0) receipt.Logs = []*types.Log{ { - Address: addr, + Address: addrr, Topics: []common.Hash{hash1}, }, } @@ -88,7 +158,7 @@ func TestGetTransactionReceiptsByBlock(t *testing.T) { receipt := types.NewReceipt(nil, false, 0) receipt.Logs = []*types.Log{ { - Address: addr, + Address: addrr, Topics: []common.Hash{hash2}, }, } @@ -98,7 +168,7 @@ func TestGetTransactionReceiptsByBlock(t *testing.T) { receipt2 := types.NewReceipt(nil, false, 0) receipt2.Logs = []*types.Log{ { - Address: addr, + Address: addrr, Topics: []common.Hash{hash3}, }, } @@ -109,18 +179,18 @@ func TestGetTransactionReceiptsByBlock(t *testing.T) { receipt := types.NewReceipt(nil, false, 0) receipt.Logs = []*types.Log{ { - Address: addr, + Address: addrr, Topics: []common.Hash{hash4}, }, } gen.AddUncheckedReceipt(receipt) - gen.AddUncheckedTx(types.NewTransaction(1000, common.HexToAddress("0x0"), big.NewInt(1000), 1000, gen.BaseFee(), nil)) + gen.AddUncheckedTx(types.NewTransaction(1000, common.HexToAddress("0x1000"), big.NewInt(1000), 1000, gen.BaseFee(), nil)) // state-sync transaction receipt2 := types.NewReceipt(nil, false, 0) receipt2.Logs = []*types.Log{ { - Address: addr, + Address: addrr, Topics: []common.Hash{hash5}, }, } @@ -173,40 +243,13 @@ func TestGetTransactionReceiptsByBlock(t *testing.T) { } } + // Testing GetTransactionReceiptsByBlock publicBlockchainAPI := backend.PublicBlockChainAPI() + testGetTransactionReceiptsByBlock(t, publicBlockchainAPI) - // check 1 : zero transactions - receiptsOut, err := publicBlockchainAPI.GetTransactionReceiptsByBlock(context.Background(), rpc.BlockNumberOrHashWithNumber(1)) - if err != nil { - t.Error(err) - } - - assert.Equal(t, 0, len(receiptsOut)) - - // check 2 : one transactions ( normal ) - receiptsOut, err = publicBlockchainAPI.GetTransactionReceiptsByBlock(context.Background(), rpc.BlockNumberOrHashWithNumber(2)) - if err != nil { - t.Error(err) - } - - assert.Equal(t, 1, len(receiptsOut)) - assert.True(t, areDifferentHashes(receiptsOut)) - - // check 3 : two transactions ( both normal ) - receiptsOut, err = publicBlockchainAPI.GetTransactionReceiptsByBlock(context.Background(), rpc.BlockNumberOrHashWithNumber(3)) - if err != nil { - t.Error(err) - } - - assert.Equal(t, 2, len(receiptsOut)) - assert.True(t, areDifferentHashes(receiptsOut)) - - // check 4 : two transactions ( one normal + one state-sync) - receiptsOut, err = publicBlockchainAPI.GetTransactionReceiptsByBlock(context.Background(), rpc.BlockNumberOrHashWithNumber(4)) - if err != nil { - t.Error(err) - } + // Testing GetTransactionByBlockNumberAndIndex + nonceLock := new(ethapi.AddrLocker) + publicTransactionPoolAPI := ethapi.NewPublicTransactionPoolAPI(backend.APIBackend, nonceLock) + testGetTransactionByBlockNumberAndIndex(t, publicTransactionPoolAPI) - assert.Equal(t, 2, len(receiptsOut)) - assert.True(t, areDifferentHashes(receiptsOut)) }