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, ¶ms.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 }