github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/tests/bor/bor_api_test.go (about)

     1  //go:build integration
     2  
     3  package bor
     4  
     5  import (
     6  	"context"
     7  	"math/big"
     8  	"testing"
     9  
    10  	"github.com/ethereum/go-ethereum/common"
    11  	"github.com/ethereum/go-ethereum/consensus/ethash"
    12  	"github.com/ethereum/go-ethereum/core"
    13  	"github.com/ethereum/go-ethereum/core/rawdb"
    14  	"github.com/ethereum/go-ethereum/core/types"
    15  	"github.com/ethereum/go-ethereum/crypto"
    16  	"github.com/ethereum/go-ethereum/eth"
    17  	"github.com/ethereum/go-ethereum/eth/ethconfig"
    18  	"github.com/ethereum/go-ethereum/internal/ethapi"
    19  	"github.com/ethereum/go-ethereum/node"
    20  	"github.com/ethereum/go-ethereum/params"
    21  	"github.com/ethereum/go-ethereum/rpc"
    22  
    23  	"github.com/stretchr/testify/assert"
    24  )
    25  
    26  var (
    27  	key1, _    = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
    28  	addrr      = crypto.PubkeyToAddress(key1.PublicKey)
    29  	stack, _   = node.New(&node.DefaultConfig)
    30  	backend, _ = eth.New(stack, &ethconfig.Defaults)
    31  	db         = backend.ChainDb()
    32  	hash1      = common.BytesToHash([]byte("topic1"))
    33  	hash2      = common.BytesToHash([]byte("topic2"))
    34  	hash3      = common.BytesToHash([]byte("topic3"))
    35  	hash4      = common.BytesToHash([]byte("topic4"))
    36  	hash5      = common.BytesToHash([]byte("topic5"))
    37  )
    38  
    39  func duplicateInArray(arr []common.Hash) bool {
    40  	visited := make(map[common.Hash]bool, 0)
    41  	for i := 0; i < len(arr); i++ {
    42  		if visited[arr[i]] == true {
    43  			return true
    44  		} else {
    45  			visited[arr[i]] = true
    46  		}
    47  	}
    48  
    49  	return false
    50  }
    51  
    52  func areDifferentHashes(receipts []map[string]interface{}) bool {
    53  	addresses := []common.Hash{}
    54  	for i := 0; i < len(receipts); i++ {
    55  		addresses = append(addresses, receipts[i]["transactionHash"].(common.Hash))
    56  		if duplicateInArray(addresses) {
    57  			return false
    58  		}
    59  	}
    60  
    61  	return true
    62  }
    63  
    64  // Test for GetTransactionReceiptsByBlock
    65  func testGetTransactionReceiptsByBlock(t *testing.T, publicBlockchainAPI *ethapi.PublicBlockChainAPI) {
    66  	// check 1 : zero transactions
    67  	receiptsOut, err := publicBlockchainAPI.GetTransactionReceiptsByBlock(context.Background(), rpc.BlockNumberOrHashWithNumber(1))
    68  	if err != nil {
    69  		t.Error(err)
    70  	}
    71  
    72  	assert.Equal(t, 0, len(receiptsOut))
    73  
    74  	// check 2 : one transactions ( normal )
    75  	receiptsOut, err = publicBlockchainAPI.GetTransactionReceiptsByBlock(context.Background(), rpc.BlockNumberOrHashWithNumber(2))
    76  	if err != nil {
    77  		t.Error(err)
    78  	}
    79  
    80  	assert.Equal(t, 1, len(receiptsOut))
    81  	assert.True(t, areDifferentHashes(receiptsOut))
    82  
    83  	// check 3 : two transactions ( both normal )
    84  	receiptsOut, err = publicBlockchainAPI.GetTransactionReceiptsByBlock(context.Background(), rpc.BlockNumberOrHashWithNumber(3))
    85  	if err != nil {
    86  		t.Error(err)
    87  	}
    88  
    89  	assert.Equal(t, 2, len(receiptsOut))
    90  	assert.True(t, areDifferentHashes(receiptsOut))
    91  
    92  	// check 4 : two transactions ( one normal + one state-sync)
    93  	receiptsOut, err = publicBlockchainAPI.GetTransactionReceiptsByBlock(context.Background(), rpc.BlockNumberOrHashWithNumber(4))
    94  	if err != nil {
    95  		t.Error(err)
    96  	}
    97  
    98  	assert.Equal(t, 2, len(receiptsOut))
    99  	assert.True(t, areDifferentHashes(receiptsOut))
   100  
   101  }
   102  
   103  // Test for GetTransactionByBlockNumberAndIndex
   104  func testGetTransactionByBlockNumberAndIndex(t *testing.T, publicTransactionPoolAPI *ethapi.PublicTransactionPoolAPI) {
   105  	// check 1 : False ( no transaction )
   106  	tx := publicTransactionPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(1), 0)
   107  	assert.Nil(t, tx)
   108  
   109  	// check 2 : Normal Transaction
   110  	tx = publicTransactionPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(2), 0)
   111  	assert.Equal(t, common.HexToAddress("0x24"), *tx.To)
   112  
   113  	// check 3 : Normal Transaction
   114  	tx = publicTransactionPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(3), 0)
   115  	assert.Equal(t, common.HexToAddress("0x992"), *tx.To)
   116  
   117  	// check 4 : Normal Transaction
   118  	tx = publicTransactionPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(3), 1)
   119  	assert.Equal(t, common.HexToAddress("0x993"), *tx.To)
   120  
   121  	// check 5 : Normal Transaction
   122  	tx = publicTransactionPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(4), 0)
   123  	assert.Equal(t, common.HexToAddress("0x1000"), *tx.To)
   124  
   125  	// check 5 : Normal Transaction
   126  	tx = publicTransactionPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(4), 1)
   127  	assert.Equal(t, common.HexToAddress("0x0"), *tx.To)
   128  }
   129  
   130  // This Testcase tests functions for RPC API calls.
   131  // NOTE : Changes to this function might affect the child testcases.
   132  func TestAPIs(t *testing.T) {
   133  
   134  	defer func() {
   135  		if err := stack.Close(); err != nil {
   136  			t.Error(err)
   137  		}
   138  	}()
   139  
   140  	genesis := core.GenesisBlockForTesting(db, addrr, big.NewInt(1000000))
   141  	testBorConfig := params.TestChainConfig.Bor
   142  
   143  	chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 6, func(i int, gen *core.BlockGen) {
   144  		switch i {
   145  
   146  		case 1: // 1 normal transaction on block 2
   147  			receipt := types.NewReceipt(nil, false, 0)
   148  			receipt.Logs = []*types.Log{
   149  				{
   150  					Address: addrr,
   151  					Topics:  []common.Hash{hash1},
   152  				},
   153  			}
   154  			gen.AddUncheckedReceipt(receipt)
   155  			gen.AddUncheckedTx(types.NewTransaction(24, common.HexToAddress("0x24"), big.NewInt(24), 24, gen.BaseFee(), nil))
   156  
   157  		case 2: // 2 normal transactions on block 3
   158  			receipt := types.NewReceipt(nil, false, 0)
   159  			receipt.Logs = []*types.Log{
   160  				{
   161  					Address: addrr,
   162  					Topics:  []common.Hash{hash2},
   163  				},
   164  			}
   165  			gen.AddUncheckedReceipt(receipt)
   166  			gen.AddUncheckedTx(types.NewTransaction(992, common.HexToAddress("0x992"), big.NewInt(992), 992, gen.BaseFee(), nil))
   167  
   168  			receipt2 := types.NewReceipt(nil, false, 0)
   169  			receipt2.Logs = []*types.Log{
   170  				{
   171  					Address: addrr,
   172  					Topics:  []common.Hash{hash3},
   173  				},
   174  			}
   175  			gen.AddUncheckedReceipt(receipt2)
   176  			gen.AddUncheckedTx(types.NewTransaction(993, common.HexToAddress("0x993"), big.NewInt(993), 993, gen.BaseFee(), nil))
   177  
   178  		case 3: // 1 normal transaction, 1 state-sync transaction on block 4
   179  			receipt := types.NewReceipt(nil, false, 0)
   180  			receipt.Logs = []*types.Log{
   181  				{
   182  					Address: addrr,
   183  					Topics:  []common.Hash{hash4},
   184  				},
   185  			}
   186  			gen.AddUncheckedReceipt(receipt)
   187  			gen.AddUncheckedTx(types.NewTransaction(1000, common.HexToAddress("0x1000"), big.NewInt(1000), 1000, gen.BaseFee(), nil))
   188  
   189  			// state-sync transaction
   190  			receipt2 := types.NewReceipt(nil, false, 0)
   191  			receipt2.Logs = []*types.Log{
   192  				{
   193  					Address: addrr,
   194  					Topics:  []common.Hash{hash5},
   195  				},
   196  			}
   197  			gen.AddUncheckedReceipt(receipt2)
   198  			// not adding unchecked tx as it will be added as a state-sync tx later
   199  
   200  		}
   201  	})
   202  
   203  	for i, block := range chain {
   204  		// write the block to database
   205  		rawdb.WriteBlock(db, block)
   206  		rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64())
   207  		rawdb.WriteHeadBlockHash(db, block.Hash())
   208  
   209  		blockBatch := db.NewBatch()
   210  
   211  		if i%int(testBorConfig.CalculateSprint(block.NumberU64())-1) != 0 {
   212  			// if it is not sprint start write all the transactions as normal transactions.
   213  			rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts[i])
   214  		} else {
   215  			// check for blocks with receipts. Since in state-sync block, we have 1 normal txn and 1 state-sync txn.
   216  			if len(receipts[i]) > 0 {
   217  				// We write receipts for the normal transaction.
   218  				rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts[i][:1])
   219  
   220  				// write the state-sync receipts to database => receipts[i][1:] => receipts[i][1]
   221  				// State sync logs don't have tx index, tx hash and other necessary fields, DeriveFieldsForBorLogs will fill those fields for websocket subscriptions
   222  				// DeriveFieldsForBorLogs argurments:
   223  				// 1. State-sync logs
   224  				// 2. Block Hash
   225  				// 3. Block Number
   226  				// 4. Transactions in the block(except state-sync) i.e. 1 in our case
   227  				// 5. AllLogs -(minus) StateSyncLogs ; since we only have state-sync tx, it will be 1
   228  				types.DeriveFieldsForBorLogs(receipts[i][1].Logs, block.Hash(), block.NumberU64(), uint(1), uint(1))
   229  
   230  				rawdb.WriteBorReceipt(blockBatch, block.Hash(), block.NumberU64(), &types.ReceiptForStorage{
   231  					Status: types.ReceiptStatusSuccessful, // make receipt status successful
   232  					Logs:   receipts[i][1].Logs,
   233  				})
   234  
   235  				rawdb.WriteBorTxLookupEntry(blockBatch, block.Hash(), block.NumberU64())
   236  
   237  			}
   238  
   239  		}
   240  
   241  		if err := blockBatch.Write(); err != nil {
   242  			t.Error("Failed to write block into disk", "err", err)
   243  		}
   244  	}
   245  
   246  	// Testing GetTransactionReceiptsByBlock
   247  	publicBlockchainAPI := backend.PublicBlockChainAPI()
   248  	testGetTransactionReceiptsByBlock(t, publicBlockchainAPI)
   249  
   250  	// Testing GetTransactionByBlockNumberAndIndex
   251  	nonceLock := new(ethapi.AddrLocker)
   252  	publicTransactionPoolAPI := ethapi.NewPublicTransactionPoolAPI(backend.APIBackend, nonceLock)
   253  	testGetTransactionByBlockNumberAndIndex(t, publicTransactionPoolAPI)
   254  
   255  }