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