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, ðconfig.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 }