github.com/klaytn/klaytn@v1.12.1/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  	"math/big"
    28  	"os"
    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{0xa}):    &kzgPointEvaluation{},
    74  	common.BytesToAddress([]byte{3, 253}): &vmLog{},
    75  	common.BytesToAddress([]byte{3, 254}): &feePayer{},
    76  	common.BytesToAddress([]byte{3, 255}): &validateSender{},
    77  }
    78  
    79  // EIP-152 test vectors
    80  var blake2FMalformedInputTests = []precompiledFailureTest{
    81  	{
    82  		Input:         "",
    83  		ExpectedError: errBlake2FInvalidInputLength.Error(),
    84  		Name:          "vector 0: empty input",
    85  	},
    86  	{
    87  		Input:         "00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
    88  		ExpectedError: errBlake2FInvalidInputLength.Error(),
    89  		Name:          "vector 1: less than 213 bytes input",
    90  	},
    91  	{
    92  		Input:         "000000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
    93  		ExpectedError: errBlake2FInvalidInputLength.Error(),
    94  		Name:          "vector 2: more than 213 bytes input",
    95  	},
    96  	{
    97  		Input:         "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000002",
    98  		ExpectedError: errBlake2FInvalidFinalFlag.Error(),
    99  		Name:          "vector 3: malformed final block indicator flag",
   100  	},
   101  }
   102  
   103  // This function prepares background environment for running vmLog, feePayer, validateSender tests.
   104  // It generates contract, evm, EOA test object.
   105  func prepare(reqGas uint64) (*Contract, *EVM, error) {
   106  	// Generate Contract
   107  	contract := NewContract(types.NewAccountRefWithFeePayer(common.HexToAddress("1337"), common.HexToAddress("133773")),
   108  		nil, new(big.Int), reqGas)
   109  
   110  	// Generate EVM
   111  	stateDb, _ := state.New(common.Hash{}, state.NewDatabase(database.NewMemoryDBManager()), nil, nil)
   112  	txhash := common.HexToHash("0xc6a37e155d3fa480faea012a68ad35fd53c8cc3cd8263a434c697755985a6577")
   113  	stateDb.SetTxContext(txhash, common.Hash{}, 0)
   114  	evm := NewEVM(BlockContext{BlockNumber: big.NewInt(0)}, TxContext{}, stateDb, &params.ChainConfig{IstanbulCompatibleBlock: big.NewInt(0)}, &Config{})
   115  
   116  	// Only stdout logging is tested to avoid file handling. It is used at vmLog test.
   117  	params.VMLogTarget = params.VMLogToStdout
   118  
   119  	// Generate EOA. It is used at validateSender test.
   120  	k, err := crypto.HexToECDSA("98275a145bc1726eb0445433088f5f882f8a4a9499135239cfb4040e78991dab")
   121  	accKey := accountkey.NewAccountKeyPublicWithValue(&k.PublicKey)
   122  	stateDb.CreateEOA(common.HexToAddress("0x123456789"), false, accKey)
   123  
   124  	return contract, evm, err
   125  }
   126  
   127  func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
   128  	p := allPrecompiles[common.HexToAddress(addr)]
   129  	in := common.Hex2Bytes(test.Input)
   130  	reqGas, _ := p.GetRequiredGasAndComputationCost(in)
   131  
   132  	contract, evm, err := prepare(reqGas)
   133  	require.NoError(t, err)
   134  
   135  	t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, reqGas), func(t *testing.T) {
   136  		if res, _, err := RunPrecompiledContract(p, in, contract, evm); err != nil {
   137  			t.Error(err)
   138  		} else if common.Bytes2Hex(res) != test.Expected {
   139  			t.Errorf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res))
   140  		}
   141  	})
   142  }
   143  
   144  func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) {
   145  	p := allPrecompiles[common.HexToAddress(addr)]
   146  	in := common.Hex2Bytes(test.Input)
   147  	reqGas, _ := p.GetRequiredGasAndComputationCost(in)
   148  	reqGas -= 1
   149  
   150  	contract, evm, _ := prepare(reqGas)
   151  
   152  	t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, reqGas), func(t *testing.T) {
   153  		_, _, err := RunPrecompiledContract(p, in, contract, evm)
   154  		if err.Error() != "out of gas" {
   155  			t.Errorf("Expected error [out of gas], got [%v]", err)
   156  		}
   157  		// Verify that the precompile did not touch the input buffer
   158  		exp := common.Hex2Bytes(test.Input)
   159  		if !bytes.Equal(in, exp) {
   160  			t.Errorf("Precompiled %v modified input data", addr)
   161  		}
   162  	})
   163  }
   164  
   165  func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing.T) {
   166  	p := allPrecompiles[common.HexToAddress(addr)]
   167  	in := common.Hex2Bytes(test.Input)
   168  	reqGas, _ := p.GetRequiredGasAndComputationCost(in)
   169  
   170  	contract, evm, _ := prepare(reqGas)
   171  
   172  	t.Run(test.Name, func(t *testing.T) {
   173  		_, _, err := RunPrecompiledContract(p, in, contract, evm)
   174  		if err.Error() != test.ExpectedError {
   175  			t.Errorf("Expected error [%v], got [%v]", test.ExpectedError, err)
   176  		}
   177  		// Verify that the precompile did not touch the input buffer
   178  		exp := common.Hex2Bytes(test.Input)
   179  		if !bytes.Equal(in, exp) {
   180  			t.Errorf("Precompiled %v modified input data", addr)
   181  		}
   182  	})
   183  }
   184  
   185  func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) {
   186  	if test.NoBenchmark {
   187  		return
   188  	}
   189  	p := allPrecompiles[common.HexToAddress(addr)]
   190  	in := common.Hex2Bytes(test.Input)
   191  	reqGas, _ := p.GetRequiredGasAndComputationCost(in)
   192  
   193  	contract, evm, _ := prepare(reqGas)
   194  
   195  	var (
   196  		res  []byte
   197  		err  error
   198  		data = make([]byte, len(in))
   199  	)
   200  
   201  	bench.Run(fmt.Sprintf("%s-Gas=%d", test.Name, contract.Gas), func(bench *testing.B) {
   202  		bench.ResetTimer()
   203  		for i := 0; i < bench.N; i++ {
   204  			contract.Gas = reqGas
   205  			copy(data, in)
   206  			res, _, err = RunPrecompiledContract(p, data, contract, evm)
   207  		}
   208  		bench.StopTimer()
   209  		// Check if it is correct
   210  		if err != nil {
   211  			bench.Error(err)
   212  			return
   213  		}
   214  		if common.Bytes2Hex(res) != test.Expected {
   215  			bench.Error(fmt.Sprintf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res)))
   216  			return
   217  		}
   218  	})
   219  }
   220  
   221  // Tests the sample inputs of the ecrecover
   222  func TestPrecompiledEcrecover(t *testing.T)      { testJson("ecRecover", "01", t) }
   223  func BenchmarkPrecompiledEcrecover(b *testing.B) { benchJson("ecRecover", "01", b) }
   224  
   225  // Benchmarks the sample inputs from the SHA256 precompile.
   226  func BenchmarkPrecompiledSha256(b *testing.B) { benchJson("sha256", "02", b) }
   227  
   228  // Benchmarks the sample inputs from the RIPEMD precompile.
   229  func BenchmarkPrecompiledRipeMD(b *testing.B) { benchJson("ripeMD", "03", b) }
   230  
   231  // Benchmarks the sample inputs from the identity precompile.
   232  func BenchmarkPrecompiledIdentity(b *testing.B) { benchJson("identity", "04", b) }
   233  
   234  // Tests the sample inputs from the ModExp EIP 198.
   235  func TestPrecompiledModExp(t *testing.T)      { testJson("modexp", "05", t) }
   236  func BenchmarkPrecompiledModExp(b *testing.B) { benchJson("modexp", "05", b) }
   237  
   238  func TestPrecompiledModExpEip2565(t *testing.T)      { testJson("modexp_eip2565", "f5", t) }
   239  func BenchmarkPrecompiledModExpEip2565(b *testing.B) { benchJson("modexp_eip2565", "f5", b) }
   240  
   241  // Tests the sample inputs from the elliptic curve addition EIP 213.
   242  func TestPrecompiledBn256Add(t *testing.T)      { testJson("bn256Add", "06", t) }
   243  func BenchmarkPrecompiledBn256Add(b *testing.B) { benchJson("bn256Add", "06", b) }
   244  
   245  // Tests the sample inputs from the elliptic curve scalar multiplication EIP 213.
   246  func TestPrecompiledBn256ScalarMul(t *testing.T)      { testJson("bn256ScalarMul", "07", t) }
   247  func BenchmarkPrecompiledBn256ScalarMul(b *testing.B) { benchJson("bn256ScalarMul", "07", b) }
   248  
   249  // Tests the sample inputs from the elliptic curve pairing check EIP 197.
   250  func TestPrecompiledBn256Pairing(t *testing.T)      { testJson("bn256Pairing", "08", t) }
   251  func BenchmarkPrecompiledBn256Pairing(b *testing.B) { benchJson("bn256Pairing", "08", b) }
   252  
   253  func TestPrecompiledBlake2F(t *testing.T)              { testJson("blake2F", "09", t) }
   254  func BenchmarkPrecompiledBlake2F(b *testing.B)         { benchJson("blake2F", "09", b) }
   255  func TestPrecompileBlake2FMalformedInput(t *testing.T) { testJsonFail("blake2F", "09", t) }
   256  
   257  func TestPrecompiledPointEvaluation(t *testing.T)      { testJson("pointEvaluation", "a", t) }
   258  func BenchmarkPrecompiledPointEvaluation(b *testing.B) { benchJson("pointEvaluation", "a", b) }
   259  
   260  // Tests the sample inputs of the vmLog
   261  func TestPrecompiledVmLog(t *testing.T)      { testJson("vmLog", "3fd", t) }
   262  func BenchmarkPrecompiledVmLog(b *testing.B) { benchJson("vmLog", "3fd", b) }
   263  
   264  // Tests the sample inputs of the feePayer
   265  func TestFeePayerContract(t *testing.T)         { testJson("feePayer", "3fe", t) }
   266  func BenchmarkPrecompiledFeePayer(b *testing.B) { benchJson("feePayer", "3fe", b) }
   267  
   268  // Tests the sample inputs of the validateSender
   269  func TestValidateSenderContract(t *testing.T)         { testJson("validateSender", "3ff", t) }
   270  func BenchmarkPrecompiledValidateSender(b *testing.B) { benchJson("validateSender", "3ff", b) }
   271  
   272  // Tests OOG (out-of-gas) of modExp
   273  func TestPrecompiledModExpOOG(t *testing.T) {
   274  	modexpTests, err := loadJson("modexp")
   275  	if err != nil {
   276  		t.Fatal(err)
   277  	}
   278  	for _, test := range modexpTests {
   279  		testPrecompiledOOG("05", test, t)
   280  	}
   281  }
   282  
   283  func loadJson(name string) ([]precompiledTest, error) {
   284  	data, err := os.ReadFile(fmt.Sprintf("testdata/precompiles/%v.json", name))
   285  	if err != nil {
   286  		return nil, err
   287  	}
   288  	var testcases []precompiledTest
   289  	err = json.Unmarshal(data, &testcases)
   290  	return testcases, err
   291  }
   292  
   293  func loadJsonFail(name string) ([]precompiledFailureTest, error) {
   294  	data, err := os.ReadFile(fmt.Sprintf("testdata/precompiles/fail-%v.json", name))
   295  	if err != nil {
   296  		return nil, err
   297  	}
   298  	var testcases []precompiledFailureTest
   299  	err = json.Unmarshal(data, &testcases)
   300  	return testcases, err
   301  }
   302  
   303  func testJson(name, addr string, t *testing.T) {
   304  	tests, err := loadJson(name)
   305  	if err != nil {
   306  		t.Fatal(err)
   307  	}
   308  	for _, test := range tests {
   309  		testPrecompiled(addr, test, t)
   310  	}
   311  }
   312  
   313  func testJsonFail(name, addr string, t *testing.T) {
   314  	tests, err := loadJsonFail(name)
   315  	if err != nil {
   316  		t.Fatal(err)
   317  	}
   318  	for _, test := range tests {
   319  		testPrecompiledFailure(addr, test, t)
   320  	}
   321  }
   322  
   323  func benchJson(name, addr string, b *testing.B) {
   324  	tests, err := loadJson(name)
   325  	if err != nil {
   326  		b.Fatal(err)
   327  	}
   328  	for _, test := range tests {
   329  		benchmarkPrecompiled(addr, test, b)
   330  	}
   331  }
   332  
   333  // TestEVM_CVE_2021_39137 tests an EVM vulnerability described in https://nvd.nist.gov/vuln/detail/CVE-2021-39137.
   334  // The vulnerable EVM bytecode exploited in Ethereum is used as a test code.
   335  // Test code reference: https://etherscan.io/tx/0x1cb6fb36633d270edefc04d048145b4298e67b8aa82a9e5ec4aa1435dd770ce4.
   336  func TestEVM_CVE_2021_39137(t *testing.T) {
   337  	fromAddr := common.HexToAddress("0x1a02a619e51cc5f8a2a61d2a60f6c80476ee8ead")
   338  	contractAddr := common.HexToAddress("0x8eae784e072e961f76948a785b62c9a950fb17ae")
   339  
   340  	testCases := []struct {
   341  		name           string
   342  		expectedResult []byte
   343  		testCode       []byte
   344  	}{
   345  		{
   346  			"staticCall test",
   347  			contractAddr.Bytes(),
   348  			hexutil.MustDecode("0x3034526020600760203460045afa602034343e604034f3"),
   349  			/*
   350  				// Pseudo code of the decompiled testCode
   351  				memory[0:0x20] = address(this); // put contract address with padding left zero into the memory
   352  				staticCall(gas, 0x04, 0x0, 0x20, 0x07, 0x20);  // operands: gas, to, in offset, in size, out offset, out size
   353  				memory[0:0x20] = returnDataCopy(); // put the returned data from staticCall into the memory
   354  				return memory[0:0x40];
   355  
   356  				// Disassembly
   357  				0000    30  ADDRESS
   358  				0001    34  CALLVALUE
   359  				0002    52  MSTORE
   360  				0003    60  PUSH1 0x20
   361  				0005    60  PUSH1 0x07
   362  				0007    60  PUSH1 0x20
   363  				0009    34  CALLVALUE
   364  				000A    60  PUSH1 0x04
   365  				000C    5A  GAS
   366  				000D    FA  STATICCALL
   367  				000E    60  PUSH1 0x20
   368  				0010    34  CALLVALUE
   369  				0011    34  CALLVALUE
   370  				0012    3E  RETURNDATACOPY
   371  				0013    60  PUSH1 0x40
   372  				0015    34  CALLVALUE
   373  				0016    F3  *RETURN
   374  			*/
   375  		},
   376  		{
   377  			"call test",
   378  			contractAddr.Bytes(),
   379  			hexutil.MustDecode("0x30345260206007602060003460045af1602034343e604034f3"),
   380  		},
   381  		{
   382  			"callCode test",
   383  			contractAddr.Bytes(),
   384  			hexutil.MustDecode("0x30345260206007602060003460045af2602034343e604034f3"),
   385  		},
   386  		{
   387  			"delegateCall test",
   388  			contractAddr.Bytes(),
   389  			hexutil.MustDecode("0x3034526020600760203460045af4602034343e604034f3"),
   390  		},
   391  	}
   392  
   393  	gasLimit := uint64(99999999)
   394  	tracer := NewStructLogger(nil)
   395  	blockCtx := BlockContext{
   396  		CanTransfer: func(StateDB, common.Address, *big.Int) bool { return true },
   397  		Transfer:    func(StateDB, common.Address, common.Address, *big.Int) {},
   398  	}
   399  	stateDb, _ := state.New(common.Hash{}, state.NewDatabase(database.NewMemoryDBManager()), nil, nil)
   400  
   401  	for _, tc := range testCases {
   402  		stateDb.SetCode(contractAddr, tc.testCode)
   403  
   404  		evm := NewEVM(blockCtx, TxContext{}, stateDb, params.TestChainConfig, &Config{Debug: true, Tracer: tracer})
   405  		ret, _, err := evm.Call(AccountRef(fromAddr), contractAddr, nil, gasLimit, new(big.Int))
   406  		if err != nil {
   407  			t.Fatal(err)
   408  		}
   409  
   410  		if testing.Verbose() {
   411  			buf := new(bytes.Buffer)
   412  			WriteTrace(buf, tracer.StructLogs())
   413  			if buf.Len() == 0 {
   414  				t.Log("no EVM operation logs generated")
   415  			} else {
   416  				t.Log("EVM operation log:\n" + buf.String())
   417  			}
   418  			t.Logf("EVM output: 0x%x", tracer.Output())
   419  			t.Logf("EVM error: %v", tracer.Error())
   420  		}
   421  
   422  		assert.Equal(t, tc.expectedResult, ret[12:32])
   423  	}
   424  }