github.com/vechain/thor@v1.7.4/vm/contracts_test.go (about) 1 // Copyright 2017 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 vm 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "fmt" 23 "io/ioutil" 24 "math/big" 25 "testing" 26 "time" 27 28 "github.com/ethereum/go-ethereum/common" 29 ) 30 31 // precompiledTest defines the input/output pairs for precompiled contract tests. 32 type precompiledTest struct { 33 Input, Expected string 34 Gas uint64 35 Name string 36 NoBenchmark bool // Benchmark primarily the worst-cases 37 } 38 39 // precompiledFailureTest defines the input/error pairs for precompiled 40 // contract failure tests. 41 type precompiledFailureTest struct { 42 Input string 43 ExpectedError string 44 Name string 45 } 46 47 // allPrecompiles does not map to the actual set of precompiles, as it also contains 48 // repriced versions of precompiles at certain slots 49 var allPrecompiles = map[common.Address]PrecompiledContract{ 50 common.BytesToAddress([]byte{1}): &safe_ecrecover{}, 51 common.BytesToAddress([]byte{2}): &sha256hash{}, 52 common.BytesToAddress([]byte{3}): &ripemd160hash{}, 53 common.BytesToAddress([]byte{4}): &dataCopy{}, 54 common.BytesToAddress([]byte{5}): &bigModExp{}, 55 common.BytesToAddress([]byte{6}): &bn256Add{}, 56 common.BytesToAddress([]byte{7}): &bn256ScalarMul{}, 57 common.BytesToAddress([]byte{8}): &bn256Pairing{}, 58 common.BytesToAddress([]byte{9}): &blake2F{}, 59 } 60 61 // EIP-152 test vectors 62 var blake2FMalformedInputTests = []precompiledFailureTest{ 63 { 64 Input: "", 65 ExpectedError: errBlake2FInvalidInputLength.Error(), 66 Name: "vector 0: empty input", 67 }, 68 { 69 Input: "00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", 70 ExpectedError: errBlake2FInvalidInputLength.Error(), 71 Name: "vector 1: less than 213 bytes input", 72 }, 73 { 74 Input: "000000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", 75 ExpectedError: errBlake2FInvalidInputLength.Error(), 76 Name: "vector 2: more than 213 bytes input", 77 }, 78 { 79 Input: "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000002", 80 ExpectedError: errBlake2FInvalidFinalFlag.Error(), 81 Name: "vector 3: malformed final block indicator flag", 82 }, 83 } 84 85 func testPrecompiled(addr string, test precompiledTest, t *testing.T) { 86 p := allPrecompiles[common.HexToAddress(addr)] 87 in := common.Hex2Bytes(test.Input) 88 gas := p.RequiredGas(in) 89 contract := NewContract(AccountRef(common.HexToAddress("1337")), 90 nil, new(big.Int), gas) 91 92 t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) { 93 if res, err := RunPrecompiledContract(p, in, contract); err != nil { 94 t.Error(err) 95 } else if common.Bytes2Hex(res) != test.Expected { 96 t.Errorf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res)) 97 } 98 if expGas := test.Gas; expGas != gas { 99 t.Errorf("%v: gas wrong, expected %d, got %d", test.Name, expGas, gas) 100 } 101 // Verify that the precompile did not touch the input buffer 102 exp := common.Hex2Bytes(test.Input) 103 if !bytes.Equal(in, exp) { 104 t.Errorf("Precompiled %v modified input data", addr) 105 } 106 }) 107 } 108 109 func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) { 110 p := allPrecompiles[common.HexToAddress(addr)] 111 in := common.Hex2Bytes(test.Input) 112 gas := p.RequiredGas(in) - 1 113 contract := NewContract(AccountRef(common.HexToAddress("1337")), 114 nil, new(big.Int), gas) 115 t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) { 116 _, err := RunPrecompiledContract(p, in, contract) 117 if err.Error() != "out of gas" { 118 t.Errorf("Expected error [out of gas], got [%v]", err) 119 } 120 // Verify that the precompile did not touch the input buffer 121 exp := common.Hex2Bytes(test.Input) 122 if !bytes.Equal(in, exp) { 123 t.Errorf("Precompiled %v modified input data", addr) 124 } 125 }) 126 } 127 128 func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing.T) { 129 p := allPrecompiles[common.HexToAddress(addr)] 130 in := common.Hex2Bytes(test.Input) 131 gas := p.RequiredGas(in) 132 contract := NewContract(AccountRef(common.HexToAddress("1337")), 133 nil, new(big.Int), gas) 134 t.Run(test.Name, func(t *testing.T) { 135 _, err := RunPrecompiledContract(p, in, contract) 136 if err.Error() != test.ExpectedError { 137 t.Errorf("Expected error [%v], got [%v]", test.ExpectedError, err) 138 } 139 // Verify that the precompile did not touch the input buffer 140 exp := common.Hex2Bytes(test.Input) 141 if !bytes.Equal(in, exp) { 142 t.Errorf("Precompiled %v modified input data", addr) 143 } 144 }) 145 } 146 147 func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) { 148 if test.NoBenchmark { 149 return 150 } 151 p := allPrecompiles[common.HexToAddress(addr)] 152 in := common.Hex2Bytes(test.Input) 153 reqGas := p.RequiredGas(in) 154 155 var ( 156 res []byte 157 err error 158 data = make([]byte, len(in)) 159 ) 160 161 bench.Run(fmt.Sprintf("%s-Gas=%d", test.Name, reqGas), func(bench *testing.B) { 162 bench.ReportAllocs() 163 start := time.Now() 164 bench.ResetTimer() 165 for i := 0; i < bench.N; i++ { 166 copy(data, in) 167 contract := NewContract(AccountRef(common.HexToAddress("1337")), 168 nil, new(big.Int), reqGas) 169 res, err = RunPrecompiledContract(p, data, contract) 170 } 171 bench.StopTimer() 172 elapsed := uint64(time.Since(start)) 173 if elapsed < 1 { 174 elapsed = 1 175 } 176 gasUsed := reqGas * uint64(bench.N) 177 bench.ReportMetric(float64(reqGas), "gas/op") 178 // Keep it as uint64, multiply 100 to get two digit float later 179 mgasps := (100 * 1000 * gasUsed) / elapsed 180 bench.ReportMetric(float64(mgasps)/100, "mgas/s") 181 //Check if it is correct 182 if err != nil { 183 bench.Error(err) 184 return 185 } 186 if common.Bytes2Hex(res) != test.Expected { 187 bench.Error(fmt.Sprintf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res))) 188 return 189 } 190 }) 191 } 192 193 // Benchmarks the sample inputs from the ECRECOVER precompile. 194 func BenchmarkPrecompiledEcrecover(bench *testing.B) { 195 t := precompiledTest{ 196 Input: "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02", 197 Expected: "000000000000000000000000ceaccac640adf55b2028469bd36ba501f28b699d", 198 Name: "", 199 } 200 benchmarkPrecompiled("01", t, bench) 201 } 202 203 // Benchmarks the sample inputs from the SHA256 precompile. 204 func BenchmarkPrecompiledSha256(bench *testing.B) { 205 t := precompiledTest{ 206 Input: "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02", 207 Expected: "811c7003375852fabd0d362e40e68607a12bdabae61a7d068fe5fdd1dbbf2a5d", 208 Name: "128", 209 } 210 benchmarkPrecompiled("02", t, bench) 211 } 212 213 // Benchmarks the sample inputs from the RIPEMD precompile. 214 func BenchmarkPrecompiledRipeMD(bench *testing.B) { 215 t := precompiledTest{ 216 Input: "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02", 217 Expected: "0000000000000000000000009215b8d9882ff46f0dfde6684d78e831467f65e6", 218 Name: "128", 219 } 220 benchmarkPrecompiled("03", t, bench) 221 } 222 223 // Benchmarks the sample inputs from the identiy precompile. 224 func BenchmarkPrecompiledIdentity(bench *testing.B) { 225 t := precompiledTest{ 226 Input: "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02", 227 Expected: "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02", 228 Name: "128", 229 } 230 benchmarkPrecompiled("04", t, bench) 231 } 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 // Tests the sample inputs from the elliptic curve addition EIP 213. 238 func TestPrecompiledBn256Add(t *testing.T) { testJson("bn256Add", "06", t) } 239 func BenchmarkPrecompiledBn256Add(b *testing.B) { benchJson("bn256Add", "06", b) } 240 241 // Tests OOG 242 func TestPrecompiledModExpOOG(t *testing.T) { 243 modexpTests, err := loadJson("modexp") 244 if err != nil { 245 t.Fatal(err) 246 } 247 for _, test := range modexpTests { 248 testPrecompiledOOG("05", test, t) 249 } 250 } 251 252 // Tests the sample inputs from the elliptic curve scalar multiplication EIP 213. 253 func TestPrecompiledBn256ScalarMul(t *testing.T) { testJson("bn256ScalarMul", "07", t) } 254 func BenchmarkPrecompiledBn256ScalarMul(b *testing.B) { benchJson("bn256ScalarMul", "07", b) } 255 256 // Tests the sample inputs from the elliptic curve pairing check EIP 197. 257 func TestPrecompiledBn256Pairing(t *testing.T) { testJson("bn256Pairing", "08", t) } 258 func BenchmarkPrecompiledBn256Pairing(b *testing.B) { benchJson("bn256Pairing", "08", b) } 259 260 func TestPrecompiledBlake2F(t *testing.T) { testJson("blake2F", "09", t) } 261 func BenchmarkPrecompiledBlake2F(b *testing.B) { benchJson("blake2F", "09", b) } 262 263 func TestPrecompileBlake2FMalformedInput(t *testing.T) { 264 for _, test := range blake2FMalformedInputTests { 265 testPrecompiledFailure("09", test, t) 266 } 267 } 268 269 func TestPrecompiledEcrecover(t *testing.T) { testJson("ecRecover", "01", t) } 270 271 func testJson(name, addr string, t *testing.T) { 272 tests, err := loadJson(name) 273 if err != nil { 274 t.Fatal(err) 275 } 276 for _, test := range tests { 277 testPrecompiled(addr, test, t) 278 } 279 } 280 281 func testJsonFail(name, addr string, t *testing.T) { 282 tests, err := loadJsonFail(name) 283 if err != nil { 284 t.Fatal(err) 285 } 286 for _, test := range tests { 287 testPrecompiledFailure(addr, test, t) 288 } 289 } 290 291 func benchJson(name, addr string, b *testing.B) { 292 tests, err := loadJson(name) 293 if err != nil { 294 b.Fatal(err) 295 } 296 for _, test := range tests { 297 benchmarkPrecompiled(addr, test, b) 298 } 299 } 300 301 func loadJson(name string) ([]precompiledTest, error) { 302 data, err := ioutil.ReadFile(fmt.Sprintf("testdata/precompiles/%v.json", name)) 303 if err != nil { 304 return nil, err 305 } 306 var testcases []precompiledTest 307 err = json.Unmarshal(data, &testcases) 308 return testcases, err 309 } 310 311 func loadJsonFail(name string) ([]precompiledFailureTest, error) { 312 data, err := ioutil.ReadFile(fmt.Sprintf("testdata/precompiles/fail-%v.json", name)) 313 if err != nil { 314 return nil, err 315 } 316 var testcases []precompiledFailureTest 317 err = json.Unmarshal(data, &testcases) 318 return testcases, err 319 }