github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/core/vm/runtime/runtime_test.go (about) 1 // Copyright 2015 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 runtime 18 19 import ( 20 "fmt" 21 "math/big" 22 "os" 23 "strings" 24 "testing" 25 "time" 26 27 "github.com/scroll-tech/go-ethereum/accounts/abi" 28 "github.com/scroll-tech/go-ethereum/common" 29 "github.com/scroll-tech/go-ethereum/consensus" 30 "github.com/scroll-tech/go-ethereum/core" 31 "github.com/scroll-tech/go-ethereum/core/asm" 32 "github.com/scroll-tech/go-ethereum/core/rawdb" 33 "github.com/scroll-tech/go-ethereum/core/state" 34 "github.com/scroll-tech/go-ethereum/core/types" 35 "github.com/scroll-tech/go-ethereum/core/vm" 36 "github.com/scroll-tech/go-ethereum/eth/tracers" 37 "github.com/scroll-tech/go-ethereum/params" 38 39 // force-load js tracers to trigger registration 40 _ "github.com/scroll-tech/go-ethereum/eth/tracers/js" 41 ) 42 43 func TestDefaults(t *testing.T) { 44 cfg := new(Config) 45 setDefaults(cfg) 46 47 if cfg.Difficulty == nil { 48 t.Error("expected difficulty to be non nil") 49 } 50 51 if cfg.Time == nil { 52 t.Error("expected time to be non nil") 53 } 54 if cfg.GasLimit == 0 { 55 t.Error("didn't expect gaslimit to be zero") 56 } 57 if cfg.GasPrice == nil { 58 t.Error("expected time to be non nil") 59 } 60 if cfg.Value == nil { 61 t.Error("expected time to be non nil") 62 } 63 if cfg.GetHashFn == nil { 64 t.Error("expected time to be non nil") 65 } 66 if cfg.BlockNumber == nil { 67 t.Error("expected block number to be non nil") 68 } 69 } 70 71 func TestEVM(t *testing.T) { 72 defer func() { 73 if r := recover(); r != nil { 74 t.Fatalf("crashed with: %v", r) 75 } 76 }() 77 78 Execute([]byte{ 79 byte(vm.DIFFICULTY), 80 byte(vm.TIMESTAMP), 81 byte(vm.GASLIMIT), 82 byte(vm.PUSH1), 83 byte(vm.ORIGIN), 84 byte(vm.BLOCKHASH), 85 byte(vm.COINBASE), 86 }, nil, nil) 87 } 88 89 func TestDifficulty(t *testing.T) { 90 ret, _, err := Execute([]byte{ 91 byte(vm.DIFFICULTY), 92 byte(vm.PUSH1), 0, 93 byte(vm.MSTORE), 94 byte(vm.PUSH1), 32, 95 byte(vm.PUSH1), 0, 96 byte(vm.RETURN), 97 }, nil, &Config{Difficulty: big.NewInt(1)}) 98 99 if err != nil { 100 t.Fatal("didn't expect error", err) 101 } 102 103 num := new(big.Int).SetBytes(ret) 104 if num.Cmp(big.NewInt(0)) != 0 { 105 t.Error("Expected 0, got", num) 106 } 107 } 108 109 func TestExecute(t *testing.T) { 110 ret, _, err := Execute([]byte{ 111 byte(vm.PUSH1), 10, 112 byte(vm.PUSH1), 0, 113 byte(vm.MSTORE), 114 byte(vm.PUSH1), 32, 115 byte(vm.PUSH1), 0, 116 byte(vm.RETURN), 117 }, nil, nil) 118 if err != nil { 119 t.Fatal("didn't expect error", err) 120 } 121 122 num := new(big.Int).SetBytes(ret) 123 if num.Cmp(big.NewInt(10)) != 0 { 124 t.Error("Expected 10, got", num) 125 } 126 } 127 128 func TestCall(t *testing.T) { 129 state, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) 130 address := common.HexToAddress("0x0a") 131 state.SetCode(address, []byte{ 132 byte(vm.PUSH1), 10, 133 byte(vm.PUSH1), 0, 134 byte(vm.MSTORE), 135 byte(vm.PUSH1), 32, 136 byte(vm.PUSH1), 0, 137 byte(vm.RETURN), 138 }) 139 140 ret, _, err := Call(address, nil, &Config{State: state}) 141 if err != nil { 142 t.Fatal("didn't expect error", err) 143 } 144 145 num := new(big.Int).SetBytes(ret) 146 if num.Cmp(big.NewInt(10)) != 0 { 147 t.Error("Expected 10, got", num) 148 } 149 } 150 151 func BenchmarkCall(b *testing.B) { 152 var definition = `[{"constant":true,"inputs":[],"name":"seller","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[],"name":"abort","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"value","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[],"name":"refund","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"buyer","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[],"name":"confirmReceived","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"state","outputs":[{"name":"","type":"uint8"}],"type":"function"},{"constant":false,"inputs":[],"name":"confirmPurchase","outputs":[],"type":"function"},{"inputs":[],"type":"constructor"},{"anonymous":false,"inputs":[],"name":"Aborted","type":"event"},{"anonymous":false,"inputs":[],"name":"PurchaseConfirmed","type":"event"},{"anonymous":false,"inputs":[],"name":"ItemReceived","type":"event"},{"anonymous":false,"inputs":[],"name":"Refunded","type":"event"}]` 153 154 var code = common.Hex2Bytes("6060604052361561006c5760e060020a600035046308551a53811461007457806335a063b4146100865780633fa4f245146100a6578063590e1ae3146100af5780637150d8ae146100cf57806373fac6f0146100e1578063c19d93fb146100fe578063d696069714610112575b610131610002565b610133600154600160a060020a031681565b610131600154600160a060020a0390811633919091161461015057610002565b61014660005481565b610131600154600160a060020a039081163391909116146102d557610002565b610133600254600160a060020a031681565b610131600254600160a060020a0333811691161461023757610002565b61014660025460ff60a060020a9091041681565b61013160025460009060ff60a060020a9091041681146101cc57610002565b005b600160a060020a03166060908152602090f35b6060908152602090f35b60025460009060a060020a900460ff16811461016b57610002565b600154600160a060020a03908116908290301631606082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517f72c874aeff0b183a56e2b79c71b46e1aed4dee5e09862134b8821ba2fddbf8bf9250a150565b80546002023414806101dd57610002565b6002805460a060020a60ff021973ffffffffffffffffffffffffffffffffffffffff1990911633171660a060020a1790557fd5d55c8a68912e9a110618df8d5e2e83b8d83211c57a8ddd1203df92885dc881826060a15050565b60025460019060a060020a900460ff16811461025257610002565b60025460008054600160a060020a0390921691606082818181858883f150508354604051600160a060020a0391821694503090911631915082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517fe89152acd703c9d8c7d28829d443260b411454d45394e7995815140c8cbcbcf79250a150565b60025460019060a060020a900460ff1681146102f057610002565b6002805460008054600160a060020a0390921692909102606082818181858883f150508354604051600160a060020a0391821694503090911631915082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517f8616bbbbad963e4e65b1366f1d75dfb63f9e9704bbbf91fb01bec70849906cf79250a15056") 155 156 abi, err := abi.JSON(strings.NewReader(definition)) 157 if err != nil { 158 b.Fatal(err) 159 } 160 161 cpurchase, err := abi.Pack("confirmPurchase") 162 if err != nil { 163 b.Fatal(err) 164 } 165 creceived, err := abi.Pack("confirmReceived") 166 if err != nil { 167 b.Fatal(err) 168 } 169 refund, err := abi.Pack("refund") 170 if err != nil { 171 b.Fatal(err) 172 } 173 174 b.ResetTimer() 175 for i := 0; i < b.N; i++ { 176 for j := 0; j < 400; j++ { 177 Execute(code, cpurchase, nil) 178 Execute(code, creceived, nil) 179 Execute(code, refund, nil) 180 } 181 } 182 } 183 func benchmarkEVM_Create(bench *testing.B, code string) { 184 var ( 185 statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) 186 sender = common.BytesToAddress([]byte("sender")) 187 receiver = common.BytesToAddress([]byte("receiver")) 188 ) 189 190 statedb.CreateAccount(sender) 191 statedb.SetCode(receiver, common.FromHex(code)) 192 runtimeConfig := Config{ 193 Origin: sender, 194 State: statedb, 195 GasLimit: 10000000, 196 Difficulty: big.NewInt(0x200000), 197 Time: new(big.Int).SetUint64(0), 198 Coinbase: common.Address{}, 199 BlockNumber: new(big.Int).SetUint64(1), 200 ChainConfig: ¶ms.ChainConfig{ 201 ChainID: big.NewInt(1), 202 HomesteadBlock: new(big.Int), 203 ByzantiumBlock: new(big.Int), 204 ConstantinopleBlock: new(big.Int), 205 DAOForkBlock: new(big.Int), 206 DAOForkSupport: false, 207 EIP150Block: new(big.Int), 208 EIP155Block: new(big.Int), 209 EIP158Block: new(big.Int), 210 }, 211 EVMConfig: vm.Config{}, 212 } 213 // Warm up the intpools and stuff 214 bench.ResetTimer() 215 for i := 0; i < bench.N; i++ { 216 Call(receiver, []byte{}, &runtimeConfig) 217 } 218 bench.StopTimer() 219 } 220 221 func BenchmarkEVM_CREATE_500(bench *testing.B) { 222 // initcode size 500K, repeatedly calls CREATE and then modifies the mem contents 223 benchmarkEVM_Create(bench, "5b6207a120600080f0600152600056") 224 } 225 func BenchmarkEVM_CREATE2_500(bench *testing.B) { 226 // initcode size 500K, repeatedly calls CREATE2 and then modifies the mem contents 227 benchmarkEVM_Create(bench, "5b586207a120600080f5600152600056") 228 } 229 func BenchmarkEVM_CREATE_1200(bench *testing.B) { 230 // initcode size 1200K, repeatedly calls CREATE and then modifies the mem contents 231 benchmarkEVM_Create(bench, "5b62124f80600080f0600152600056") 232 } 233 func BenchmarkEVM_CREATE2_1200(bench *testing.B) { 234 // initcode size 1200K, repeatedly calls CREATE2 and then modifies the mem contents 235 benchmarkEVM_Create(bench, "5b5862124f80600080f5600152600056") 236 } 237 238 func fakeHeader(n uint64, parentHash common.Hash) *types.Header { 239 header := types.Header{ 240 Coinbase: common.HexToAddress("0x00000000000000000000000000000000deadbeef"), 241 Number: big.NewInt(int64(n)), 242 ParentHash: parentHash, 243 Time: 1000, 244 Nonce: types.BlockNonce{0x1}, 245 Extra: []byte{}, 246 Difficulty: big.NewInt(0), 247 GasLimit: 100000, 248 } 249 return &header 250 } 251 252 type dummyChain struct { 253 counter int 254 } 255 256 // Engine retrieves the chain's consensus engine. 257 func (d *dummyChain) Engine() consensus.Engine { 258 return nil 259 } 260 261 // GetHeader returns the hash corresponding to their hash. 262 func (d *dummyChain) GetHeader(h common.Hash, n uint64) *types.Header { 263 d.counter++ 264 parentHash := common.Hash{} 265 s := common.LeftPadBytes(big.NewInt(int64(n-1)).Bytes(), 32) 266 copy(parentHash[:], s) 267 268 //parentHash := common.Hash{byte(n - 1)} 269 //fmt.Printf("GetHeader(%x, %d) => header with parent %x\n", h, n, parentHash) 270 return fakeHeader(n, parentHash) 271 } 272 273 // TestBlockhash tests the blockhash operation. It's a bit special, since it internally 274 // requires access to a chain reader. 275 func TestBlockhash(t *testing.T) { 276 // Current head 277 n := uint64(1000) 278 parentHash := common.Hash{} 279 s := common.LeftPadBytes(big.NewInt(int64(n-1)).Bytes(), 32) 280 copy(parentHash[:], s) 281 header := fakeHeader(n, parentHash) 282 283 // This is the contract we're using. It requests the blockhash for current num (should be all zeroes), 284 // then iteratively fetches all blockhashes back to n-260. 285 // It returns 286 // 1. the first (should be zero) 287 // 2. the second (should be the parent hash) 288 // 3. the last non-zero hash 289 // By making the chain reader return hashes which correlate to the number, we can 290 // verify that it obtained the right hashes where it should 291 292 /* 293 294 pragma solidity ^0.5.3; 295 contract Hasher{ 296 297 function test() public view returns (bytes32, bytes32, bytes32){ 298 uint256 x = block.number; 299 bytes32 first; 300 bytes32 last; 301 bytes32 zero; 302 zero = blockhash(x); // Should be zeroes 303 first = blockhash(x-1); 304 for(uint256 i = 2 ; i < 260; i++){ 305 bytes32 hash = blockhash(x - i); 306 if (uint256(hash) != 0){ 307 last = hash; 308 } 309 } 310 return (zero, first, last); 311 } 312 } 313 314 */ 315 // The contract above 316 data := common.Hex2Bytes("6080604052348015600f57600080fd5b50600436106045576000357c010000000000000000000000000000000000000000000000000000000090048063f8a8fd6d14604a575b600080fd5b60506074565b60405180848152602001838152602001828152602001935050505060405180910390f35b600080600080439050600080600083409050600184034092506000600290505b61010481101560c35760008186034090506000816001900414151560b6578093505b5080806001019150506094565b508083839650965096505050505090919256fea165627a7a72305820462d71b510c1725ff35946c20b415b0d50b468ea157c8c77dff9466c9cb85f560029") 317 // The method call to 'test()' 318 input := common.Hex2Bytes("f8a8fd6d") 319 chain := &dummyChain{} 320 ret, _, err := Execute(data, input, &Config{ 321 GetHashFn: core.GetHashFn(header, chain), 322 BlockNumber: new(big.Int).Set(header.Number), 323 }) 324 if err != nil { 325 t.Fatalf("expected no error, got %v", err) 326 } 327 if len(ret) != 96 { 328 t.Fatalf("expected returndata to be 96 bytes, got %d", len(ret)) 329 } 330 331 zero := new(big.Int).SetBytes(ret[0:32]) 332 first := new(big.Int).SetBytes(ret[32:64]) 333 last := new(big.Int).SetBytes(ret[64:96]) 334 if zero.BitLen() != 0 { 335 t.Fatalf("expected zeroes, got %x", ret[0:32]) 336 } 337 firstExpectedHash := new(big.Int) 338 firstExpectedHash.SetString("13215081625009140218242111988507489764601005198286886925088730931502473149599", 10) 339 if first.Uint64() != firstExpectedHash.Uint64() { 340 t.Fatalf("first hash should be 13215081625009140218242111988507489764601005198286886925088730931502473149599, got %d (%x)", first, ret[32:64]) 341 } 342 lastExpectedHash := new(big.Int) 343 lastExpectedHash.SetString("2851160567348483005169712516804956111111231427377973738952179767509712807467", 10) 344 if last.Uint64() != lastExpectedHash.Uint64() { 345 t.Fatalf("last hash should be 2851160567348483005169712516804956111111231427377973738952179767509712807467, got %d (%x)", last, ret[64:96]) 346 } 347 if exp, got := 0, chain.counter; exp != got { 348 t.Errorf("suboptimal; too much chain iteration, expected %d, got %d", exp, got) 349 } 350 } 351 352 type stepCounter struct { 353 inner *vm.JSONLogger 354 steps int 355 } 356 357 func (s *stepCounter) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { 358 } 359 360 func (s *stepCounter) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { 361 } 362 363 func (s *stepCounter) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {} 364 365 func (s *stepCounter) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { 366 s.steps++ 367 // Enable this for more output 368 //s.inner.CaptureState(env, pc, op, gas, cost, memory, stack, rStack, contract, depth, err) 369 } 370 371 // benchmarkNonModifyingCode benchmarks code, but if the code modifies the 372 // state, this should not be used, since it does not reset the state between runs. 373 func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode string, b *testing.B) { 374 cfg := new(Config) 375 setDefaults(cfg) 376 cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) 377 cfg.GasLimit = gas 378 if len(tracerCode) > 0 { 379 tracer, err := tracers.New(tracerCode, new(tracers.Context)) 380 if err != nil { 381 b.Fatal(err) 382 } 383 cfg.EVMConfig = vm.Config{ 384 Debug: true, 385 Tracer: tracer, 386 } 387 } 388 var ( 389 destination = common.BytesToAddress([]byte("contract")) 390 vmenv = NewEnv(cfg) 391 sender = vm.AccountRef(cfg.Origin) 392 ) 393 cfg.State.CreateAccount(destination) 394 eoa := common.HexToAddress("E0") 395 { 396 cfg.State.CreateAccount(eoa) 397 cfg.State.SetNonce(eoa, 100) 398 } 399 reverting := common.HexToAddress("EE") 400 { 401 cfg.State.CreateAccount(reverting) 402 cfg.State.SetCode(reverting, []byte{ 403 byte(vm.PUSH1), 0x00, 404 byte(vm.PUSH1), 0x00, 405 byte(vm.REVERT), 406 }) 407 } 408 409 //cfg.State.CreateAccount(cfg.Origin) 410 // set the receiver's (the executing contract) code for execution. 411 cfg.State.SetCode(destination, code) 412 vmenv.Call(sender, destination, nil, gas, cfg.Value) 413 414 b.Run(name, func(b *testing.B) { 415 b.ReportAllocs() 416 for i := 0; i < b.N; i++ { 417 vmenv.Call(sender, destination, nil, gas, cfg.Value) 418 } 419 }) 420 } 421 422 // BenchmarkSimpleLoop test a pretty simple loop which loops until OOG 423 // 55 ms 424 func BenchmarkSimpleLoop(b *testing.B) { 425 426 staticCallIdentity := []byte{ 427 byte(vm.JUMPDEST), // [ count ] 428 // push args for the call 429 byte(vm.PUSH1), 0, // out size 430 byte(vm.DUP1), // out offset 431 byte(vm.DUP1), // out insize 432 byte(vm.DUP1), // in offset 433 byte(vm.PUSH1), 0x4, // address of identity 434 byte(vm.GAS), // gas 435 byte(vm.STATICCALL), 436 byte(vm.POP), // pop return value 437 byte(vm.PUSH1), 0, // jumpdestination 438 byte(vm.JUMP), 439 } 440 441 callIdentity := []byte{ 442 byte(vm.JUMPDEST), // [ count ] 443 // push args for the call 444 byte(vm.PUSH1), 0, // out size 445 byte(vm.DUP1), // out offset 446 byte(vm.DUP1), // out insize 447 byte(vm.DUP1), // in offset 448 byte(vm.DUP1), // value 449 byte(vm.PUSH1), 0x4, // address of identity 450 byte(vm.GAS), // gas 451 byte(vm.CALL), 452 byte(vm.POP), // pop return value 453 byte(vm.PUSH1), 0, // jumpdestination 454 byte(vm.JUMP), 455 } 456 457 callInexistant := []byte{ 458 byte(vm.JUMPDEST), // [ count ] 459 // push args for the call 460 byte(vm.PUSH1), 0, // out size 461 byte(vm.DUP1), // out offset 462 byte(vm.DUP1), // out insize 463 byte(vm.DUP1), // in offset 464 byte(vm.DUP1), // value 465 byte(vm.PUSH1), 0xff, // address of existing contract 466 byte(vm.GAS), // gas 467 byte(vm.CALL), 468 byte(vm.POP), // pop return value 469 byte(vm.PUSH1), 0, // jumpdestination 470 byte(vm.JUMP), 471 } 472 473 callEOA := []byte{ 474 byte(vm.JUMPDEST), // [ count ] 475 // push args for the call 476 byte(vm.PUSH1), 0, // out size 477 byte(vm.DUP1), // out offset 478 byte(vm.DUP1), // out insize 479 byte(vm.DUP1), // in offset 480 byte(vm.DUP1), // value 481 byte(vm.PUSH1), 0xE0, // address of EOA 482 byte(vm.GAS), // gas 483 byte(vm.CALL), 484 byte(vm.POP), // pop return value 485 byte(vm.PUSH1), 0, // jumpdestination 486 byte(vm.JUMP), 487 } 488 489 loopingCode := []byte{ 490 byte(vm.JUMPDEST), // [ count ] 491 // push args for the call 492 byte(vm.PUSH1), 0, // out size 493 byte(vm.DUP1), // out offset 494 byte(vm.DUP1), // out insize 495 byte(vm.DUP1), // in offset 496 byte(vm.PUSH1), 0x4, // address of identity 497 byte(vm.GAS), // gas 498 499 byte(vm.POP), byte(vm.POP), byte(vm.POP), byte(vm.POP), byte(vm.POP), byte(vm.POP), 500 byte(vm.PUSH1), 0, // jumpdestination 501 byte(vm.JUMP), 502 } 503 504 calllRevertingContractWithInput := []byte{ 505 byte(vm.JUMPDEST), // 506 // push args for the call 507 byte(vm.PUSH1), 0, // out size 508 byte(vm.DUP1), // out offset 509 byte(vm.PUSH1), 0x20, // in size 510 byte(vm.PUSH1), 0x00, // in offset 511 byte(vm.PUSH1), 0x00, // value 512 byte(vm.PUSH1), 0xEE, // address of reverting contract 513 byte(vm.GAS), // gas 514 byte(vm.CALL), 515 byte(vm.POP), // pop return value 516 byte(vm.PUSH1), 0, // jumpdestination 517 byte(vm.JUMP), 518 } 519 520 //tracer := vm.NewJSONLogger(nil, os.Stdout) 521 //Execute(loopingCode, nil, &Config{ 522 // EVMConfig: vm.Config{ 523 // Debug: true, 524 // Tracer: tracer, 525 // }}) 526 // 100M gas 527 benchmarkNonModifyingCode(100000000, staticCallIdentity, "staticcall-identity-100M", "", b) 528 benchmarkNonModifyingCode(100000000, callIdentity, "call-identity-100M", "", b) 529 benchmarkNonModifyingCode(100000000, loopingCode, "loop-100M", "", b) 530 benchmarkNonModifyingCode(100000000, callInexistant, "call-nonexist-100M", "", b) 531 benchmarkNonModifyingCode(100000000, callEOA, "call-EOA-100M", "", b) 532 benchmarkNonModifyingCode(100000000, calllRevertingContractWithInput, "call-reverting-100M", "", b) 533 534 //benchmarkNonModifyingCode(10000000, staticCallIdentity, "staticcall-identity-10M", b) 535 //benchmarkNonModifyingCode(10000000, loopingCode, "loop-10M", b) 536 } 537 538 // TestEip2929Cases contains various testcases that are used for 539 // EIP-2929 about gas repricings 540 func TestEip2929Cases(t *testing.T) { 541 t.Skip("Test only useful for generating documentation") 542 id := 1 543 prettyPrint := func(comment string, code []byte) { 544 545 instrs := make([]string, 0) 546 it := asm.NewInstructionIterator(code) 547 for it.Next() { 548 if it.Arg() != nil && 0 < len(it.Arg()) { 549 instrs = append(instrs, fmt.Sprintf("%v 0x%x", it.Op(), it.Arg())) 550 } else { 551 instrs = append(instrs, fmt.Sprintf("%v", it.Op())) 552 } 553 } 554 ops := strings.Join(instrs, ", ") 555 fmt.Printf("### Case %d\n\n", id) 556 id++ 557 fmt.Printf("%v\n\nBytecode: \n```\n0x%x\n```\nOperations: \n```\n%v\n```\n\n", 558 comment, 559 code, ops) 560 Execute(code, nil, &Config{ 561 EVMConfig: vm.Config{ 562 Debug: true, 563 Tracer: vm.NewMarkdownLogger(nil, os.Stdout), 564 ExtraEips: []int{2929}, 565 }, 566 }) 567 } 568 569 { // First eip testcase 570 code := []byte{ 571 // Three checks against a precompile 572 byte(vm.PUSH1), 1, byte(vm.EXTCODEHASH), byte(vm.POP), 573 byte(vm.PUSH1), 2, byte(vm.EXTCODESIZE), byte(vm.POP), 574 byte(vm.PUSH1), 3, byte(vm.BALANCE), byte(vm.POP), 575 // Three checks against a non-precompile 576 byte(vm.PUSH1), 0xf1, byte(vm.EXTCODEHASH), byte(vm.POP), 577 byte(vm.PUSH1), 0xf2, byte(vm.EXTCODESIZE), byte(vm.POP), 578 byte(vm.PUSH1), 0xf3, byte(vm.BALANCE), byte(vm.POP), 579 // Same three checks (should be cheaper) 580 byte(vm.PUSH1), 0xf2, byte(vm.EXTCODEHASH), byte(vm.POP), 581 byte(vm.PUSH1), 0xf3, byte(vm.EXTCODESIZE), byte(vm.POP), 582 byte(vm.PUSH1), 0xf1, byte(vm.BALANCE), byte(vm.POP), 583 // Check the origin, and the 'this' 584 byte(vm.ORIGIN), byte(vm.BALANCE), byte(vm.POP), 585 byte(vm.ADDRESS), byte(vm.BALANCE), byte(vm.POP), 586 587 byte(vm.STOP), 588 } 589 prettyPrint("This checks `EXT`(codehash,codesize,balance) of precompiles, which should be `100`, "+ 590 "and later checks the same operations twice against some non-precompiles. "+ 591 "Those are cheaper second time they are accessed. Lastly, it checks the `BALANCE` of `origin` and `this`.", code) 592 } 593 594 { // EXTCODECOPY 595 code := []byte{ 596 // extcodecopy( 0xff,0,0,0,0) 597 byte(vm.PUSH1), 0x00, byte(vm.PUSH1), 0x00, byte(vm.PUSH1), 0x00, //length, codeoffset, memoffset 598 byte(vm.PUSH1), 0xff, byte(vm.EXTCODECOPY), 599 // extcodecopy( 0xff,0,0,0,0) 600 byte(vm.PUSH1), 0x00, byte(vm.PUSH1), 0x00, byte(vm.PUSH1), 0x00, //length, codeoffset, memoffset 601 byte(vm.PUSH1), 0xff, byte(vm.EXTCODECOPY), 602 // extcodecopy( this,0,0,0,0) 603 byte(vm.PUSH1), 0x00, byte(vm.PUSH1), 0x00, byte(vm.PUSH1), 0x00, //length, codeoffset, memoffset 604 byte(vm.ADDRESS), byte(vm.EXTCODECOPY), 605 606 byte(vm.STOP), 607 } 608 prettyPrint("This checks `extcodecopy( 0xff,0,0,0,0)` twice, (should be expensive first time), "+ 609 "and then does `extcodecopy( this,0,0,0,0)`.", code) 610 } 611 612 { // SLOAD + SSTORE 613 code := []byte{ 614 615 // Add slot `0x1` to access list 616 byte(vm.PUSH1), 0x01, byte(vm.SLOAD), byte(vm.POP), // SLOAD( 0x1) (add to access list) 617 // Write to `0x1` which is already in access list 618 byte(vm.PUSH1), 0x11, byte(vm.PUSH1), 0x01, byte(vm.SSTORE), // SSTORE( loc: 0x01, val: 0x11) 619 // Write to `0x2` which is not in access list 620 byte(vm.PUSH1), 0x11, byte(vm.PUSH1), 0x02, byte(vm.SSTORE), // SSTORE( loc: 0x02, val: 0x11) 621 // Write again to `0x2` 622 byte(vm.PUSH1), 0x11, byte(vm.PUSH1), 0x02, byte(vm.SSTORE), // SSTORE( loc: 0x02, val: 0x11) 623 // Read slot in access list (0x2) 624 byte(vm.PUSH1), 0x02, byte(vm.SLOAD), // SLOAD( 0x2) 625 // Read slot in access list (0x1) 626 byte(vm.PUSH1), 0x01, byte(vm.SLOAD), // SLOAD( 0x1) 627 } 628 prettyPrint("This checks `sload( 0x1)` followed by `sstore(loc: 0x01, val:0x11)`, then 'naked' sstore:"+ 629 "`sstore(loc: 0x02, val:0x11)` twice, and `sload(0x2)`, `sload(0x1)`. ", code) 630 } 631 { // Call variants 632 code := []byte{ 633 // identity precompile 634 byte(vm.PUSH1), 0x0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), 635 byte(vm.PUSH1), 0x04, byte(vm.PUSH1), 0x0, byte(vm.CALL), byte(vm.POP), 636 637 // random account - call 1 638 byte(vm.PUSH1), 0x0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), 639 byte(vm.PUSH1), 0xff, byte(vm.PUSH1), 0x0, byte(vm.CALL), byte(vm.POP), 640 641 // random account - call 2 642 byte(vm.PUSH1), 0x0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), 643 byte(vm.PUSH1), 0xff, byte(vm.PUSH1), 0x0, byte(vm.STATICCALL), byte(vm.POP), 644 } 645 prettyPrint("This calls the `identity`-precompile (cheap), then calls an account (expensive) and `staticcall`s the same"+ 646 "account (cheap)", code) 647 } 648 } 649 650 // TestColdAccountAccessCost test that the cold account access cost is reported 651 // correctly 652 // see: https://github.com/scroll-tech/go-ethereum/issues/22649 653 func TestColdAccountAccessCost(t *testing.T) { 654 for i, tc := range []struct { 655 code []byte 656 step int 657 want uint64 658 }{ 659 { // EXTCODEHASH(0xff) 660 code: []byte{byte(vm.PUSH1), 0xFF, byte(vm.EXTCODEHASH), byte(vm.POP)}, 661 step: 1, 662 want: 2600, 663 }, 664 { // BALANCE(0xff) 665 code: []byte{byte(vm.PUSH1), 0xFF, byte(vm.BALANCE), byte(vm.POP)}, 666 step: 1, 667 want: 2600, 668 }, 669 { // CALL(0xff) 670 code: []byte{ 671 byte(vm.PUSH1), 0x0, 672 byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), 673 byte(vm.PUSH1), 0xff, byte(vm.DUP1), byte(vm.CALL), byte(vm.POP), 674 }, 675 step: 7, 676 want: 2855, 677 }, 678 { // CALLCODE(0xff) 679 code: []byte{ 680 byte(vm.PUSH1), 0x0, 681 byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), 682 byte(vm.PUSH1), 0xff, byte(vm.DUP1), byte(vm.CALLCODE), byte(vm.POP), 683 }, 684 step: 7, 685 want: 2855, 686 }, 687 { // DELEGATECALL(0xff) 688 code: []byte{ 689 byte(vm.PUSH1), 0x0, 690 byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), 691 byte(vm.PUSH1), 0xff, byte(vm.DUP1), byte(vm.DELEGATECALL), byte(vm.POP), 692 }, 693 step: 6, 694 want: 2855, 695 }, 696 { // STATICCALL(0xff) 697 code: []byte{ 698 byte(vm.PUSH1), 0x0, 699 byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), 700 byte(vm.PUSH1), 0xff, byte(vm.DUP1), byte(vm.STATICCALL), byte(vm.POP), 701 }, 702 step: 6, 703 want: 2855, 704 }, 705 { // SELFDESTRUCT(0xff) 706 code: []byte{ 707 byte(vm.PUSH1), 0xff, byte(vm.SELFDESTRUCT), 708 }, 709 step: 1, 710 want: 7600, 711 }, 712 } { 713 tracer := vm.NewStructLogger(nil) 714 Execute(tc.code, nil, &Config{ 715 EVMConfig: vm.Config{ 716 Debug: true, 717 Tracer: tracer, 718 }, 719 }) 720 have := tracer.StructLogs()[tc.step].GasCost 721 if want := tc.want; have != want { 722 for ii, op := range tracer.StructLogs() { 723 t.Logf("%d: %v %d", ii, op.OpName(), op.GasCost) 724 } 725 t.Fatalf("tescase %d, gas report wrong, step %d, have %d want %d", i, tc.step, have, want) 726 } 727 } 728 } 729 730 func TestRuntimeJSTracer(t *testing.T) { 731 jsTracers := []string{ 732 `{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, steps:0, 733 step: function() { this.steps++}, 734 fault: function() {}, 735 result: function() { 736 return [this.enters, this.exits,this.enterGas,this.gasUsed, this.steps].join(",") 737 }, 738 enter: function(frame) { 739 this.enters++; 740 this.enterGas = frame.getGas(); 741 }, 742 exit: function(res) { 743 this.exits++; 744 this.gasUsed = res.getGasUsed(); 745 }}`, 746 `{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, steps:0, 747 fault: function() {}, 748 result: function() { 749 return [this.enters, this.exits,this.enterGas,this.gasUsed, this.steps].join(",") 750 }, 751 enter: function(frame) { 752 this.enters++; 753 this.enterGas = frame.getGas(); 754 }, 755 exit: function(res) { 756 this.exits++; 757 this.gasUsed = res.getGasUsed(); 758 }}`} 759 tests := []struct { 760 code []byte 761 // One result per tracer 762 results []string 763 }{ 764 { 765 // CREATE 766 code: []byte{ 767 // Store initcode in memory at 0x00 (5 bytes left-padded to 32 bytes) 768 byte(vm.PUSH5), 769 // Init code: PUSH1 0, PUSH1 0, RETURN (3 steps) 770 byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN), 771 byte(vm.PUSH1), 0, 772 byte(vm.MSTORE), 773 // length, offset, value 774 byte(vm.PUSH1), 5, byte(vm.PUSH1), 27, byte(vm.PUSH1), 0, 775 byte(vm.CREATE), 776 byte(vm.POP), 777 }, 778 results: []string{`"1,1,4294935775,6,12"`, `"1,1,4294935775,6,0"`}, 779 }, 780 { 781 // CREATE2 782 code: []byte{ 783 // Store initcode in memory at 0x00 (5 bytes left-padded to 32 bytes) 784 byte(vm.PUSH5), 785 // Init code: PUSH1 0, PUSH1 0, RETURN (3 steps) 786 byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN), 787 byte(vm.PUSH1), 0, 788 byte(vm.MSTORE), 789 // salt, length, offset, value 790 byte(vm.PUSH1), 1, byte(vm.PUSH1), 5, byte(vm.PUSH1), 27, byte(vm.PUSH1), 0, 791 byte(vm.CREATE2), 792 byte(vm.POP), 793 }, 794 results: []string{`"1,1,4294935766,6,13"`, `"1,1,4294935766,6,0"`}, 795 }, 796 { 797 // CALL 798 code: []byte{ 799 // outsize, outoffset, insize, inoffset 800 byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, 801 byte(vm.PUSH1), 0, // value 802 byte(vm.PUSH1), 0xbb, //address 803 byte(vm.GAS), // gas 804 byte(vm.CALL), 805 byte(vm.POP), 806 }, 807 results: []string{`"1,1,4294964716,6,13"`, `"1,1,4294964716,6,0"`}, 808 }, 809 { 810 // CALLCODE 811 code: []byte{ 812 // outsize, outoffset, insize, inoffset 813 byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, 814 byte(vm.PUSH1), 0, // value 815 byte(vm.PUSH1), 0xcc, //address 816 byte(vm.GAS), // gas 817 byte(vm.CALLCODE), 818 byte(vm.POP), 819 }, 820 results: []string{`"1,1,4294964716,6,13"`, `"1,1,4294964716,6,0"`}, 821 }, 822 { 823 // STATICCALL 824 code: []byte{ 825 // outsize, outoffset, insize, inoffset 826 byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, 827 byte(vm.PUSH1), 0xdd, //address 828 byte(vm.GAS), // gas 829 byte(vm.STATICCALL), 830 byte(vm.POP), 831 }, 832 results: []string{`"1,1,4294964719,6,12"`, `"1,1,4294964719,6,0"`}, 833 }, 834 { 835 // DELEGATECALL 836 code: []byte{ 837 // outsize, outoffset, insize, inoffset 838 byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, 839 byte(vm.PUSH1), 0xee, //address 840 byte(vm.GAS), // gas 841 byte(vm.DELEGATECALL), 842 byte(vm.POP), 843 }, 844 results: []string{`"1,1,4294964719,6,12"`, `"1,1,4294964719,6,0"`}, 845 }, 846 { 847 // CALL self-destructing contract 848 code: []byte{ 849 // outsize, outoffset, insize, inoffset 850 byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, 851 byte(vm.PUSH1), 0, // value 852 byte(vm.PUSH1), 0xff, //address 853 byte(vm.GAS), // gas 854 byte(vm.CALL), 855 byte(vm.POP), 856 }, 857 results: []string{`"2,2,0,5003,12"`, `"2,2,0,5003,0"`}, 858 }, 859 } 860 calleeCode := []byte{ 861 byte(vm.PUSH1), 0, 862 byte(vm.PUSH1), 0, 863 byte(vm.RETURN), 864 } 865 depressedCode := []byte{ 866 byte(vm.PUSH1), 0xaa, 867 byte(vm.SELFDESTRUCT), 868 } 869 main := common.HexToAddress("0xaa") 870 for i, jsTracer := range jsTracers { 871 for j, tc := range tests { 872 statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) 873 statedb.SetCode(main, tc.code) 874 statedb.SetCode(common.HexToAddress("0xbb"), calleeCode) 875 statedb.SetCode(common.HexToAddress("0xcc"), calleeCode) 876 statedb.SetCode(common.HexToAddress("0xdd"), calleeCode) 877 statedb.SetCode(common.HexToAddress("0xee"), calleeCode) 878 statedb.SetCode(common.HexToAddress("0xff"), depressedCode) 879 880 tracer, err := tracers.New(jsTracer, new(tracers.Context)) 881 if err != nil { 882 t.Fatal(err) 883 } 884 _, _, err = Call(main, nil, &Config{ 885 State: statedb, 886 EVMConfig: vm.Config{ 887 Debug: true, 888 Tracer: tracer, 889 }}) 890 if err != nil { 891 t.Fatal("didn't expect error", err) 892 } 893 res, err := tracer.GetResult() 894 if err != nil { 895 t.Fatal(err) 896 } 897 if have, want := string(res), tc.results[i]; have != want { 898 t.Errorf("wrong result for tracer %d testcase %d, have \n%v\nwant\n%v\n", i, j, have, want) 899 } 900 } 901 } 902 } 903 904 func TestJSTracerCreateTx(t *testing.T) { 905 jsTracer := ` 906 {enters: 0, exits: 0, 907 step: function() {}, 908 fault: function() {}, 909 result: function() { return [this.enters, this.exits].join(",") }, 910 enter: function(frame) { this.enters++ }, 911 exit: function(res) { this.exits++ }}` 912 code := []byte{byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN)} 913 914 statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) 915 tracer, err := tracers.New(jsTracer, new(tracers.Context)) 916 if err != nil { 917 t.Fatal(err) 918 } 919 _, _, _, err = Create(code, &Config{ 920 State: statedb, 921 EVMConfig: vm.Config{ 922 Debug: true, 923 Tracer: tracer, 924 }}) 925 if err != nil { 926 t.Fatal(err) 927 } 928 929 res, err := tracer.GetResult() 930 if err != nil { 931 t.Fatal(err) 932 } 933 if have, want := string(res), `"0,0"`; have != want { 934 t.Errorf("wrong result for tracer, have \n%v\nwant\n%v\n", have, want) 935 } 936 } 937 938 func BenchmarkTracerStepVsCallFrame(b *testing.B) { 939 // Simply pushes and pops some values in a loop 940 code := []byte{ 941 byte(vm.JUMPDEST), 942 byte(vm.PUSH1), 0, 943 byte(vm.PUSH1), 0, 944 byte(vm.POP), 945 byte(vm.POP), 946 byte(vm.PUSH1), 0, // jumpdestination 947 byte(vm.JUMP), 948 } 949 950 stepTracer := ` 951 { 952 step: function() {}, 953 fault: function() {}, 954 result: function() {}, 955 }` 956 callFrameTracer := ` 957 { 958 enter: function() {}, 959 exit: function() {}, 960 fault: function() {}, 961 result: function() {}, 962 }` 963 964 benchmarkNonModifyingCode(10000000, code, "tracer-step-10M", stepTracer, b) 965 benchmarkNonModifyingCode(10000000, code, "tracer-call-frame-10M", callFrameTracer, b) 966 }