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