github.com/ethereum/go-ethereum@v1.16.1/core/vm/program/program_test.go (about) 1 // Copyright 2024 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 program 18 19 import ( 20 "bytes" 21 "math/big" 22 "testing" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/core/vm" 26 "github.com/holiman/uint256" 27 ) 28 29 func TestPush(t *testing.T) { 30 tests := []struct { 31 input interface{} 32 expected string 33 }{ 34 // native ints 35 {0, "6000"}, 36 {0xfff, "610fff"}, 37 {nil, "6000"}, 38 {uint8(1), "6001"}, 39 {uint16(1), "6001"}, 40 {uint32(1), "6001"}, 41 {uint64(1), "6001"}, 42 // bigints 43 {big.NewInt(0), "6000"}, 44 {big.NewInt(1), "6001"}, 45 {big.NewInt(0xfff), "610fff"}, 46 // uint256 47 {uint256.NewInt(1), "6001"}, 48 {uint256.Int{1, 0, 0, 0}, "6001"}, 49 // Addresses 50 {common.HexToAddress("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"), "73deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"}, 51 {&common.Address{}, "6000"}, 52 } 53 for i, tc := range tests { 54 have := New().Push(tc.input).Hex() 55 if have != tc.expected { 56 t.Errorf("test %d: got %v expected %v", i, have, tc.expected) 57 } 58 } 59 } 60 61 func TestCall(t *testing.T) { 62 { // Nil gas 63 have := New().Call(nil, common.HexToAddress("0x1337"), big.NewInt(1), 1, 2, 3, 4).Hex() 64 want := "600460036002600160016113375af1" 65 if have != want { 66 t.Errorf("have %v want %v", have, want) 67 } 68 } 69 { // Non nil gas 70 have := New().Call(uint256.NewInt(0xffff), common.HexToAddress("0x1337"), big.NewInt(1), 1, 2, 3, 4).Hex() 71 want := "6004600360026001600161133761fffff1" 72 if have != want { 73 t.Errorf("have %v want %v", have, want) 74 } 75 } 76 } 77 78 func TestMstore(t *testing.T) { 79 { 80 have := New().Mstore(common.FromHex("0xaabb"), 0).Hex() 81 want := "60aa60005360bb600153" 82 if have != want { 83 t.Errorf("have %v want %v", have, want) 84 } 85 } 86 { // store at offset 87 have := New().Mstore(common.FromHex("0xaabb"), 3).Hex() 88 want := "60aa60035360bb600453" 89 if have != want { 90 t.Errorf("have %v want %v", have, want) 91 } 92 } 93 { // 34 bytes 94 data := common.FromHex("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + 95 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + 96 "FFFF") 97 98 have := New().Mstore(data, 0).Hex() 99 want := "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260ff60205360ff602153" 100 if have != want { 101 t.Errorf("have %v want %v", have, want) 102 } 103 } 104 } 105 106 func TestMemToStorage(t *testing.T) { 107 have := New().MemToStorage(0, 33, 1).Hex() 108 want := "600051600155602051600255" 109 if have != want { 110 t.Errorf("have %v want %v", have, want) 111 } 112 } 113 114 func TestSstore(t *testing.T) { 115 have := New().Sstore(0x1337, []byte("1234")).Hex() 116 want := "633132333461133755" 117 if have != want { 118 t.Errorf("have %v want %v", have, want) 119 } 120 } 121 122 func TestReturnData(t *testing.T) { 123 { 124 have := New().ReturnData([]byte{0xFF}).Hex() 125 want := "60ff60005360016000f3" 126 if have != want { 127 t.Errorf("have %v want %v", have, want) 128 } 129 } 130 { 131 // 32 bytes 132 data := common.FromHex("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF") 133 have := New().ReturnData(data).Hex() 134 want := "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000f3" 135 if have != want { 136 t.Errorf("have %v want %v", have, want) 137 } 138 } 139 { // ReturnViaCodeCopy 140 data := common.FromHex("0x6001") 141 have := New().Append([]byte{0x5b, 0x5b, 0x5b}).ReturnViaCodeCopy(data).Hex() 142 want := "5b5b5b600261001060003960026000f36001" 143 if have != want { 144 t.Errorf("have %v want %v", have, want) 145 } 146 } 147 { // ReturnViaCodeCopy larger code 148 data := common.FromHex("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000f3") 149 have := New().Append([]byte{0x5b, 0x5b, 0x5b}).ReturnViaCodeCopy(data).Hex() 150 want := "5b5b5b602961001060003960296000f37fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000f3" 151 if have != want { 152 t.Errorf("have %v want %v", have, want) 153 } 154 } 155 } 156 157 func TestCreateAndCall(t *testing.T) { 158 // A constructor that stores a slot 159 ctor := New().Sstore(0, big.NewInt(5)) 160 161 // A runtime bytecode which reads the slot and returns 162 deployed := New() 163 deployed.Push(0).Op(vm.SLOAD) // [value] in stack 164 deployed.Push(0) // [value, 0] 165 deployed.Op(vm.MSTORE) 166 deployed.Return(0, 32) 167 168 // Pack them 169 ctor.ReturnData(deployed.Bytes()) 170 // Verify constructor + runtime code 171 { 172 want := "6005600055606060005360006001536054600253606060035360006004536052600553606060065360206007536060600853600060095360f3600a53600b6000f3" 173 if got := ctor.Hex(); got != want { 174 t.Fatalf("1: got %v expected %v", got, want) 175 } 176 } 177 } 178 179 func TestCreate2Call(t *testing.T) { 180 // Some runtime code 181 runtime := New().Op(vm.ADDRESS, vm.SELFDESTRUCT).Bytes() 182 want := common.FromHex("0x30ff") 183 if !bytes.Equal(want, runtime) { 184 t.Fatalf("runtime code error\nwant: %x\nhave: %x\n", want, runtime) 185 } 186 // A constructor returning the runtime code 187 initcode := New().ReturnData(runtime).Bytes() 188 want = common.FromHex("603060005360ff60015360026000f3") 189 if !bytes.Equal(want, initcode) { 190 t.Fatalf("initcode error\nwant: %x\nhave: %x\n", want, initcode) 191 } 192 // A factory invoking the constructor 193 outer := New().Create2ThenCall(initcode, nil).Bytes() 194 want = common.FromHex("60606000536030600153606060025360006003536053600453606060055360ff6006536060600753600160085360536009536060600a536002600b536060600c536000600d5360f3600e536000600f60006000f560006000600060006000855af15050") 195 if !bytes.Equal(want, outer) { 196 t.Fatalf("factory error\nwant: %x\nhave: %x\n", want, outer) 197 } 198 } 199 200 func TestGenerator(t *testing.T) { 201 for i, tc := range []struct { 202 want []byte 203 haveFn func() []byte 204 }{ 205 { // CREATE 206 want: []byte{ 207 // Store initcode in memory at 0x00 (5 bytes left-padded to 32 bytes) 208 byte(vm.PUSH5), 209 // Init code: PUSH1 0, PUSH1 0, RETURN (3 steps) 210 byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN), 211 byte(vm.PUSH1), 0, 212 byte(vm.MSTORE), 213 // length, offset, value 214 byte(vm.PUSH1), 5, byte(vm.PUSH1), 27, byte(vm.PUSH1), 0, 215 byte(vm.CREATE), 216 byte(vm.POP), 217 }, 218 haveFn: func() []byte { 219 initcode := New().Return(0, 0).Bytes() 220 return New().MstoreSmall(initcode, 0). 221 Push(len(initcode)). // length 222 Push(32 - len(initcode)). // offset 223 Push(0). // value 224 Op(vm.CREATE). 225 Op(vm.POP).Bytes() 226 }, 227 }, 228 { // CREATE2 229 want: []byte{ 230 // Store initcode in memory at 0x00 (5 bytes left-padded to 32 bytes) 231 byte(vm.PUSH5), 232 // Init code: PUSH1 0, PUSH1 0, RETURN (3 steps) 233 byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN), 234 byte(vm.PUSH1), 0, 235 byte(vm.MSTORE), 236 // salt, length, offset, value 237 byte(vm.PUSH1), 1, byte(vm.PUSH1), 5, byte(vm.PUSH1), 27, byte(vm.PUSH1), 0, 238 byte(vm.CREATE2), 239 byte(vm.POP), 240 }, 241 haveFn: func() []byte { 242 initcode := New().Return(0, 0).Bytes() 243 return New().MstoreSmall(initcode, 0). 244 Push(1). // salt 245 Push(len(initcode)). // length 246 Push(32 - len(initcode)). // offset 247 Push(0). // value 248 Op(vm.CREATE2). 249 Op(vm.POP).Bytes() 250 }, 251 }, 252 { // CALL 253 want: []byte{ 254 // outsize, outoffset, insize, inoffset 255 byte(vm.PUSH1), 0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), 256 byte(vm.DUP1), // value 257 byte(vm.PUSH1), 0xbb, //address 258 byte(vm.GAS), // gas 259 byte(vm.CALL), 260 byte(vm.POP), 261 }, 262 haveFn: func() []byte { 263 return New().Call(nil, 0xbb, 0, 0, 0, 0, 0).Op(vm.POP).Bytes() 264 }, 265 }, 266 { // CALLCODE 267 want: []byte{ 268 // outsize, outoffset, insize, inoffset 269 byte(vm.PUSH1), 0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), 270 byte(vm.PUSH1), 0, // value 271 byte(vm.PUSH1), 0xcc, //address 272 byte(vm.GAS), // gas 273 byte(vm.CALLCODE), 274 byte(vm.POP), 275 }, 276 haveFn: func() []byte { 277 return New().CallCode(nil, 0xcc, 0, 0, 0, 0, 0).Op(vm.POP).Bytes() 278 }, 279 }, 280 { // STATICCALL 281 want: []byte{ 282 // outsize, outoffset, insize, inoffset 283 byte(vm.PUSH1), 0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), 284 byte(vm.PUSH1), 0xdd, //address 285 byte(vm.GAS), // gas 286 byte(vm.STATICCALL), 287 byte(vm.POP), 288 }, 289 haveFn: func() []byte { 290 return New().StaticCall(nil, 0xdd, 0, 0, 0, 0).Op(vm.POP).Bytes() 291 }, 292 }, 293 { // DELEGATECALL 294 want: []byte{ 295 // outsize, outoffset, insize, inoffset 296 byte(vm.PUSH1), 0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), 297 byte(vm.PUSH1), 0xee, //address 298 byte(vm.GAS), // gas 299 byte(vm.DELEGATECALL), 300 byte(vm.POP), 301 }, 302 haveFn: func() []byte { 303 return New().DelegateCall(nil, 0xee, 0, 0, 0, 0).Op(vm.POP).Bytes() 304 }, 305 }, 306 } { 307 if have := tc.haveFn(); !bytes.Equal(have, tc.want) { 308 t.Fatalf("test %d error\nhave: %x\nwant: %x\n", i, have, tc.want) 309 } 310 } 311 }