github.com/klaytn/klaytn@v1.10.2/blockchain/vm/contracts_test.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2017 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from core/vm/contracts_test.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package vm
    22  
    23  import (
    24  	"bytes"
    25  	"encoding/json"
    26  	"fmt"
    27  	"io/ioutil"
    28  	"math/big"
    29  	"testing"
    30  
    31  	"github.com/klaytn/klaytn/blockchain/state"
    32  	"github.com/klaytn/klaytn/blockchain/types"
    33  	"github.com/klaytn/klaytn/blockchain/types/accountkey"
    34  	"github.com/klaytn/klaytn/common"
    35  	"github.com/klaytn/klaytn/common/hexutil"
    36  	"github.com/klaytn/klaytn/crypto"
    37  	"github.com/klaytn/klaytn/params"
    38  	"github.com/klaytn/klaytn/storage/database"
    39  	"github.com/stretchr/testify/assert"
    40  	"github.com/stretchr/testify/require"
    41  )
    42  
    43  // precompiledTest defines the input/output pairs for precompiled contract tests.
    44  type precompiledTest struct {
    45  	Input, Expected string
    46  	Gas             uint64
    47  	Name            string
    48  	NoBenchmark     bool // Benchmark primarily the worst-cases
    49  }
    50  
    51  // precompiledFailureTest defines the input/error pairs for precompiled
    52  // contract failure tests.
    53  type precompiledFailureTest struct {
    54  	Input         string
    55  	ExpectedError string
    56  	Name          string
    57  }
    58  
    59  // allPrecompiles does not map to the actual set of precompiles, as it also contains
    60  // repriced versions of precompiles at certain slots
    61  var allPrecompiles = map[common.Address]PrecompiledContract{
    62  	common.BytesToAddress([]byte{1}):    &ecrecover{},
    63  	common.BytesToAddress([]byte{2}):    &sha256hash{},
    64  	common.BytesToAddress([]byte{3}):    &ripemd160hash{},
    65  	common.BytesToAddress([]byte{4}):    &dataCopy{},
    66  	common.BytesToAddress([]byte{5}):    &bigModExp{eip2565: false},
    67  	common.BytesToAddress([]byte{0xf5}): &bigModExp{eip2565: true},
    68  	common.BytesToAddress([]byte{6}):    &bn256AddIstanbul{},
    69  	common.BytesToAddress([]byte{7}):    &bn256ScalarMulIstanbul{},
    70  	common.BytesToAddress([]byte{8}):    &bn256PairingIstanbul{},
    71  	common.BytesToAddress([]byte{9}):    &blake2F{},
    72  	// TODO-klaytn import bls-signature precompiled contracts
    73  	common.BytesToAddress([]byte{3, 253}): &vmLog{},
    74  	common.BytesToAddress([]byte{3, 254}): &feePayer{},
    75  	common.BytesToAddress([]byte{3, 255}): &validateSender{},
    76  }
    77  
    78  // EIP-152 test vectors
    79  var blake2FMalformedInputTests = []precompiledFailureTest{
    80  	{
    81  		Input:         "",
    82  		ExpectedError: errBlake2FInvalidInputLength.Error(),
    83  		Name:          "vector 0: empty input",
    84  	},
    85  	{
    86  		Input:         "00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
    87  		ExpectedError: errBlake2FInvalidInputLength.Error(),
    88  		Name:          "vector 1: less than 213 bytes input",
    89  	},
    90  	{
    91  		Input:         "000000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
    92  		ExpectedError: errBlake2FInvalidInputLength.Error(),
    93  		Name:          "vector 2: more than 213 bytes input",
    94  	},
    95  	{
    96  		Input:         "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000002",
    97  		ExpectedError: errBlake2FInvalidFinalFlag.Error(),
    98  		Name:          "vector 3: malformed final block indicator flag",
    99  	},
   100  }
   101  
   102  // This function prepares background environment for running vmLog, feePayer, validateSender tests.
   103  // It generates contract, evm, EOA test object.
   104  func prepare(reqGas uint64) (*Contract, *EVM, error) {
   105  	// Generate Contract
   106  	contract := NewContract(types.NewAccountRefWithFeePayer(common.HexToAddress("1337"), common.HexToAddress("133773")),
   107  		nil, new(big.Int), reqGas)
   108  
   109  	// Generate EVM
   110  	stateDb, _ := state.New(common.Hash{}, state.NewDatabase(database.NewMemoryDBManager()), nil)
   111  	txhash := common.HexToHash("0xc6a37e155d3fa480faea012a68ad35fd53c8cc3cd8263a434c697755985a6577")
   112  	stateDb.Prepare(txhash, common.Hash{}, 0)
   113  	evm := NewEVM(Context{BlockNumber: big.NewInt(0)}, stateDb, &params.ChainConfig{IstanbulCompatibleBlock: big.NewInt(0)}, &Config{})
   114  
   115  	// Only stdout logging is tested to avoid file handling. It is used at vmLog test.
   116  	params.VMLogTarget = params.VMLogToStdout
   117  
   118  	// Generate EOA. It is used at validateSender test.
   119  	k, err := crypto.HexToECDSA("98275a145bc1726eb0445433088f5f882f8a4a9499135239cfb4040e78991dab")
   120  	accKey := accountkey.NewAccountKeyPublicWithValue(&k.PublicKey)
   121  	stateDb.CreateEOA(common.HexToAddress("0x123456789"), false, accKey)
   122  
   123  	return contract, evm, err
   124  }
   125  
   126  func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
   127  	p := allPrecompiles[common.HexToAddress(addr)]
   128  	in := common.Hex2Bytes(test.Input)
   129  	reqGas, _ := p.GetRequiredGasAndComputationCost(in)
   130  
   131  	contract, evm, err := prepare(reqGas)
   132  	require.NoError(t, err)
   133  
   134  	t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, reqGas), func(t *testing.T) {
   135  		if res, _, err := RunPrecompiledContract(p, in, contract, evm); err != nil {
   136  			t.Error(err)
   137  		} else if common.Bytes2Hex(res) != test.Expected {
   138  			t.Errorf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res))
   139  		}
   140  	})
   141  }
   142  
   143  func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) {
   144  	p := allPrecompiles[common.HexToAddress(addr)]
   145  	in := common.Hex2Bytes(test.Input)
   146  	reqGas, _ := p.GetRequiredGasAndComputationCost(in)
   147  	reqGas -= 1
   148  
   149  	contract, evm, _ := prepare(reqGas)
   150  
   151  	t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, reqGas), func(t *testing.T) {
   152  		_, _, err := RunPrecompiledContract(p, in, contract, evm)
   153  		if err.Error() != "out of gas" {
   154  			t.Errorf("Expected error [out of gas], got [%v]", err)
   155  		}
   156  		// Verify that the precompile did not touch the input buffer
   157  		exp := common.Hex2Bytes(test.Input)
   158  		if !bytes.Equal(in, exp) {
   159  			t.Errorf("Precompiled %v modified input data", addr)
   160  		}
   161  	})
   162  }
   163  
   164  func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing.T) {
   165  	p := allPrecompiles[common.HexToAddress(addr)]
   166  	in := common.Hex2Bytes(test.Input)
   167  	reqGas, _ := p.GetRequiredGasAndComputationCost(in)
   168  
   169  	contract, evm, _ := prepare(reqGas)
   170  
   171  	t.Run(test.Name, func(t *testing.T) {
   172  		_, _, err := RunPrecompiledContract(p, in, contract, evm)
   173  		if err.Error() != test.ExpectedError {
   174  			t.Errorf("Expected error [%v], got [%v]", test.ExpectedError, err)
   175  		}
   176  		// Verify that the precompile did not touch the input buffer
   177  		exp := common.Hex2Bytes(test.Input)
   178  		if !bytes.Equal(in, exp) {
   179  			t.Errorf("Precompiled %v modified input data", addr)
   180  		}
   181  	})
   182  }
   183  
   184  func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) {
   185  	if test.NoBenchmark {
   186  		return
   187  	}
   188  	p := allPrecompiles[common.HexToAddress(addr)]
   189  	in := common.Hex2Bytes(test.Input)
   190  	reqGas, _ := p.GetRequiredGasAndComputationCost(in)
   191  
   192  	contract, evm, _ := prepare(reqGas)
   193  
   194  	var (
   195  		res  []byte
   196  		err  error
   197  		data = make([]byte, len(in))
   198  	)
   199  
   200  	bench.Run(fmt.Sprintf("%s-Gas=%d", test.Name, contract.Gas), func(bench *testing.B) {
   201  		bench.ResetTimer()
   202  		for i := 0; i < bench.N; i++ {
   203  			contract.Gas = reqGas
   204  			copy(data, in)
   205  			res, _, err = RunPrecompiledContract(p, data, contract, evm)
   206  		}
   207  		bench.StopTimer()
   208  		// Check if it is correct
   209  		if err != nil {
   210  			bench.Error(err)
   211  			return
   212  		}
   213  		if common.Bytes2Hex(res) != test.Expected {
   214  			bench.Error(fmt.Sprintf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res)))
   215  			return
   216  		}
   217  	})
   218  }
   219  
   220  // Tests the sample inputs of the ecrecover
   221  func TestPrecompiledEcrecover(t *testing.T)      { testJson("ecRecover", "01", t) }
   222  func BenchmarkPrecompiledEcrecover(b *testing.B) { benchJson("ecRecover", "01", b) }
   223  
   224  // Benchmarks the sample inputs from the SHA256 precompile.
   225  func BenchmarkPrecompiledSha256(b *testing.B) { benchJson("sha256", "02", b) }
   226  
   227  // Benchmarks the sample inputs from the RIPEMD precompile.
   228  func BenchmarkPrecompiledRipeMD(b *testing.B) { benchJson("ripeMD", "03", b) }
   229  
   230  // Benchmarks the sample inputs from the identity precompile.
   231  func BenchmarkPrecompiledIdentity(b *testing.B) { benchJson("identity", "04", b) }
   232  
   233  // Tests the sample inputs from the ModExp EIP 198.
   234  func TestPrecompiledModExp(t *testing.T)      { testJson("modexp", "05", t) }
   235  func BenchmarkPrecompiledModExp(b *testing.B) { benchJson("modexp", "05", b) }
   236  
   237  func TestPrecompiledModExpEip2565(t *testing.T)      { testJson("modexp_eip2565", "f5", t) }
   238  func BenchmarkPrecompiledModExpEip2565(b *testing.B) { benchJson("modexp_eip2565", "f5", b) }
   239  
   240  // Tests the sample inputs from the elliptic curve addition EIP 213.
   241  func TestPrecompiledBn256Add(t *testing.T)      { testJson("bn256Add", "06", t) }
   242  func BenchmarkPrecompiledBn256Add(b *testing.B) { benchJson("bn256Add", "06", b) }
   243  
   244  // Tests the sample inputs from the elliptic curve scalar multiplication EIP 213.
   245  func TestPrecompiledBn256ScalarMul(t *testing.T)      { testJson("bn256ScalarMul", "07", t) }
   246  func BenchmarkPrecompiledBn256ScalarMul(b *testing.B) { benchJson("bn256ScalarMul", "07", b) }
   247  
   248  // Tests the sample inputs from the elliptic curve pairing check EIP 197.
   249  func TestPrecompiledBn256Pairing(t *testing.T)      { testJson("bn256Pairing", "08", t) }
   250  func BenchmarkPrecompiledBn256Pairing(b *testing.B) { benchJson("bn256Pairing", "08", b) }
   251  
   252  func TestPrecompiledBlake2F(t *testing.T)              { testJson("blake2F", "09", t) }
   253  func BenchmarkPrecompiledBlake2F(b *testing.B)         { benchJson("blake2F", "09", b) }
   254  func TestPrecompileBlake2FMalformedInput(t *testing.T) { testJsonFail("blake2F", "09", t) }
   255  
   256  // Tests the sample inputs of the vmLog
   257  func TestPrecompiledVmLog(t *testing.T)      { testJson("vmLog", "3fd", t) }
   258  func BenchmarkPrecompiledVmLog(b *testing.B) { benchJson("vmLog", "3fd", b) }
   259  
   260  // Tests the sample inputs of the feePayer
   261  func TestFeePayerContract(t *testing.T)         { testJson("feePayer", "3fe", t) }
   262  func BenchmarkPrecompiledFeePayer(b *testing.B) { benchJson("feePayer", "3fe", b) }
   263  
   264  // Tests the sample inputs of the validateSender
   265  func TestValidateSenderContract(t *testing.T)         { testJson("validateSender", "3ff", t) }
   266  func BenchmarkPrecompiledValidateSender(b *testing.B) { benchJson("validateSender", "3ff", b) }
   267  
   268  // Tests OOG (out-of-gas) of modExp
   269  func TestPrecompiledModExpOOG(t *testing.T) {
   270  	modexpTests, err := loadJson("modexp")
   271  	if err != nil {
   272  		t.Fatal(err)
   273  	}
   274  	for _, test := range modexpTests {
   275  		testPrecompiledOOG("05", test, t)
   276  	}
   277  }
   278  
   279  func loadJson(name string) ([]precompiledTest, error) {
   280  	data, err := ioutil.ReadFile(fmt.Sprintf("testdata/precompiles/%v.json", name))
   281  	if err != nil {
   282  		return nil, err
   283  	}
   284  	var testcases []precompiledTest
   285  	err = json.Unmarshal(data, &testcases)
   286  	return testcases, err
   287  }
   288  
   289  func loadJsonFail(name string) ([]precompiledFailureTest, error) {
   290  	data, err := ioutil.ReadFile(fmt.Sprintf("testdata/precompiles/fail-%v.json", name))
   291  	if err != nil {
   292  		return nil, err
   293  	}
   294  	var testcases []precompiledFailureTest
   295  	err = json.Unmarshal(data, &testcases)
   296  	return testcases, err
   297  }
   298  
   299  func testJson(name, addr string, t *testing.T) {
   300  	tests, err := loadJson(name)
   301  	if err != nil {
   302  		t.Fatal(err)
   303  	}
   304  	for _, test := range tests {
   305  		testPrecompiled(addr, test, t)
   306  	}
   307  }
   308  
   309  func testJsonFail(name, addr string, t *testing.T) {
   310  	tests, err := loadJsonFail(name)
   311  	if err != nil {
   312  		t.Fatal(err)
   313  	}
   314  	for _, test := range tests {
   315  		testPrecompiledFailure(addr, test, t)
   316  	}
   317  }
   318  
   319  func benchJson(name, addr string, b *testing.B) {
   320  	tests, err := loadJson(name)
   321  	if err != nil {
   322  		b.Fatal(err)
   323  	}
   324  	for _, test := range tests {
   325  		benchmarkPrecompiled(addr, test, b)
   326  	}
   327  }
   328  
   329  // TestEVM_CVE_2021_39137 tests an EVM vulnerability described in https://nvd.nist.gov/vuln/detail/CVE-2021-39137.
   330  // The vulnerable EVM bytecode exploited in Ethereum is used as a test code.
   331  // Test code reference: https://etherscan.io/tx/0x1cb6fb36633d270edefc04d048145b4298e67b8aa82a9e5ec4aa1435dd770ce4.
   332  func TestEVM_CVE_2021_39137(t *testing.T) {
   333  	fromAddr := common.HexToAddress("0x1a02a619e51cc5f8a2a61d2a60f6c80476ee8ead")
   334  	contractAddr := common.HexToAddress("0x8eae784e072e961f76948a785b62c9a950fb17ae")
   335  
   336  	testCases := []struct {
   337  		name           string
   338  		expectedResult []byte
   339  		testCode       []byte
   340  	}{
   341  		{
   342  			"staticCall test",
   343  			contractAddr.Bytes(),
   344  			hexutil.MustDecode("0x3034526020600760203460045afa602034343e604034f3"),
   345  			/*
   346  				// Pseudo code of the decompiled testCode
   347  				memory[0:0x20] = address(this); // put contract address with padding left zero into the memory
   348  				staticCall(gas, 0x04, 0x0, 0x20, 0x07, 0x20);  // operands: gas, to, in offset, in size, out offset, out size
   349  				memory[0:0x20] = returnDataCopy(); // put the returned data from staticCall into the memory
   350  				return memory[0:0x40];
   351  
   352  				// Disassembly
   353  				0000    30  ADDRESS
   354  				0001    34  CALLVALUE
   355  				0002    52  MSTORE
   356  				0003    60  PUSH1 0x20
   357  				0005    60  PUSH1 0x07
   358  				0007    60  PUSH1 0x20
   359  				0009    34  CALLVALUE
   360  				000A    60  PUSH1 0x04
   361  				000C    5A  GAS
   362  				000D    FA  STATICCALL
   363  				000E    60  PUSH1 0x20
   364  				0010    34  CALLVALUE
   365  				0011    34  CALLVALUE
   366  				0012    3E  RETURNDATACOPY
   367  				0013    60  PUSH1 0x40
   368  				0015    34  CALLVALUE
   369  				0016    F3  *RETURN
   370  			*/
   371  		},
   372  		{
   373  			"call test",
   374  			contractAddr.Bytes(),
   375  			hexutil.MustDecode("0x30345260206007602060003460045af1602034343e604034f3"),
   376  		},
   377  		{
   378  			"callCode test",
   379  			contractAddr.Bytes(),
   380  			hexutil.MustDecode("0x30345260206007602060003460045af2602034343e604034f3"),
   381  		},
   382  		{
   383  			"delegateCall test",
   384  			contractAddr.Bytes(),
   385  			hexutil.MustDecode("0x3034526020600760203460045af4602034343e604034f3"),
   386  		},
   387  	}
   388  
   389  	gasLimit := uint64(99999999)
   390  	tracer := NewStructLogger(nil)
   391  	vmctx := Context{
   392  		CanTransfer: func(StateDB, common.Address, *big.Int) bool { return true },
   393  		Transfer:    func(StateDB, common.Address, common.Address, *big.Int) {},
   394  	}
   395  	stateDb, _ := state.New(common.Hash{}, state.NewDatabase(database.NewMemoryDBManager()), nil)
   396  
   397  	for _, tc := range testCases {
   398  		stateDb.SetCode(contractAddr, tc.testCode)
   399  
   400  		evm := NewEVM(vmctx, stateDb, params.TestChainConfig, &Config{Debug: true, Tracer: tracer})
   401  		ret, _, err := evm.Call(AccountRef(fromAddr), contractAddr, nil, gasLimit, new(big.Int))
   402  		if err != nil {
   403  			t.Fatal(err)
   404  		}
   405  
   406  		if testing.Verbose() {
   407  			buf := new(bytes.Buffer)
   408  			WriteTrace(buf, tracer.StructLogs())
   409  			if buf.Len() == 0 {
   410  				t.Log("no EVM operation logs generated")
   411  			} else {
   412  				t.Log("EVM operation log:\n" + buf.String())
   413  			}
   414  			t.Logf("EVM output: 0x%x", tracer.Output())
   415  			t.Logf("EVM error: %v", tracer.Error())
   416  		}
   417  
   418  		assert.Equal(t, tc.expectedResult, ret[12:32])
   419  	}
   420  }