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