Skip to content

Commit

Permalink
Merge pull request #1404 from maticnetwork/lmartins/rpc-state-sync-tests
Browse files Browse the repository at this point in the history
StateSync Unit Tests on RPC Methods
  • Loading branch information
avalkov authored Jan 16, 2025
2 parents 14ea2ca + b0bba24 commit 62e7448
Show file tree
Hide file tree
Showing 16 changed files with 364 additions and 116 deletions.
23 changes: 18 additions & 5 deletions internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/davecgh/go-spew/spew"
"github.com/tyler-smith/go-bip39"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/accounts/scwallet"
Expand Down Expand Up @@ -704,7 +705,10 @@ func (api *BlockChainAPI) GetTransactionReceiptsByBlock(ctx context.Context, blo

var txHash common.Hash

borReceipt := rawdb.ReadBorReceipt(api.b.ChainDb(), block.Hash(), block.NumberU64(), api.b.ChainConfig())
borReceipt, err := api.b.GetBorBlockReceipt(ctx, block.Hash())
if err != nil && err != ethereum.NotFound {
return nil, err
}
if borReceipt != nil {
receipts = append(receipts, borReceipt)

Expand Down Expand Up @@ -1115,7 +1119,10 @@ func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rp
result[i] = marshalReceipt(receipt, block.Hash(), block.NumberU64(), signer, txs[i], i, false)
}

stateSyncReceipt := rawdb.ReadBorReceipt(api.b.ChainDb(), block.Hash(), block.NumberU64(), api.b.ChainConfig())
stateSyncReceipt, err := api.b.GetBorBlockReceipt(ctx, block.Hash())
if err != nil && err != ethereum.NotFound {
return nil, err
}
if stateSyncReceipt != nil {
tx, _, _, _ := rawdb.ReadBorTransaction(api.b.ChainDb(), stateSyncReceipt.TxHash)
result = append(result, marshalReceipt(stateSyncReceipt, block.Hash(), block.NumberU64(), signer, tx, len(result), true))
Expand Down Expand Up @@ -1901,7 +1908,7 @@ func (api *TransactionAPI) getAllBlockTransactions(ctx context.Context, block *t

stateSyncPresent := false

borReceipt := rawdb.ReadBorReceipt(api.b.ChainDb(), block.Hash(), block.NumberU64(), api.b.ChainConfig())
borReceipt, _ := api.b.GetBorBlockReceipt(ctx, block.Hash())
if borReceipt != nil {
txHash := types.GetDerivedBorTxHash(types.BorReceiptKey(block.Number().Uint64(), block.Hash()))
if txHash != (common.Hash{}) {
Expand Down Expand Up @@ -2074,7 +2081,10 @@ func (api *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash commo
}

if !found {
tx, blockHash, blockNumber, index = rawdb.ReadBorTransaction(api.b.ChainDb(), hash)
tx, blockHash, blockNumber, index, err = api.b.GetBorBlockTransaction(ctx, hash)
if err != nil {
return nil, err
}
borTx = true
}

Expand All @@ -2086,7 +2096,10 @@ func (api *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash commo

if borTx {
// Fetch bor block receipt
receipt = rawdb.ReadBorReceipt(api.b.ChainDb(), blockHash, blockNumber, api.b.ChainConfig())
receipt, err = api.b.GetBorBlockReceipt(ctx, blockHash)
if err != nil && err != ethereum.NotFound {
return nil, err
}
} else {
receipts, err := api.b.GetReceipts(ctx, blockHash)
if err != nil {
Expand Down
219 changes: 164 additions & 55 deletions internal/ethapi/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -587,10 +587,16 @@ func (b testBackend) SendTx(ctx context.Context, signedTx *types.Transaction) er
}
func (b testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) {
tx, blockHash, blockNumber, index := rawdb.ReadTransaction(b.db, txHash)
return true, tx, blockHash, blockNumber, index, nil
found := true
if tx == nil {
found = false
}
return found, tx, blockHash, blockNumber, index, nil
}
func (b testBackend) GetPoolTransactions() (types.Transactions, error) { panic("implement me") }
func (b testBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction {
return nil
}
func (b testBackend) GetPoolTransactions() (types.Transactions, error) { panic("implement me") }
func (b testBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { panic("implement me") }
func (b testBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
return 0, nil
}
Expand Down Expand Up @@ -625,7 +631,8 @@ func (b testBackend) ServiceFilter(ctx context.Context, session *bloombits.Match

// GetBorBlockTransaction returns bor block tx
func (b testBackend) GetBorBlockTransaction(ctx context.Context, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
panic("implement me")
tx, blockHash, blockNumber, index := rawdb.ReadBorTransaction(b.ChainDb(), hash)
return tx, blockHash, blockNumber, index, nil
}

func (b testBackend) GetBorBlockTransactionWithBlockHash(ctx context.Context, txHash common.Hash, blockHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
Expand Down Expand Up @@ -683,14 +690,9 @@ func (b testBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*
}

func (b testBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) {
number := rawdb.ReadHeaderNumber(b.db, hash)
if number == nil {
return nil, nil
}

receipt := rawdb.ReadRawBorReceipt(b.db, hash, *number)
receipt := b.chain.GetBorReceiptByHash(hash)
if receipt == nil {
return nil, nil
return nil, ethereum.NotFound
}

return receipt, nil
Expand Down Expand Up @@ -1902,9 +1904,12 @@ func TestRPCGetBlockOrHeader(t *testing.T) {
}
}

func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Hash) {
func setupTransactionsToApiTest(t *testing.T) (*TransactionAPI, []common.Hash, []struct {
txHash common.Hash
file string
}) {
config := *params.TestChainConfig

genBlocks := 5
config.ShanghaiBlock = big.NewInt(0)
config.CancunBlock = big.NewInt(0)

Expand Down Expand Up @@ -1935,7 +1940,7 @@ func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Ha
},
}
signer = types.LatestSignerForChainID(params.TestChainConfig.ChainID)
txHashes = make([]common.Hash, genBlocks)
txHashes = make([]common.Hash, genBlocks+1)
)

// Set the terminal total difficulty in the config
Expand Down Expand Up @@ -1974,20 +1979,6 @@ func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Ha
StorageKeys: []common.Hash{{0}},
}}
tx, err = types.SignTx(types.NewTx(&types.AccessListTx{Nonce: uint64(i), To: nil, Gas: 58100, GasPrice: b.BaseFee(), Data: common.FromHex("0x60806040"), AccessList: accessList}), signer, acc1Key)
case 5:
// blob tx
fee := big.NewInt(500)
fee.Add(fee, b.BaseFee())
tx, err = types.SignTx(types.NewTx(&types.BlobTx{
Nonce: uint64(i),
GasTipCap: uint256.NewInt(1),
GasFeeCap: uint256.MustFromBig(fee),
Gas: params.TxGas,
To: acc2Addr,
BlobFeeCap: uint256.NewInt(1),
BlobHashes: []common.Hash{{1}},
Value: new(uint256.Int),
}), signer, acc1Key)
}
if err != nil {
t.Errorf("failed to sign tx: %v", err)
Expand All @@ -1997,16 +1988,8 @@ func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Ha
txHashes[i] = tx.Hash()
}
})
return backend, txHashes
}

func TestRPCGetTransactionReceipt(t *testing.T) {
t.Parallel()

var (
backend, txHashes = setupReceiptBackend(t, 6)
api = NewTransactionAPI(backend, new(AddrLocker))
)
txHashes[genBlocks] = mockStateSyncTxOnCurrentBlock(t, backend)

var testSuite = []struct {
txHash common.Hash
Expand Down Expand Up @@ -2047,12 +2030,45 @@ func TestRPCGetTransactionReceipt(t *testing.T) {
txHash: common.HexToHash("deadbeef"),
file: "txhash-notfound",
},
// 7. blob tx
// 7. state sync tx found
{
txHash: txHashes[5],
file: "blob-tx",
file: "state-sync-tx",
},
}
// map sprint 0 to block 6
backend.ChainConfig().Bor.Sprint["0"] = uint64(genBlocks)

api := NewTransactionAPI(backend, new(AddrLocker))

return api, txHashes, testSuite
}

func mockStateSyncTxOnCurrentBlock(t *testing.T, backend *testBackend) common.Hash {
// State Sync Tx Setup
var stateSyncLogs []*types.Log
block, err := backend.BlockByHash(context.Background(), backend.CurrentBlock().Hash())
if err != nil {
t.Errorf("failed to get current block: %v", err)
}

types.DeriveFieldsForBorLogs(stateSyncLogs, block.Hash(), block.NumberU64(), 0, 0)

// Write bor receipt
rawdb.WriteBorReceipt(backend.ChainDb(), block.Hash(), block.NumberU64(), &types.ReceiptForStorage{
Status: types.ReceiptStatusSuccessful, // make receipt status successful
Logs: stateSyncLogs,
})

// Write bor tx reverse lookup
rawdb.WriteBorTxLookupEntry(backend.ChainDb(), block.Hash(), block.NumberU64())
return types.GetDerivedBorTxHash(types.BorReceiptKey(block.NumberU64(), block.Hash()))
}

func TestRPCGetTransactionReceipt(t *testing.T) {
var (
api, _, testSuite = setupTransactionsToApiTest(t)
)

for i, tt := range testSuite {
var (
Expand All @@ -2067,6 +2083,48 @@ func TestRPCGetTransactionReceipt(t *testing.T) {
testRPCResponseWithFile(t, i, result, "eth_getTransactionReceipt", tt.file)
}
}
func TestRPCGetTransactionByHash(t *testing.T) {
var (
api, _, testSuite = setupTransactionsToApiTest(t)
)

for i, tt := range testSuite {
var (
result interface{}
err error
)
result, err = api.GetTransactionByHash(context.Background(), tt.txHash)
if err != nil {
t.Errorf("test %d: want no error, have %v", i, err)
continue
}
testRPCResponseWithFile(t, i, result, "eth_getTransactionByHash", tt.file)
}
}

func TestRPCGetBlockTransactionCountByHash(t *testing.T) {
var (
api, _, _ = setupTransactionsToApiTest(t)
)

cnt := api.GetBlockTransactionCountByHash(context.Background(), api.b.CurrentBlock().Hash())

// 2 txs: create-contract-with-access-list + state sync tx
expected := hexutil.Uint(2)
require.Equal(t, expected, *cnt)
}

func TestRPCGetTransactionByBlockHashAndIndex(t *testing.T) {
var (
api, _, _ = setupTransactionsToApiTest(t)
)

createContractWithAccessList := api.GetTransactionByBlockHashAndIndex(context.Background(), api.b.CurrentBlock().Hash(), 0)
stateSyncTx := api.GetTransactionByBlockHashAndIndex(context.Background(), api.b.CurrentBlock().Hash(), 1)

testRPCResponseWithFile(t, 0, createContractWithAccessList, "eth_getTransactionByBlockHashAndIndex", "create-contract-with-access-list")
testRPCResponseWithFile(t, 1, stateSyncTx, "eth_getTransactionByBlockHashAndIndex", "state-sync-tx")
}

func testRPCResponseWithFile(t *testing.T, testid int, result interface{}, rpc string, file string) {
data, err := json.MarshalIndent(result, "", " ")
Expand All @@ -2086,8 +2144,47 @@ func testRPCResponseWithFile(t *testing.T, testid int, result interface{}, rpc s
}

func TestRPCGetTransactionReceiptsByBlock(t *testing.T) {
t.Parallel()
api, blockNrOrHash, testSuite := setupBlocksToApiTest(t)

receipts, err := api.GetTransactionReceiptsByBlock(context.Background(), blockNrOrHash)
if err != nil {
t.Fatal("api error")
}

for i, tt := range testSuite {
data, err := json.Marshal(receipts[i])
if err != nil {
t.Errorf("test %d: json marshal error", i)
continue
}
want, have := tt.want, string(data)
require.JSONEqf(t, want, have, "test %d: json not match, want: %s, have: %s", i, want, have)
}
}

func TestRPCGetBlockReceipts(t *testing.T) {
api, blockNrOrHash, testSuite := setupBlocksToApiTest(t)

receipts, err := api.GetBlockReceipts(context.Background(), blockNrOrHash)
if err != nil {
t.Fatal("api error")
}

for i, tt := range testSuite {
data, err := json.Marshal(receipts[i])
if err != nil {
t.Errorf("test %d: json marshal error", i)
continue
}
want, have := tt.want, string(data)
require.JSONEqf(t, want, have, "test %d: json not match, want: %s, have: %s", i, want, have)
}
}

func setupBlocksToApiTest(t *testing.T) (*BlockChainAPI, rpc.BlockNumberOrHash, []struct {
txHash common.Hash
want string
}) {
// Initialize test accounts
var (
acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
Expand All @@ -2103,7 +2200,7 @@ func TestRPCGetTransactionReceiptsByBlock(t *testing.T) {
contract: {Balance: big.NewInt(params.Ether), Code: common.FromHex("0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063a9059cbb14610030575b600080fd5b61004a6004803603810190610045919061016a565b610060565b60405161005791906101c5565b60405180910390f35b60008273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516100bf91906101ef565b60405180910390a36001905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610101826100d6565b9050919050565b610111816100f6565b811461011c57600080fd5b50565b60008135905061012e81610108565b92915050565b6000819050919050565b61014781610134565b811461015257600080fd5b50565b6000813590506101648161013e565b92915050565b60008060408385031215610181576101806100d1565b5b600061018f8582860161011f565b92505060206101a085828601610155565b9150509250929050565b60008115159050919050565b6101bf816101aa565b82525050565b60006020820190506101da60008301846101b6565b92915050565b6101e981610134565b82525050565b600060208201905061020460008301846101e0565b9291505056fea2646970667358221220b469033f4b77b9565ee84e0a2f04d496b18160d26034d54f9487e57788fd36d564736f6c63430008120033")},
},
}
genTxs = 5
genTxs = 6
genBlocks = 1
signer = types.LatestSignerForChainID(params.TestChainConfig.ChainID)
txHashes = make([]common.Hash, 0, genTxs)
Expand Down Expand Up @@ -2149,6 +2246,11 @@ func TestRPCGetTransactionReceiptsByBlock(t *testing.T) {
}
})

txHashes = append(txHashes, mockStateSyncTxOnCurrentBlock(t, backend))

// map sprint 0 to block 1
backend.ChainConfig().Bor.Sprint["0"] = 1

api := NewBlockChainAPI(backend)
blockHashes := make([]common.Hash, genBlocks+1)
ctx := context.Background()
Expand Down Expand Up @@ -2315,20 +2417,27 @@ func TestRPCGetTransactionReceiptsByBlock(t *testing.T) {
"type": "0x1"
}`,
},
// 5. state sync tx
{
txHash: txHashes[5],
want: `{
"blockHash": "0x1728b788dfe51e507d25f14f01414b5a17f807953c13833811d2afae1982b53b",
"blockNumber": "0x1",
"contractAddress": null,
"cumulativeGasUsed": "0x0",
"effectiveGasPrice": "0x0",
"from": "0x0000000000000000000000000000000000000000",
"gasUsed": "0x0",
"logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1",
"to": "0x0000000000000000000000000000000000000000",
"transactionHash": "0xba46f68d5c3729ac3fb672fec579fc2cad543bc9edf5b2d47d7c6636ac2fbec9",
"transactionIndex": "0x5",
"type": "0x0"
}`,
},
}

receipts, err := api.GetTransactionReceiptsByBlock(context.Background(), blockNrOrHash)
if err != nil {
t.Fatal("api error")
}

for i, tt := range testSuite {
data, err := json.Marshal(receipts[i])
if err != nil {
t.Errorf("test %d: json marshal error", i)
continue
}
want, have := tt.want, string(data)
require.JSONEqf(t, want, have, "test %d: json not match, want: %s, have: %s", i, want, have)
}
return api, blockNrOrHash, testSuite
}
Loading

0 comments on commit 62e7448

Please sign in to comment.