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  }