github.com/ethereum/go-ethereum@v1.16.1/core/vm/gas_table_test.go (about) 1 // Copyright 2017 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 vm 18 19 import ( 20 "bytes" 21 "errors" 22 "math" 23 "math/big" 24 "sort" 25 "testing" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/common/hexutil" 29 "github.com/ethereum/go-ethereum/core/state" 30 "github.com/ethereum/go-ethereum/core/types" 31 "github.com/ethereum/go-ethereum/params" 32 "github.com/holiman/uint256" 33 ) 34 35 func TestMemoryGasCost(t *testing.T) { 36 tests := []struct { 37 size uint64 38 cost uint64 39 overflow bool 40 }{ 41 {0x1fffffffe0, 36028809887088637, false}, 42 {0x1fffffffe1, 0, true}, 43 } 44 for i, tt := range tests { 45 v, err := memoryGasCost(&Memory{}, tt.size) 46 if (err == ErrGasUintOverflow) != tt.overflow { 47 t.Errorf("test %d: overflow mismatch: have %v, want %v", i, err == ErrGasUintOverflow, tt.overflow) 48 } 49 if v != tt.cost { 50 t.Errorf("test %d: gas cost mismatch: have %v, want %v", i, v, tt.cost) 51 } 52 } 53 } 54 55 var eip2200Tests = []struct { 56 original byte 57 gaspool uint64 58 input string 59 used uint64 60 refund uint64 61 failure error 62 }{ 63 {0, math.MaxUint64, "0x60006000556000600055", 1612, 0, nil}, // 0 -> 0 -> 0 64 {0, math.MaxUint64, "0x60006000556001600055", 20812, 0, nil}, // 0 -> 0 -> 1 65 {0, math.MaxUint64, "0x60016000556000600055", 20812, 19200, nil}, // 0 -> 1 -> 0 66 {0, math.MaxUint64, "0x60016000556002600055", 20812, 0, nil}, // 0 -> 1 -> 2 67 {0, math.MaxUint64, "0x60016000556001600055", 20812, 0, nil}, // 0 -> 1 -> 1 68 {1, math.MaxUint64, "0x60006000556000600055", 5812, 15000, nil}, // 1 -> 0 -> 0 69 {1, math.MaxUint64, "0x60006000556001600055", 5812, 4200, nil}, // 1 -> 0 -> 1 70 {1, math.MaxUint64, "0x60006000556002600055", 5812, 0, nil}, // 1 -> 0 -> 2 71 {1, math.MaxUint64, "0x60026000556000600055", 5812, 15000, nil}, // 1 -> 2 -> 0 72 {1, math.MaxUint64, "0x60026000556003600055", 5812, 0, nil}, // 1 -> 2 -> 3 73 {1, math.MaxUint64, "0x60026000556001600055", 5812, 4200, nil}, // 1 -> 2 -> 1 74 {1, math.MaxUint64, "0x60026000556002600055", 5812, 0, nil}, // 1 -> 2 -> 2 75 {1, math.MaxUint64, "0x60016000556000600055", 5812, 15000, nil}, // 1 -> 1 -> 0 76 {1, math.MaxUint64, "0x60016000556002600055", 5812, 0, nil}, // 1 -> 1 -> 2 77 {1, math.MaxUint64, "0x60016000556001600055", 1612, 0, nil}, // 1 -> 1 -> 1 78 {0, math.MaxUint64, "0x600160005560006000556001600055", 40818, 19200, nil}, // 0 -> 1 -> 0 -> 1 79 {1, math.MaxUint64, "0x600060005560016000556000600055", 10818, 19200, nil}, // 1 -> 0 -> 1 -> 0 80 {1, 2306, "0x6001600055", 2306, 0, ErrOutOfGas}, // 1 -> 1 (2300 sentry + 2xPUSH) 81 {1, 2307, "0x6001600055", 806, 0, nil}, // 1 -> 1 (2301 sentry + 2xPUSH) 82 } 83 84 func TestEIP2200(t *testing.T) { 85 for i, tt := range eip2200Tests { 86 address := common.BytesToAddress([]byte("contract")) 87 88 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 89 statedb.CreateAccount(address) 90 statedb.SetCode(address, hexutil.MustDecode(tt.input)) 91 statedb.SetState(address, common.Hash{}, common.BytesToHash([]byte{tt.original})) 92 statedb.Finalise(true) // Push the state into the "original" slot 93 94 vmctx := BlockContext{ 95 CanTransfer: func(StateDB, common.Address, *uint256.Int) bool { return true }, 96 Transfer: func(StateDB, common.Address, common.Address, *uint256.Int) {}, 97 } 98 evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}}) 99 100 _, gas, err := evm.Call(common.Address{}, address, nil, tt.gaspool, new(uint256.Int)) 101 if !errors.Is(err, tt.failure) { 102 t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure) 103 } 104 if used := tt.gaspool - gas; used != tt.used { 105 t.Errorf("test %d: gas used mismatch: have %v, want %v", i, used, tt.used) 106 } 107 if refund := evm.StateDB.GetRefund(); refund != tt.refund { 108 t.Errorf("test %d: gas refund mismatch: have %v, want %v", i, refund, tt.refund) 109 } 110 } 111 } 112 113 var createGasTests = []struct { 114 code string 115 eip3860 bool 116 gasUsed uint64 117 minimumGas uint64 118 }{ 119 // legacy create(0, 0, 0xc000) without 3860 used 120 {"0x61C00060006000f0" + "600052" + "60206000F3", false, 41237, 41237}, 121 // legacy create(0, 0, 0xc000) _with_ 3860 122 {"0x61C00060006000f0" + "600052" + "60206000F3", true, 44309, 44309}, 123 // create2(0, 0, 0xc001, 0) without 3860 124 {"0x600061C00160006000f5" + "600052" + "60206000F3", false, 50471, 50471}, 125 // create2(0, 0, 0xc001, 0) (too large), with 3860 126 {"0x600061C00160006000f5" + "600052" + "60206000F3", true, 32012, 100_000}, 127 // create2(0, 0, 0xc000, 0) 128 // This case is trying to deploy code at (within) the limit 129 {"0x600061C00060006000f5" + "600052" + "60206000F3", true, 53528, 53528}, 130 // create2(0, 0, 0xc001, 0) 131 // This case is trying to deploy code exceeding the limit 132 {"0x600061C00160006000f5" + "600052" + "60206000F3", true, 32024, 100000}, 133 } 134 135 func TestCreateGas(t *testing.T) { 136 for i, tt := range createGasTests { 137 var gasUsed = uint64(0) 138 doCheck := func(testGas int) bool { 139 address := common.BytesToAddress([]byte("contract")) 140 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 141 statedb.CreateAccount(address) 142 statedb.SetCode(address, hexutil.MustDecode(tt.code)) 143 statedb.Finalise(true) 144 vmctx := BlockContext{ 145 CanTransfer: func(StateDB, common.Address, *uint256.Int) bool { return true }, 146 Transfer: func(StateDB, common.Address, common.Address, *uint256.Int) {}, 147 BlockNumber: big.NewInt(0), 148 } 149 config := Config{} 150 if tt.eip3860 { 151 config.ExtraEips = []int{3860} 152 } 153 154 evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, config) 155 var startGas = uint64(testGas) 156 ret, gas, err := evm.Call(common.Address{}, address, nil, startGas, new(uint256.Int)) 157 if err != nil { 158 return false 159 } 160 gasUsed = startGas - gas 161 if len(ret) != 32 { 162 t.Fatalf("test %d: expected 32 bytes returned, have %d", i, len(ret)) 163 } 164 if bytes.Equal(ret, make([]byte, 32)) { 165 // Failure 166 return false 167 } 168 return true 169 } 170 minGas := sort.Search(100_000, doCheck) 171 if uint64(minGas) != tt.minimumGas { 172 t.Fatalf("test %d: min gas error, want %d, have %d", i, tt.minimumGas, minGas) 173 } 174 // If the deployment succeeded, we also check the gas used 175 if minGas < 100_000 { 176 if gasUsed != tt.gasUsed { 177 t.Errorf("test %d: gas used mismatch: have %v, want %v", i, gasUsed, tt.gasUsed) 178 } 179 } 180 } 181 }