github.com/ava-labs/subnet-evm@v0.6.4/internal/ethapi/api_test.go (about) 1 // (c) 2023, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2023 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package ethapi 28 29 import ( 30 "context" 31 "crypto/ecdsa" 32 "encoding/json" 33 "errors" 34 "fmt" 35 "math/big" 36 "os" 37 "path/filepath" 38 "reflect" 39 "testing" 40 "time" 41 42 "github.com/ava-labs/subnet-evm/accounts" 43 "github.com/ava-labs/subnet-evm/commontype" 44 "github.com/ava-labs/subnet-evm/consensus" 45 "github.com/ava-labs/subnet-evm/consensus/dummy" 46 "github.com/ava-labs/subnet-evm/core" 47 "github.com/ava-labs/subnet-evm/core/bloombits" 48 "github.com/ava-labs/subnet-evm/core/rawdb" 49 "github.com/ava-labs/subnet-evm/core/state" 50 "github.com/ava-labs/subnet-evm/core/types" 51 "github.com/ava-labs/subnet-evm/core/vm" 52 "github.com/ava-labs/subnet-evm/internal/blocktest" 53 "github.com/ava-labs/subnet-evm/params" 54 "github.com/ava-labs/subnet-evm/rpc" 55 "github.com/ethereum/go-ethereum/common" 56 "github.com/ethereum/go-ethereum/common/hexutil" 57 "github.com/ethereum/go-ethereum/crypto" 58 "github.com/ethereum/go-ethereum/ethdb" 59 "github.com/ethereum/go-ethereum/event" 60 "github.com/holiman/uint256" 61 "github.com/stretchr/testify/require" 62 "golang.org/x/exp/slices" 63 ) 64 65 func testTransactionMarshal(t *testing.T, tests []txData, config *params.ChainConfig) { 66 t.Parallel() 67 var ( 68 signer = types.LatestSigner(config) 69 key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 70 ) 71 72 for i, tt := range tests { 73 var tx2 types.Transaction 74 tx, err := types.SignNewTx(key, signer, tt.Tx) 75 if err != nil { 76 t.Fatalf("test %d: signing failed: %v", i, err) 77 } 78 // Regular transaction 79 if data, err := json.Marshal(tx); err != nil { 80 t.Fatalf("test %d: marshalling failed; %v", i, err) 81 } else if err = tx2.UnmarshalJSON(data); err != nil { 82 t.Fatalf("test %d: sunmarshal failed: %v", i, err) 83 } else if want, have := tx.Hash(), tx2.Hash(); want != have { 84 t.Fatalf("test %d: stx changed, want %x have %x", i, want, have) 85 } 86 87 // rpcTransaction 88 rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, 0, nil, config) 89 if data, err := json.Marshal(rpcTx); err != nil { 90 t.Fatalf("test %d: marshalling failed; %v", i, err) 91 } else if err = tx2.UnmarshalJSON(data); err != nil { 92 t.Fatalf("test %d: unmarshal failed: %v", i, err) 93 } else if want, have := tx.Hash(), tx2.Hash(); want != have { 94 t.Fatalf("test %d: tx changed, want %x have %x", i, want, have) 95 } else { 96 want, have := tt.Want, string(data) 97 require.JSONEqf(t, want, have, "test %d: rpc json not match, want %s have %s", i, want, have) 98 } 99 } 100 } 101 102 func TestTransaction_RoundTripRpcJSON(t *testing.T) { 103 var ( 104 config = params.TestChainConfig 105 tests = allTransactionTypes(common.Address{0xde, 0xad}, config) 106 ) 107 testTransactionMarshal(t, tests, config) 108 } 109 110 func TestTransactionBlobTx(t *testing.T) { 111 config := *params.TestChainConfig 112 // config.ShanghaiTime = new(uint64) 113 config.CancunTime = new(uint64) 114 tests := allBlobTxs(common.Address{0xde, 0xad}, &config) 115 116 testTransactionMarshal(t, tests, &config) 117 } 118 119 type txData struct { 120 Tx types.TxData 121 Want string 122 } 123 124 func allTransactionTypes(addr common.Address, config *params.ChainConfig) []txData { 125 return []txData{ 126 { 127 Tx: &types.LegacyTx{ 128 Nonce: 5, 129 GasPrice: big.NewInt(6), 130 Gas: 7, 131 To: &addr, 132 Value: big.NewInt(8), 133 Data: []byte{0, 1, 2, 3, 4}, 134 V: big.NewInt(9), 135 R: big.NewInt(10), 136 S: big.NewInt(11), 137 }, 138 Want: `{ 139 "blockHash": null, 140 "blockNumber": null, 141 "from": "0x71562b71999873db5b286df957af199ec94617f7", 142 "gas": "0x7", 143 "gasPrice": "0x6", 144 "hash": "0x3fa586d2448ae279279fa7036da74eb932763661543428c1a0aba21b95b37bdb", 145 "input": "0x0001020304", 146 "nonce": "0x5", 147 "to": "0xdead000000000000000000000000000000000000", 148 "transactionIndex": null, 149 "value": "0x8", 150 "type": "0x0", 151 "chainId": "0x1", 152 "v": "0x25", 153 "r": "0xac639f4319e9268898e29444b97101f1225e2a0837151626da23e73dda2443fc", 154 "s": "0x4fcc3f4c3a75f70ee45bb42d4b0aad432cc8c0140efb3e2611d6a6dda8460907" 155 }`, 156 }, { 157 Tx: &types.LegacyTx{ 158 Nonce: 5, 159 GasPrice: big.NewInt(6), 160 Gas: 7, 161 To: nil, 162 Value: big.NewInt(8), 163 Data: []byte{0, 1, 2, 3, 4}, 164 V: big.NewInt(32), 165 R: big.NewInt(10), 166 S: big.NewInt(11), 167 }, 168 Want: `{ 169 "blockHash": null, 170 "blockNumber": null, 171 "from": "0x71562b71999873db5b286df957af199ec94617f7", 172 "gas": "0x7", 173 "gasPrice": "0x6", 174 "hash": "0x617a316c6ff7ed2aa6ead1b4bb28a1322c2156c1c72f376a976d2d2adb1748ee", 175 "input": "0x0001020304", 176 "nonce": "0x5", 177 "to": null, 178 "transactionIndex": null, 179 "value": "0x8", 180 "type": "0x0", 181 "chainId": "0x1", 182 "v": "0x25", 183 "r": "0xee8e89b513778d4815ae5969f3d55e0f7590f31b08f2a2290d5bc4ae37fce299", 184 "s": "0x663db5c74c10e2b6525e7026e7cfd569b819ec91a042322655ff2b35060784b1" 185 }`, 186 }, 187 { 188 Tx: &types.AccessListTx{ 189 ChainID: config.ChainID, 190 Nonce: 5, 191 GasPrice: big.NewInt(6), 192 Gas: 7, 193 To: &addr, 194 Value: big.NewInt(8), 195 Data: []byte{0, 1, 2, 3, 4}, 196 AccessList: types.AccessList{ 197 types.AccessTuple{ 198 Address: common.Address{0x2}, 199 StorageKeys: []common.Hash{types.EmptyRootHash}, 200 }, 201 }, 202 V: big.NewInt(32), 203 R: big.NewInt(10), 204 S: big.NewInt(11), 205 }, 206 Want: `{ 207 "blockHash": null, 208 "blockNumber": null, 209 "from": "0x71562b71999873db5b286df957af199ec94617f7", 210 "gas": "0x7", 211 "gasPrice": "0x6", 212 "hash": "0x6becb7b9c171aa0d6d0a90dcd97bc3529c4d521f9cc9b7e31616aa9afc178c10", 213 "input": "0x0001020304", 214 "nonce": "0x5", 215 "to": "0xdead000000000000000000000000000000000000", 216 "transactionIndex": null, 217 "value": "0x8", 218 "type": "0x1", 219 "accessList": [ 220 { 221 "address": "0x0200000000000000000000000000000000000000", 222 "storageKeys": [ 223 "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" 224 ] 225 } 226 ], 227 "chainId": "0x1", 228 "v": "0x1", 229 "r": "0xea2289ca0243beecbe69d337bbc53c618e1fb6bd2ec69fd4121df47149a4d4be", 230 "s": "0x2dc134b6bc43abbdfebef0b2d62c175459fc1e8ddff60c8e740c461d7ea1522f", 231 "yParity": "0x1" 232 }`, 233 }, { 234 Tx: &types.AccessListTx{ 235 ChainID: config.ChainID, 236 Nonce: 5, 237 GasPrice: big.NewInt(6), 238 Gas: 7, 239 To: nil, 240 Value: big.NewInt(8), 241 Data: []byte{0, 1, 2, 3, 4}, 242 AccessList: types.AccessList{ 243 types.AccessTuple{ 244 Address: common.Address{0x2}, 245 StorageKeys: []common.Hash{types.EmptyRootHash}, 246 }, 247 }, 248 V: big.NewInt(32), 249 R: big.NewInt(10), 250 S: big.NewInt(11), 251 }, 252 Want: `{ 253 "blockHash": null, 254 "blockNumber": null, 255 "from": "0x71562b71999873db5b286df957af199ec94617f7", 256 "gas": "0x7", 257 "gasPrice": "0x6", 258 "hash": "0x22fbf81bae4640511c706e2c72d2f2ef1abc1e7861f2b82c4cae5b102a40709c", 259 "input": "0x0001020304", 260 "nonce": "0x5", 261 "to": null, 262 "transactionIndex": null, 263 "value": "0x8", 264 "type": "0x1", 265 "accessList": [ 266 { 267 "address": "0x0200000000000000000000000000000000000000", 268 "storageKeys": [ 269 "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" 270 ] 271 } 272 ], 273 "chainId": "0x1", 274 "v": "0x1", 275 "r": "0xc50e18edd861639735ec69ca12d82fcbb2c1921d2e2a8fd3a75f408d2d4b8118", 276 "s": "0x32a908d1bc2db0229354f4dd392ffc37934e24ae8b18a620c6588c72660b6238", 277 "yParity": "0x1" 278 }`, 279 }, { 280 Tx: &types.DynamicFeeTx{ 281 ChainID: config.ChainID, 282 Nonce: 5, 283 GasTipCap: big.NewInt(6), 284 GasFeeCap: big.NewInt(9), 285 Gas: 7, 286 To: &addr, 287 Value: big.NewInt(8), 288 Data: []byte{0, 1, 2, 3, 4}, 289 AccessList: types.AccessList{ 290 types.AccessTuple{ 291 Address: common.Address{0x2}, 292 StorageKeys: []common.Hash{types.EmptyRootHash}, 293 }, 294 }, 295 V: big.NewInt(32), 296 R: big.NewInt(10), 297 S: big.NewInt(11), 298 }, 299 Want: `{ 300 "blockHash": null, 301 "blockNumber": null, 302 "from": "0x71562b71999873db5b286df957af199ec94617f7", 303 "gas": "0x7", 304 "gasPrice": "0x9", 305 "maxFeePerGas": "0x9", 306 "maxPriorityFeePerGas": "0x6", 307 "hash": "0xc5763d2ce6af3f694dcda8a9a50d4f75005a711edd382e993dd0406e0c54cfde", 308 "input": "0x0001020304", 309 "nonce": "0x5", 310 "to": "0xdead000000000000000000000000000000000000", 311 "transactionIndex": null, 312 "value": "0x8", 313 "type": "0x2", 314 "accessList": [ 315 { 316 "address": "0x0200000000000000000000000000000000000000", 317 "storageKeys": [ 318 "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" 319 ] 320 } 321 ], 322 "chainId": "0x1", 323 "v": "0x0", 324 "r": "0x740eb1e3bc206760182993845b7815fd8cf7a42f1a1ed26027f736e9eccfd20f", 325 "s": "0x31da567e2b3a83e58e42f7902c3706926c926625f6978c24fdaa21b9d143bbf7", 326 "yParity": "0x0" 327 }`, 328 }, { 329 Tx: &types.DynamicFeeTx{ 330 ChainID: config.ChainID, 331 Nonce: 5, 332 GasTipCap: big.NewInt(6), 333 GasFeeCap: big.NewInt(9), 334 Gas: 7, 335 To: nil, 336 Value: big.NewInt(8), 337 Data: []byte{0, 1, 2, 3, 4}, 338 AccessList: types.AccessList{}, 339 V: big.NewInt(32), 340 R: big.NewInt(10), 341 S: big.NewInt(11), 342 }, 343 Want: `{ 344 "blockHash": null, 345 "blockNumber": null, 346 "from": "0x71562b71999873db5b286df957af199ec94617f7", 347 "gas": "0x7", 348 "gasPrice": "0x9", 349 "maxFeePerGas": "0x9", 350 "maxPriorityFeePerGas": "0x6", 351 "hash": "0x85545f69b2410640fbbb7157b9a79adece45bac4b2803733d250d049e9501a28", 352 "input": "0x0001020304", 353 "nonce": "0x5", 354 "to": null, 355 "transactionIndex": null, 356 "value": "0x8", 357 "type": "0x2", 358 "accessList": [], 359 "chainId": "0x1", 360 "v": "0x1", 361 "r": "0x5004538adbe499313737033b22eb2b50a9450f02fab3971a591e6d57761b2cdf", 362 "s": "0x5f7b1f5d11bd467d84f32beb2e89629351b96c5204c4f72d5d2040bee369a73a", 363 "yParity": "0x1" 364 }`, 365 }, 366 } 367 } 368 369 func allBlobTxs(addr common.Address, config *params.ChainConfig) []txData { 370 return []txData{ 371 { 372 Tx: &types.BlobTx{ 373 Nonce: 6, 374 GasTipCap: uint256.NewInt(1), 375 GasFeeCap: uint256.NewInt(5), 376 Gas: 6, 377 To: addr, 378 BlobFeeCap: uint256.NewInt(1), 379 BlobHashes: []common.Hash{{1}}, 380 Value: new(uint256.Int), 381 V: uint256.NewInt(32), 382 R: uint256.NewInt(10), 383 S: uint256.NewInt(11), 384 }, 385 Want: `{ 386 "blockHash": null, 387 "blockNumber": null, 388 "from": "0x71562b71999873db5b286df957af199ec94617f7", 389 "gas": "0x6", 390 "gasPrice": "0x5", 391 "maxFeePerGas": "0x5", 392 "maxPriorityFeePerGas": "0x1", 393 "maxFeePerBlobGas": "0x1", 394 "hash": "0x1f2b59a20e61efc615ad0cbe936379d6bbea6f938aafaf35eb1da05d8e7f46a3", 395 "input": "0x", 396 "nonce": "0x6", 397 "to": "0xdead000000000000000000000000000000000000", 398 "transactionIndex": null, 399 "value": "0x0", 400 "type": "0x3", 401 "accessList": [], 402 "chainId": "0x1", 403 "blobVersionedHashes": [ 404 "0x0100000000000000000000000000000000000000000000000000000000000000" 405 ], 406 "v": "0x0", 407 "r": "0x618be8908e0e5320f8f3b48042a079fe5a335ebd4ed1422a7d2207cd45d872bc", 408 "s": "0x27b2bc6c80e849a8e8b764d4549d8c2efac3441e73cf37054eb0a9b9f8e89b27", 409 "yParity": "0x0" 410 }`, 411 }, 412 } 413 } 414 415 type testBackend struct { 416 db ethdb.Database 417 chain *core.BlockChain 418 } 419 420 func newTestBackend(t *testing.T, n int, gspec *core.Genesis, engine consensus.Engine, generator func(i int, b *core.BlockGen)) *testBackend { 421 var ( 422 cacheConfig = &core.CacheConfig{ 423 TrieCleanLimit: 256, 424 TrieDirtyLimit: 256, 425 SnapshotLimit: 0, 426 Pruning: false, // Archive mode 427 } 428 ) 429 // Generate blocks for testing 430 db, blocks, _, _ := core.GenerateChainWithGenesis(gspec, engine, n, 10, generator) 431 chain, err := core.NewBlockChain(db, cacheConfig, gspec, engine, vm.Config{}, gspec.ToBlock().Hash(), false) 432 if err != nil { 433 t.Fatalf("failed to create tester chain: %v", err) 434 } 435 if n, err := chain.InsertChain(blocks); err != nil { 436 t.Fatalf("block %d: failed to insert into chain: %v", n, err) 437 } 438 for _, block := range blocks { 439 if err := chain.Accept(block); err != nil { 440 t.Fatalf("block %d: failed to accept into chain: %v", block.NumberU64(), err) 441 } 442 } 443 chain.DrainAcceptorQueue() 444 445 backend := &testBackend{db: db, chain: chain} 446 return backend 447 } 448 449 func (b testBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { 450 return big.NewInt(0), nil 451 } 452 func (b testBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { 453 return nil, nil, nil, nil, nil 454 } 455 func (b testBackend) ChainDb() ethdb.Database { return b.db } 456 func (b testBackend) AccountManager() *accounts.Manager { return nil } 457 func (b testBackend) ExtRPCEnabled() bool { return false } 458 func (b testBackend) RPCGasCap() uint64 { return 10000000 } 459 func (b testBackend) RPCEVMTimeout() time.Duration { return time.Second } 460 func (b testBackend) RPCTxFeeCap() float64 { return 0 } 461 func (b testBackend) UnprotectedAllowed(*types.Transaction) bool { return false } 462 func (b testBackend) SetHead(number uint64) {} 463 func (b testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { 464 if number == rpc.LatestBlockNumber { 465 return b.chain.CurrentBlock(), nil 466 } 467 return b.chain.GetHeaderByNumber(uint64(number)), nil 468 } 469 func (b testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { 470 return b.chain.GetHeaderByHash(hash), nil 471 } 472 func (b testBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) { 473 if blockNr, ok := blockNrOrHash.Number(); ok { 474 return b.HeaderByNumber(ctx, blockNr) 475 } 476 if blockHash, ok := blockNrOrHash.Hash(); ok { 477 return b.HeaderByHash(ctx, blockHash) 478 } 479 panic("unknown type rpc.BlockNumberOrHash") 480 } 481 func (b testBackend) CurrentHeader() *types.Header { return b.chain.CurrentBlock() } 482 func (b testBackend) CurrentBlock() *types.Header { return b.chain.CurrentBlock() } 483 func (b testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { 484 if number == rpc.LatestBlockNumber { 485 head := b.chain.CurrentBlock() 486 return b.chain.GetBlock(head.Hash(), head.Number.Uint64()), nil 487 } 488 return b.chain.GetBlockByNumber(uint64(number)), nil 489 } 490 func (b testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { 491 return b.chain.GetBlockByHash(hash), nil 492 } 493 func (b testBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { 494 if blockNr, ok := blockNrOrHash.Number(); ok { 495 return b.BlockByNumber(ctx, blockNr) 496 } 497 if blockHash, ok := blockNrOrHash.Hash(); ok { 498 return b.BlockByHash(ctx, blockHash) 499 } 500 panic("unknown type rpc.BlockNumberOrHash") 501 } 502 func (b testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { 503 return b.chain.GetBlock(hash, uint64(number.Int64())).Body(), nil 504 } 505 func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { 506 if number == rpc.PendingBlockNumber { 507 panic("pending state not implemented") 508 } 509 header, err := b.HeaderByNumber(ctx, number) 510 if err != nil { 511 return nil, nil, err 512 } 513 if header == nil { 514 return nil, nil, errors.New("header not found") 515 } 516 stateDb, err := b.chain.StateAt(header.Root) 517 return stateDb, header, err 518 } 519 func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { 520 if blockNr, ok := blockNrOrHash.Number(); ok { 521 return b.StateAndHeaderByNumber(ctx, blockNr) 522 } 523 panic("only implemented for number") 524 } 525 func (b testBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { panic("implement me") } 526 func (b testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { 527 header, err := b.HeaderByHash(ctx, hash) 528 if header == nil || err != nil { 529 return nil, err 530 } 531 receipts := rawdb.ReadReceipts(b.db, hash, header.Number.Uint64(), header.Time, b.chain.Config()) 532 return receipts, nil 533 } 534 func (b testBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockContext *vm.BlockContext) (*vm.EVM, func() error) { 535 vmError := func() error { return nil } 536 if vmConfig == nil { 537 vmConfig = b.chain.GetVMConfig() 538 } 539 txContext := core.NewEVMTxContext(msg) 540 context := core.NewEVMBlockContext(header, b.chain, nil) 541 if blockContext != nil { 542 context = *blockContext 543 } 544 return vm.NewEVM(context, txContext, state, b.chain.Config(), *vmConfig), vmError 545 } 546 func (b testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { 547 panic("implement me") 548 } 549 func (b testBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { 550 panic("implement me") 551 } 552 func (b testBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription { 553 panic("implement me") 554 } 555 func (b testBackend) GetFeeConfigAt(parent *types.Header) (commontype.FeeConfig, *big.Int, error) { 556 panic("implement me") 557 } 558 func (b testBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { 559 panic("implement me") 560 } 561 func (b testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { 562 tx, blockHash, blockNumber, index := rawdb.ReadTransaction(b.db, txHash) 563 return tx, blockHash, blockNumber, index, nil 564 } 565 func (b testBackend) GetPoolTransactions() (types.Transactions, error) { panic("implement me") } 566 func (b testBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { panic("implement me") } 567 func (b testBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { 568 panic("implement me") 569 } 570 func (b testBackend) Stats() (pending int, queued int) { panic("implement me") } 571 func (b testBackend) TxPoolContent() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) { 572 panic("implement me") 573 } 574 func (b testBackend) TxPoolContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) { 575 panic("implement me") 576 } 577 func (b testBackend) SubscribeNewTxsEvent(events chan<- core.NewTxsEvent) event.Subscription { 578 panic("implement me") 579 } 580 func (b testBackend) ChainConfig() *params.ChainConfig { return b.chain.Config() } 581 func (b testBackend) Engine() consensus.Engine { return b.chain.Engine() } 582 func (b testBackend) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) { 583 panic("implement me") 584 } 585 func (b testBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { 586 panic("implement me") 587 } 588 func (b testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { 589 panic("implement me") 590 } 591 func (b testBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { 592 panic("implement me") 593 } 594 func (b testBackend) BloomStatus() (uint64, uint64) { panic("implement me") } 595 func (b testBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { 596 panic("implement me") 597 } 598 func (b testBackend) BadBlocks() ([]*types.Block, []*core.BadBlockReason) { return nil, nil } 599 func (b testBackend) EstimateBaseFee(ctx context.Context) (*big.Int, error) { 600 panic("implement me") 601 } 602 func (b testBackend) LastAcceptedBlock() *types.Block { panic("implement me") } 603 func (b testBackend) SuggestPrice(ctx context.Context) (*big.Int, error) { 604 panic("implement me") 605 } 606 607 func TestEstimateGas(t *testing.T) { 608 t.Parallel() 609 // Initialize test accounts 610 var ( 611 accounts = newAccounts(2) 612 genesis = &core.Genesis{ 613 Config: params.TestChainConfig, 614 Alloc: core.GenesisAlloc{ 615 accounts[0].addr: {Balance: big.NewInt(params.Ether)}, 616 accounts[1].addr: {Balance: big.NewInt(params.Ether)}, 617 }, 618 } 619 genBlocks = 10 620 signer = types.HomesteadSigner{} 621 randomAccounts = newAccounts(2) 622 ) 623 api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, dummy.NewCoinbaseFaker(), func(i int, b *core.BlockGen) { 624 // Transfer from account[0] to account[1] 625 // value: 1000 wei 626 // fee: 0 wei 627 tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &accounts[1].addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), signer, accounts[0].key) 628 b.AddTx(tx) 629 })) 630 var testSuite = []struct { 631 blockNumber rpc.BlockNumber 632 call TransactionArgs 633 overrides StateOverride 634 expectErr error 635 want uint64 636 }{ 637 // simple transfer on latest block 638 { 639 blockNumber: rpc.LatestBlockNumber, 640 call: TransactionArgs{ 641 From: &accounts[0].addr, 642 To: &accounts[1].addr, 643 Value: (*hexutil.Big)(big.NewInt(1000)), 644 }, 645 expectErr: nil, 646 want: 21000, 647 }, 648 // simple transfer with insufficient funds on latest block 649 { 650 blockNumber: rpc.LatestBlockNumber, 651 call: TransactionArgs{ 652 From: &randomAccounts[0].addr, 653 To: &accounts[1].addr, 654 Value: (*hexutil.Big)(big.NewInt(1000)), 655 }, 656 expectErr: core.ErrInsufficientFunds, 657 want: 21000, 658 }, 659 // empty create 660 { 661 blockNumber: rpc.LatestBlockNumber, 662 call: TransactionArgs{}, 663 expectErr: nil, 664 want: 53000, 665 }, 666 { 667 blockNumber: rpc.LatestBlockNumber, 668 call: TransactionArgs{}, 669 overrides: StateOverride{ 670 randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, 671 }, 672 expectErr: nil, 673 want: 53000, 674 }, 675 { 676 blockNumber: rpc.LatestBlockNumber, 677 call: TransactionArgs{ 678 From: &randomAccounts[0].addr, 679 To: &randomAccounts[1].addr, 680 Value: (*hexutil.Big)(big.NewInt(1000)), 681 }, 682 overrides: StateOverride{ 683 randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(0))}, 684 }, 685 expectErr: core.ErrInsufficientFunds, 686 }, 687 } 688 for i, tc := range testSuite { 689 result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides) 690 if tc.expectErr != nil { 691 if err == nil { 692 t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr) 693 continue 694 } 695 if !errors.Is(err, tc.expectErr) { 696 t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err) 697 } 698 continue 699 } 700 if err != nil { 701 t.Errorf("test %d: want no error, have %v", i, err) 702 continue 703 } 704 if uint64(result) != tc.want { 705 t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, uint64(result), tc.want) 706 } 707 } 708 } 709 710 func TestCall(t *testing.T) { 711 t.Parallel() 712 // Initialize test accounts 713 var ( 714 accounts = newAccounts(3) 715 genesis = &core.Genesis{ 716 Config: params.TestChainConfig, 717 Alloc: core.GenesisAlloc{ 718 accounts[0].addr: {Balance: big.NewInt(params.Ether)}, 719 accounts[1].addr: {Balance: big.NewInt(params.Ether)}, 720 accounts[2].addr: {Balance: big.NewInt(params.Ether)}, 721 }, 722 } 723 genBlocks = 10 724 signer = types.HomesteadSigner{} 725 ) 726 api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, dummy.NewCoinbaseFaker(), func(i int, b *core.BlockGen) { 727 // Transfer from account[0] to account[1] 728 // value: 1000 wei 729 // fee: 0 wei 730 tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &accounts[1].addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), signer, accounts[0].key) 731 b.AddTx(tx) 732 })) 733 randomAccounts := newAccounts(3) 734 var testSuite = []struct { 735 blockNumber rpc.BlockNumber 736 overrides StateOverride 737 call TransactionArgs 738 blockOverrides BlockOverrides 739 expectErr error 740 want string 741 }{ 742 // transfer on genesis 743 { 744 blockNumber: rpc.BlockNumber(0), 745 call: TransactionArgs{ 746 From: &accounts[0].addr, 747 To: &accounts[1].addr, 748 Value: (*hexutil.Big)(big.NewInt(1000)), 749 }, 750 expectErr: nil, 751 want: "0x", 752 }, 753 // transfer on the head 754 { 755 blockNumber: rpc.BlockNumber(genBlocks), 756 call: TransactionArgs{ 757 From: &accounts[0].addr, 758 To: &accounts[1].addr, 759 Value: (*hexutil.Big)(big.NewInt(1000)), 760 }, 761 expectErr: nil, 762 want: "0x", 763 }, 764 // transfer on a non-existent block, error expects 765 { 766 blockNumber: rpc.BlockNumber(genBlocks + 1), 767 call: TransactionArgs{ 768 From: &accounts[0].addr, 769 To: &accounts[1].addr, 770 Value: (*hexutil.Big)(big.NewInt(1000)), 771 }, 772 expectErr: errors.New("header not found"), 773 }, 774 // transfer on the latest block 775 { 776 blockNumber: rpc.LatestBlockNumber, 777 call: TransactionArgs{ 778 From: &accounts[0].addr, 779 To: &accounts[1].addr, 780 Value: (*hexutil.Big)(big.NewInt(1000)), 781 }, 782 expectErr: nil, 783 want: "0x", 784 }, 785 // Call which can only succeed if state is state overridden 786 { 787 blockNumber: rpc.LatestBlockNumber, 788 call: TransactionArgs{ 789 From: &randomAccounts[0].addr, 790 To: &randomAccounts[1].addr, 791 Value: (*hexutil.Big)(big.NewInt(1000)), 792 }, 793 overrides: StateOverride{ 794 randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, 795 }, 796 want: "0x", 797 }, 798 // Invalid call without state overriding 799 { 800 blockNumber: rpc.LatestBlockNumber, 801 call: TransactionArgs{ 802 From: &randomAccounts[0].addr, 803 To: &randomAccounts[1].addr, 804 Value: (*hexutil.Big)(big.NewInt(1000)), 805 }, 806 expectErr: core.ErrInsufficientFunds, 807 }, 808 // Successful simple contract call 809 // 810 // // SPDX-License-Identifier: GPL-3.0 811 // 812 // pragma solidity >=0.7.0 <0.8.0; 813 // 814 // /** 815 // * @title Storage 816 // * @dev Store & retrieve value in a variable 817 // */ 818 // contract Storage { 819 // uint256 public number; 820 // constructor() { 821 // number = block.number; 822 // } 823 // } 824 { 825 blockNumber: rpc.LatestBlockNumber, 826 call: TransactionArgs{ 827 From: &randomAccounts[0].addr, 828 To: &randomAccounts[2].addr, 829 Data: hex2Bytes("8381f58a"), // call number() 830 }, 831 overrides: StateOverride{ 832 randomAccounts[2].addr: OverrideAccount{ 833 Code: hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033"), 834 StateDiff: &map[common.Hash]common.Hash{{}: common.BigToHash(big.NewInt(123))}, 835 }, 836 }, 837 want: "0x000000000000000000000000000000000000000000000000000000000000007b", 838 }, 839 // Block overrides should work 840 { 841 blockNumber: rpc.LatestBlockNumber, 842 call: TransactionArgs{ 843 From: &accounts[1].addr, 844 Input: &hexutil.Bytes{ 845 0x43, // NUMBER 846 0x60, 0x00, 0x52, // MSTORE offset 0 847 0x60, 0x20, 0x60, 0x00, 0xf3, 848 }, 849 }, 850 blockOverrides: BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))}, 851 want: "0x000000000000000000000000000000000000000000000000000000000000000b", 852 }, 853 } 854 for i, tc := range testSuite { 855 result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides) 856 if tc.expectErr != nil { 857 if err == nil { 858 t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr) 859 continue 860 } 861 if !errors.Is(err, tc.expectErr) { 862 // Second try 863 if !reflect.DeepEqual(err, tc.expectErr) { 864 t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err) 865 } 866 } 867 continue 868 } 869 if err != nil { 870 t.Errorf("test %d: want no error, have %v", i, err) 871 continue 872 } 873 if !reflect.DeepEqual(result.String(), tc.want) { 874 t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, result.String(), tc.want) 875 } 876 } 877 } 878 879 type Account struct { 880 key *ecdsa.PrivateKey 881 addr common.Address 882 } 883 884 func newAccounts(n int) (accounts []Account) { 885 for i := 0; i < n; i++ { 886 key, _ := crypto.GenerateKey() 887 addr := crypto.PubkeyToAddress(key.PublicKey) 888 accounts = append(accounts, Account{key: key, addr: addr}) 889 } 890 slices.SortFunc(accounts, func(a, b Account) int { return a.addr.Cmp(b.addr) }) 891 return accounts 892 } 893 894 func newRPCBalance(balance *big.Int) **hexutil.Big { 895 rpcBalance := (*hexutil.Big)(balance) 896 return &rpcBalance 897 } 898 899 func hex2Bytes(str string) *hexutil.Bytes { 900 rpcBytes := hexutil.Bytes(common.Hex2Bytes(str)) 901 return &rpcBytes 902 } 903 904 func TestRPCMarshalBlock(t *testing.T) { 905 t.Parallel() 906 var ( 907 txs []*types.Transaction 908 to = common.BytesToAddress([]byte{0x11}) 909 ) 910 for i := uint64(1); i <= 4; i++ { 911 var tx *types.Transaction 912 if i%2 == 0 { 913 tx = types.NewTx(&types.LegacyTx{ 914 Nonce: i, 915 GasPrice: big.NewInt(11111), 916 Gas: 1111, 917 To: &to, 918 Value: big.NewInt(111), 919 Data: []byte{0x11, 0x11, 0x11}, 920 }) 921 } else { 922 tx = types.NewTx(&types.AccessListTx{ 923 ChainID: big.NewInt(1337), 924 Nonce: i, 925 GasPrice: big.NewInt(11111), 926 Gas: 1111, 927 To: &to, 928 Value: big.NewInt(111), 929 Data: []byte{0x11, 0x11, 0x11}, 930 }) 931 } 932 txs = append(txs, tx) 933 } 934 block := types.NewBlock(&types.Header{Number: big.NewInt(100)}, txs, nil, nil, blocktest.NewHasher()) 935 936 var testSuite = []struct { 937 inclTx bool 938 fullTx bool 939 want string 940 }{ 941 // without txs 942 { 943 inclTx: false, 944 fullTx: false, 945 want: `{ 946 "difficulty": "0x0", 947 "extraData": "0x", 948 "gasLimit": "0x0", 949 "gasUsed": "0x0", 950 "hash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee", 951 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 952 "miner": "0x0000000000000000000000000000000000000000", 953 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 954 "nonce": "0x0000000000000000", 955 "number": "0x64", 956 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 957 "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", 958 "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", 959 "size": "0x296", 960 "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", 961 "timestamp": "0x0", 962 "transactionsRoot": "0x661a9febcfa8f1890af549b874faf9fa274aede26ef489d9db0b25daa569450e", 963 "uncles": [] 964 }`, 965 }, 966 // only tx hashes 967 { 968 inclTx: true, 969 fullTx: false, 970 want: `{ 971 "difficulty": "0x0", 972 "extraData": "0x", 973 "gasLimit": "0x0", 974 "gasUsed": "0x0", 975 "hash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee", 976 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 977 "miner": "0x0000000000000000000000000000000000000000", 978 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 979 "nonce": "0x0000000000000000", 980 "number": "0x64", 981 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 982 "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", 983 "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", 984 "size": "0x296", 985 "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", 986 "timestamp": "0x0", 987 "transactions": [ 988 "0x7d39df979e34172322c64983a9ad48302c2b889e55bda35324afecf043a77605", 989 "0x9bba4c34e57c875ff57ac8d172805a26ae912006985395dc1bdf8f44140a7bf4", 990 "0x98909ea1ff040da6be56bc4231d484de1414b3c1dac372d69293a4beb9032cb5", 991 "0x12e1f81207b40c3bdcc13c0ee18f5f86af6d31754d57a0ea1b0d4cfef21abef1" 992 ], 993 "transactionsRoot": "0x661a9febcfa8f1890af549b874faf9fa274aede26ef489d9db0b25daa569450e", 994 "uncles": [] 995 }`, 996 }, 997 // full tx details 998 { 999 inclTx: true, 1000 fullTx: true, 1001 want: `{ 1002 "difficulty": "0x0", 1003 "extraData": "0x", 1004 "gasLimit": "0x0", 1005 "gasUsed": "0x0", 1006 "hash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee", 1007 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 1008 "miner": "0x0000000000000000000000000000000000000000", 1009 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 1010 "nonce": "0x0000000000000000", 1011 "number": "0x64", 1012 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 1013 "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", 1014 "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", 1015 "size": "0x296", 1016 "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", 1017 "timestamp": "0x0", 1018 "transactions": [ 1019 { 1020 "blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee", 1021 "blockNumber": "0x64", 1022 "from": "0x0000000000000000000000000000000000000000", 1023 "gas": "0x457", 1024 "gasPrice": "0x2b67", 1025 "hash": "0x7d39df979e34172322c64983a9ad48302c2b889e55bda35324afecf043a77605", 1026 "input": "0x111111", 1027 "nonce": "0x1", 1028 "to": "0x0000000000000000000000000000000000000011", 1029 "transactionIndex": "0x0", 1030 "value": "0x6f", 1031 "type": "0x1", 1032 "accessList": [], 1033 "chainId": "0x539", 1034 "v": "0x0", 1035 "r": "0x0", 1036 "s": "0x0", 1037 "yParity": "0x0" 1038 }, 1039 { 1040 "blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee", 1041 "blockNumber": "0x64", 1042 "from": "0x0000000000000000000000000000000000000000", 1043 "gas": "0x457", 1044 "gasPrice": "0x2b67", 1045 "hash": "0x9bba4c34e57c875ff57ac8d172805a26ae912006985395dc1bdf8f44140a7bf4", 1046 "input": "0x111111", 1047 "nonce": "0x2", 1048 "to": "0x0000000000000000000000000000000000000011", 1049 "transactionIndex": "0x1", 1050 "value": "0x6f", 1051 "type": "0x0", 1052 "chainId": "0x7fffffffffffffee", 1053 "v": "0x0", 1054 "r": "0x0", 1055 "s": "0x0" 1056 }, 1057 { 1058 "blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee", 1059 "blockNumber": "0x64", 1060 "from": "0x0000000000000000000000000000000000000000", 1061 "gas": "0x457", 1062 "gasPrice": "0x2b67", 1063 "hash": "0x98909ea1ff040da6be56bc4231d484de1414b3c1dac372d69293a4beb9032cb5", 1064 "input": "0x111111", 1065 "nonce": "0x3", 1066 "to": "0x0000000000000000000000000000000000000011", 1067 "transactionIndex": "0x2", 1068 "value": "0x6f", 1069 "type": "0x1", 1070 "accessList": [], 1071 "chainId": "0x539", 1072 "v": "0x0", 1073 "r": "0x0", 1074 "s": "0x0", 1075 "yParity": "0x0" 1076 }, 1077 { 1078 "blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee", 1079 "blockNumber": "0x64", 1080 "from": "0x0000000000000000000000000000000000000000", 1081 "gas": "0x457", 1082 "gasPrice": "0x2b67", 1083 "hash": "0x12e1f81207b40c3bdcc13c0ee18f5f86af6d31754d57a0ea1b0d4cfef21abef1", 1084 "input": "0x111111", 1085 "nonce": "0x4", 1086 "to": "0x0000000000000000000000000000000000000011", 1087 "transactionIndex": "0x3", 1088 "value": "0x6f", 1089 "type": "0x0", 1090 "chainId": "0x7fffffffffffffee", 1091 "v": "0x0", 1092 "r": "0x0", 1093 "s": "0x0" 1094 } 1095 ], 1096 "transactionsRoot": "0x661a9febcfa8f1890af549b874faf9fa274aede26ef489d9db0b25daa569450e", 1097 "uncles": [] 1098 }`, 1099 }, 1100 } 1101 1102 for i, tc := range testSuite { 1103 resp := RPCMarshalBlock(block, tc.inclTx, tc.fullTx, params.TestSubnetEVMConfig) 1104 out, err := json.Marshal(resp) 1105 if err != nil { 1106 t.Errorf("test %d: json marshal error: %v", i, err) 1107 continue 1108 } 1109 require.JSONEqf(t, tc.want, string(out), "test %d", i) 1110 } 1111 } 1112 1113 func TestRPCGetBlockOrHeader(t *testing.T) { 1114 t.Parallel() 1115 1116 // Initialize test accounts 1117 var ( 1118 acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 1119 acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") 1120 acc1Addr = crypto.PubkeyToAddress(acc1Key.PublicKey) 1121 acc2Addr = crypto.PubkeyToAddress(acc2Key.PublicKey) 1122 genesis = &core.Genesis{ 1123 Config: params.TestSubnetEVMConfig, 1124 Alloc: core.GenesisAlloc{ 1125 acc1Addr: {Balance: big.NewInt(params.Ether)}, 1126 acc2Addr: {Balance: big.NewInt(params.Ether)}, 1127 }, 1128 } 1129 genBlocks = 10 1130 signer = types.HomesteadSigner{} 1131 tx = types.NewTx(&types.LegacyTx{ 1132 Nonce: 11, 1133 GasPrice: big.NewInt(11111), 1134 Gas: 1111, 1135 To: &acc2Addr, 1136 Value: big.NewInt(111), 1137 Data: []byte{0x11, 0x11, 0x11}, 1138 }) 1139 pending = types.NewBlock(&types.Header{Number: big.NewInt(11), Time: 42}, []*types.Transaction{tx}, nil, nil, blocktest.NewHasher()) 1140 ) 1141 backend := newTestBackend(t, genBlocks, genesis, dummy.NewCoinbaseFaker(), func(i int, b *core.BlockGen) { 1142 // Transfer from account[0] to account[1] 1143 // value: 1000 wei 1144 // fee: 0 wei 1145 tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &acc2Addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), signer, acc1Key) 1146 b.AddTx(tx) 1147 }) 1148 api := NewBlockChainAPI(backend) 1149 blockHashes := make([]common.Hash, genBlocks+1) 1150 ctx := context.Background() 1151 for i := 0; i <= genBlocks; i++ { 1152 header, err := backend.HeaderByNumber(ctx, rpc.BlockNumber(i)) 1153 if err != nil { 1154 t.Errorf("failed to get block: %d err: %v", i, err) 1155 } 1156 blockHashes[i] = header.Hash() 1157 } 1158 pendingHash := pending.Hash() 1159 1160 var testSuite = []struct { 1161 blockNumber rpc.BlockNumber 1162 blockHash *common.Hash 1163 fullTx bool 1164 reqHeader bool 1165 file string 1166 expectErr error 1167 }{ 1168 // 0. latest header 1169 { 1170 blockNumber: rpc.LatestBlockNumber, 1171 reqHeader: true, 1172 file: "tag-latest", 1173 }, 1174 // 1. genesis header 1175 { 1176 blockNumber: rpc.BlockNumber(0), 1177 reqHeader: true, 1178 file: "number-0", 1179 }, 1180 // 2. #1 header 1181 { 1182 blockNumber: rpc.BlockNumber(1), 1183 reqHeader: true, 1184 file: "number-1", 1185 }, 1186 // 3. latest-1 header 1187 { 1188 blockNumber: rpc.BlockNumber(9), 1189 reqHeader: true, 1190 file: "number-latest-1", 1191 }, 1192 // 4. latest+1 header 1193 { 1194 blockNumber: rpc.BlockNumber(11), 1195 reqHeader: true, 1196 file: "number-latest+1", 1197 }, 1198 // 5. pending header 1199 { 1200 blockNumber: rpc.PendingBlockNumber, 1201 reqHeader: true, 1202 file: "tag-pending", 1203 }, 1204 // 6. latest block 1205 { 1206 blockNumber: rpc.LatestBlockNumber, 1207 file: "tag-latest", 1208 }, 1209 // 7. genesis block 1210 { 1211 blockNumber: rpc.BlockNumber(0), 1212 file: "number-0", 1213 }, 1214 // 8. #1 block 1215 { 1216 blockNumber: rpc.BlockNumber(1), 1217 file: "number-1", 1218 }, 1219 // 9. latest-1 block 1220 { 1221 blockNumber: rpc.BlockNumber(9), 1222 fullTx: true, 1223 file: "number-latest-1", 1224 }, 1225 // 10. latest+1 block 1226 { 1227 blockNumber: rpc.BlockNumber(11), 1228 fullTx: true, 1229 file: "number-latest+1", 1230 }, 1231 // 11. pending block 1232 { 1233 blockNumber: rpc.PendingBlockNumber, 1234 file: "tag-pending", 1235 }, 1236 // 12. pending block + fullTx 1237 { 1238 blockNumber: rpc.PendingBlockNumber, 1239 fullTx: true, 1240 file: "tag-pending-fullTx", 1241 }, 1242 // 13. latest header by hash 1243 { 1244 blockHash: &blockHashes[len(blockHashes)-1], 1245 reqHeader: true, 1246 file: "hash-latest", 1247 }, 1248 // 14. genesis header by hash 1249 { 1250 blockHash: &blockHashes[0], 1251 reqHeader: true, 1252 file: "hash-0", 1253 }, 1254 // 15. #1 header 1255 { 1256 blockHash: &blockHashes[1], 1257 reqHeader: true, 1258 file: "hash-1", 1259 }, 1260 // 16. latest-1 header 1261 { 1262 blockHash: &blockHashes[len(blockHashes)-2], 1263 reqHeader: true, 1264 file: "hash-latest-1", 1265 }, 1266 // 17. empty hash 1267 { 1268 blockHash: &common.Hash{}, 1269 reqHeader: true, 1270 file: "hash-empty", 1271 }, 1272 // 18. pending hash 1273 { 1274 blockHash: &pendingHash, 1275 reqHeader: true, 1276 file: `hash-pending`, 1277 }, 1278 // 19. latest block 1279 { 1280 blockHash: &blockHashes[len(blockHashes)-1], 1281 file: "hash-latest", 1282 }, 1283 // 20. genesis block 1284 { 1285 blockHash: &blockHashes[0], 1286 file: "hash-genesis", 1287 }, 1288 // 21. #1 block 1289 { 1290 blockHash: &blockHashes[1], 1291 file: "hash-1", 1292 }, 1293 // 22. latest-1 block 1294 { 1295 blockHash: &blockHashes[len(blockHashes)-2], 1296 fullTx: true, 1297 file: "hash-latest-1-fullTx", 1298 }, 1299 // 23. empty hash + body 1300 { 1301 blockHash: &common.Hash{}, 1302 fullTx: true, 1303 file: "hash-empty-fullTx", 1304 }, 1305 // 24. pending block 1306 { 1307 blockHash: &pendingHash, 1308 file: `hash-pending`, 1309 }, 1310 // 25. pending block + fullTx 1311 { 1312 blockHash: &pendingHash, 1313 fullTx: true, 1314 file: "hash-pending-fullTx", 1315 }, 1316 } 1317 1318 for i, tt := range testSuite { 1319 var ( 1320 result map[string]interface{} 1321 err error 1322 rpc string 1323 ) 1324 if tt.blockHash != nil { 1325 if tt.reqHeader { 1326 result = api.GetHeaderByHash(context.Background(), *tt.blockHash) 1327 rpc = "eth_getHeaderByHash" 1328 } else { 1329 result, err = api.GetBlockByHash(context.Background(), *tt.blockHash, tt.fullTx) 1330 rpc = "eth_getBlockByHash" 1331 } 1332 } else { 1333 if tt.reqHeader { 1334 result, err = api.GetHeaderByNumber(context.Background(), tt.blockNumber) 1335 rpc = "eth_getHeaderByNumber" 1336 } else { 1337 result, err = api.GetBlockByNumber(context.Background(), tt.blockNumber, tt.fullTx) 1338 rpc = "eth_getBlockByNumber" 1339 } 1340 } 1341 if tt.expectErr != nil { 1342 if err == nil { 1343 t.Errorf("test %d: want error %v, have nothing", i, tt.expectErr) 1344 continue 1345 } 1346 if !errors.Is(err, tt.expectErr) { 1347 t.Errorf("test %d: error mismatch, want %v, have %v", i, tt.expectErr, err) 1348 } 1349 continue 1350 } 1351 if err != nil { 1352 t.Errorf("test %d: want no error, have %v", i, err) 1353 continue 1354 } 1355 1356 testRPCResponseWithFile(t, i, result, rpc, tt.file) 1357 } 1358 } 1359 1360 func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Hash) { 1361 config := *params.TestChainConfig 1362 var ( 1363 acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 1364 acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") 1365 acc1Addr = crypto.PubkeyToAddress(acc1Key.PublicKey) 1366 acc2Addr = crypto.PubkeyToAddress(acc2Key.PublicKey) 1367 contract = common.HexToAddress("0000000000000000000000000000000000031ec7") 1368 genesis = &core.Genesis{ 1369 Config: &config, 1370 ExcessBlobGas: new(uint64), 1371 BlobGasUsed: new(uint64), 1372 Timestamp: uint64(params.DefaultGenesisTime.Unix()), 1373 Alloc: core.GenesisAlloc{ 1374 acc1Addr: {Balance: big.NewInt(params.Ether)}, 1375 acc2Addr: {Balance: big.NewInt(params.Ether)}, 1376 // // SPDX-License-Identifier: GPL-3.0 1377 // pragma solidity >=0.7.0 <0.9.0; 1378 // 1379 // contract Token { 1380 // event Transfer(address indexed from, address indexed to, uint256 value); 1381 // function transfer(address to, uint256 value) public returns (bool) { 1382 // emit Transfer(msg.sender, to, value); 1383 // return true; 1384 // } 1385 // } 1386 contract: {Balance: big.NewInt(params.Ether), Code: common.FromHex("0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063a9059cbb14610030575b600080fd5b61004a6004803603810190610045919061016a565b610060565b60405161005791906101c5565b60405180910390f35b60008273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516100bf91906101ef565b60405180910390a36001905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610101826100d6565b9050919050565b610111816100f6565b811461011c57600080fd5b50565b60008135905061012e81610108565b92915050565b6000819050919050565b61014781610134565b811461015257600080fd5b50565b6000813590506101648161013e565b92915050565b60008060408385031215610181576101806100d1565b5b600061018f8582860161011f565b92505060206101a085828601610155565b9150509250929050565b60008115159050919050565b6101bf816101aa565b82525050565b60006020820190506101da60008301846101b6565b92915050565b6101e981610134565b82525050565b600060208201905061020460008301846101e0565b9291505056fea2646970667358221220b469033f4b77b9565ee84e0a2f04d496b18160d26034d54f9487e57788fd36d564736f6c63430008120033")}, 1387 }, 1388 } 1389 signer = types.LatestSignerForChainID(params.TestChainConfig.ChainID) 1390 txHashes = make([]common.Hash, genBlocks) 1391 ) 1392 1393 // Set the terminal total difficulty in the config 1394 // genesis.Config.TerminalTotalDifficulty = big.NewInt(0) 1395 // genesis.Config.TerminalTotalDifficultyPassed = true 1396 backend := newTestBackend(t, genBlocks, genesis, dummy.NewCoinbaseFaker(), func(i int, b *core.BlockGen) { 1397 var ( 1398 tx *types.Transaction 1399 err error 1400 ) 1401 switch i { 1402 case 0: 1403 // transfer 1000wei 1404 tx, err = types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &acc2Addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), types.HomesteadSigner{}, acc1Key) 1405 case 1: 1406 // create contract 1407 tx, err = types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: nil, Gas: 53100, GasPrice: b.BaseFee(), Data: common.FromHex("0x60806040")}), signer, acc1Key) 1408 case 2: 1409 // with logs 1410 // transfer(address to, uint256 value) 1411 data := fmt.Sprintf("0xa9059cbb%s%s", common.HexToHash(common.BigToAddress(big.NewInt(int64(i + 1))).Hex()).String()[2:], common.BytesToHash([]byte{byte(i + 11)}).String()[2:]) 1412 tx, err = types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &contract, Gas: 60000, GasPrice: b.BaseFee(), Data: common.FromHex(data)}), signer, acc1Key) 1413 case 3: 1414 // dynamic fee with logs 1415 // transfer(address to, uint256 value) 1416 data := fmt.Sprintf("0xa9059cbb%s%s", common.HexToHash(common.BigToAddress(big.NewInt(int64(i + 1))).Hex()).String()[2:], common.BytesToHash([]byte{byte(i + 11)}).String()[2:]) 1417 fee := big.NewInt(500) 1418 fee.Add(fee, b.BaseFee()) 1419 tx, err = types.SignTx(types.NewTx(&types.DynamicFeeTx{Nonce: uint64(i), To: &contract, Gas: 60000, Value: big.NewInt(1), GasTipCap: big.NewInt(500), GasFeeCap: fee, Data: common.FromHex(data)}), signer, acc1Key) 1420 case 4: 1421 // access list with contract create 1422 accessList := types.AccessList{{ 1423 Address: contract, 1424 StorageKeys: []common.Hash{{0}}, 1425 }} 1426 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) 1427 case 5: 1428 // blob tx 1429 fee := big.NewInt(500) 1430 fee.Add(fee, b.BaseFee()) 1431 tx, err = types.SignTx(types.NewTx(&types.BlobTx{ 1432 Nonce: uint64(i), 1433 GasTipCap: uint256.NewInt(1), 1434 GasFeeCap: uint256.MustFromBig(fee), 1435 Gas: params.TxGas, 1436 To: acc2Addr, 1437 BlobFeeCap: uint256.NewInt(1), 1438 BlobHashes: []common.Hash{{1}}, 1439 Value: new(uint256.Int), 1440 }), signer, acc1Key) 1441 } 1442 if err != nil { 1443 t.Errorf("failed to sign tx: %v", err) 1444 } 1445 if tx != nil { 1446 b.AddTx(tx) 1447 txHashes[i] = tx.Hash() 1448 } 1449 if i == 5 { 1450 b.SetBlobGas(params.BlobTxBlobGasPerBlob) 1451 } 1452 // b.SetPoS() 1453 }) 1454 return backend, txHashes 1455 } 1456 1457 func TestRPCGetTransactionReceipt(t *testing.T) { 1458 t.Parallel() 1459 1460 var ( 1461 backend, txHashes = setupReceiptBackend(t, 6) 1462 api = NewTransactionAPI(backend, new(AddrLocker)) 1463 ) 1464 1465 var testSuite = []struct { 1466 txHash common.Hash 1467 file string 1468 }{ 1469 // 0. normal success 1470 { 1471 txHash: txHashes[0], 1472 file: "normal-transfer-tx", 1473 }, 1474 // 1. create contract 1475 { 1476 txHash: txHashes[1], 1477 file: "create-contract-tx", 1478 }, 1479 // 2. with logs success 1480 { 1481 txHash: txHashes[2], 1482 file: "with-logs", 1483 }, 1484 // 3. dynamic tx with logs success 1485 { 1486 txHash: txHashes[3], 1487 file: `dynamic-tx-with-logs`, 1488 }, 1489 // 4. access list tx with create contract 1490 { 1491 txHash: txHashes[4], 1492 file: "create-contract-with-access-list", 1493 }, 1494 // 5. txhash empty 1495 { 1496 txHash: common.Hash{}, 1497 file: "txhash-empty", 1498 }, 1499 // 6. txhash not found 1500 { 1501 txHash: common.HexToHash("deadbeef"), 1502 file: "txhash-notfound", 1503 }, 1504 // 7. blob tx 1505 { 1506 txHash: txHashes[5], 1507 file: "blob-tx", 1508 }, 1509 } 1510 1511 for i, tt := range testSuite { 1512 var ( 1513 result interface{} 1514 err error 1515 ) 1516 result, err = api.GetTransactionReceipt(context.Background(), tt.txHash) 1517 if err != nil { 1518 t.Errorf("test %d: want no error, have %v", i, err) 1519 continue 1520 } 1521 testRPCResponseWithFile(t, i, result, "eth_getTransactionReceipt", tt.file) 1522 } 1523 } 1524 1525 func TestRPCGetBlockReceipts(t *testing.T) { 1526 t.Parallel() 1527 1528 var ( 1529 genBlocks = 6 1530 backend, _ = setupReceiptBackend(t, genBlocks) 1531 api = NewBlockChainAPI(backend) 1532 ) 1533 blockHashes := make([]common.Hash, genBlocks+1) 1534 ctx := context.Background() 1535 for i := 0; i <= genBlocks; i++ { 1536 header, err := backend.HeaderByNumber(ctx, rpc.BlockNumber(i)) 1537 if err != nil { 1538 t.Errorf("failed to get block: %d err: %v", i, err) 1539 } 1540 blockHashes[i] = header.Hash() 1541 } 1542 1543 var testSuite = []struct { 1544 test rpc.BlockNumberOrHash 1545 file string 1546 }{ 1547 // 0. block without any txs(hash) 1548 { 1549 test: rpc.BlockNumberOrHashWithHash(blockHashes[0], false), 1550 file: "number-0", 1551 }, 1552 // 1. block without any txs(number) 1553 { 1554 test: rpc.BlockNumberOrHashWithNumber(0), 1555 file: "number-1", 1556 }, 1557 // 2. earliest tag 1558 { 1559 test: rpc.BlockNumberOrHashWithNumber(rpc.EarliestBlockNumber), 1560 file: "tag-earliest", 1561 }, 1562 // 3. latest tag 1563 { 1564 test: rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber), 1565 file: "tag-latest", 1566 }, 1567 // 4. block with legacy transfer tx(hash) 1568 { 1569 test: rpc.BlockNumberOrHashWithHash(blockHashes[1], false), 1570 file: "block-with-legacy-transfer-tx", 1571 }, 1572 // 5. block with contract create tx(number) 1573 { 1574 test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(2)), 1575 file: "block-with-contract-create-tx", 1576 }, 1577 // 6. block with legacy contract call tx(hash) 1578 { 1579 test: rpc.BlockNumberOrHashWithHash(blockHashes[3], false), 1580 file: "block-with-legacy-contract-call-tx", 1581 }, 1582 // 7. block with dynamic fee tx(number) 1583 { 1584 test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(4)), 1585 file: "block-with-dynamic-fee-tx", 1586 }, 1587 // 8. block is empty 1588 { 1589 test: rpc.BlockNumberOrHashWithHash(common.Hash{}, false), 1590 file: "hash-empty", 1591 }, 1592 // 9. block is not found 1593 { 1594 test: rpc.BlockNumberOrHashWithHash(common.HexToHash("deadbeef"), false), 1595 file: "hash-notfound", 1596 }, 1597 // 10. block is not found 1598 { 1599 test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(genBlocks + 1)), 1600 file: "block-notfound", 1601 }, 1602 // 11. block with blob tx 1603 { 1604 test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(6)), 1605 file: "block-with-blob-tx", 1606 }, 1607 } 1608 1609 for i, tt := range testSuite { 1610 var ( 1611 result interface{} 1612 err error 1613 ) 1614 result, err = api.GetBlockReceipts(context.Background(), tt.test) 1615 if err != nil { 1616 t.Errorf("test %d: want no error, have %v", i, err) 1617 continue 1618 } 1619 testRPCResponseWithFile(t, i, result, "eth_getBlockReceipts", tt.file) 1620 } 1621 } 1622 1623 func testRPCResponseWithFile(t *testing.T, testid int, result interface{}, rpc string, file string) { 1624 data, err := json.MarshalIndent(result, "", " ") 1625 if err != nil { 1626 t.Errorf("test %d: json marshal error", testid) 1627 return 1628 } 1629 outputFile := filepath.Join("testdata", fmt.Sprintf("%s-%s.json", rpc, file)) 1630 if os.Getenv("WRITE_TEST_FILES") != "" { 1631 os.WriteFile(outputFile, data, 0644) 1632 } 1633 want, err := os.ReadFile(outputFile) 1634 if err != nil { 1635 t.Fatalf("error reading expected test file: %s output: %v", outputFile, err) 1636 } 1637 require.JSONEqf(t, string(want), string(data), "test %d: json not match, want: %s, have: %s", testid, string(want), string(data)) 1638 }