github.com/ethereum/go-ethereum@v1.16.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 "bytes" 21 "context" 22 "crypto/ecdsa" 23 "crypto/sha256" 24 "encoding/json" 25 "errors" 26 "fmt" 27 "math" 28 "math/big" 29 "os" 30 "path/filepath" 31 "reflect" 32 "slices" 33 "strings" 34 "testing" 35 "time" 36 37 "github.com/ethereum/go-ethereum/accounts/abi" 38 "github.com/ethereum/go-ethereum/internal/ethapi/override" 39 40 "github.com/ethereum/go-ethereum" 41 "github.com/ethereum/go-ethereum/accounts" 42 "github.com/ethereum/go-ethereum/accounts/keystore" 43 "github.com/ethereum/go-ethereum/common" 44 "github.com/ethereum/go-ethereum/common/hexutil" 45 "github.com/ethereum/go-ethereum/consensus" 46 "github.com/ethereum/go-ethereum/consensus/beacon" 47 "github.com/ethereum/go-ethereum/consensus/ethash" 48 "github.com/ethereum/go-ethereum/core" 49 "github.com/ethereum/go-ethereum/core/filtermaps" 50 "github.com/ethereum/go-ethereum/core/rawdb" 51 "github.com/ethereum/go-ethereum/core/state" 52 "github.com/ethereum/go-ethereum/core/types" 53 "github.com/ethereum/go-ethereum/core/vm" 54 "github.com/ethereum/go-ethereum/crypto" 55 "github.com/ethereum/go-ethereum/crypto/kzg4844" 56 "github.com/ethereum/go-ethereum/ethdb" 57 "github.com/ethereum/go-ethereum/event" 58 "github.com/ethereum/go-ethereum/internal/blocktest" 59 "github.com/ethereum/go-ethereum/params" 60 "github.com/ethereum/go-ethereum/rpc" 61 "github.com/holiman/uint256" 62 "github.com/stretchr/testify/require" 63 ) 64 65 func testTransactionMarshal(t *testing.T, tests []txData, config *params.ChainConfig) { 66 var ( 67 signer = types.LatestSigner(config) 68 key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 69 ) 70 71 for i, tt := range tests { 72 var tx2 types.Transaction 73 tx, err := types.SignNewTx(key, signer, tt.Tx) 74 if err != nil { 75 t.Fatalf("test %d: signing failed: %v", i, err) 76 } 77 // Regular transaction 78 if data, err := json.Marshal(tx); err != nil { 79 t.Fatalf("test %d: marshalling failed; %v", i, err) 80 } else if err = tx2.UnmarshalJSON(data); err != nil { 81 t.Fatalf("test %d: sunmarshal failed: %v", i, err) 82 } else if want, have := tx.Hash(), tx2.Hash(); want != have { 83 t.Fatalf("test %d: stx changed, want %x have %x", i, want, have) 84 } 85 86 // rpcTransaction 87 rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, 0, nil, config) 88 if data, err := json.Marshal(rpcTx); err != nil { 89 t.Fatalf("test %d: marshalling failed; %v", i, err) 90 } else if err = tx2.UnmarshalJSON(data); err != nil { 91 t.Fatalf("test %d: unmarshal failed: %v", i, err) 92 } else if want, have := tx.Hash(), tx2.Hash(); want != have { 93 t.Fatalf("test %d: tx changed, want %x have %x", i, want, have) 94 } else { 95 want, have := tt.Want, string(data) 96 require.JSONEqf(t, want, have, "test %d: rpc json not match, want %s have %s", i, want, have) 97 } 98 } 99 } 100 101 func TestTransaction_RoundTripRpcJSON(t *testing.T) { 102 t.Parallel() 103 104 var ( 105 config = params.AllEthashProtocolChanges 106 tests = allTransactionTypes(common.Address{0xde, 0xad}, config) 107 ) 108 testTransactionMarshal(t, tests, config) 109 } 110 111 func TestTransactionBlobTx(t *testing.T) { 112 t.Parallel() 113 114 config := *params.TestChainConfig 115 config.ShanghaiTime = new(uint64) 116 config.CancunTime = new(uint64) 117 tests := allBlobTxs(common.Address{0xde, 0xad}, &config) 118 119 testTransactionMarshal(t, tests, &config) 120 } 121 122 type txData struct { 123 Tx types.TxData 124 Want string 125 } 126 127 func allTransactionTypes(addr common.Address, config *params.ChainConfig) []txData { 128 return []txData{ 129 { 130 Tx: &types.LegacyTx{ 131 Nonce: 5, 132 GasPrice: big.NewInt(6), 133 Gas: 7, 134 To: &addr, 135 Value: big.NewInt(8), 136 Data: []byte{0, 1, 2, 3, 4}, 137 V: big.NewInt(9), 138 R: big.NewInt(10), 139 S: big.NewInt(11), 140 }, 141 Want: `{ 142 "blockHash": null, 143 "blockNumber": null, 144 "from": "0x71562b71999873db5b286df957af199ec94617f7", 145 "gas": "0x7", 146 "gasPrice": "0x6", 147 "hash": "0x5f3240454cd09a5d8b1c5d651eefae7a339262875bcd2d0e6676f3d989967008", 148 "input": "0x0001020304", 149 "nonce": "0x5", 150 "to": "0xdead000000000000000000000000000000000000", 151 "transactionIndex": null, 152 "value": "0x8", 153 "type": "0x0", 154 "chainId": "0x539", 155 "v": "0xa96", 156 "r": "0xbc85e96592b95f7160825d837abb407f009df9ebe8f1b9158a4b8dd093377f75", 157 "s": "0x1b55ea3af5574c536967b039ba6999ef6c89cf22fc04bcb296e0e8b0b9b576f5" 158 }`, 159 }, { 160 Tx: &types.LegacyTx{ 161 Nonce: 5, 162 GasPrice: big.NewInt(6), 163 Gas: 7, 164 To: nil, 165 Value: big.NewInt(8), 166 Data: []byte{0, 1, 2, 3, 4}, 167 V: big.NewInt(32), 168 R: big.NewInt(10), 169 S: big.NewInt(11), 170 }, 171 Want: `{ 172 "blockHash": null, 173 "blockNumber": null, 174 "from": "0x71562b71999873db5b286df957af199ec94617f7", 175 "gas": "0x7", 176 "gasPrice": "0x6", 177 "hash": "0x806e97f9d712b6cb7e781122001380a2837531b0fc1e5f5d78174ad4cb699873", 178 "input": "0x0001020304", 179 "nonce": "0x5", 180 "to": null, 181 "transactionIndex": null, 182 "value": "0x8", 183 "type": "0x0", 184 "chainId": "0x539", 185 "v": "0xa96", 186 "r": "0x9dc28b267b6ad4e4af6fe9289668f9305c2eb7a3241567860699e478af06835a", 187 "s": "0xa0b51a071aa9bed2cd70aedea859779dff039e3630ea38497d95202e9b1fec7" 188 }`, 189 }, 190 { 191 Tx: &types.AccessListTx{ 192 ChainID: config.ChainID, 193 Nonce: 5, 194 GasPrice: big.NewInt(6), 195 Gas: 7, 196 To: &addr, 197 Value: big.NewInt(8), 198 Data: []byte{0, 1, 2, 3, 4}, 199 AccessList: types.AccessList{ 200 types.AccessTuple{ 201 Address: common.Address{0x2}, 202 StorageKeys: []common.Hash{types.EmptyRootHash}, 203 }, 204 }, 205 V: big.NewInt(32), 206 R: big.NewInt(10), 207 S: big.NewInt(11), 208 }, 209 Want: `{ 210 "blockHash": null, 211 "blockNumber": null, 212 "from": "0x71562b71999873db5b286df957af199ec94617f7", 213 "gas": "0x7", 214 "gasPrice": "0x6", 215 "hash": "0x121347468ee5fe0a29f02b49b4ffd1c8342bc4255146bb686cd07117f79e7129", 216 "input": "0x0001020304", 217 "nonce": "0x5", 218 "to": "0xdead000000000000000000000000000000000000", 219 "transactionIndex": null, 220 "value": "0x8", 221 "type": "0x1", 222 "accessList": [ 223 { 224 "address": "0x0200000000000000000000000000000000000000", 225 "storageKeys": [ 226 "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" 227 ] 228 } 229 ], 230 "chainId": "0x539", 231 "v": "0x0", 232 "r": "0xf372ad499239ae11d91d34c559ffc5dab4daffc0069e03afcabdcdf231a0c16b", 233 "s": "0x28573161d1f9472fa0fd4752533609e72f06414f7ab5588699a7141f65d2abf", 234 "yParity": "0x0" 235 }`, 236 }, { 237 Tx: &types.AccessListTx{ 238 ChainID: config.ChainID, 239 Nonce: 5, 240 GasPrice: big.NewInt(6), 241 Gas: 7, 242 To: nil, 243 Value: big.NewInt(8), 244 Data: []byte{0, 1, 2, 3, 4}, 245 AccessList: types.AccessList{ 246 types.AccessTuple{ 247 Address: common.Address{0x2}, 248 StorageKeys: []common.Hash{types.EmptyRootHash}, 249 }, 250 }, 251 V: big.NewInt(32), 252 R: big.NewInt(10), 253 S: big.NewInt(11), 254 }, 255 Want: `{ 256 "blockHash": null, 257 "blockNumber": null, 258 "from": "0x71562b71999873db5b286df957af199ec94617f7", 259 "gas": "0x7", 260 "gasPrice": "0x6", 261 "hash": "0x067c3baebede8027b0f828a9d933be545f7caaec623b00684ac0659726e2055b", 262 "input": "0x0001020304", 263 "nonce": "0x5", 264 "to": null, 265 "transactionIndex": null, 266 "value": "0x8", 267 "type": "0x1", 268 "accessList": [ 269 { 270 "address": "0x0200000000000000000000000000000000000000", 271 "storageKeys": [ 272 "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" 273 ] 274 } 275 ], 276 "chainId": "0x539", 277 "v": "0x1", 278 "r": "0x542981b5130d4613897fbab144796cb36d3cb3d7807d47d9c7f89ca7745b085c", 279 "s": "0x7425b9dd6c5deaa42e4ede35d0c4570c4624f68c28d812c10d806ffdf86ce63", 280 "yParity": "0x1" 281 }`, 282 }, { 283 Tx: &types.DynamicFeeTx{ 284 ChainID: config.ChainID, 285 Nonce: 5, 286 GasTipCap: big.NewInt(6), 287 GasFeeCap: big.NewInt(9), 288 Gas: 7, 289 To: &addr, 290 Value: big.NewInt(8), 291 Data: []byte{0, 1, 2, 3, 4}, 292 AccessList: types.AccessList{ 293 types.AccessTuple{ 294 Address: common.Address{0x2}, 295 StorageKeys: []common.Hash{types.EmptyRootHash}, 296 }, 297 }, 298 V: big.NewInt(32), 299 R: big.NewInt(10), 300 S: big.NewInt(11), 301 }, 302 Want: `{ 303 "blockHash": null, 304 "blockNumber": null, 305 "from": "0x71562b71999873db5b286df957af199ec94617f7", 306 "gas": "0x7", 307 "gasPrice": "0x9", 308 "maxFeePerGas": "0x9", 309 "maxPriorityFeePerGas": "0x6", 310 "hash": "0xb63e0b146b34c3e9cb7fbabb5b3c081254a7ded6f1b65324b5898cc0545d79ff", 311 "input": "0x0001020304", 312 "nonce": "0x5", 313 "to": "0xdead000000000000000000000000000000000000", 314 "transactionIndex": null, 315 "value": "0x8", 316 "type": "0x2", 317 "accessList": [ 318 { 319 "address": "0x0200000000000000000000000000000000000000", 320 "storageKeys": [ 321 "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" 322 ] 323 } 324 ], 325 "chainId": "0x539", 326 "v": "0x1", 327 "r": "0x3b167e05418a8932cd53d7578711fe1a76b9b96c48642402bb94978b7a107e80", 328 "s": "0x22f98a332d15ea2cc80386c1ebaa31b0afebfa79ebc7d039a1e0074418301fef", 329 "yParity": "0x1" 330 }`, 331 }, { 332 Tx: &types.DynamicFeeTx{ 333 ChainID: config.ChainID, 334 Nonce: 5, 335 GasTipCap: big.NewInt(6), 336 GasFeeCap: big.NewInt(9), 337 Gas: 7, 338 To: nil, 339 Value: big.NewInt(8), 340 Data: []byte{0, 1, 2, 3, 4}, 341 AccessList: types.AccessList{}, 342 V: big.NewInt(32), 343 R: big.NewInt(10), 344 S: big.NewInt(11), 345 }, 346 Want: `{ 347 "blockHash": null, 348 "blockNumber": null, 349 "from": "0x71562b71999873db5b286df957af199ec94617f7", 350 "gas": "0x7", 351 "gasPrice": "0x9", 352 "maxFeePerGas": "0x9", 353 "maxPriorityFeePerGas": "0x6", 354 "hash": "0xcbab17ee031a9d5b5a09dff909f0a28aedb9b295ac0635d8710d11c7b806ec68", 355 "input": "0x0001020304", 356 "nonce": "0x5", 357 "to": null, 358 "transactionIndex": null, 359 "value": "0x8", 360 "type": "0x2", 361 "accessList": [], 362 "chainId": "0x539", 363 "v": "0x0", 364 "r": "0x6446b8a682db7e619fc6b4f6d1f708f6a17351a41c7fbd63665f469bc78b41b9", 365 "s": "0x7626abc15834f391a117c63450047309dbf84c5ce3e8e609b607062641e2de43", 366 "yParity": "0x0" 367 }`, 368 }, 369 } 370 } 371 372 func allBlobTxs(addr common.Address, config *params.ChainConfig) []txData { 373 return []txData{ 374 { 375 Tx: &types.BlobTx{ 376 Nonce: 6, 377 GasTipCap: uint256.NewInt(1), 378 GasFeeCap: uint256.NewInt(5), 379 Gas: 6, 380 To: addr, 381 BlobFeeCap: uint256.NewInt(1), 382 BlobHashes: []common.Hash{{1}}, 383 Value: new(uint256.Int), 384 V: uint256.NewInt(32), 385 R: uint256.NewInt(10), 386 S: uint256.NewInt(11), 387 }, 388 Want: `{ 389 "blockHash": null, 390 "blockNumber": null, 391 "from": "0x71562b71999873db5b286df957af199ec94617f7", 392 "gas": "0x6", 393 "gasPrice": "0x5", 394 "maxFeePerGas": "0x5", 395 "maxPriorityFeePerGas": "0x1", 396 "maxFeePerBlobGas": "0x1", 397 "hash": "0x1f2b59a20e61efc615ad0cbe936379d6bbea6f938aafaf35eb1da05d8e7f46a3", 398 "input": "0x", 399 "nonce": "0x6", 400 "to": "0xdead000000000000000000000000000000000000", 401 "transactionIndex": null, 402 "value": "0x0", 403 "type": "0x3", 404 "accessList": [], 405 "chainId": "0x1", 406 "blobVersionedHashes": [ 407 "0x0100000000000000000000000000000000000000000000000000000000000000" 408 ], 409 "v": "0x0", 410 "r": "0x618be8908e0e5320f8f3b48042a079fe5a335ebd4ed1422a7d2207cd45d872bc", 411 "s": "0x27b2bc6c80e849a8e8b764d4549d8c2efac3441e73cf37054eb0a9b9f8e89b27", 412 "yParity": "0x0" 413 }`, 414 }, 415 } 416 } 417 418 func newTestAccountManager(t *testing.T) (*accounts.Manager, accounts.Account) { 419 var ( 420 dir = t.TempDir() 421 am = accounts.NewManager(nil) 422 b = keystore.NewKeyStore(dir, 2, 1) 423 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 424 ) 425 acc, err := b.ImportECDSA(testKey, "") 426 if err != nil { 427 t.Fatalf("failed to create test account: %v", err) 428 } 429 if err := b.Unlock(acc, ""); err != nil { 430 t.Fatalf("failed to unlock account: %v\n", err) 431 } 432 am.AddBackend(b) 433 return am, acc 434 } 435 436 type testBackend struct { 437 db ethdb.Database 438 chain *core.BlockChain 439 pending *types.Block 440 accman *accounts.Manager 441 acc accounts.Account 442 } 443 444 func newTestBackend(t *testing.T, n int, gspec *core.Genesis, engine consensus.Engine, generator func(i int, b *core.BlockGen)) *testBackend { 445 options := core.DefaultConfig().WithArchive(true) 446 options.TxLookupLimit = 0 // index all txs 447 448 accman, acc := newTestAccountManager(t) 449 gspec.Alloc[acc.Address] = types.Account{Balance: big.NewInt(params.Ether)} 450 451 // Generate blocks for testing 452 db, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, n, generator) 453 454 chain, err := core.NewBlockChain(db, gspec, engine, options) 455 if err != nil { 456 t.Fatalf("failed to create tester chain: %v", err) 457 } 458 if n, err := chain.InsertChain(blocks); err != nil { 459 t.Fatalf("block %d: failed to insert into chain: %v", n, err) 460 } 461 462 backend := &testBackend{db: db, chain: chain, accman: accman, acc: acc} 463 return backend 464 } 465 466 func (b *testBackend) setPendingBlock(block *types.Block) { 467 b.pending = block 468 } 469 470 func (b testBackend) SyncProgress(ctx context.Context) ethereum.SyncProgress { 471 return ethereum.SyncProgress{} 472 } 473 func (b testBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { 474 return big.NewInt(0), nil 475 } 476 func (b testBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, []*big.Int, []float64, error) { 477 return nil, nil, nil, nil, nil, nil, nil 478 } 479 func (b testBackend) BlobBaseFee(ctx context.Context) *big.Int { return new(big.Int) } 480 func (b testBackend) ChainDb() ethdb.Database { return b.db } 481 func (b testBackend) AccountManager() *accounts.Manager { return b.accman } 482 func (b testBackend) ExtRPCEnabled() bool { return false } 483 func (b testBackend) RPCGasCap() uint64 { return 10000000 } 484 func (b testBackend) RPCEVMTimeout() time.Duration { return time.Second } 485 func (b testBackend) RPCTxFeeCap() float64 { return 0 } 486 func (b testBackend) UnprotectedAllowed() bool { return false } 487 func (b testBackend) SetHead(number uint64) {} 488 func (b testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { 489 if number == rpc.LatestBlockNumber { 490 return b.chain.CurrentBlock(), nil 491 } 492 if number == rpc.PendingBlockNumber && b.pending != nil { 493 return b.pending.Header(), nil 494 } 495 return b.chain.GetHeaderByNumber(uint64(number)), nil 496 } 497 func (b testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { 498 return b.chain.GetHeaderByHash(hash), nil 499 } 500 func (b testBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) { 501 if blockNr, ok := blockNrOrHash.Number(); ok { 502 return b.HeaderByNumber(ctx, blockNr) 503 } 504 if blockHash, ok := blockNrOrHash.Hash(); ok { 505 return b.HeaderByHash(ctx, blockHash) 506 } 507 panic("unknown type rpc.BlockNumberOrHash") 508 } 509 510 func (b testBackend) CurrentHeader() *types.Header { return b.chain.CurrentHeader() } 511 func (b testBackend) CurrentBlock() *types.Header { return b.chain.CurrentBlock() } 512 func (b testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { 513 if number == rpc.LatestBlockNumber { 514 head := b.chain.CurrentBlock() 515 return b.chain.GetBlock(head.Hash(), head.Number.Uint64()), nil 516 } 517 if number == rpc.PendingBlockNumber { 518 return b.pending, nil 519 } 520 if number == rpc.EarliestBlockNumber { 521 number = 0 522 } 523 return b.chain.GetBlockByNumber(uint64(number)), nil 524 } 525 526 func (b testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { 527 return b.chain.GetBlockByHash(hash), nil 528 } 529 func (b testBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { 530 if blockNr, ok := blockNrOrHash.Number(); ok { 531 return b.BlockByNumber(ctx, blockNr) 532 } 533 if blockHash, ok := blockNrOrHash.Hash(); ok { 534 return b.BlockByHash(ctx, blockHash) 535 } 536 panic("unknown type rpc.BlockNumberOrHash") 537 } 538 func (b testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { 539 return b.chain.GetBlock(hash, uint64(number.Int64())).Body(), nil 540 } 541 func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { 542 if number == rpc.PendingBlockNumber { 543 panic("pending state not implemented") 544 } 545 header, err := b.HeaderByNumber(ctx, number) 546 if err != nil { 547 return nil, nil, err 548 } 549 if header == nil { 550 return nil, nil, errors.New("header not found") 551 } 552 stateDb, err := b.chain.StateAt(header.Root) 553 return stateDb, header, err 554 } 555 func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { 556 if blockNr, ok := blockNrOrHash.Number(); ok { 557 return b.StateAndHeaderByNumber(ctx, blockNr) 558 } 559 panic("only implemented for number") 560 } 561 func (b testBackend) Pending() (*types.Block, types.Receipts, *state.StateDB) { panic("implement me") } 562 func (b testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { 563 header, err := b.HeaderByHash(ctx, hash) 564 if header == nil || err != nil { 565 return nil, err 566 } 567 receipts := rawdb.ReadReceipts(b.db, hash, header.Number.Uint64(), header.Time, b.chain.Config()) 568 return receipts, nil 569 } 570 func (b testBackend) GetEVM(ctx context.Context, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockContext *vm.BlockContext) *vm.EVM { 571 if vmConfig == nil { 572 vmConfig = b.chain.GetVMConfig() 573 } 574 context := core.NewEVMBlockContext(header, b.chain, nil) 575 if blockContext != nil { 576 context = *blockContext 577 } 578 return vm.NewEVM(context, state, b.chain.Config(), *vmConfig) 579 } 580 func (b testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { 581 panic("implement me") 582 } 583 func (b testBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { 584 panic("implement me") 585 } 586 func (b testBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { 587 panic("implement me") 588 } 589 func (b testBackend) GetCanonicalTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64) { 590 tx, blockHash, blockNumber, index := rawdb.ReadCanonicalTransaction(b.db, txHash) 591 return tx != nil, tx, blockHash, blockNumber, index 592 } 593 func (b testBackend) GetCanonicalReceipt(tx *types.Transaction, blockHash common.Hash, blockNumber, blockIndex uint64) (*types.Receipt, error) { 594 return b.chain.GetCanonicalReceipt(tx, blockHash, blockNumber, blockIndex) 595 } 596 func (b testBackend) TxIndexDone() bool { 597 return true 598 } 599 func (b testBackend) GetPoolTransactions() (types.Transactions, error) { panic("implement me") } 600 func (b testBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { panic("implement me") } 601 func (b testBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { 602 return 0, nil 603 } 604 func (b testBackend) Stats() (pending int, queued int) { panic("implement me") } 605 func (b testBackend) TxPoolContent() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) { 606 panic("implement me") 607 } 608 func (b testBackend) TxPoolContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) { 609 panic("implement me") 610 } 611 func (b testBackend) SubscribeNewTxsEvent(events chan<- core.NewTxsEvent) event.Subscription { 612 panic("implement me") 613 } 614 func (b testBackend) ChainConfig() *params.ChainConfig { return b.chain.Config() } 615 func (b testBackend) Engine() consensus.Engine { return b.chain.Engine() } 616 func (b testBackend) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) { 617 panic("implement me") 618 } 619 func (b testBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { 620 panic("implement me") 621 } 622 func (b testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { 623 panic("implement me") 624 } 625 func (b testBackend) CurrentView() *filtermaps.ChainView { 626 panic("implement me") 627 } 628 func (b testBackend) NewMatcherBackend() filtermaps.MatcherBackend { 629 panic("implement me") 630 } 631 632 func (b testBackend) HistoryPruningCutoff() uint64 { 633 bn, _ := b.chain.HistoryPruningCutoff() 634 return bn 635 } 636 637 func TestEstimateGas(t *testing.T) { 638 t.Parallel() 639 // Initialize test accounts 640 var ( 641 accounts = newAccounts(4) 642 genesis = &core.Genesis{ 643 Config: params.MergedTestChainConfig, 644 Alloc: types.GenesisAlloc{ 645 accounts[0].addr: {Balance: big.NewInt(params.Ether)}, 646 accounts[1].addr: {Balance: big.NewInt(params.Ether)}, 647 accounts[2].addr: {Balance: big.NewInt(params.Ether), Code: append(types.DelegationPrefix, accounts[3].addr.Bytes()...)}, 648 }, 649 } 650 genBlocks = 10 651 signer = types.HomesteadSigner{} 652 randomAccounts = newAccounts(2) 653 ) 654 packRevert := func(revertMessage string) []byte { 655 var revertSelector = crypto.Keccak256([]byte("Error(string)"))[:4] 656 stringType, _ := abi.NewType("string", "", nil) 657 args := abi.Arguments{ 658 {Type: stringType}, 659 } 660 encodedMessage, _ := args.Pack(revertMessage) 661 662 return append(revertSelector, encodedMessage...) 663 } 664 665 api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) { 666 // Transfer from account[0] to account[1] 667 // value: 1000 wei 668 // fee: 0 wei 669 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) 670 b.AddTx(tx) 671 b.SetPoS() 672 })) 673 674 setCodeAuthorization, _ := types.SignSetCode(accounts[0].key, types.SetCodeAuthorization{ 675 Address: accounts[0].addr, 676 Nonce: uint64(genBlocks + 1), 677 }) 678 679 var testSuite = []struct { 680 blockNumber rpc.BlockNumber 681 call TransactionArgs 682 overrides override.StateOverride 683 blockOverrides override.BlockOverrides 684 expectErr error 685 want uint64 686 }{ 687 //simple transfer on latest block 688 { 689 blockNumber: rpc.LatestBlockNumber, 690 call: TransactionArgs{ 691 From: &accounts[0].addr, 692 To: &accounts[1].addr, 693 Value: (*hexutil.Big)(big.NewInt(1000)), 694 }, 695 expectErr: nil, 696 want: 21000, 697 }, 698 // simple transfer with insufficient funds on latest block 699 { 700 blockNumber: rpc.LatestBlockNumber, 701 call: TransactionArgs{ 702 From: &randomAccounts[0].addr, 703 To: &accounts[1].addr, 704 Value: (*hexutil.Big)(big.NewInt(1000)), 705 }, 706 expectErr: core.ErrInsufficientFunds, 707 want: 21000, 708 }, 709 // empty create 710 { 711 blockNumber: rpc.LatestBlockNumber, 712 call: TransactionArgs{}, 713 expectErr: nil, 714 want: 53000, 715 }, 716 { 717 blockNumber: rpc.LatestBlockNumber, 718 call: TransactionArgs{}, 719 overrides: override.StateOverride{ 720 randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, 721 }, 722 expectErr: nil, 723 want: 53000, 724 }, 725 { 726 blockNumber: rpc.LatestBlockNumber, 727 call: TransactionArgs{ 728 From: &randomAccounts[0].addr, 729 To: &randomAccounts[1].addr, 730 Value: (*hexutil.Big)(big.NewInt(1000)), 731 }, 732 overrides: override.StateOverride{ 733 randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(big.NewInt(0))}, 734 }, 735 expectErr: core.ErrInsufficientFunds, 736 }, 737 // Test for a bug where the gas price was set to zero but the basefee non-zero 738 // 739 // contract BasefeeChecker { 740 // constructor() { 741 // require(tx.gasprice >= block.basefee); 742 // if (tx.gasprice > 0) { 743 // require(block.basefee > 0); 744 // } 745 // } 746 //} 747 { 748 blockNumber: rpc.LatestBlockNumber, 749 call: TransactionArgs{ 750 From: &accounts[0].addr, 751 Input: hex2Bytes("6080604052348015600f57600080fd5b50483a1015601c57600080fd5b60003a111560315760004811603057600080fd5b5b603f80603e6000396000f3fe6080604052600080fdfea264697066735822122060729c2cee02b10748fae5200f1c9da4661963354973d9154c13a8e9ce9dee1564736f6c63430008130033"), 752 GasPrice: (*hexutil.Big)(big.NewInt(1_000_000_000)), // Legacy as pricing 753 }, 754 expectErr: nil, 755 want: 67617, 756 }, 757 { 758 blockNumber: rpc.LatestBlockNumber, 759 call: TransactionArgs{ 760 From: &accounts[0].addr, 761 Input: hex2Bytes("6080604052348015600f57600080fd5b50483a1015601c57600080fd5b60003a111560315760004811603057600080fd5b5b603f80603e6000396000f3fe6080604052600080fdfea264697066735822122060729c2cee02b10748fae5200f1c9da4661963354973d9154c13a8e9ce9dee1564736f6c63430008130033"), 762 MaxFeePerGas: (*hexutil.Big)(big.NewInt(1_000_000_000)), // 1559 gas pricing 763 }, 764 expectErr: nil, 765 want: 67617, 766 }, 767 { 768 blockNumber: rpc.LatestBlockNumber, 769 call: TransactionArgs{ 770 From: &accounts[0].addr, 771 Input: hex2Bytes("6080604052348015600f57600080fd5b50483a1015601c57600080fd5b60003a111560315760004811603057600080fd5b5b603f80603e6000396000f3fe6080604052600080fdfea264697066735822122060729c2cee02b10748fae5200f1c9da4661963354973d9154c13a8e9ce9dee1564736f6c63430008130033"), 772 GasPrice: nil, // No legacy gas pricing 773 MaxFeePerGas: nil, // No 1559 gas pricing 774 }, 775 expectErr: nil, 776 want: 67595, 777 }, 778 // Blobs should have no effect on gas estimate 779 { 780 blockNumber: rpc.LatestBlockNumber, 781 call: TransactionArgs{ 782 From: &accounts[0].addr, 783 To: &accounts[1].addr, 784 Value: (*hexutil.Big)(big.NewInt(1)), 785 BlobHashes: []common.Hash{{0x01, 0x22}}, 786 BlobFeeCap: (*hexutil.Big)(big.NewInt(1)), 787 }, 788 want: 21000, 789 }, 790 // // SPDX-License-Identifier: GPL-3.0 791 //pragma solidity >=0.8.2 <0.9.0; 792 // 793 //contract BlockOverridesTest { 794 // function call() public view returns (uint256) { 795 // return block.number; 796 // } 797 // 798 // function estimate() public view { 799 // revert(string.concat("block ", uint2str(block.number))); 800 // } 801 // 802 // function uint2str(uint256 _i) internal pure returns (string memory str) { 803 // if (_i == 0) { 804 // return "0"; 805 // } 806 // uint256 j = _i; 807 // uint256 length; 808 // while (j != 0) { 809 // length++; 810 // j /= 10; 811 // } 812 // bytes memory bstr = new bytes(length); 813 // uint256 k = length; 814 // j = _i; 815 // while (j != 0) { 816 // bstr[--k] = bytes1(uint8(48 + (j % 10))); 817 // j /= 10; 818 // } 819 // str = string(bstr); 820 // } 821 //} 822 { 823 blockNumber: rpc.LatestBlockNumber, 824 call: TransactionArgs{ 825 From: &accounts[0].addr, 826 To: &accounts[1].addr, 827 Data: hex2Bytes("0x3592d016"), //estimate 828 }, 829 overrides: override.StateOverride{ 830 accounts[1].addr: override.OverrideAccount{ 831 Code: hex2Bytes("608060405234801561000f575f5ffd5b5060043610610034575f3560e01c806328b5e32b146100385780633592d0161461004b575b5f5ffd5b4360405190815260200160405180910390f35b610053610055565b005b61005e4361009d565b60405160200161006e91906101a5565b60408051601f198184030181529082905262461bcd60e51b8252610094916004016101cd565b60405180910390fd5b6060815f036100c35750506040805180820190915260018152600360fc1b602082015290565b815f5b81156100ec57806100d681610216565b91506100e59050600a83610242565b91506100c6565b5f8167ffffffffffffffff81111561010657610106610255565b6040519080825280601f01601f191660200182016040528015610130576020820181803683370190505b508593509050815b831561019c57610149600a85610269565b61015490603061027c565b60f81b8261016183610295565b92508281518110610174576101746102aa565b60200101906001600160f81b03191690815f1a905350610195600a85610242565b9350610138565b50949350505050565b650313637b1b5960d51b81525f82518060208501600685015e5f920160060191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b634e487b7160e01b5f52601160045260245ffd5b5f6001820161022757610227610202565b5060010190565b634e487b7160e01b5f52601260045260245ffd5b5f826102505761025061022e565b500490565b634e487b7160e01b5f52604160045260245ffd5b5f826102775761027761022e565b500690565b8082018082111561028f5761028f610202565b92915050565b5f816102a3576102a3610202565b505f190190565b634e487b7160e01b5f52603260045260245ffdfea2646970667358221220a253cad1e2e3523b8c053c1d0cd1e39d7f3bafcedd73440a244872701f05dab264736f6c634300081c0033"), 832 }, 833 }, 834 blockOverrides: override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))}, 835 expectErr: newRevertError(packRevert("block 11")), 836 }, 837 // Should be able to send to an EIP-7702 delegated account. 838 { 839 blockNumber: rpc.LatestBlockNumber, 840 call: TransactionArgs{ 841 From: &accounts[0].addr, 842 To: &accounts[2].addr, 843 Value: (*hexutil.Big)(big.NewInt(1)), 844 }, 845 want: 21000, 846 }, 847 // Should be able to send as EIP-7702 delegated account. 848 { 849 blockNumber: rpc.LatestBlockNumber, 850 call: TransactionArgs{ 851 From: &accounts[2].addr, 852 To: &accounts[1].addr, 853 Value: (*hexutil.Big)(big.NewInt(1)), 854 }, 855 want: 21000, 856 }, 857 // Should be able to estimate SetCodeTx. 858 { 859 blockNumber: rpc.LatestBlockNumber, 860 call: TransactionArgs{ 861 From: &accounts[0].addr, 862 To: &accounts[1].addr, 863 Value: (*hexutil.Big)(big.NewInt(0)), 864 AuthorizationList: []types.SetCodeAuthorization{setCodeAuthorization}, 865 }, 866 want: 46000, 867 }, 868 // Should retrieve the code of 0xef0001 || accounts[0].addr and return an invalid opcode error. 869 { 870 blockNumber: rpc.LatestBlockNumber, 871 call: TransactionArgs{ 872 From: &accounts[0].addr, 873 To: &accounts[0].addr, 874 Value: (*hexutil.Big)(big.NewInt(0)), 875 AuthorizationList: []types.SetCodeAuthorization{setCodeAuthorization}, 876 }, 877 expectErr: errors.New("invalid opcode: opcode 0xef not defined"), 878 }, 879 // SetCodeTx with empty authorization list should fail. 880 { 881 blockNumber: rpc.LatestBlockNumber, 882 call: TransactionArgs{ 883 From: &accounts[0].addr, 884 To: &common.Address{}, 885 Value: (*hexutil.Big)(big.NewInt(0)), 886 AuthorizationList: []types.SetCodeAuthorization{}, 887 }, 888 expectErr: core.ErrEmptyAuthList, 889 }, 890 // SetCodeTx with nil `to` should fail. 891 { 892 blockNumber: rpc.LatestBlockNumber, 893 call: TransactionArgs{ 894 From: &accounts[0].addr, 895 To: nil, 896 Value: (*hexutil.Big)(big.NewInt(0)), 897 AuthorizationList: []types.SetCodeAuthorization{setCodeAuthorization}, 898 }, 899 expectErr: core.ErrSetCodeTxCreate, 900 }, 901 } 902 for i, tc := range testSuite { 903 result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides) 904 if tc.expectErr != nil { 905 if err == nil { 906 t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr) 907 continue 908 } 909 if !errors.Is(err, tc.expectErr) { 910 if err.Error() != tc.expectErr.Error() { 911 t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err) 912 } 913 } 914 continue 915 } 916 if err != nil { 917 t.Errorf("test %d: want no error, have %v", i, err) 918 continue 919 } 920 if float64(result) > float64(tc.want)*(1+estimateGasErrorRatio) { 921 t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, uint64(result), tc.want) 922 } 923 } 924 } 925 926 func TestCall(t *testing.T) { 927 t.Parallel() 928 929 // Initialize test accounts 930 var ( 931 accounts = newAccounts(3) 932 dad = common.HexToAddress("0x0000000000000000000000000000000000000dad") 933 genesis = &core.Genesis{ 934 Config: params.MergedTestChainConfig, 935 Alloc: types.GenesisAlloc{ 936 accounts[0].addr: {Balance: big.NewInt(params.Ether)}, 937 accounts[1].addr: {Balance: big.NewInt(params.Ether)}, 938 accounts[2].addr: {Balance: big.NewInt(params.Ether)}, 939 dad: { 940 Balance: big.NewInt(params.Ether), 941 Nonce: 1, 942 Storage: map[common.Hash]common.Hash{ 943 common.Hash{}: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001"), 944 }, 945 }, 946 }, 947 } 948 genBlocks = 10 949 signer = types.HomesteadSigner{} 950 ) 951 api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) { 952 // Transfer from account[0] to account[1] 953 // value: 1000 wei 954 // fee: 0 wei 955 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) 956 b.AddTx(tx) 957 b.SetPoS() 958 })) 959 randomAccounts := newAccounts(3) 960 var testSuite = []struct { 961 name string 962 blockNumber rpc.BlockNumber 963 overrides override.StateOverride 964 call TransactionArgs 965 blockOverrides override.BlockOverrides 966 expectErr error 967 want string 968 }{ 969 // transfer on genesis 970 { 971 name: "transfer-on-genesis", 972 blockNumber: rpc.BlockNumber(0), 973 call: TransactionArgs{ 974 From: &accounts[0].addr, 975 To: &accounts[1].addr, 976 Value: (*hexutil.Big)(big.NewInt(1000)), 977 }, 978 expectErr: nil, 979 want: "0x", 980 }, 981 // transfer on the head 982 { 983 name: "transfer-on-the-head", 984 blockNumber: rpc.BlockNumber(genBlocks), 985 call: TransactionArgs{ 986 From: &accounts[0].addr, 987 To: &accounts[1].addr, 988 Value: (*hexutil.Big)(big.NewInt(1000)), 989 }, 990 expectErr: nil, 991 want: "0x", 992 }, 993 // transfer on a non-existent block, error expects 994 { 995 name: "transfer-non-existent-block", 996 blockNumber: rpc.BlockNumber(genBlocks + 1), 997 call: TransactionArgs{ 998 From: &accounts[0].addr, 999 To: &accounts[1].addr, 1000 Value: (*hexutil.Big)(big.NewInt(1000)), 1001 }, 1002 expectErr: errors.New("header not found"), 1003 }, 1004 // transfer on the latest block 1005 { 1006 name: "transfer-latest-block", 1007 blockNumber: rpc.LatestBlockNumber, 1008 call: TransactionArgs{ 1009 From: &accounts[0].addr, 1010 To: &accounts[1].addr, 1011 Value: (*hexutil.Big)(big.NewInt(1000)), 1012 }, 1013 expectErr: nil, 1014 want: "0x", 1015 }, 1016 // Call which can only succeed if state is state overridden 1017 { 1018 name: "state-override-success", 1019 blockNumber: rpc.LatestBlockNumber, 1020 call: TransactionArgs{ 1021 From: &randomAccounts[0].addr, 1022 To: &randomAccounts[1].addr, 1023 Value: (*hexutil.Big)(big.NewInt(1000)), 1024 }, 1025 overrides: override.StateOverride{ 1026 randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, 1027 }, 1028 want: "0x", 1029 }, 1030 // Invalid call without state overriding 1031 { 1032 name: "insufficient-funds-simple", 1033 blockNumber: rpc.LatestBlockNumber, 1034 call: TransactionArgs{ 1035 From: &randomAccounts[0].addr, 1036 To: &randomAccounts[1].addr, 1037 Value: (*hexutil.Big)(big.NewInt(1000)), 1038 }, 1039 expectErr: core.ErrInsufficientFunds, 1040 }, 1041 // Successful simple contract call 1042 // 1043 // // SPDX-License-Identifier: GPL-3.0 1044 // 1045 // pragma solidity >=0.7.0 <0.8.0; 1046 // 1047 // /** 1048 // * @title Storage 1049 // * @dev Store & retrieve value in a variable 1050 // */ 1051 // contract Storage { 1052 // uint256 public number; 1053 // constructor() { 1054 // number = block.number; 1055 // } 1056 // } 1057 { 1058 name: "simple-contract-call", 1059 blockNumber: rpc.LatestBlockNumber, 1060 call: TransactionArgs{ 1061 From: &randomAccounts[0].addr, 1062 To: &randomAccounts[2].addr, 1063 Data: hex2Bytes("8381f58a"), // call number() 1064 }, 1065 overrides: override.StateOverride{ 1066 randomAccounts[2].addr: override.OverrideAccount{ 1067 Code: hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033"), 1068 StateDiff: map[common.Hash]common.Hash{{}: common.BigToHash(big.NewInt(123))}, 1069 }, 1070 }, 1071 want: "0x000000000000000000000000000000000000000000000000000000000000007b", 1072 }, 1073 // // SPDX-License-Identifier: GPL-3.0 1074 //pragma solidity >=0.8.2 <0.9.0; 1075 // 1076 //contract BlockOverridesTest { 1077 // function call() public view returns (uint256) { 1078 // return block.number; 1079 // } 1080 // 1081 // function estimate() public view { 1082 // revert(string.concat("block ", uint2str(block.number))); 1083 // } 1084 // 1085 // function uint2str(uint256 _i) internal pure returns (string memory str) { 1086 // if (_i == 0) { 1087 // return "0"; 1088 // } 1089 // uint256 j = _i; 1090 // uint256 length; 1091 // while (j != 0) { 1092 // length++; 1093 // j /= 10; 1094 // } 1095 // bytes memory bstr = new bytes(length); 1096 // uint256 k = length; 1097 // j = _i; 1098 // while (j != 0) { 1099 // bstr[--k] = bytes1(uint8(48 + (j % 10))); 1100 // j /= 10; 1101 // } 1102 // str = string(bstr); 1103 // } 1104 //} 1105 { 1106 name: "block-override-with-state-override", 1107 blockNumber: rpc.LatestBlockNumber, 1108 call: TransactionArgs{ 1109 From: &accounts[1].addr, 1110 To: &accounts[2].addr, 1111 Data: hex2Bytes("0x28b5e32b"), //call 1112 }, 1113 overrides: override.StateOverride{ 1114 accounts[2].addr: override.OverrideAccount{ 1115 Code: hex2Bytes("608060405234801561000f575f5ffd5b5060043610610034575f3560e01c806328b5e32b146100385780633592d0161461004b575b5f5ffd5b4360405190815260200160405180910390f35b610053610055565b005b61005e4361009d565b60405160200161006e91906101a5565b60408051601f198184030181529082905262461bcd60e51b8252610094916004016101cd565b60405180910390fd5b6060815f036100c35750506040805180820190915260018152600360fc1b602082015290565b815f5b81156100ec57806100d681610216565b91506100e59050600a83610242565b91506100c6565b5f8167ffffffffffffffff81111561010657610106610255565b6040519080825280601f01601f191660200182016040528015610130576020820181803683370190505b508593509050815b831561019c57610149600a85610269565b61015490603061027c565b60f81b8261016183610295565b92508281518110610174576101746102aa565b60200101906001600160f81b03191690815f1a905350610195600a85610242565b9350610138565b50949350505050565b650313637b1b5960d51b81525f82518060208501600685015e5f920160060191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b634e487b7160e01b5f52601160045260245ffd5b5f6001820161022757610227610202565b5060010190565b634e487b7160e01b5f52601260045260245ffd5b5f826102505761025061022e565b500490565b634e487b7160e01b5f52604160045260245ffd5b5f826102775761027761022e565b500690565b8082018082111561028f5761028f610202565b92915050565b5f816102a3576102a3610202565b505f190190565b634e487b7160e01b5f52603260045260245ffdfea2646970667358221220a253cad1e2e3523b8c053c1d0cd1e39d7f3bafcedd73440a244872701f05dab264736f6c634300081c0033"), 1116 }, 1117 }, 1118 blockOverrides: override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))}, 1119 want: "0x000000000000000000000000000000000000000000000000000000000000000b", 1120 }, 1121 // Clear storage trie 1122 { 1123 name: "clear-storage-trie", 1124 blockNumber: rpc.LatestBlockNumber, 1125 call: TransactionArgs{ 1126 From: &accounts[1].addr, 1127 // Yul: 1128 // object "Test" { 1129 // code { 1130 // let dad := 0x0000000000000000000000000000000000000dad 1131 // if eq(balance(dad), 0) { 1132 // revert(0, 0) 1133 // } 1134 // let slot := sload(0) 1135 // mstore(0, slot) 1136 // return(0, 32) 1137 // } 1138 // } 1139 Input: hex2Bytes("610dad6000813103600f57600080fd5b6000548060005260206000f3"), 1140 }, 1141 overrides: override.StateOverride{ 1142 dad: override.OverrideAccount{ 1143 State: map[common.Hash]common.Hash{}, 1144 }, 1145 }, 1146 want: "0x0000000000000000000000000000000000000000000000000000000000000000", 1147 }, 1148 // Invalid blob tx 1149 { 1150 name: "invalid-blob-tx", 1151 blockNumber: rpc.LatestBlockNumber, 1152 call: TransactionArgs{ 1153 From: &accounts[1].addr, 1154 Input: &hexutil.Bytes{0x00}, 1155 BlobHashes: []common.Hash{}, 1156 }, 1157 expectErr: core.ErrBlobTxCreate, 1158 }, 1159 // BLOBHASH opcode 1160 { 1161 name: "blobhash-opcode", 1162 blockNumber: rpc.LatestBlockNumber, 1163 call: TransactionArgs{ 1164 From: &accounts[1].addr, 1165 To: &randomAccounts[2].addr, 1166 BlobHashes: []common.Hash{{0x01, 0x22}}, 1167 BlobFeeCap: (*hexutil.Big)(big.NewInt(1)), 1168 }, 1169 overrides: override.StateOverride{ 1170 randomAccounts[2].addr: { 1171 Code: hex2Bytes("60004960005260206000f3"), 1172 }, 1173 }, 1174 want: "0x0122000000000000000000000000000000000000000000000000000000000000", 1175 }, 1176 // Clear the entire storage set 1177 { 1178 blockNumber: rpc.LatestBlockNumber, 1179 call: TransactionArgs{ 1180 From: &accounts[1].addr, 1181 // Yul: 1182 // object "Test" { 1183 // code { 1184 // let dad := 0x0000000000000000000000000000000000000dad 1185 // if eq(balance(dad), 0) { 1186 // revert(0, 0) 1187 // } 1188 // let slot := sload(0) 1189 // mstore(0, slot) 1190 // return(0, 32) 1191 // } 1192 // } 1193 Input: hex2Bytes("610dad6000813103600f57600080fd5b6000548060005260206000f3"), 1194 }, 1195 overrides: override.StateOverride{ 1196 dad: override.OverrideAccount{ 1197 State: map[common.Hash]common.Hash{}, 1198 }, 1199 }, 1200 want: "0x0000000000000000000000000000000000000000000000000000000000000000", 1201 }, 1202 { 1203 name: "unsupported block override beaconRoot", 1204 blockNumber: rpc.LatestBlockNumber, 1205 call: TransactionArgs{}, 1206 blockOverrides: override.BlockOverrides{ 1207 BeaconRoot: &common.Hash{0, 1, 2}, 1208 }, 1209 expectErr: errors.New(`block override "beaconRoot" is not supported for this RPC method`), 1210 }, 1211 { 1212 name: "unsupported block override withdrawals", 1213 blockNumber: rpc.LatestBlockNumber, 1214 call: TransactionArgs{}, 1215 blockOverrides: override.BlockOverrides{ 1216 Withdrawals: &types.Withdrawals{}, 1217 }, 1218 expectErr: errors.New(`block override "withdrawals" is not supported for this RPC method`), 1219 }, 1220 } 1221 for _, tc := range testSuite { 1222 result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides) 1223 if tc.expectErr != nil { 1224 if err == nil { 1225 t.Errorf("test %s: want error %v, have nothing", tc.name, tc.expectErr) 1226 continue 1227 } 1228 if !errors.Is(err, tc.expectErr) { 1229 // Second try 1230 if !reflect.DeepEqual(err, tc.expectErr) { 1231 t.Errorf("test %s: error mismatch, want %v, have %v", tc.name, tc.expectErr, err) 1232 } 1233 } 1234 continue 1235 } 1236 if err != nil { 1237 t.Errorf("test %s: want no error, have %v", tc.name, err) 1238 continue 1239 } 1240 if !reflect.DeepEqual(result.String(), tc.want) { 1241 t.Errorf("test %s, result mismatch, have\n%v\n, want\n%v\n", tc.name, result.String(), tc.want) 1242 } 1243 } 1244 } 1245 1246 func TestSimulateV1(t *testing.T) { 1247 t.Parallel() 1248 // Initialize test accounts 1249 var ( 1250 accounts = newAccounts(3) 1251 fixedAccount = newTestAccount() 1252 genBlocks = 10 1253 signer = types.HomesteadSigner{} 1254 cac = common.HexToAddress("0x0000000000000000000000000000000000000cac") 1255 bab = common.HexToAddress("0x0000000000000000000000000000000000000bab") 1256 coinbase = "0x000000000000000000000000000000000000ffff" 1257 genesis = &core.Genesis{ 1258 Config: params.TestChainConfig, 1259 Alloc: types.GenesisAlloc{ 1260 accounts[0].addr: {Balance: big.NewInt(params.Ether)}, 1261 accounts[1].addr: {Balance: big.NewInt(params.Ether)}, 1262 accounts[2].addr: {Balance: big.NewInt(params.Ether)}, 1263 // Yul: 1264 // object "Test" { 1265 // code { 1266 // let dad := 0x0000000000000000000000000000000000000dad 1267 // selfdestruct(dad) 1268 // } 1269 // } 1270 cac: {Balance: big.NewInt(params.Ether), Code: common.Hex2Bytes("610dad80ff")}, 1271 bab: { 1272 Balance: big.NewInt(1), 1273 // object "Test" { 1274 // code { 1275 // let value1 := sload(1) 1276 // let value2 := sload(2) 1277 // 1278 // // Shift value1 by 128 bits to the left by multiplying it with 2^128 1279 // value1 := mul(value1, 0x100000000000000000000000000000000) 1280 // 1281 // // Concatenate value1 and value2 1282 // let concatenatedValue := add(value1, value2) 1283 // 1284 // // Store the result in memory and return it 1285 // mstore(0, concatenatedValue) 1286 // return(0, 0x20) 1287 // } 1288 // } 1289 Code: common.FromHex("0x600154600254700100000000000000000000000000000000820291508082018060005260206000f3"), 1290 Storage: map[common.Hash]common.Hash{ 1291 common.BigToHash(big.NewInt(1)): common.BigToHash(big.NewInt(10)), 1292 common.BigToHash(big.NewInt(2)): common.BigToHash(big.NewInt(12)), 1293 }, 1294 }, 1295 }, 1296 } 1297 sha256Address = common.BytesToAddress([]byte{0x02}) 1298 ) 1299 api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, ethash.NewFaker(), func(i int, b *core.BlockGen) { 1300 b.SetCoinbase(common.HexToAddress(coinbase)) 1301 // Transfer from account[0] to account[1] 1302 // value: 1000 wei 1303 // fee: 0 wei 1304 tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ 1305 Nonce: uint64(i), 1306 To: &accounts[1].addr, 1307 Value: big.NewInt(1000), 1308 Gas: params.TxGas, 1309 GasPrice: b.BaseFee(), 1310 Data: nil, 1311 }), signer, accounts[0].key) 1312 b.AddTx(tx) 1313 })) 1314 var ( 1315 randomAccounts = newAccounts(4) 1316 latest = rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) 1317 includeTransfers = true 1318 validation = true 1319 ) 1320 type log struct { 1321 Address common.Address `json:"address"` 1322 Topics []common.Hash `json:"topics"` 1323 Data hexutil.Bytes `json:"data"` 1324 BlockNumber hexutil.Uint64 `json:"blockNumber"` 1325 // Skip txHash 1326 //TxHash common.Hash `json:"transactionHash" gencodec:"required"` 1327 TxIndex hexutil.Uint `json:"transactionIndex"` 1328 //BlockHash common.Hash `json:"blockHash"` 1329 Index hexutil.Uint `json:"logIndex"` 1330 } 1331 type callErr struct { 1332 Message string 1333 Code int 1334 } 1335 type callRes struct { 1336 ReturnValue string `json:"returnData"` 1337 Error callErr 1338 Logs []log 1339 GasUsed string 1340 Status string 1341 } 1342 type blockRes struct { 1343 Number string 1344 //Hash string 1345 // Ignore timestamp 1346 GasLimit string 1347 GasUsed string 1348 Miner string 1349 BaseFeePerGas string 1350 Calls []callRes 1351 } 1352 var testSuite = []struct { 1353 name string 1354 blocks []simBlock 1355 tag rpc.BlockNumberOrHash 1356 includeTransfers *bool 1357 validation *bool 1358 expectErr error 1359 want []blockRes 1360 }{ 1361 // State build-up over calls: 1362 // First value transfer OK after state override. 1363 // Second one should succeed because of first transfer. 1364 { 1365 name: "simple", 1366 tag: latest, 1367 blocks: []simBlock{{ 1368 StateOverrides: &override.StateOverride{ 1369 randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(big.NewInt(1000))}, 1370 }, 1371 Calls: []TransactionArgs{{ 1372 From: &randomAccounts[0].addr, 1373 To: &randomAccounts[1].addr, 1374 Value: (*hexutil.Big)(big.NewInt(1000)), 1375 }, { 1376 From: &randomAccounts[1].addr, 1377 To: &randomAccounts[2].addr, 1378 Value: (*hexutil.Big)(big.NewInt(1000)), 1379 }, { 1380 To: &randomAccounts[3].addr, 1381 }}, 1382 }}, 1383 want: []blockRes{{ 1384 Number: "0xb", 1385 GasLimit: "0x47e7c4", 1386 GasUsed: "0xf618", 1387 Miner: coinbase, 1388 BaseFeePerGas: "0x0", 1389 Calls: []callRes{{ 1390 ReturnValue: "0x", 1391 GasUsed: "0x5208", 1392 Logs: []log{}, 1393 Status: "0x1", 1394 }, { 1395 ReturnValue: "0x", 1396 GasUsed: "0x5208", 1397 Logs: []log{}, 1398 Status: "0x1", 1399 }, { 1400 ReturnValue: "0x", 1401 GasUsed: "0x5208", 1402 Logs: []log{}, 1403 Status: "0x1", 1404 }}, 1405 }}, 1406 }, { 1407 // State build-up over blocks. 1408 name: "simple-multi-block", 1409 tag: latest, 1410 blocks: []simBlock{{ 1411 StateOverrides: &override.StateOverride{ 1412 randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(big.NewInt(2000))}, 1413 }, 1414 Calls: []TransactionArgs{ 1415 { 1416 From: &randomAccounts[0].addr, 1417 To: &randomAccounts[1].addr, 1418 Value: (*hexutil.Big)(big.NewInt(1000)), 1419 }, { 1420 From: &randomAccounts[0].addr, 1421 To: &randomAccounts[3].addr, 1422 Value: (*hexutil.Big)(big.NewInt(1000)), 1423 }, 1424 }, 1425 }, { 1426 StateOverrides: &override.StateOverride{ 1427 randomAccounts[3].addr: override.OverrideAccount{Balance: newRPCBalance(big.NewInt(0))}, 1428 }, 1429 Calls: []TransactionArgs{ 1430 { 1431 From: &randomAccounts[1].addr, 1432 To: &randomAccounts[2].addr, 1433 Value: (*hexutil.Big)(big.NewInt(1000)), 1434 }, 1435 }, 1436 }}, 1437 want: []blockRes{{ 1438 Number: "0xb", 1439 GasLimit: "0x47e7c4", 1440 GasUsed: "0xa410", 1441 Miner: coinbase, 1442 BaseFeePerGas: "0x0", 1443 Calls: []callRes{{ 1444 ReturnValue: "0x", 1445 GasUsed: "0x5208", 1446 Logs: []log{}, 1447 Status: "0x1", 1448 }, { 1449 ReturnValue: "0x", 1450 GasUsed: "0x5208", 1451 Logs: []log{}, 1452 Status: "0x1", 1453 }}, 1454 }, { 1455 Number: "0xc", 1456 GasLimit: "0x47e7c4", 1457 GasUsed: "0x5208", 1458 Miner: coinbase, 1459 BaseFeePerGas: "0x0", 1460 Calls: []callRes{{ 1461 ReturnValue: "0x", 1462 GasUsed: "0x5208", 1463 Logs: []log{}, 1464 Status: "0x1", 1465 }}, 1466 }}, 1467 }, { 1468 // insufficient funds 1469 name: "insufficient-funds", 1470 tag: latest, 1471 blocks: []simBlock{{ 1472 Calls: []TransactionArgs{{ 1473 From: &randomAccounts[0].addr, 1474 To: &randomAccounts[1].addr, 1475 Value: (*hexutil.Big)(big.NewInt(1000)), 1476 }}, 1477 }}, 1478 want: nil, 1479 expectErr: &invalidTxError{Message: fmt.Sprintf("err: insufficient funds for gas * price + value: address %s have 0 want 1000 (supplied gas 4712388)", randomAccounts[0].addr.String()), Code: errCodeInsufficientFunds}, 1480 }, { 1481 // EVM error 1482 name: "evm-error", 1483 tag: latest, 1484 blocks: []simBlock{{ 1485 StateOverrides: &override.StateOverride{ 1486 randomAccounts[2].addr: override.OverrideAccount{Code: hex2Bytes("f3")}, 1487 }, 1488 Calls: []TransactionArgs{{ 1489 From: &randomAccounts[0].addr, 1490 To: &randomAccounts[2].addr, 1491 }}, 1492 }}, 1493 want: []blockRes{{ 1494 Number: "0xb", 1495 GasLimit: "0x47e7c4", 1496 GasUsed: "0x47e7c4", 1497 Miner: coinbase, 1498 BaseFeePerGas: "0x0", 1499 Calls: []callRes{{ 1500 ReturnValue: "0x", 1501 Error: callErr{Message: "stack underflow (0 <=> 2)", Code: errCodeVMError}, 1502 GasUsed: "0x47e7c4", 1503 Logs: []log{}, 1504 Status: "0x0", 1505 }}, 1506 }}, 1507 }, { 1508 // Block overrides should work, each call is simulated on a different block number 1509 name: "block-overrides", 1510 tag: latest, 1511 blocks: []simBlock{{ 1512 BlockOverrides: &override.BlockOverrides{ 1513 Number: (*hexutil.Big)(big.NewInt(11)), 1514 FeeRecipient: &cac, 1515 }, 1516 Calls: []TransactionArgs{ 1517 { 1518 From: &accounts[0].addr, 1519 Input: &hexutil.Bytes{ 1520 0x43, // NUMBER 1521 0x60, 0x00, 0x52, // MSTORE offset 0 1522 0x60, 0x20, 0x60, 0x00, 0xf3, // RETURN 1523 }, 1524 }, 1525 }, 1526 }, { 1527 BlockOverrides: &override.BlockOverrides{ 1528 Number: (*hexutil.Big)(big.NewInt(12)), 1529 }, 1530 Calls: []TransactionArgs{{ 1531 From: &accounts[1].addr, 1532 Input: &hexutil.Bytes{ 1533 0x43, // NUMBER 1534 0x60, 0x00, 0x52, // MSTORE offset 0 1535 0x60, 0x20, 0x60, 0x00, 0xf3, 1536 }, 1537 }}, 1538 }}, 1539 want: []blockRes{{ 1540 Number: "0xb", 1541 GasLimit: "0x47e7c4", 1542 GasUsed: "0xe891", 1543 Miner: strings.ToLower(cac.String()), 1544 BaseFeePerGas: "0x0", 1545 Calls: []callRes{{ 1546 ReturnValue: "0x000000000000000000000000000000000000000000000000000000000000000b", 1547 GasUsed: "0xe891", 1548 Logs: []log{}, 1549 Status: "0x1", 1550 }}, 1551 }, { 1552 Number: "0xc", 1553 GasLimit: "0x47e7c4", 1554 GasUsed: "0xe891", 1555 Miner: strings.ToLower(cac.String()), 1556 BaseFeePerGas: "0x0", 1557 Calls: []callRes{{ 1558 ReturnValue: "0x000000000000000000000000000000000000000000000000000000000000000c", 1559 GasUsed: "0xe891", 1560 Logs: []log{}, 1561 Status: "0x1", 1562 }}, 1563 }}, 1564 }, 1565 // Block numbers must be in order. 1566 { 1567 name: "block-number-order", 1568 tag: latest, 1569 blocks: []simBlock{{ 1570 BlockOverrides: &override.BlockOverrides{ 1571 Number: (*hexutil.Big)(big.NewInt(12)), 1572 }, 1573 Calls: []TransactionArgs{{ 1574 From: &accounts[1].addr, 1575 Input: &hexutil.Bytes{ 1576 0x43, // NUMBER 1577 0x60, 0x00, 0x52, // MSTORE offset 0 1578 0x60, 0x20, 0x60, 0x00, 0xf3, // RETURN 1579 }, 1580 }}, 1581 }, { 1582 BlockOverrides: &override.BlockOverrides{ 1583 Number: (*hexutil.Big)(big.NewInt(11)), 1584 }, 1585 Calls: []TransactionArgs{{ 1586 From: &accounts[0].addr, 1587 Input: &hexutil.Bytes{ 1588 0x43, // NUMBER 1589 0x60, 0x00, 0x52, // MSTORE offset 0 1590 0x60, 0x20, 0x60, 0x00, 0xf3, // RETURN 1591 }, 1592 }}, 1593 }}, 1594 want: []blockRes{}, 1595 expectErr: &invalidBlockNumberError{message: "block numbers must be in order: 11 <= 12"}, 1596 }, 1597 // Test on solidity storage example. Set value in one call, read in next. 1598 { 1599 name: "storage-contract", 1600 tag: latest, 1601 blocks: []simBlock{{ 1602 StateOverrides: &override.StateOverride{ 1603 randomAccounts[2].addr: override.OverrideAccount{ 1604 Code: hex2Bytes("608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100d9565b60405180910390f35b610073600480360381019061006e919061009d565b61007e565b005b60008054905090565b8060008190555050565b60008135905061009781610103565b92915050565b6000602082840312156100b3576100b26100fe565b5b60006100c184828501610088565b91505092915050565b6100d3816100f4565b82525050565b60006020820190506100ee60008301846100ca565b92915050565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea2646970667358221220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070033"), 1605 }, 1606 }, 1607 Calls: []TransactionArgs{{ 1608 // Set value to 5 1609 From: &randomAccounts[0].addr, 1610 To: &randomAccounts[2].addr, 1611 Input: hex2Bytes("6057361d0000000000000000000000000000000000000000000000000000000000000005"), 1612 }, { 1613 // Read value 1614 From: &randomAccounts[0].addr, 1615 To: &randomAccounts[2].addr, 1616 Input: hex2Bytes("2e64cec1"), 1617 }, 1618 }, 1619 }}, 1620 want: []blockRes{{ 1621 Number: "0xb", 1622 GasLimit: "0x47e7c4", 1623 GasUsed: "0x10683", 1624 Miner: coinbase, 1625 BaseFeePerGas: "0x0", 1626 Calls: []callRes{{ 1627 ReturnValue: "0x", 1628 GasUsed: "0xaacc", 1629 Logs: []log{}, 1630 Status: "0x1", 1631 }, { 1632 ReturnValue: "0x0000000000000000000000000000000000000000000000000000000000000005", 1633 GasUsed: "0x5bb7", 1634 Logs: []log{}, 1635 Status: "0x1", 1636 }}, 1637 }}, 1638 }, 1639 // Test logs output. 1640 { 1641 name: "logs", 1642 tag: latest, 1643 blocks: []simBlock{{ 1644 StateOverrides: &override.StateOverride{ 1645 randomAccounts[2].addr: override.OverrideAccount{ 1646 // Yul code: 1647 // object "Test" { 1648 // code { 1649 // let hash:u256 := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 1650 // log1(0, 0, hash) 1651 // return (0, 0) 1652 // } 1653 // } 1654 Code: hex2Bytes("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80600080a1600080f3"), 1655 }, 1656 }, 1657 Calls: []TransactionArgs{{ 1658 From: &randomAccounts[0].addr, 1659 To: &randomAccounts[2].addr, 1660 }}, 1661 }}, 1662 want: []blockRes{{ 1663 Number: "0xb", 1664 GasLimit: "0x47e7c4", 1665 GasUsed: "0x5508", 1666 Miner: coinbase, 1667 BaseFeePerGas: "0x0", 1668 Calls: []callRes{{ 1669 ReturnValue: "0x", 1670 Logs: []log{{ 1671 Address: randomAccounts[2].addr, 1672 Topics: []common.Hash{common.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")}, 1673 BlockNumber: hexutil.Uint64(11), 1674 Data: hexutil.Bytes{}, 1675 }}, 1676 GasUsed: "0x5508", 1677 Status: "0x1", 1678 }}, 1679 }}, 1680 }, 1681 // Test ecrecover override 1682 { 1683 name: "ecrecover-override", 1684 tag: latest, 1685 blocks: []simBlock{{ 1686 StateOverrides: &override.StateOverride{ 1687 randomAccounts[2].addr: override.OverrideAccount{ 1688 // Yul code that returns ecrecover(0, 0, 0, 0). 1689 // object "Test" { 1690 // code { 1691 // // Free memory pointer 1692 // let free_ptr := mload(0x40) 1693 // 1694 // // Initialize inputs with zeros 1695 // mstore(free_ptr, 0) // Hash 1696 // mstore(add(free_ptr, 0x20), 0) // v 1697 // mstore(add(free_ptr, 0x40), 0) // r 1698 // mstore(add(free_ptr, 0x60), 0) // s 1699 // 1700 // // Call ecrecover precompile (at address 1) with all 0 inputs 1701 // let success := staticcall(gas(), 1, free_ptr, 0x80, free_ptr, 0x20) 1702 // 1703 // // Check if the call was successful 1704 // if eq(success, 0) { 1705 // revert(0, 0) 1706 // } 1707 // 1708 // // Return the recovered address 1709 // return(free_ptr, 0x14) 1710 // } 1711 // } 1712 Code: hex2Bytes("6040516000815260006020820152600060408201526000606082015260208160808360015afa60008103603157600080fd5b601482f3"), 1713 }, 1714 common.BytesToAddress([]byte{0x01}): override.OverrideAccount{ 1715 // Yul code that returns the address of the caller. 1716 // object "Test" { 1717 // code { 1718 // let c := caller() 1719 // mstore(0, c) 1720 // return(0xc, 0x14) 1721 // } 1722 // } 1723 Code: hex2Bytes("33806000526014600cf3"), 1724 }, 1725 }, 1726 Calls: []TransactionArgs{{ 1727 From: &randomAccounts[0].addr, 1728 To: &randomAccounts[2].addr, 1729 }}, 1730 }}, 1731 want: []blockRes{{ 1732 Number: "0xb", 1733 GasLimit: "0x47e7c4", 1734 GasUsed: "0x52f6", 1735 Miner: coinbase, 1736 BaseFeePerGas: "0x0", 1737 Calls: []callRes{{ 1738 // Caller is in this case the contract that invokes ecrecover. 1739 ReturnValue: strings.ToLower(randomAccounts[2].addr.String()), 1740 GasUsed: "0x52f6", 1741 Logs: []log{}, 1742 Status: "0x1", 1743 }}, 1744 }}, 1745 }, 1746 // Test moving the sha256 precompile. 1747 { 1748 name: "precompile-move", 1749 tag: latest, 1750 blocks: []simBlock{{ 1751 StateOverrides: &override.StateOverride{ 1752 sha256Address: override.OverrideAccount{ 1753 // Yul code that returns the calldata. 1754 // object "Test" { 1755 // code { 1756 // let size := calldatasize() // Get the size of the calldata 1757 // 1758 // // Allocate memory to store the calldata 1759 // let memPtr := msize() 1760 // 1761 // // Copy calldata to memory 1762 // calldatacopy(memPtr, 0, size) 1763 // 1764 // // Return the calldata from memory 1765 // return(memPtr, size) 1766 // } 1767 // } 1768 Code: hex2Bytes("365981600082378181f3"), 1769 MovePrecompileTo: &randomAccounts[2].addr, 1770 }, 1771 }, 1772 Calls: []TransactionArgs{{ 1773 From: &randomAccounts[0].addr, 1774 To: &randomAccounts[2].addr, 1775 Input: hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"), 1776 }, { 1777 From: &randomAccounts[0].addr, 1778 To: &sha256Address, 1779 Input: hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"), 1780 }}, 1781 }}, 1782 want: []blockRes{{ 1783 Number: "0xb", 1784 GasLimit: "0x47e7c4", 1785 GasUsed: "0xa58c", 1786 Miner: coinbase, 1787 BaseFeePerGas: "0x0", 1788 Calls: []callRes{{ 1789 ReturnValue: "0xec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5", 1790 GasUsed: "0x52dc", 1791 Logs: []log{}, 1792 Status: "0x1", 1793 }, { 1794 ReturnValue: "0x0000000000000000000000000000000000000000000000000000000000000001", 1795 GasUsed: "0x52b0", 1796 Logs: []log{}, 1797 Status: "0x1", 1798 }}, 1799 }}, 1800 }, 1801 // Test ether transfers. 1802 { 1803 name: "transfer-logs", 1804 tag: latest, 1805 blocks: []simBlock{{ 1806 StateOverrides: &override.StateOverride{ 1807 randomAccounts[0].addr: override.OverrideAccount{ 1808 Balance: newRPCBalance(big.NewInt(100)), 1809 // Yul code that transfers 100 wei to address passed in calldata: 1810 // object "Test" { 1811 // code { 1812 // let recipient := shr(96, calldataload(0)) 1813 // let value := 100 1814 // let success := call(gas(), recipient, value, 0, 0, 0, 0) 1815 // if eq(success, 0) { 1816 // revert(0, 0) 1817 // } 1818 // } 1819 // } 1820 Code: hex2Bytes("60003560601c606460008060008084865af160008103601d57600080fd5b505050"), 1821 }, 1822 }, 1823 Calls: []TransactionArgs{{ 1824 From: &accounts[0].addr, 1825 To: &randomAccounts[0].addr, 1826 Value: (*hexutil.Big)(big.NewInt(50)), 1827 Input: hex2Bytes(strings.TrimPrefix(fixedAccount.addr.String(), "0x")), 1828 }}, 1829 }}, 1830 includeTransfers: &includeTransfers, 1831 want: []blockRes{{ 1832 Number: "0xb", 1833 GasLimit: "0x47e7c4", 1834 GasUsed: "0x77dc", 1835 Miner: coinbase, 1836 BaseFeePerGas: "0x0", 1837 Calls: []callRes{{ 1838 ReturnValue: "0x", 1839 GasUsed: "0x77dc", 1840 Logs: []log{{ 1841 Address: transferAddress, 1842 Topics: []common.Hash{ 1843 transferTopic, 1844 addressToHash(accounts[0].addr), 1845 addressToHash(randomAccounts[0].addr), 1846 }, 1847 Data: hexutil.Bytes(common.BigToHash(big.NewInt(50)).Bytes()), 1848 BlockNumber: hexutil.Uint64(11), 1849 }, { 1850 Address: transferAddress, 1851 Topics: []common.Hash{ 1852 transferTopic, 1853 addressToHash(randomAccounts[0].addr), 1854 addressToHash(fixedAccount.addr), 1855 }, 1856 Data: hexutil.Bytes(common.BigToHash(big.NewInt(100)).Bytes()), 1857 BlockNumber: hexutil.Uint64(11), 1858 Index: hexutil.Uint(1), 1859 }}, 1860 Status: "0x1", 1861 }}, 1862 }}, 1863 }, 1864 // Tests selfdestructed contract. 1865 { 1866 name: "selfdestruct", 1867 tag: latest, 1868 blocks: []simBlock{{ 1869 Calls: []TransactionArgs{{ 1870 From: &accounts[0].addr, 1871 To: &cac, 1872 }, { 1873 From: &accounts[0].addr, 1874 // Check that cac is selfdestructed and balance transferred to dad. 1875 // object "Test" { 1876 // code { 1877 // let cac := 0x0000000000000000000000000000000000000cac 1878 // let dad := 0x0000000000000000000000000000000000000dad 1879 // if gt(balance(cac), 0) { 1880 // revert(0, 0) 1881 // } 1882 // if gt(extcodesize(cac), 0) { 1883 // revert(0, 0) 1884 // } 1885 // if eq(balance(dad), 0) { 1886 // revert(0, 0) 1887 // } 1888 // } 1889 // } 1890 Input: hex2Bytes("610cac610dad600082311115601357600080fd5b6000823b1115602157600080fd5b6000813103602e57600080fd5b5050"), 1891 }}, 1892 }, { 1893 Calls: []TransactionArgs{{ 1894 From: &accounts[0].addr, 1895 Input: hex2Bytes("610cac610dad600082311115601357600080fd5b6000823b1115602157600080fd5b6000813103602e57600080fd5b5050"), 1896 }}, 1897 }}, 1898 want: []blockRes{{ 1899 Number: "0xb", 1900 GasLimit: "0x47e7c4", 1901 GasUsed: "0x1b83f", 1902 Miner: coinbase, 1903 BaseFeePerGas: "0x0", 1904 Calls: []callRes{{ 1905 ReturnValue: "0x", 1906 GasUsed: "0xd166", 1907 Logs: []log{}, 1908 Status: "0x1", 1909 }, { 1910 ReturnValue: "0x", 1911 GasUsed: "0xe6d9", 1912 Logs: []log{}, 1913 Status: "0x1", 1914 }}, 1915 }, { 1916 Number: "0xc", 1917 GasLimit: "0x47e7c4", 1918 GasUsed: "0xe6d9", 1919 Miner: coinbase, 1920 BaseFeePerGas: "0x0", 1921 Calls: []callRes{{ 1922 ReturnValue: "0x", 1923 GasUsed: "0xe6d9", 1924 Logs: []log{}, 1925 Status: "0x1", 1926 }}, 1927 }}, 1928 }, 1929 // Enable validation checks. 1930 { 1931 name: "validation-checks", 1932 tag: latest, 1933 blocks: []simBlock{{ 1934 Calls: []TransactionArgs{{ 1935 From: &accounts[2].addr, 1936 To: &cac, 1937 Nonce: newUint64(2), 1938 }}, 1939 }}, 1940 validation: &validation, 1941 want: nil, 1942 expectErr: &invalidTxError{Message: fmt.Sprintf("err: nonce too high: address %s, tx: 2 state: 0 (supplied gas 4712388)", accounts[2].addr), Code: errCodeNonceTooHigh}, 1943 }, 1944 // Contract sends tx in validation mode. 1945 { 1946 name: "validation-checks-from-contract", 1947 tag: latest, 1948 blocks: []simBlock{{ 1949 StateOverrides: &override.StateOverride{ 1950 randomAccounts[2].addr: override.OverrideAccount{ 1951 Balance: newRPCBalance(big.NewInt(2098640803896784)), 1952 Code: hex2Bytes("00"), 1953 Nonce: newUint64(1), 1954 }, 1955 }, 1956 Calls: []TransactionArgs{{ 1957 From: &randomAccounts[2].addr, 1958 To: &cac, 1959 Nonce: newUint64(1), 1960 MaxFeePerGas: newInt(233138868), 1961 MaxPriorityFeePerGas: newInt(1), 1962 }}, 1963 }}, 1964 validation: &validation, 1965 want: []blockRes{{ 1966 Number: "0xb", 1967 GasLimit: "0x47e7c4", 1968 GasUsed: "0xd166", 1969 Miner: coinbase, 1970 BaseFeePerGas: "0xde56ab3", 1971 Calls: []callRes{{ 1972 ReturnValue: "0x", 1973 GasUsed: "0xd166", 1974 Logs: []log{}, 1975 Status: "0x1", 1976 }}, 1977 }}, 1978 }, 1979 // Successful validation 1980 { 1981 name: "validation-checks-success", 1982 tag: latest, 1983 blocks: []simBlock{{ 1984 BlockOverrides: &override.BlockOverrides{ 1985 BaseFeePerGas: (*hexutil.Big)(big.NewInt(1)), 1986 }, 1987 StateOverrides: &override.StateOverride{ 1988 randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(big.NewInt(10000000))}, 1989 }, 1990 Calls: []TransactionArgs{{ 1991 From: &randomAccounts[0].addr, 1992 To: &randomAccounts[1].addr, 1993 Value: (*hexutil.Big)(big.NewInt(1000)), 1994 MaxFeePerGas: (*hexutil.Big)(big.NewInt(2)), 1995 }}, 1996 }}, 1997 validation: &validation, 1998 want: []blockRes{{ 1999 Number: "0xb", 2000 GasLimit: "0x47e7c4", 2001 GasUsed: "0x5208", 2002 Miner: coinbase, 2003 BaseFeePerGas: "0x1", 2004 Calls: []callRes{{ 2005 ReturnValue: "0x", 2006 GasUsed: "0x5208", 2007 Logs: []log{}, 2008 Status: "0x1", 2009 }}, 2010 }}, 2011 }, 2012 // Clear storage. 2013 { 2014 name: "clear-storage", 2015 tag: latest, 2016 blocks: []simBlock{{ 2017 StateOverrides: &override.StateOverride{ 2018 randomAccounts[2].addr: { 2019 Code: newBytes(genesis.Alloc[bab].Code), 2020 StateDiff: map[common.Hash]common.Hash{ 2021 common.BigToHash(big.NewInt(1)): common.BigToHash(big.NewInt(2)), 2022 common.BigToHash(big.NewInt(2)): common.BigToHash(big.NewInt(3)), 2023 }, 2024 }, 2025 bab: { 2026 State: map[common.Hash]common.Hash{ 2027 common.BigToHash(big.NewInt(1)): common.BigToHash(big.NewInt(1)), 2028 }, 2029 }, 2030 }, 2031 Calls: []TransactionArgs{{ 2032 From: &accounts[0].addr, 2033 To: &randomAccounts[2].addr, 2034 }, { 2035 From: &accounts[0].addr, 2036 To: &bab, 2037 }}, 2038 }, { 2039 StateOverrides: &override.StateOverride{ 2040 randomAccounts[2].addr: { 2041 State: map[common.Hash]common.Hash{ 2042 common.BigToHash(big.NewInt(1)): common.BigToHash(big.NewInt(5)), 2043 }, 2044 }, 2045 }, 2046 Calls: []TransactionArgs{{ 2047 From: &accounts[0].addr, 2048 To: &randomAccounts[2].addr, 2049 }}, 2050 }}, 2051 want: []blockRes{{ 2052 Number: "0xb", 2053 GasLimit: "0x47e7c4", 2054 GasUsed: "0xc542", 2055 Miner: coinbase, 2056 BaseFeePerGas: "0x0", 2057 Calls: []callRes{{ 2058 ReturnValue: "0x0000000000000000000000000000000200000000000000000000000000000003", 2059 GasUsed: "0x62a1", 2060 Logs: []log{}, 2061 Status: "0x1", 2062 }, { 2063 ReturnValue: "0x0000000000000000000000000000000100000000000000000000000000000000", 2064 GasUsed: "0x62a1", 2065 Logs: []log{}, 2066 Status: "0x1", 2067 }}, 2068 }, { 2069 Number: "0xc", 2070 GasLimit: "0x47e7c4", 2071 GasUsed: "0x62a1", 2072 Miner: coinbase, 2073 BaseFeePerGas: "0x0", 2074 Calls: []callRes{{ 2075 ReturnValue: "0x0000000000000000000000000000000500000000000000000000000000000000", 2076 GasUsed: "0x62a1", 2077 Logs: []log{}, 2078 Status: "0x1", 2079 }}, 2080 }}, 2081 }, 2082 { 2083 name: "blockhash-opcode", 2084 tag: latest, 2085 blocks: []simBlock{{ 2086 BlockOverrides: &override.BlockOverrides{ 2087 Number: (*hexutil.Big)(big.NewInt(12)), 2088 }, 2089 StateOverrides: &override.StateOverride{ 2090 randomAccounts[2].addr: { 2091 Code: hex2Bytes("600035804060008103601057600080fd5b5050"), 2092 }, 2093 }, 2094 Calls: []TransactionArgs{{ 2095 From: &accounts[0].addr, 2096 To: &randomAccounts[2].addr, 2097 // Phantom block after base. 2098 Input: uint256ToBytes(uint256.NewInt(11)), 2099 }, { 2100 From: &accounts[0].addr, 2101 To: &randomAccounts[2].addr, 2102 // Canonical block. 2103 Input: uint256ToBytes(uint256.NewInt(8)), 2104 }, { 2105 From: &accounts[0].addr, 2106 To: &randomAccounts[2].addr, 2107 // base block. 2108 Input: uint256ToBytes(uint256.NewInt(10)), 2109 }}, 2110 }, { 2111 BlockOverrides: &override.BlockOverrides{ 2112 Number: (*hexutil.Big)(big.NewInt(16)), 2113 }, 2114 Calls: []TransactionArgs{{ 2115 From: &accounts[0].addr, 2116 To: &randomAccounts[2].addr, 2117 // blocks[0] 2118 Input: uint256ToBytes(uint256.NewInt(12)), 2119 }, { 2120 From: &accounts[0].addr, 2121 To: &randomAccounts[2].addr, 2122 // Phantom after blocks[0] 2123 Input: uint256ToBytes(uint256.NewInt(13)), 2124 }}, 2125 }}, 2126 want: []blockRes{{ 2127 Number: "0xb", 2128 GasLimit: "0x47e7c4", 2129 GasUsed: "0x0", 2130 Miner: coinbase, 2131 BaseFeePerGas: "0x0", 2132 Calls: []callRes{}, 2133 }, { 2134 Number: "0xc", 2135 GasLimit: "0x47e7c4", 2136 GasUsed: "0xf864", 2137 Miner: coinbase, 2138 BaseFeePerGas: "0x0", 2139 Calls: []callRes{{ 2140 ReturnValue: "0x", 2141 GasUsed: "0x52cc", 2142 Logs: []log{}, 2143 Status: "0x1", 2144 }, { 2145 ReturnValue: "0x", 2146 GasUsed: "0x52cc", 2147 Logs: []log{}, 2148 Status: "0x1", 2149 }, { 2150 2151 ReturnValue: "0x", 2152 GasUsed: "0x52cc", 2153 Logs: []log{}, 2154 Status: "0x1", 2155 }}, 2156 }, { 2157 Number: "0xd", 2158 GasLimit: "0x47e7c4", 2159 GasUsed: "0x0", 2160 Miner: coinbase, 2161 BaseFeePerGas: "0x0", 2162 Calls: []callRes{}, 2163 }, { 2164 Number: "0xe", 2165 GasLimit: "0x47e7c4", 2166 GasUsed: "0x0", 2167 Miner: coinbase, 2168 BaseFeePerGas: "0x0", 2169 Calls: []callRes{}, 2170 }, { 2171 Number: "0xf", 2172 GasLimit: "0x47e7c4", 2173 GasUsed: "0x0", 2174 Miner: coinbase, 2175 BaseFeePerGas: "0x0", 2176 Calls: []callRes{}, 2177 }, { 2178 Number: "0x10", 2179 GasLimit: "0x47e7c4", 2180 GasUsed: "0xa598", 2181 Miner: coinbase, 2182 BaseFeePerGas: "0x0", 2183 Calls: []callRes{{ 2184 ReturnValue: "0x", 2185 GasUsed: "0x52cc", 2186 Logs: []log{}, 2187 Status: "0x1", 2188 }, { 2189 2190 ReturnValue: "0x", 2191 GasUsed: "0x52cc", 2192 Logs: []log{}, 2193 Status: "0x1", 2194 }}, 2195 }}, 2196 }, 2197 { 2198 name: "basefee-non-validation", 2199 tag: latest, 2200 blocks: []simBlock{{ 2201 StateOverrides: &override.StateOverride{ 2202 randomAccounts[2].addr: { 2203 // Yul code: 2204 // object "Test" { 2205 // code { 2206 // // Get the gas price from the transaction 2207 // let gasPrice := gasprice() 2208 // 2209 // // Get the base fee from the block 2210 // let baseFee := basefee() 2211 // 2212 // // Store gasPrice and baseFee in memory 2213 // mstore(0x0, gasPrice) 2214 // mstore(0x20, baseFee) 2215 // 2216 // // Return the data 2217 // return(0x0, 0x40) 2218 // } 2219 // } 2220 Code: hex2Bytes("3a489060005260205260406000f3"), 2221 }, 2222 }, 2223 Calls: []TransactionArgs{{ 2224 From: &accounts[0].addr, 2225 To: &randomAccounts[2].addr, 2226 // 0 gas price 2227 }, { 2228 From: &accounts[0].addr, 2229 To: &randomAccounts[2].addr, 2230 // non-zero gas price 2231 MaxPriorityFeePerGas: newInt(1), 2232 MaxFeePerGas: newInt(2), 2233 }, 2234 }, 2235 }, { 2236 BlockOverrides: &override.BlockOverrides{ 2237 BaseFeePerGas: (*hexutil.Big)(big.NewInt(1)), 2238 }, 2239 Calls: []TransactionArgs{{ 2240 From: &accounts[0].addr, 2241 To: &randomAccounts[2].addr, 2242 // 0 gas price 2243 }, { 2244 From: &accounts[0].addr, 2245 To: &randomAccounts[2].addr, 2246 // non-zero gas price 2247 MaxPriorityFeePerGas: newInt(1), 2248 MaxFeePerGas: newInt(2), 2249 }, 2250 }, 2251 }, { 2252 // Base fee should be 0 to zero even if it was set in previous block. 2253 Calls: []TransactionArgs{{ 2254 From: &accounts[0].addr, 2255 To: &randomAccounts[2].addr, 2256 }}, 2257 }}, 2258 want: []blockRes{{ 2259 Number: "0xb", 2260 GasLimit: "0x47e7c4", 2261 GasUsed: "0xa44e", 2262 Miner: coinbase, 2263 BaseFeePerGas: "0x0", 2264 Calls: []callRes{{ 2265 ReturnValue: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 2266 GasUsed: "0x5227", 2267 Logs: []log{}, 2268 Status: "0x1", 2269 }, { 2270 ReturnValue: "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000", 2271 GasUsed: "0x5227", 2272 Logs: []log{}, 2273 Status: "0x1", 2274 }}, 2275 }, { 2276 Number: "0xc", 2277 GasLimit: "0x47e7c4", 2278 GasUsed: "0xa44e", 2279 Miner: coinbase, 2280 BaseFeePerGas: "0x1", 2281 Calls: []callRes{{ 2282 ReturnValue: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", 2283 GasUsed: "0x5227", 2284 Logs: []log{}, 2285 Status: "0x1", 2286 }, { 2287 ReturnValue: "0x00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001", 2288 GasUsed: "0x5227", 2289 Logs: []log{}, 2290 Status: "0x1", 2291 }}, 2292 }, { 2293 Number: "0xd", 2294 GasLimit: "0x47e7c4", 2295 GasUsed: "0x5227", 2296 Miner: coinbase, 2297 BaseFeePerGas: "0x0", 2298 Calls: []callRes{{ 2299 ReturnValue: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 2300 GasUsed: "0x5227", 2301 Logs: []log{}, 2302 Status: "0x1", 2303 }}, 2304 }}, 2305 }, { 2306 name: "basefee-validation-mode", 2307 tag: latest, 2308 blocks: []simBlock{{ 2309 StateOverrides: &override.StateOverride{ 2310 randomAccounts[2].addr: { 2311 // Yul code: 2312 // object "Test" { 2313 // code { 2314 // // Get the gas price from the transaction 2315 // let gasPrice := gasprice() 2316 // 2317 // // Get the base fee from the block 2318 // let baseFee := basefee() 2319 // 2320 // // Store gasPrice and baseFee in memory 2321 // mstore(0x0, gasPrice) 2322 // mstore(0x20, baseFee) 2323 // 2324 // // Return the data 2325 // return(0x0, 0x40) 2326 // } 2327 // } 2328 Code: hex2Bytes("3a489060005260205260406000f3"), 2329 }, 2330 }, 2331 Calls: []TransactionArgs{{ 2332 From: &accounts[0].addr, 2333 To: &randomAccounts[2].addr, 2334 MaxFeePerGas: newInt(233138868), 2335 MaxPriorityFeePerGas: newInt(1), 2336 }}, 2337 }}, 2338 validation: &validation, 2339 want: []blockRes{{ 2340 Number: "0xb", 2341 GasLimit: "0x47e7c4", 2342 GasUsed: "0x5227", 2343 Miner: coinbase, 2344 BaseFeePerGas: "0xde56ab3", 2345 Calls: []callRes{{ 2346 ReturnValue: "0x000000000000000000000000000000000000000000000000000000000de56ab4000000000000000000000000000000000000000000000000000000000de56ab3", 2347 GasUsed: "0x5227", 2348 Logs: []log{}, 2349 Status: "0x1", 2350 }}, 2351 }}, 2352 }, 2353 } 2354 2355 for _, tc := range testSuite { 2356 t.Run(tc.name, func(t *testing.T) { 2357 opts := simOpts{BlockStateCalls: tc.blocks} 2358 if tc.includeTransfers != nil && *tc.includeTransfers { 2359 opts.TraceTransfers = true 2360 } 2361 if tc.validation != nil && *tc.validation { 2362 opts.Validation = true 2363 } 2364 result, err := api.SimulateV1(context.Background(), opts, &tc.tag) 2365 if tc.expectErr != nil { 2366 if err == nil { 2367 t.Fatalf("test %s: want error %v, have nothing", tc.name, tc.expectErr) 2368 } 2369 if !errors.Is(err, tc.expectErr) { 2370 // Second try 2371 if !reflect.DeepEqual(err, tc.expectErr) { 2372 t.Errorf("test %s: error mismatch, want %v, have %v", tc.name, tc.expectErr, err) 2373 } 2374 } 2375 return 2376 } 2377 if err != nil { 2378 t.Fatalf("test %s: want no error, have %v", tc.name, err) 2379 } 2380 // Turn result into res-struct 2381 var have []blockRes 2382 resBytes, _ := json.Marshal(result) 2383 if err := json.Unmarshal(resBytes, &have); err != nil { 2384 t.Fatalf("failed to unmarshal result: %v", err) 2385 } 2386 if !reflect.DeepEqual(have, tc.want) { 2387 t.Log(string(resBytes)) 2388 t.Errorf("test %s, result mismatch, have\n%v\n, want\n%v\n", tc.name, have, tc.want) 2389 } 2390 }) 2391 } 2392 } 2393 2394 func TestSimulateV1ChainLinkage(t *testing.T) { 2395 var ( 2396 acc = newTestAccount() 2397 sender = acc.addr 2398 contractAddr = common.Address{0xaa, 0xaa} 2399 recipient = common.Address{0xbb, 0xbb} 2400 gspec = &core.Genesis{ 2401 Config: params.MergedTestChainConfig, 2402 Alloc: types.GenesisAlloc{ 2403 sender: {Balance: big.NewInt(params.Ether)}, 2404 contractAddr: {Code: common.Hex2Bytes("5f35405f8114600f575f5260205ff35b5f80fd")}, 2405 }, 2406 } 2407 signer = types.LatestSigner(params.MergedTestChainConfig) 2408 ) 2409 backend := newTestBackend(t, 1, gspec, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) { 2410 tx := types.MustSignNewTx(acc.key, signer, &types.LegacyTx{ 2411 Nonce: uint64(i), 2412 GasPrice: b.BaseFee(), 2413 Gas: params.TxGas, 2414 To: &recipient, 2415 Value: big.NewInt(500), 2416 }) 2417 b.AddTx(tx) 2418 }) 2419 2420 ctx := context.Background() 2421 stateDB, baseHeader, err := backend.StateAndHeaderByNumberOrHash(ctx, rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)) 2422 if err != nil { 2423 t.Fatalf("failed to get state and header: %v", err) 2424 } 2425 2426 sim := &simulator{ 2427 b: backend, 2428 state: stateDB, 2429 base: baseHeader, 2430 chainConfig: backend.ChainConfig(), 2431 gp: new(core.GasPool).AddGas(math.MaxUint64), 2432 traceTransfers: false, 2433 validate: false, 2434 fullTx: false, 2435 } 2436 2437 var ( 2438 call1 = TransactionArgs{ 2439 From: &sender, 2440 To: &recipient, 2441 Value: (*hexutil.Big)(big.NewInt(1000)), 2442 } 2443 call2 = TransactionArgs{ 2444 From: &sender, 2445 To: &recipient, 2446 Value: (*hexutil.Big)(big.NewInt(2000)), 2447 } 2448 call3a = TransactionArgs{ 2449 From: &sender, 2450 To: &contractAddr, 2451 Input: uint256ToBytes(uint256.NewInt(baseHeader.Number.Uint64() + 1)), 2452 Gas: newUint64(1000000), 2453 } 2454 call3b = TransactionArgs{ 2455 From: &sender, 2456 To: &contractAddr, 2457 Input: uint256ToBytes(uint256.NewInt(baseHeader.Number.Uint64() + 2)), 2458 Gas: newUint64(1000000), 2459 } 2460 blocks = []simBlock{ 2461 {Calls: []TransactionArgs{call1}}, 2462 {Calls: []TransactionArgs{call2}}, 2463 {Calls: []TransactionArgs{call3a, call3b}}, 2464 } 2465 ) 2466 2467 results, err := sim.execute(ctx, blocks) 2468 if err != nil { 2469 t.Fatalf("simulation execution failed: %v", err) 2470 } 2471 require.Equal(t, 3, len(results), "expected 3 simulated blocks") 2472 2473 // Check linkages of simulated blocks: 2474 // Verify that block2's parent hash equals block1's hash. 2475 block1 := results[0].Block 2476 block2 := results[1].Block 2477 block3 := results[2].Block 2478 require.Equal(t, block1.ParentHash(), baseHeader.Hash(), "parent hash of block1 should equal hash of base block") 2479 require.Equal(t, block1.Hash(), block2.Header().ParentHash, "parent hash of block2 should equal hash of block1") 2480 require.Equal(t, block2.Hash(), block3.Header().ParentHash, "parent hash of block3 should equal hash of block2") 2481 2482 // In block3, two calls were executed to our contract. 2483 // The first call in block3 should return the blockhash for block1 (i.e. block1.Hash()), 2484 // whereas the second call should return the blockhash for block2 (i.e. block2.Hash()). 2485 require.Equal(t, block1.Hash().Bytes(), []byte(results[2].Calls[0].ReturnValue), "returned blockhash for block1 does not match") 2486 require.Equal(t, block2.Hash().Bytes(), []byte(results[2].Calls[1].ReturnValue), "returned blockhash for block2 does not match") 2487 } 2488 2489 func TestSimulateV1TxSender(t *testing.T) { 2490 var ( 2491 sender = common.Address{0xaa, 0xaa} 2492 sender2 = common.Address{0xaa, 0xab} 2493 sender3 = common.Address{0xaa, 0xac} 2494 recipient = common.Address{0xbb, 0xbb} 2495 gspec = &core.Genesis{ 2496 Config: params.MergedTestChainConfig, 2497 Alloc: types.GenesisAlloc{ 2498 sender: {Balance: big.NewInt(params.Ether)}, 2499 sender2: {Balance: big.NewInt(params.Ether)}, 2500 sender3: {Balance: big.NewInt(params.Ether)}, 2501 }, 2502 } 2503 ctx = context.Background() 2504 ) 2505 backend := newTestBackend(t, 0, gspec, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) {}) 2506 stateDB, baseHeader, err := backend.StateAndHeaderByNumberOrHash(ctx, rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)) 2507 if err != nil { 2508 t.Fatalf("failed to get state and header: %v", err) 2509 } 2510 2511 sim := &simulator{ 2512 b: backend, 2513 state: stateDB, 2514 base: baseHeader, 2515 chainConfig: backend.ChainConfig(), 2516 gp: new(core.GasPool).AddGas(math.MaxUint64), 2517 traceTransfers: false, 2518 validate: false, 2519 fullTx: true, 2520 } 2521 2522 results, err := sim.execute(ctx, []simBlock{ 2523 {Calls: []TransactionArgs{ 2524 {From: &sender, To: &recipient, Value: (*hexutil.Big)(big.NewInt(1000))}, 2525 {From: &sender2, To: &recipient, Value: (*hexutil.Big)(big.NewInt(2000))}, 2526 {From: &sender3, To: &recipient, Value: (*hexutil.Big)(big.NewInt(3000))}, 2527 }}, 2528 {Calls: []TransactionArgs{ 2529 {From: &sender2, To: &recipient, Value: (*hexutil.Big)(big.NewInt(4000))}, 2530 }}, 2531 }) 2532 if err != nil { 2533 t.Fatalf("simulation execution failed: %v", err) 2534 } 2535 require.Len(t, results, 2, "expected 2 simulated blocks") 2536 require.Len(t, results[0].Block.Transactions(), 3, "expected 3 transaction in simulated block") 2537 require.Len(t, results[1].Block.Transactions(), 1, "expected 1 transaction in 2nd simulated block") 2538 enc, err := json.Marshal(results) 2539 if err != nil { 2540 t.Fatalf("failed to marshal results: %v", err) 2541 } 2542 type resultType struct { 2543 Transactions []struct { 2544 From common.Address `json:"from"` 2545 } 2546 } 2547 var summary []resultType 2548 if err := json.Unmarshal(enc, &summary); err != nil { 2549 t.Fatalf("failed to unmarshal results: %v", err) 2550 } 2551 require.Len(t, summary, 2, "expected 2 simulated blocks") 2552 require.Len(t, summary[0].Transactions, 3, "expected 3 transaction in simulated block") 2553 require.Equal(t, sender, summary[0].Transactions[0].From, "sender address mismatch") 2554 require.Equal(t, sender2, summary[0].Transactions[1].From, "sender address mismatch") 2555 require.Equal(t, sender3, summary[0].Transactions[2].From, "sender address mismatch") 2556 require.Len(t, summary[1].Transactions, 1, "expected 1 transaction in simulated block") 2557 require.Equal(t, sender2, summary[1].Transactions[0].From, "sender address mismatch") 2558 } 2559 2560 func TestSignTransaction(t *testing.T) { 2561 t.Parallel() 2562 // Initialize test accounts 2563 var ( 2564 key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 2565 to = crypto.PubkeyToAddress(key.PublicKey) 2566 genesis = &core.Genesis{ 2567 Config: params.MergedTestChainConfig, 2568 Alloc: types.GenesisAlloc{}, 2569 } 2570 ) 2571 b := newTestBackend(t, 1, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) { 2572 b.SetPoS() 2573 }) 2574 api := NewTransactionAPI(b, nil) 2575 res, err := api.FillTransaction(context.Background(), TransactionArgs{ 2576 From: &b.acc.Address, 2577 To: &to, 2578 Value: (*hexutil.Big)(big.NewInt(1)), 2579 }) 2580 if err != nil { 2581 t.Fatalf("failed to fill tx defaults: %v\n", err) 2582 } 2583 2584 res, err = api.SignTransaction(context.Background(), argsFromTransaction(res.Tx, b.acc.Address)) 2585 if err != nil { 2586 t.Fatalf("failed to sign tx: %v\n", err) 2587 } 2588 tx, err := json.Marshal(res.Tx) 2589 if err != nil { 2590 t.Fatal(err) 2591 } 2592 expect := `{"type":"0x2","chainId":"0x1","nonce":"0x0","to":"0x703c4b2bd70c169f5717101caee543299fc946c7","gas":"0x5208","gasPrice":null,"maxPriorityFeePerGas":"0x0","maxFeePerGas":"0x684ee180","value":"0x1","input":"0x","accessList":[],"v":"0x0","r":"0x8fabeb142d585dd9247f459f7e6fe77e2520c88d50ba5d220da1533cea8b34e1","s":"0x582dd68b21aef36ba23f34e49607329c20d981d30404daf749077f5606785ce7","yParity":"0x0","hash":"0x93927839207cfbec395da84b8a2bc38b7b65d2cb2819e9fef1f091f5b1d4cc8f"}` 2593 if !bytes.Equal(tx, []byte(expect)) { 2594 t.Errorf("result mismatch. Have:\n%s\nWant:\n%s\n", tx, expect) 2595 } 2596 } 2597 2598 func TestSignBlobTransaction(t *testing.T) { 2599 t.Parallel() 2600 // Initialize test accounts 2601 var ( 2602 key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 2603 to = crypto.PubkeyToAddress(key.PublicKey) 2604 genesis = &core.Genesis{ 2605 Config: params.MergedTestChainConfig, 2606 Alloc: types.GenesisAlloc{}, 2607 } 2608 ) 2609 b := newTestBackend(t, 1, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) { 2610 b.SetPoS() 2611 }) 2612 api := NewTransactionAPI(b, nil) 2613 res, err := api.FillTransaction(context.Background(), TransactionArgs{ 2614 From: &b.acc.Address, 2615 To: &to, 2616 Value: (*hexutil.Big)(big.NewInt(1)), 2617 BlobHashes: []common.Hash{{0x01, 0x22}}, 2618 }) 2619 if err != nil { 2620 t.Fatalf("failed to fill tx defaults: %v\n", err) 2621 } 2622 2623 _, err = api.SignTransaction(context.Background(), argsFromTransaction(res.Tx, b.acc.Address)) 2624 if err != nil { 2625 t.Fatalf("should not fail on blob transaction") 2626 } 2627 } 2628 2629 func TestSendBlobTransaction(t *testing.T) { 2630 t.Parallel() 2631 // Initialize test accounts 2632 var ( 2633 key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 2634 to = crypto.PubkeyToAddress(key.PublicKey) 2635 genesis = &core.Genesis{ 2636 Config: params.MergedTestChainConfig, 2637 Alloc: types.GenesisAlloc{}, 2638 } 2639 ) 2640 b := newTestBackend(t, 1, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) { 2641 b.SetPoS() 2642 }) 2643 api := NewTransactionAPI(b, nil) 2644 res, err := api.FillTransaction(context.Background(), TransactionArgs{ 2645 From: &b.acc.Address, 2646 To: &to, 2647 Value: (*hexutil.Big)(big.NewInt(1)), 2648 BlobHashes: []common.Hash{{0x01, 0x22}}, 2649 }) 2650 if err != nil { 2651 t.Fatalf("failed to fill tx defaults: %v\n", err) 2652 } 2653 2654 _, err = api.SendTransaction(context.Background(), argsFromTransaction(res.Tx, b.acc.Address)) 2655 if err == nil { 2656 t.Errorf("sending tx should have failed") 2657 } else if !errors.Is(err, errBlobTxNotSupported) { 2658 t.Errorf("unexpected error. Have %v, want %v\n", err, errBlobTxNotSupported) 2659 } 2660 } 2661 2662 func TestFillBlobTransaction(t *testing.T) { 2663 t.Parallel() 2664 // Initialize test accounts 2665 var ( 2666 key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 2667 to = crypto.PubkeyToAddress(key.PublicKey) 2668 genesis = &core.Genesis{ 2669 Config: params.MergedTestChainConfig, 2670 Alloc: types.GenesisAlloc{}, 2671 } 2672 emptyBlob = new(kzg4844.Blob) 2673 emptyBlobs = []kzg4844.Blob{*emptyBlob} 2674 emptyBlobCommit, _ = kzg4844.BlobToCommitment(emptyBlob) 2675 emptyBlobProof, _ = kzg4844.ComputeBlobProof(emptyBlob, emptyBlobCommit) 2676 emptyBlobHash common.Hash = kzg4844.CalcBlobHashV1(sha256.New(), &emptyBlobCommit) 2677 ) 2678 b := newTestBackend(t, 1, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) { 2679 b.SetPoS() 2680 }) 2681 api := NewTransactionAPI(b, nil) 2682 type result struct { 2683 Hashes []common.Hash 2684 Sidecar *types.BlobTxSidecar 2685 } 2686 suite := []struct { 2687 name string 2688 args TransactionArgs 2689 err string 2690 want *result 2691 }{ 2692 { 2693 name: "TestInvalidParamsCombination1", 2694 args: TransactionArgs{ 2695 From: &b.acc.Address, 2696 To: &to, 2697 Value: (*hexutil.Big)(big.NewInt(1)), 2698 Blobs: []kzg4844.Blob{{}}, 2699 Proofs: []kzg4844.Proof{{}}, 2700 }, 2701 err: `blob proofs provided while commitments were not`, 2702 }, 2703 { 2704 name: "TestInvalidParamsCombination2", 2705 args: TransactionArgs{ 2706 From: &b.acc.Address, 2707 To: &to, 2708 Value: (*hexutil.Big)(big.NewInt(1)), 2709 Blobs: []kzg4844.Blob{{}}, 2710 Commitments: []kzg4844.Commitment{{}}, 2711 }, 2712 err: `blob commitments provided while proofs were not`, 2713 }, 2714 { 2715 name: "TestInvalidParamsCount1", 2716 args: TransactionArgs{ 2717 From: &b.acc.Address, 2718 To: &to, 2719 Value: (*hexutil.Big)(big.NewInt(1)), 2720 Blobs: []kzg4844.Blob{{}}, 2721 Commitments: []kzg4844.Commitment{{}, {}}, 2722 Proofs: []kzg4844.Proof{{}, {}}, 2723 }, 2724 err: `number of blobs and commitments mismatch (have=2, want=1)`, 2725 }, 2726 { 2727 name: "TestInvalidParamsCount2", 2728 args: TransactionArgs{ 2729 From: &b.acc.Address, 2730 To: &to, 2731 Value: (*hexutil.Big)(big.NewInt(1)), 2732 Blobs: []kzg4844.Blob{{}, {}}, 2733 Commitments: []kzg4844.Commitment{{}, {}}, 2734 Proofs: []kzg4844.Proof{{}}, 2735 }, 2736 err: `number of blobs and proofs mismatch (have=1, want=2)`, 2737 }, 2738 { 2739 name: "TestInvalidProofVerification", 2740 args: TransactionArgs{ 2741 From: &b.acc.Address, 2742 To: &to, 2743 Value: (*hexutil.Big)(big.NewInt(1)), 2744 Blobs: []kzg4844.Blob{{}, {}}, 2745 Commitments: []kzg4844.Commitment{{}, {}}, 2746 Proofs: []kzg4844.Proof{{}, {}}, 2747 }, 2748 err: `failed to verify blob proof: short buffer`, 2749 }, 2750 { 2751 name: "TestGenerateBlobHashes", 2752 args: TransactionArgs{ 2753 From: &b.acc.Address, 2754 To: &to, 2755 Value: (*hexutil.Big)(big.NewInt(1)), 2756 Blobs: emptyBlobs, 2757 Commitments: []kzg4844.Commitment{emptyBlobCommit}, 2758 Proofs: []kzg4844.Proof{emptyBlobProof}, 2759 }, 2760 want: &result{ 2761 Hashes: []common.Hash{emptyBlobHash}, 2762 Sidecar: &types.BlobTxSidecar{ 2763 Blobs: emptyBlobs, 2764 Commitments: []kzg4844.Commitment{emptyBlobCommit}, 2765 Proofs: []kzg4844.Proof{emptyBlobProof}, 2766 }, 2767 }, 2768 }, 2769 { 2770 name: "TestValidBlobHashes", 2771 args: TransactionArgs{ 2772 From: &b.acc.Address, 2773 To: &to, 2774 Value: (*hexutil.Big)(big.NewInt(1)), 2775 BlobHashes: []common.Hash{emptyBlobHash}, 2776 Blobs: emptyBlobs, 2777 Commitments: []kzg4844.Commitment{emptyBlobCommit}, 2778 Proofs: []kzg4844.Proof{emptyBlobProof}, 2779 }, 2780 want: &result{ 2781 Hashes: []common.Hash{emptyBlobHash}, 2782 Sidecar: &types.BlobTxSidecar{ 2783 Blobs: emptyBlobs, 2784 Commitments: []kzg4844.Commitment{emptyBlobCommit}, 2785 Proofs: []kzg4844.Proof{emptyBlobProof}, 2786 }, 2787 }, 2788 }, 2789 { 2790 name: "TestInvalidBlobHashes", 2791 args: TransactionArgs{ 2792 From: &b.acc.Address, 2793 To: &to, 2794 Value: (*hexutil.Big)(big.NewInt(1)), 2795 BlobHashes: []common.Hash{{0x01, 0x22}}, 2796 Blobs: emptyBlobs, 2797 Commitments: []kzg4844.Commitment{emptyBlobCommit}, 2798 Proofs: []kzg4844.Proof{emptyBlobProof}, 2799 }, 2800 err: fmt.Sprintf("blob hash verification failed (have=%s, want=%s)", common.Hash{0x01, 0x22}, emptyBlobHash), 2801 }, 2802 { 2803 name: "TestGenerateBlobProofs", 2804 args: TransactionArgs{ 2805 From: &b.acc.Address, 2806 To: &to, 2807 Value: (*hexutil.Big)(big.NewInt(1)), 2808 Blobs: emptyBlobs, 2809 }, 2810 want: &result{ 2811 Hashes: []common.Hash{emptyBlobHash}, 2812 Sidecar: &types.BlobTxSidecar{ 2813 Blobs: emptyBlobs, 2814 Commitments: []kzg4844.Commitment{emptyBlobCommit}, 2815 Proofs: []kzg4844.Proof{emptyBlobProof}, 2816 }, 2817 }, 2818 }, 2819 } 2820 for _, tc := range suite { 2821 t.Run(tc.name, func(t *testing.T) { 2822 t.Parallel() 2823 2824 res, err := api.FillTransaction(context.Background(), tc.args) 2825 if len(tc.err) > 0 { 2826 if err == nil { 2827 t.Fatalf("missing error. want: %s", tc.err) 2828 } else if err.Error() != tc.err { 2829 t.Fatalf("error mismatch. want: %s, have: %s", tc.err, err.Error()) 2830 } 2831 return 2832 } 2833 if err != nil && len(tc.err) == 0 { 2834 t.Fatalf("expected no error. have: %s", err) 2835 } 2836 if res == nil { 2837 t.Fatal("result missing") 2838 } 2839 want, err := json.Marshal(tc.want) 2840 if err != nil { 2841 t.Fatalf("failed to encode expected: %v", err) 2842 } 2843 have, err := json.Marshal(result{Hashes: res.Tx.BlobHashes(), Sidecar: res.Tx.BlobTxSidecar()}) 2844 if err != nil { 2845 t.Fatalf("failed to encode computed sidecar: %v", err) 2846 } 2847 if !bytes.Equal(have, want) { 2848 t.Errorf("blob sidecar mismatch. Have: %s, want: %s", have, want) 2849 } 2850 }) 2851 } 2852 } 2853 2854 func argsFromTransaction(tx *types.Transaction, from common.Address) TransactionArgs { 2855 var ( 2856 gas = tx.Gas() 2857 nonce = tx.Nonce() 2858 input = tx.Data() 2859 accessList *types.AccessList 2860 ) 2861 if acl := tx.AccessList(); acl != nil { 2862 accessList = &acl 2863 } 2864 return TransactionArgs{ 2865 From: &from, 2866 To: tx.To(), 2867 Gas: (*hexutil.Uint64)(&gas), 2868 MaxFeePerGas: (*hexutil.Big)(tx.GasFeeCap()), 2869 MaxPriorityFeePerGas: (*hexutil.Big)(tx.GasTipCap()), 2870 Value: (*hexutil.Big)(tx.Value()), 2871 Nonce: (*hexutil.Uint64)(&nonce), 2872 Input: (*hexutil.Bytes)(&input), 2873 ChainID: (*hexutil.Big)(tx.ChainId()), 2874 AccessList: accessList, 2875 BlobFeeCap: (*hexutil.Big)(tx.BlobGasFeeCap()), 2876 BlobHashes: tx.BlobHashes(), 2877 } 2878 } 2879 2880 type account struct { 2881 key *ecdsa.PrivateKey 2882 addr common.Address 2883 } 2884 2885 func newAccounts(n int) (accounts []account) { 2886 for i := 0; i < n; i++ { 2887 key, _ := crypto.GenerateKey() 2888 addr := crypto.PubkeyToAddress(key.PublicKey) 2889 accounts = append(accounts, account{key: key, addr: addr}) 2890 } 2891 slices.SortFunc(accounts, func(a, b account) int { return a.addr.Cmp(b.addr) }) 2892 return accounts 2893 } 2894 2895 func newTestAccount() account { 2896 // testKey is a private key to use for funding a tester account. 2897 key, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 2898 // testAddr is the Ethereum address of the tester account. 2899 addr := crypto.PubkeyToAddress(key.PublicKey) 2900 return account{key: key, addr: addr} 2901 } 2902 2903 func newRPCBalance(balance *big.Int) *hexutil.Big { 2904 rpcBalance := (*hexutil.Big)(balance) 2905 return rpcBalance 2906 } 2907 2908 func hex2Bytes(str string) *hexutil.Bytes { 2909 rpcBytes := hexutil.Bytes(common.FromHex(str)) 2910 return &rpcBytes 2911 } 2912 2913 func newUint64(v uint64) *hexutil.Uint64 { 2914 rpcUint64 := hexutil.Uint64(v) 2915 return &rpcUint64 2916 } 2917 2918 func newBytes(b []byte) *hexutil.Bytes { 2919 rpcBytes := hexutil.Bytes(b) 2920 return &rpcBytes 2921 } 2922 2923 func uint256ToBytes(v *uint256.Int) *hexutil.Bytes { 2924 b := v.Bytes32() 2925 r := hexutil.Bytes(b[:]) 2926 return &r 2927 } 2928 2929 func TestRPCMarshalBlock(t *testing.T) { 2930 t.Parallel() 2931 var ( 2932 txs []*types.Transaction 2933 to = common.BytesToAddress([]byte{0x11}) 2934 ) 2935 for i := uint64(1); i <= 4; i++ { 2936 var tx *types.Transaction 2937 if i%2 == 0 { 2938 tx = types.NewTx(&types.LegacyTx{ 2939 Nonce: i, 2940 GasPrice: big.NewInt(11111), 2941 Gas: 1111, 2942 To: &to, 2943 Value: big.NewInt(111), 2944 Data: []byte{0x11, 0x11, 0x11}, 2945 }) 2946 } else { 2947 tx = types.NewTx(&types.AccessListTx{ 2948 ChainID: big.NewInt(1337), 2949 Nonce: i, 2950 GasPrice: big.NewInt(11111), 2951 Gas: 1111, 2952 To: &to, 2953 Value: big.NewInt(111), 2954 Data: []byte{0x11, 0x11, 0x11}, 2955 }) 2956 } 2957 txs = append(txs, tx) 2958 } 2959 block := types.NewBlock(&types.Header{Number: big.NewInt(100)}, &types.Body{Transactions: txs}, nil, blocktest.NewHasher()) 2960 2961 var testSuite = []struct { 2962 inclTx bool 2963 fullTx bool 2964 want string 2965 }{ 2966 // without txs 2967 { 2968 inclTx: false, 2969 fullTx: false, 2970 want: `{ 2971 "difficulty": "0x0", 2972 "extraData": "0x", 2973 "gasLimit": "0x0", 2974 "gasUsed": "0x0", 2975 "hash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee", 2976 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 2977 "miner": "0x0000000000000000000000000000000000000000", 2978 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 2979 "nonce": "0x0000000000000000", 2980 "number": "0x64", 2981 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 2982 "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", 2983 "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", 2984 "size": "0x296", 2985 "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", 2986 "timestamp": "0x0", 2987 "transactionsRoot": "0x661a9febcfa8f1890af549b874faf9fa274aede26ef489d9db0b25daa569450e", 2988 "uncles": [] 2989 }`, 2990 }, 2991 // only tx hashes 2992 { 2993 inclTx: true, 2994 fullTx: false, 2995 want: `{ 2996 "difficulty": "0x0", 2997 "extraData": "0x", 2998 "gasLimit": "0x0", 2999 "gasUsed": "0x0", 3000 "hash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee", 3001 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 3002 "miner": "0x0000000000000000000000000000000000000000", 3003 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 3004 "nonce": "0x0000000000000000", 3005 "number": "0x64", 3006 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 3007 "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", 3008 "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", 3009 "size": "0x296", 3010 "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", 3011 "timestamp": "0x0", 3012 "transactions": [ 3013 "0x7d39df979e34172322c64983a9ad48302c2b889e55bda35324afecf043a77605", 3014 "0x9bba4c34e57c875ff57ac8d172805a26ae912006985395dc1bdf8f44140a7bf4", 3015 "0x98909ea1ff040da6be56bc4231d484de1414b3c1dac372d69293a4beb9032cb5", 3016 "0x12e1f81207b40c3bdcc13c0ee18f5f86af6d31754d57a0ea1b0d4cfef21abef1" 3017 ], 3018 "transactionsRoot": "0x661a9febcfa8f1890af549b874faf9fa274aede26ef489d9db0b25daa569450e", 3019 "uncles": [] 3020 }`, 3021 }, 3022 // full tx details 3023 { 3024 inclTx: true, 3025 fullTx: true, 3026 want: `{ 3027 "difficulty": "0x0", 3028 "extraData": "0x", 3029 "gasLimit": "0x0", 3030 "gasUsed": "0x0", 3031 "hash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee", 3032 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 3033 "miner": "0x0000000000000000000000000000000000000000", 3034 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 3035 "nonce": "0x0000000000000000", 3036 "number": "0x64", 3037 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 3038 "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", 3039 "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", 3040 "size": "0x296", 3041 "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", 3042 "timestamp": "0x0", 3043 "transactions": [ 3044 { 3045 "blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee", 3046 "blockNumber": "0x64", 3047 "from": "0x0000000000000000000000000000000000000000", 3048 "gas": "0x457", 3049 "gasPrice": "0x2b67", 3050 "hash": "0x7d39df979e34172322c64983a9ad48302c2b889e55bda35324afecf043a77605", 3051 "input": "0x111111", 3052 "nonce": "0x1", 3053 "to": "0x0000000000000000000000000000000000000011", 3054 "transactionIndex": "0x0", 3055 "value": "0x6f", 3056 "type": "0x1", 3057 "accessList": [], 3058 "chainId": "0x539", 3059 "v": "0x0", 3060 "r": "0x0", 3061 "s": "0x0", 3062 "yParity": "0x0" 3063 }, 3064 { 3065 "blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee", 3066 "blockNumber": "0x64", 3067 "from": "0x0000000000000000000000000000000000000000", 3068 "gas": "0x457", 3069 "gasPrice": "0x2b67", 3070 "hash": "0x9bba4c34e57c875ff57ac8d172805a26ae912006985395dc1bdf8f44140a7bf4", 3071 "input": "0x111111", 3072 "nonce": "0x2", 3073 "to": "0x0000000000000000000000000000000000000011", 3074 "transactionIndex": "0x1", 3075 "value": "0x6f", 3076 "type": "0x0", 3077 "chainId": "0x7fffffffffffffee", 3078 "v": "0x0", 3079 "r": "0x0", 3080 "s": "0x0" 3081 }, 3082 { 3083 "blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee", 3084 "blockNumber": "0x64", 3085 "from": "0x0000000000000000000000000000000000000000", 3086 "gas": "0x457", 3087 "gasPrice": "0x2b67", 3088 "hash": "0x98909ea1ff040da6be56bc4231d484de1414b3c1dac372d69293a4beb9032cb5", 3089 "input": "0x111111", 3090 "nonce": "0x3", 3091 "to": "0x0000000000000000000000000000000000000011", 3092 "transactionIndex": "0x2", 3093 "value": "0x6f", 3094 "type": "0x1", 3095 "accessList": [], 3096 "chainId": "0x539", 3097 "v": "0x0", 3098 "r": "0x0", 3099 "s": "0x0", 3100 "yParity": "0x0" 3101 }, 3102 { 3103 "blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee", 3104 "blockNumber": "0x64", 3105 "from": "0x0000000000000000000000000000000000000000", 3106 "gas": "0x457", 3107 "gasPrice": "0x2b67", 3108 "hash": "0x12e1f81207b40c3bdcc13c0ee18f5f86af6d31754d57a0ea1b0d4cfef21abef1", 3109 "input": "0x111111", 3110 "nonce": "0x4", 3111 "to": "0x0000000000000000000000000000000000000011", 3112 "transactionIndex": "0x3", 3113 "value": "0x6f", 3114 "type": "0x0", 3115 "chainId": "0x7fffffffffffffee", 3116 "v": "0x0", 3117 "r": "0x0", 3118 "s": "0x0" 3119 } 3120 ], 3121 "transactionsRoot": "0x661a9febcfa8f1890af549b874faf9fa274aede26ef489d9db0b25daa569450e", 3122 "uncles": [] 3123 }`, 3124 }, 3125 } 3126 3127 for i, tc := range testSuite { 3128 resp := RPCMarshalBlock(block, tc.inclTx, tc.fullTx, params.MainnetChainConfig) 3129 out, err := json.Marshal(resp) 3130 if err != nil { 3131 t.Errorf("test %d: json marshal error: %v", i, err) 3132 continue 3133 } 3134 require.JSONEqf(t, tc.want, string(out), "test %d", i) 3135 } 3136 } 3137 3138 func TestRPCGetBlockOrHeader(t *testing.T) { 3139 t.Parallel() 3140 3141 // Initialize test accounts 3142 var ( 3143 acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 3144 acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") 3145 acc1Addr = crypto.PubkeyToAddress(acc1Key.PublicKey) 3146 acc2Addr = crypto.PubkeyToAddress(acc2Key.PublicKey) 3147 genesis = &core.Genesis{ 3148 Config: params.TestChainConfig, 3149 Alloc: types.GenesisAlloc{ 3150 acc1Addr: {Balance: big.NewInt(params.Ether)}, 3151 acc2Addr: {Balance: big.NewInt(params.Ether)}, 3152 }, 3153 } 3154 genBlocks = 10 3155 signer = types.HomesteadSigner{} 3156 tx = types.NewTx(&types.LegacyTx{ 3157 Nonce: 11, 3158 GasPrice: big.NewInt(11111), 3159 Gas: 1111, 3160 To: &acc2Addr, 3161 Value: big.NewInt(111), 3162 Data: []byte{0x11, 0x11, 0x11}, 3163 }) 3164 withdrawal = &types.Withdrawal{ 3165 Index: 0, 3166 Validator: 1, 3167 Address: common.Address{0x12, 0x34}, 3168 Amount: 10, 3169 } 3170 pending = types.NewBlock(&types.Header{Number: big.NewInt(11), Time: 42}, &types.Body{Transactions: types.Transactions{tx}, Withdrawals: types.Withdrawals{withdrawal}}, nil, blocktest.NewHasher()) 3171 ) 3172 backend := newTestBackend(t, genBlocks, genesis, ethash.NewFaker(), func(i int, b *core.BlockGen) { 3173 // Transfer from account[0] to account[1] 3174 // value: 1000 wei 3175 // fee: 0 wei 3176 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) 3177 b.AddTx(tx) 3178 }) 3179 backend.setPendingBlock(pending) 3180 api := NewBlockChainAPI(backend) 3181 blockHashes := make([]common.Hash, genBlocks+1) 3182 ctx := context.Background() 3183 for i := 0; i <= genBlocks; i++ { 3184 header, err := backend.HeaderByNumber(ctx, rpc.BlockNumber(i)) 3185 if err != nil { 3186 t.Errorf("failed to get block: %d err: %v", i, err) 3187 } 3188 blockHashes[i] = header.Hash() 3189 } 3190 pendingHash := pending.Hash() 3191 3192 var testSuite = []struct { 3193 blockNumber rpc.BlockNumber 3194 blockHash *common.Hash 3195 fullTx bool 3196 reqHeader bool 3197 file string 3198 expectErr error 3199 }{ 3200 // 0. latest header 3201 { 3202 blockNumber: rpc.LatestBlockNumber, 3203 reqHeader: true, 3204 file: "tag-latest", 3205 }, 3206 // 1. genesis header 3207 { 3208 blockNumber: rpc.BlockNumber(0), 3209 reqHeader: true, 3210 file: "number-0", 3211 }, 3212 // 2. #1 header 3213 { 3214 blockNumber: rpc.BlockNumber(1), 3215 reqHeader: true, 3216 file: "number-1", 3217 }, 3218 // 3. latest-1 header 3219 { 3220 blockNumber: rpc.BlockNumber(9), 3221 reqHeader: true, 3222 file: "number-latest-1", 3223 }, 3224 // 4. latest+1 header 3225 { 3226 blockNumber: rpc.BlockNumber(11), 3227 reqHeader: true, 3228 file: "number-latest+1", 3229 }, 3230 // 5. pending header 3231 { 3232 blockNumber: rpc.PendingBlockNumber, 3233 reqHeader: true, 3234 file: "tag-pending", 3235 }, 3236 // 6. latest block 3237 { 3238 blockNumber: rpc.LatestBlockNumber, 3239 file: "tag-latest", 3240 }, 3241 // 7. genesis block 3242 { 3243 blockNumber: rpc.BlockNumber(0), 3244 file: "number-0", 3245 }, 3246 // 8. #1 block 3247 { 3248 blockNumber: rpc.BlockNumber(1), 3249 file: "number-1", 3250 }, 3251 // 9. latest-1 block 3252 { 3253 blockNumber: rpc.BlockNumber(9), 3254 fullTx: true, 3255 file: "number-latest-1", 3256 }, 3257 // 10. latest+1 block 3258 { 3259 blockNumber: rpc.BlockNumber(11), 3260 fullTx: true, 3261 file: "number-latest+1", 3262 }, 3263 // 11. pending block 3264 { 3265 blockNumber: rpc.PendingBlockNumber, 3266 file: "tag-pending", 3267 }, 3268 // 12. pending block + fullTx 3269 { 3270 blockNumber: rpc.PendingBlockNumber, 3271 fullTx: true, 3272 file: "tag-pending-fullTx", 3273 }, 3274 // 13. latest header by hash 3275 { 3276 blockHash: &blockHashes[len(blockHashes)-1], 3277 reqHeader: true, 3278 file: "hash-latest", 3279 }, 3280 // 14. genesis header by hash 3281 { 3282 blockHash: &blockHashes[0], 3283 reqHeader: true, 3284 file: "hash-0", 3285 }, 3286 // 15. #1 header 3287 { 3288 blockHash: &blockHashes[1], 3289 reqHeader: true, 3290 file: "hash-1", 3291 }, 3292 // 16. latest-1 header 3293 { 3294 blockHash: &blockHashes[len(blockHashes)-2], 3295 reqHeader: true, 3296 file: "hash-latest-1", 3297 }, 3298 // 17. empty hash 3299 { 3300 blockHash: &common.Hash{}, 3301 reqHeader: true, 3302 file: "hash-empty", 3303 }, 3304 // 18. pending hash 3305 { 3306 blockHash: &pendingHash, 3307 reqHeader: true, 3308 file: `hash-pending`, 3309 }, 3310 // 19. latest block 3311 { 3312 blockHash: &blockHashes[len(blockHashes)-1], 3313 file: "hash-latest", 3314 }, 3315 // 20. genesis block 3316 { 3317 blockHash: &blockHashes[0], 3318 file: "hash-genesis", 3319 }, 3320 // 21. #1 block 3321 { 3322 blockHash: &blockHashes[1], 3323 file: "hash-1", 3324 }, 3325 // 22. latest-1 block 3326 { 3327 blockHash: &blockHashes[len(blockHashes)-2], 3328 fullTx: true, 3329 file: "hash-latest-1-fullTx", 3330 }, 3331 // 23. empty hash + body 3332 { 3333 blockHash: &common.Hash{}, 3334 fullTx: true, 3335 file: "hash-empty-fullTx", 3336 }, 3337 // 24. pending block 3338 { 3339 blockHash: &pendingHash, 3340 file: `hash-pending`, 3341 }, 3342 // 25. pending block + fullTx 3343 { 3344 blockHash: &pendingHash, 3345 fullTx: true, 3346 file: "hash-pending-fullTx", 3347 }, 3348 } 3349 3350 for i, tt := range testSuite { 3351 var ( 3352 result map[string]interface{} 3353 err error 3354 rpc string 3355 ) 3356 if tt.blockHash != nil { 3357 if tt.reqHeader { 3358 result = api.GetHeaderByHash(context.Background(), *tt.blockHash) 3359 rpc = "eth_getHeaderByHash" 3360 } else { 3361 result, err = api.GetBlockByHash(context.Background(), *tt.blockHash, tt.fullTx) 3362 rpc = "eth_getBlockByHash" 3363 } 3364 } else { 3365 if tt.reqHeader { 3366 result, err = api.GetHeaderByNumber(context.Background(), tt.blockNumber) 3367 rpc = "eth_getHeaderByNumber" 3368 } else { 3369 result, err = api.GetBlockByNumber(context.Background(), tt.blockNumber, tt.fullTx) 3370 rpc = "eth_getBlockByNumber" 3371 } 3372 } 3373 if tt.expectErr != nil { 3374 if err == nil { 3375 t.Errorf("test %d: want error %v, have nothing", i, tt.expectErr) 3376 continue 3377 } 3378 if !errors.Is(err, tt.expectErr) { 3379 t.Errorf("test %d: error mismatch, want %v, have %v", i, tt.expectErr, err) 3380 } 3381 continue 3382 } 3383 if err != nil { 3384 t.Errorf("test %d: want no error, have %v", i, err) 3385 continue 3386 } 3387 3388 testRPCResponseWithFile(t, i, result, rpc, tt.file) 3389 } 3390 } 3391 3392 func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Hash) { 3393 config := *params.MergedTestChainConfig 3394 var ( 3395 acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 3396 acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") 3397 acc1Addr = crypto.PubkeyToAddress(acc1Key.PublicKey) 3398 acc2Addr = crypto.PubkeyToAddress(acc2Key.PublicKey) 3399 contract = common.HexToAddress("0000000000000000000000000000000000031ec7") 3400 genesis = &core.Genesis{ 3401 Config: &config, 3402 ExcessBlobGas: new(uint64), 3403 BlobGasUsed: new(uint64), 3404 Alloc: types.GenesisAlloc{ 3405 acc1Addr: {Balance: big.NewInt(params.Ether)}, 3406 acc2Addr: {Balance: big.NewInt(params.Ether)}, 3407 // // SPDX-License-Identifier: GPL-3.0 3408 // pragma solidity >=0.7.0 <0.9.0; 3409 // 3410 // contract Token { 3411 // event Transfer(address indexed from, address indexed to, uint256 value); 3412 // function transfer(address to, uint256 value) public returns (bool) { 3413 // emit Transfer(msg.sender, to, value); 3414 // return true; 3415 // } 3416 // } 3417 contract: {Balance: big.NewInt(params.Ether), Code: common.FromHex("0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063a9059cbb14610030575b600080fd5b61004a6004803603810190610045919061016a565b610060565b60405161005791906101c5565b60405180910390f35b60008273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516100bf91906101ef565b60405180910390a36001905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610101826100d6565b9050919050565b610111816100f6565b811461011c57600080fd5b50565b60008135905061012e81610108565b92915050565b6000819050919050565b61014781610134565b811461015257600080fd5b50565b6000813590506101648161013e565b92915050565b60008060408385031215610181576101806100d1565b5b600061018f8582860161011f565b92505060206101a085828601610155565b9150509250929050565b60008115159050919050565b6101bf816101aa565b82525050565b60006020820190506101da60008301846101b6565b92915050565b6101e981610134565b82525050565b600060208201905061020460008301846101e0565b9291505056fea2646970667358221220b469033f4b77b9565ee84e0a2f04d496b18160d26034d54f9487e57788fd36d564736f6c63430008120033")}, 3418 }, 3419 } 3420 signer = types.LatestSignerForChainID(params.TestChainConfig.ChainID) 3421 txHashes = make([]common.Hash, genBlocks) 3422 ) 3423 3424 backend := newTestBackend(t, genBlocks, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) { 3425 var ( 3426 tx *types.Transaction 3427 err error 3428 ) 3429 b.SetPoS() 3430 switch i { 3431 case 0: 3432 // transfer 1000wei 3433 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) 3434 case 1: 3435 // create contract 3436 tx, err = types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: nil, Gas: 53100, GasPrice: b.BaseFee(), Data: common.FromHex("0x60806040")}), signer, acc1Key) 3437 case 2: 3438 // with logs 3439 // transfer(address to, uint256 value) 3440 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:]) 3441 tx, err = types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &contract, Gas: 60000, GasPrice: b.BaseFee(), Data: common.FromHex(data)}), signer, acc1Key) 3442 case 3: 3443 // dynamic fee with logs 3444 // transfer(address to, uint256 value) 3445 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:]) 3446 fee := big.NewInt(500) 3447 fee.Add(fee, b.BaseFee()) 3448 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) 3449 case 4: 3450 // access list with contract create 3451 accessList := types.AccessList{{ 3452 Address: contract, 3453 StorageKeys: []common.Hash{{0}}, 3454 }} 3455 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) 3456 case 5: 3457 // blob tx 3458 fee := big.NewInt(500) 3459 fee.Add(fee, b.BaseFee()) 3460 tx, err = types.SignTx(types.NewTx(&types.BlobTx{ 3461 Nonce: uint64(i), 3462 GasTipCap: uint256.NewInt(1), 3463 GasFeeCap: uint256.MustFromBig(fee), 3464 Gas: params.TxGas, 3465 To: acc2Addr, 3466 BlobFeeCap: uint256.NewInt(1), 3467 BlobHashes: []common.Hash{{1}}, 3468 Value: new(uint256.Int), 3469 }), signer, acc1Key) 3470 } 3471 if err != nil { 3472 t.Errorf("failed to sign tx: %v", err) 3473 } 3474 if tx != nil { 3475 b.AddTx(tx) 3476 txHashes[i] = tx.Hash() 3477 } 3478 }) 3479 return backend, txHashes 3480 } 3481 3482 func TestRPCGetTransactionReceipt(t *testing.T) { 3483 t.Parallel() 3484 3485 var ( 3486 backend, txHashes = setupReceiptBackend(t, 6) 3487 api = NewTransactionAPI(backend, new(AddrLocker)) 3488 ) 3489 3490 var testSuite = []struct { 3491 txHash common.Hash 3492 file string 3493 }{ 3494 // 0. normal success 3495 { 3496 txHash: txHashes[0], 3497 file: "normal-transfer-tx", 3498 }, 3499 // 1. create contract 3500 { 3501 txHash: txHashes[1], 3502 file: "create-contract-tx", 3503 }, 3504 // 2. with logs success 3505 { 3506 txHash: txHashes[2], 3507 file: "with-logs", 3508 }, 3509 // 3. dynamic tx with logs success 3510 { 3511 txHash: txHashes[3], 3512 file: `dynamic-tx-with-logs`, 3513 }, 3514 // 4. access list tx with create contract 3515 { 3516 txHash: txHashes[4], 3517 file: "create-contract-with-access-list", 3518 }, 3519 // 5. txhash empty 3520 { 3521 txHash: common.Hash{}, 3522 file: "txhash-empty", 3523 }, 3524 // 6. txhash not found 3525 { 3526 txHash: common.HexToHash("deadbeef"), 3527 file: "txhash-notfound", 3528 }, 3529 // 7. blob tx 3530 { 3531 txHash: txHashes[5], 3532 file: "blob-tx", 3533 }, 3534 } 3535 3536 for i, tt := range testSuite { 3537 var ( 3538 result interface{} 3539 err error 3540 ) 3541 result, err = api.GetTransactionReceipt(context.Background(), tt.txHash) 3542 if err != nil { 3543 t.Errorf("test %d: want no error, have %v", i, err) 3544 continue 3545 } 3546 testRPCResponseWithFile(t, i, result, "eth_getTransactionReceipt", tt.file) 3547 } 3548 } 3549 3550 func TestRPCGetBlockReceipts(t *testing.T) { 3551 t.Parallel() 3552 3553 var ( 3554 genBlocks = 6 3555 backend, _ = setupReceiptBackend(t, genBlocks) 3556 api = NewBlockChainAPI(backend) 3557 ) 3558 blockHashes := make([]common.Hash, genBlocks+1) 3559 ctx := context.Background() 3560 for i := 0; i <= genBlocks; i++ { 3561 header, err := backend.HeaderByNumber(ctx, rpc.BlockNumber(i)) 3562 if err != nil { 3563 t.Errorf("failed to get block: %d err: %v", i, err) 3564 } 3565 blockHashes[i] = header.Hash() 3566 } 3567 3568 var testSuite = []struct { 3569 test rpc.BlockNumberOrHash 3570 file string 3571 }{ 3572 // 0. block without any txs(hash) 3573 { 3574 test: rpc.BlockNumberOrHashWithHash(blockHashes[0], false), 3575 file: "number-0", 3576 }, 3577 // 1. block without any txs(number) 3578 { 3579 test: rpc.BlockNumberOrHashWithNumber(0), 3580 file: "number-1", 3581 }, 3582 // 2. earliest tag 3583 { 3584 test: rpc.BlockNumberOrHashWithNumber(rpc.EarliestBlockNumber), 3585 file: "tag-earliest", 3586 }, 3587 // 3. latest tag 3588 { 3589 test: rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber), 3590 file: "tag-latest", 3591 }, 3592 // 4. block with legacy transfer tx(hash) 3593 { 3594 test: rpc.BlockNumberOrHashWithHash(blockHashes[1], false), 3595 file: "block-with-legacy-transfer-tx", 3596 }, 3597 // 5. block with contract create tx(number) 3598 { 3599 test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(2)), 3600 file: "block-with-contract-create-tx", 3601 }, 3602 // 6. block with legacy contract call tx(hash) 3603 { 3604 test: rpc.BlockNumberOrHashWithHash(blockHashes[3], false), 3605 file: "block-with-legacy-contract-call-tx", 3606 }, 3607 // 7. block with dynamic fee tx(number) 3608 { 3609 test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(4)), 3610 file: "block-with-dynamic-fee-tx", 3611 }, 3612 // 8. block is empty 3613 { 3614 test: rpc.BlockNumberOrHashWithHash(common.Hash{}, false), 3615 file: "hash-empty", 3616 }, 3617 // 9. block is not found 3618 { 3619 test: rpc.BlockNumberOrHashWithHash(common.HexToHash("deadbeef"), false), 3620 file: "hash-notfound", 3621 }, 3622 // 10. block is not found 3623 { 3624 test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(genBlocks + 1)), 3625 file: "block-notfound", 3626 }, 3627 // 11. block with blob tx 3628 { 3629 test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(6)), 3630 file: "block-with-blob-tx", 3631 }, 3632 } 3633 3634 for i, tt := range testSuite { 3635 var ( 3636 result interface{} 3637 err error 3638 ) 3639 result, err = api.GetBlockReceipts(context.Background(), tt.test) 3640 if err != nil { 3641 t.Errorf("test %d: want no error, have %v", i, err) 3642 continue 3643 } 3644 testRPCResponseWithFile(t, i, result, "eth_getBlockReceipts", tt.file) 3645 } 3646 } 3647 3648 func testRPCResponseWithFile(t *testing.T, testid int, result interface{}, rpc string, file string) { 3649 data, err := json.MarshalIndent(result, "", " ") 3650 if err != nil { 3651 t.Errorf("test %d: json marshal error", testid) 3652 return 3653 } 3654 outputFile := filepath.Join("testdata", fmt.Sprintf("%s-%s.json", rpc, file)) 3655 if os.Getenv("WRITE_TEST_FILES") != "" { 3656 os.WriteFile(outputFile, data, 0644) 3657 } 3658 want, err := os.ReadFile(outputFile) 3659 if err != nil { 3660 t.Fatalf("error reading expected test file: %s output: %v", outputFile, err) 3661 } 3662 require.JSONEqf(t, string(want), string(data), "test %d: json not match, want: %s, have: %s", testid, string(want), string(data)) 3663 } 3664 3665 func addressToHash(a common.Address) common.Hash { 3666 return common.BytesToHash(a.Bytes()) 3667 } 3668 3669 func TestCreateAccessListWithStateOverrides(t *testing.T) { 3670 // Initialize test backend 3671 genesis := &core.Genesis{ 3672 Config: params.TestChainConfig, 3673 Alloc: types.GenesisAlloc{ 3674 common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7"): {Balance: big.NewInt(1000000000000000000)}, 3675 }, 3676 } 3677 backend := newTestBackend(t, 1, genesis, ethash.NewFaker(), nil) 3678 3679 // Create a new BlockChainAPI instance 3680 api := NewBlockChainAPI(backend) 3681 3682 // Create test contract code - a simple storage contract 3683 // 3684 // SPDX-License-Identifier: MIT 3685 // pragma solidity ^0.8.0; 3686 // 3687 // contract SimpleStorage { 3688 // uint256 private value; 3689 // 3690 // function retrieve() public view returns (uint256) { 3691 // return value; 3692 // } 3693 // } 3694 var ( 3695 contractCode = hexutil.Bytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80632e64cec114602d575b600080fd5b60336047565b604051603e91906067565b60405180910390f35b60008054905090565b6000819050919050565b6061816050565b82525050565b6000602082019050607a6000830184605a565b9291505056")) 3696 // Create state overrides with more complete state 3697 contractAddr = common.HexToAddress("0x1234567890123456789012345678901234567890") 3698 nonce = hexutil.Uint64(1) 3699 overrides = &override.StateOverride{ 3700 contractAddr: override.OverrideAccount{ 3701 Code: &contractCode, 3702 Balance: (*hexutil.Big)(big.NewInt(1000000000000000000)), 3703 Nonce: &nonce, 3704 State: map[common.Hash]common.Hash{ 3705 common.Hash{}: common.HexToHash("0x000000000000000000000000000000000000000000000000000000000000002a"), 3706 }, 3707 }, 3708 } 3709 ) 3710 3711 // Create transaction arguments with gas and value 3712 var ( 3713 from = common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") 3714 data = hexutil.Bytes(common.Hex2Bytes("2e64cec1")) // retrieve() 3715 gas = hexutil.Uint64(100000) 3716 args = TransactionArgs{ 3717 From: &from, 3718 To: &contractAddr, 3719 Data: &data, 3720 Gas: &gas, 3721 Value: new(hexutil.Big), 3722 } 3723 ) 3724 // Call CreateAccessList 3725 result, err := api.CreateAccessList(context.Background(), args, nil, overrides) 3726 if err != nil { 3727 t.Fatalf("Failed to create access list: %v", err) 3728 } 3729 if err != nil || result == nil { 3730 t.Fatalf("Failed to create access list: %v", err) 3731 } 3732 require.NotNil(t, result.Accesslist) 3733 3734 // Verify access list contains the contract address and storage slot 3735 expected := &types.AccessList{{ 3736 Address: contractAddr, 3737 StorageKeys: []common.Hash{{}}, 3738 }} 3739 require.Equal(t, expected, result.Accesslist) 3740 }