github.com/klaytn/klaytn@v1.12.1/tests/precompiled_contracts_test.go (about) 1 // Copyright 2019 The klaytn Authors 2 // This file is part of the klaytn library. 3 // 4 // The klaytn 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 klaytn 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 klaytn library. If not, see <http://www.gnu.org/licenses/>. 16 17 package tests 18 19 import ( 20 "crypto/sha256" 21 "fmt" 22 "math/big" 23 "strings" 24 "testing" 25 "time" 26 27 "github.com/klaytn/klaytn/accounts/abi" 28 "github.com/klaytn/klaytn/blockchain/types" 29 "github.com/klaytn/klaytn/common" 30 "github.com/klaytn/klaytn/common/hexutil" 31 "github.com/klaytn/klaytn/common/profile" 32 "github.com/klaytn/klaytn/crypto" 33 "github.com/stretchr/testify/require" 34 "golang.org/x/crypto/ripemd160" 35 ) 36 37 func TestPrecompiledContract(t *testing.T) { 38 prof := profile.NewProfiler() 39 40 if isCompilerAvailable() == false { 41 if testing.Verbose() { 42 fmt.Printf("TestFeePayerContract is skipped due to the lack of solc.") 43 } 44 return 45 } 46 47 // Initialize blockchain 48 start := time.Now() 49 bcdata, err := NewBCData(2000, 4) 50 if err != nil { 51 t.Fatal(err) 52 } 53 prof.Profile("main_init_blockchain", time.Now().Sub(start)) 54 defer bcdata.Shutdown() 55 56 // Initialize address-balance map for verification 57 start = time.Now() 58 accountMap := NewAccountMap() 59 if err := accountMap.Initialize(bcdata); err != nil { 60 t.Fatal(err) 61 } 62 prof.Profile("main_init_accountMap", time.Now().Sub(start)) 63 64 // Deploy the contract. 65 start = time.Now() 66 filepath := "../contracts/precompiledContracts/precompiled.sol" 67 contracts, err := deployContract(filepath, bcdata, accountMap, prof) 68 if err != nil { 69 t.Fatal(err) 70 } 71 prof.Profile("main_deployContract", time.Now().Sub(start)) 72 73 signer := types.MakeSigner(bcdata.bc.Config(), bcdata.bc.CurrentHeader().Number) 74 75 // PrecompiledContracts 0x01: ecrecover 76 { 77 c := contracts["../contracts/precompiledContracts/precompiled.sol:PrecompiledEcrecover"] 78 abii, err := abi.JSON(strings.NewReader(c.abi)) 79 80 hash := crypto.Keccak256Hash([]byte{1, 2, 3, 4}) 81 sig, err := crypto.Sign(hash[:], bcdata.privKeys[0]) 82 require.NoError(t, err) 83 84 v := sig[crypto.RecoveryIDOffset] + 27 85 var r, s [32]byte 86 copy(r[:], sig[:32]) 87 copy(s[:], sig[32:64]) 88 89 // Make an input data for the contract call. 90 data, err := abii.Pack("callEcrecover", hash, v, r, s) 91 if err != nil { 92 t.Fatal(err) 93 } 94 95 n := accountMap.GetNonce(*bcdata.addrs[0]) 96 97 tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractExecution, map[types.TxValueKeyType]interface{}{ 98 types.TxValueKeyNonce: n, 99 types.TxValueKeyFeePayer: *bcdata.addrs[1], 100 types.TxValueKeyGasPrice: big.NewInt(0), 101 types.TxValueKeyGasLimit: uint64(5000000), 102 types.TxValueKeyFrom: *bcdata.addrs[0], 103 types.TxValueKeyAmount: big.NewInt(0), 104 types.TxValueKeyTo: c.address, 105 types.TxValueKeyData: data, 106 }) 107 require.Equal(t, nil, err) 108 109 err = tx.Sign(signer, bcdata.privKeys[0]) 110 require.Equal(t, nil, err) 111 112 err = tx.SignFeePayer(signer, bcdata.privKeys[1]) 113 require.Equal(t, nil, err) 114 115 ret, err := callContract(bcdata, tx) 116 require.Equal(t, nil, err) 117 118 // Check the returned value. 119 var addr common.Address 120 if err := abii.UnpackIntoInterface(&addr, "callEcrecover", ret); err != nil { 121 t.Fatal(err) 122 } 123 require.Equal(t, *bcdata.addrs[0], addr) 124 } 125 126 // PrecompiledContracts 0x02: sha256 127 { 128 c := contracts["../contracts/precompiledContracts/precompiled.sol:PrecompiledSha256Hash"] 129 abii, err := abi.JSON(strings.NewReader(c.abi)) 130 131 fn := "callSha256" 132 133 dd := []byte{1, 2, 3, 4} 134 hash := sha256.Sum256(dd) 135 136 // Make an input data for the contract call. 137 data, err := abii.Pack(fn, dd) 138 if err != nil { 139 t.Fatal(err) 140 } 141 142 n := accountMap.GetNonce(*bcdata.addrs[0]) 143 144 tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractExecution, map[types.TxValueKeyType]interface{}{ 145 types.TxValueKeyNonce: n, 146 types.TxValueKeyFeePayer: *bcdata.addrs[1], 147 types.TxValueKeyGasPrice: big.NewInt(0), 148 types.TxValueKeyGasLimit: uint64(5000000), 149 types.TxValueKeyFrom: *bcdata.addrs[0], 150 types.TxValueKeyAmount: big.NewInt(0), 151 types.TxValueKeyTo: c.address, 152 types.TxValueKeyData: data, 153 }) 154 require.Equal(t, nil, err) 155 156 err = tx.Sign(signer, bcdata.privKeys[0]) 157 require.Equal(t, nil, err) 158 159 err = tx.SignFeePayer(signer, bcdata.privKeys[1]) 160 require.Equal(t, nil, err) 161 162 ret, err := callContract(bcdata, tx) 163 require.Equal(t, nil, err) 164 165 // Check the returned value. 166 var addr [32]byte 167 var bb [32]byte 168 copy(bb[:], hash[:]) 169 if err := abii.UnpackIntoInterface(&addr, fn, ret); err != nil { 170 t.Fatal(err) 171 } 172 require.Equal(t, bb, addr) 173 } 174 175 // PrecompiledContracts 0x03: ripemd160 176 { 177 c := contracts["../contracts/precompiledContracts/precompiled.sol:PrecompiledRipemd160Hash"] 178 abii, err := abi.JSON(strings.NewReader(c.abi)) 179 180 fn := "callRipemd160" 181 182 dd := []byte{1, 2, 3, 4} 183 ripemd := ripemd160.New() 184 ripemd.Write(dd) 185 hash := ripemd.Sum(nil) 186 187 // Make an input data for the contract call. 188 data, err := abii.Pack(fn, dd) 189 if err != nil { 190 t.Fatal(err) 191 } 192 193 n := accountMap.GetNonce(*bcdata.addrs[0]) 194 195 tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractExecution, map[types.TxValueKeyType]interface{}{ 196 types.TxValueKeyNonce: n, 197 types.TxValueKeyFeePayer: *bcdata.addrs[1], 198 types.TxValueKeyGasPrice: big.NewInt(0), 199 types.TxValueKeyGasLimit: uint64(5000000), 200 types.TxValueKeyFrom: *bcdata.addrs[0], 201 types.TxValueKeyAmount: big.NewInt(0), 202 types.TxValueKeyTo: c.address, 203 types.TxValueKeyData: data, 204 }) 205 require.Equal(t, nil, err) 206 207 err = tx.Sign(signer, bcdata.privKeys[0]) 208 require.Equal(t, nil, err) 209 210 err = tx.SignFeePayer(signer, bcdata.privKeys[1]) 211 require.Equal(t, nil, err) 212 213 ret, err := callContract(bcdata, tx) 214 require.Equal(t, nil, err) 215 216 // Check the returned value. 217 var addr [32]byte 218 var bb [32]byte 219 copy(bb[:], hash[:]) 220 if err := abii.UnpackIntoInterface(&addr, fn, ret); err != nil { 221 t.Fatal(err) 222 } 223 require.Equal(t, bb, addr) 224 } 225 226 // PrecompiledContracts 0x04: datacopy (identity) 227 { 228 c := contracts["../contracts/precompiledContracts/precompiled.sol:PrecompiledDatacopy"] 229 abii, err := abi.JSON(strings.NewReader(c.abi)) 230 231 fn := "callDatacopy" 232 233 dd := []byte{1, 2, 3, 4} 234 235 // Make an input data for the contract call. 236 data, err := abii.Pack(fn, dd) 237 if err != nil { 238 t.Fatal(err) 239 } 240 241 n := accountMap.GetNonce(*bcdata.addrs[0]) 242 243 tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractExecution, map[types.TxValueKeyType]interface{}{ 244 types.TxValueKeyNonce: n, 245 types.TxValueKeyFeePayer: *bcdata.addrs[1], 246 types.TxValueKeyGasPrice: big.NewInt(0), 247 types.TxValueKeyGasLimit: uint64(5000000), 248 types.TxValueKeyFrom: *bcdata.addrs[0], 249 types.TxValueKeyAmount: big.NewInt(0), 250 types.TxValueKeyTo: c.address, 251 types.TxValueKeyData: data, 252 }) 253 require.Equal(t, nil, err) 254 255 err = tx.Sign(signer, bcdata.privKeys[0]) 256 require.Equal(t, nil, err) 257 258 err = tx.SignFeePayer(signer, bcdata.privKeys[1]) 259 require.Equal(t, nil, err) 260 261 ret, err := callContract(bcdata, tx) 262 require.Equal(t, nil, err) 263 264 // Check the returned value. 265 var addr []byte 266 if err := abii.UnpackIntoInterface(&addr, fn, ret); err != nil { 267 t.Fatal(err) 268 } 269 require.Equal(t, dd, addr) 270 } 271 272 // PrecompiledContracts 0x05: bigModExp 273 { 274 c := contracts["../contracts/precompiledContracts/precompiled.sol:PrecompiledBigModExp"] 275 abii, err := abi.JSON(strings.NewReader(c.abi)) 276 277 fn := "callBigModExp" 278 279 var base, exp, mod [32]byte 280 copy(base[:], hexutil.MustDecode("0x0000000000000000000000000000000462e4ded88953a39ce849a8a7fa163fa9")) 281 copy(exp[:], hexutil.MustDecode("0x1f4a3123ff1223a1b0d040057af8a9fe70baa9258e0b959273ffc5718c6d4cc7")) 282 copy(mod[:], hexutil.MustDecode("0x00000000000000000000000000077d29a9c710b7e616683f194f18c43b43b869")) 283 284 // Make an input data for the contract call. 285 data, err := abii.Pack(fn, base, exp, mod) 286 if err != nil { 287 t.Fatal(err) 288 } 289 290 n := accountMap.GetNonce(*bcdata.addrs[0]) 291 292 tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractExecution, map[types.TxValueKeyType]interface{}{ 293 types.TxValueKeyNonce: n, 294 types.TxValueKeyFeePayer: *bcdata.addrs[1], 295 types.TxValueKeyGasPrice: big.NewInt(0), 296 types.TxValueKeyGasLimit: uint64(5000000), 297 types.TxValueKeyFrom: *bcdata.addrs[0], 298 types.TxValueKeyAmount: big.NewInt(0), 299 types.TxValueKeyTo: c.address, 300 types.TxValueKeyData: data, 301 }) 302 require.Equal(t, nil, err) 303 304 err = tx.Sign(signer, bcdata.privKeys[0]) 305 require.Equal(t, nil, err) 306 307 err = tx.SignFeePayer(signer, bcdata.privKeys[1]) 308 require.Equal(t, nil, err) 309 310 ret, err := callContract(bcdata, tx) 311 require.Equal(t, nil, err) 312 313 // Check the returned value. 314 var result [32]byte 315 if err := abii.UnpackIntoInterface(&result, fn, ret); err != nil { 316 t.Fatal(err) 317 } 318 require.Equal(t, hexutil.MustDecode("0x0000000000000000000000000002dc17ba6bb47224fccc9a5ece97e2f691b4aa"), result[:]) 319 } 320 321 // PrecompiledContracts 0x06: bn256Add 322 { 323 c := contracts["../contracts/precompiledContracts/precompiled.sol:PrecompiledBn256Add"] 324 abii, err := abi.JSON(strings.NewReader(c.abi)) 325 326 fn := "callBn256Add" 327 328 var ax, ay, bx, by [32]byte 329 copy(ax[:], hexutil.MustDecode("0x17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa9")) 330 copy(ay[:], hexutil.MustDecode("0x01e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c")) 331 copy(bx[:], hexutil.MustDecode("0x039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869")) 332 copy(by[:], hexutil.MustDecode("0x073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98")) 333 334 // Make an input data for the contract call. 335 data, err := abii.Pack(fn, ax, ay, bx, by) 336 if err != nil { 337 t.Fatal(err) 338 } 339 340 n := accountMap.GetNonce(*bcdata.addrs[0]) 341 342 tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractExecution, map[types.TxValueKeyType]interface{}{ 343 types.TxValueKeyNonce: n, 344 types.TxValueKeyFeePayer: *bcdata.addrs[1], 345 types.TxValueKeyGasPrice: big.NewInt(0), 346 types.TxValueKeyGasLimit: uint64(5000000), 347 types.TxValueKeyFrom: *bcdata.addrs[0], 348 types.TxValueKeyAmount: big.NewInt(0), 349 types.TxValueKeyTo: c.address, 350 types.TxValueKeyData: data, 351 }) 352 require.Equal(t, nil, err) 353 354 err = tx.Sign(signer, bcdata.privKeys[0]) 355 require.Equal(t, nil, err) 356 357 err = tx.SignFeePayer(signer, bcdata.privKeys[1]) 358 require.Equal(t, nil, err) 359 360 ret, err := callContract(bcdata, tx) 361 require.Equal(t, nil, err) 362 363 // Check the returned value. 364 var result [2][32]byte 365 if err := abii.UnpackIntoInterface(&result, fn, ret); err != nil { 366 t.Fatal(err) 367 } 368 require.Equal(t, hexutil.MustDecode("0x15bf2bb17880144b5d1cd2b1f46eff9d617bffd1ca57c37fb5a49bd84e53cf66"), result[0][:]) 369 require.Equal(t, hexutil.MustDecode("0x049c797f9ce0d17083deb32b5e36f2ea2a212ee036598dd7624c168993d1355f"), result[1][:]) 370 } 371 372 // PrecompiledContracts 0x07: bn256ScalarMul 373 { 374 c := contracts["../contracts/precompiledContracts/precompiled.sol:PrecompiledBn256ScalarMul"] 375 abii, err := abi.JSON(strings.NewReader(c.abi)) 376 377 fn := "callBn256ScalarMul" 378 379 var ax, ay, scalar [32]byte 380 copy(ax[:], hexutil.MustDecode("0x2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb7")) 381 copy(ay[:], hexutil.MustDecode("0x21611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb204")) 382 copy(scalar[:], hexutil.MustDecode("0x00000000000000000000000000000000000000000000000011138ce750fa15c2")) 383 384 // Make an input data for the contract call. 385 data, err := abii.Pack(fn, ax, ay, scalar) 386 if err != nil { 387 t.Fatal(err) 388 } 389 390 n := accountMap.GetNonce(*bcdata.addrs[0]) 391 392 tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractExecution, map[types.TxValueKeyType]interface{}{ 393 types.TxValueKeyNonce: n, 394 types.TxValueKeyFeePayer: *bcdata.addrs[1], 395 types.TxValueKeyGasPrice: big.NewInt(0), 396 types.TxValueKeyGasLimit: uint64(5000000), 397 types.TxValueKeyFrom: *bcdata.addrs[0], 398 types.TxValueKeyAmount: big.NewInt(0), 399 types.TxValueKeyTo: c.address, 400 types.TxValueKeyData: data, 401 }) 402 require.Equal(t, nil, err) 403 404 err = tx.Sign(signer, bcdata.privKeys[0]) 405 require.Equal(t, nil, err) 406 407 err = tx.SignFeePayer(signer, bcdata.privKeys[1]) 408 require.Equal(t, nil, err) 409 410 ret, err := callContract(bcdata, tx) 411 require.Equal(t, nil, err) 412 413 // Check the returned value. 414 var result [2][32]byte 415 if err := abii.UnpackIntoInterface(&result, fn, ret); err != nil { 416 t.Fatal(err) 417 } 418 require.Equal(t, hexutil.MustDecode("0x070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c"), result[0][:]) 419 require.Equal(t, hexutil.MustDecode("0x031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc"), result[1][:]) 420 } 421 422 // PrecompiledContracts 0x08: bn256Paring 423 { 424 c := contracts["../contracts/precompiledContracts/precompiled.sol:PrecompiledBn256Pairing"] 425 abii, err := abi.JSON(strings.NewReader(c.abi)) 426 427 fn := "callBn256Pairing" 428 429 x1 := hexutil.MustDecode("0x1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59") 430 y1 := hexutil.MustDecode("0x3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41") 431 x2 := hexutil.MustDecode("0x209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf7") 432 y2 := hexutil.MustDecode("0x04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a41678") 433 x3 := hexutil.MustDecode("0x2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d") 434 y3 := hexutil.MustDecode("0x120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550") 435 x4 := hexutil.MustDecode("0x111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c") 436 y4 := hexutil.MustDecode("0x2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411") 437 x5 := hexutil.MustDecode("0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2") 438 y5 := hexutil.MustDecode("0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed") 439 x6 := hexutil.MustDecode("0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b") 440 y6 := hexutil.MustDecode("0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa") 441 442 input := make([]byte, 32*2*6) 443 copy(input[32*0:32*1], x1) 444 copy(input[32*1:32*2], y1) 445 copy(input[32*2:32*3], x2) 446 copy(input[32*3:32*4], y2) 447 copy(input[32*4:32*5], x3) 448 copy(input[32*5:32*6], y3) 449 copy(input[32*6:32*7], x4) 450 copy(input[32*7:32*8], y4) 451 copy(input[32*8:32*9], x5) 452 copy(input[32*9:32*10], y5) 453 copy(input[32*10:32*11], x6) 454 copy(input[32*11:32*12], y6) 455 456 // Make an input data for the contract call. 457 data, err := abii.Pack(fn, input) 458 if err != nil { 459 t.Fatal(err) 460 } 461 462 n := accountMap.GetNonce(*bcdata.addrs[0]) 463 464 tx, err := types.NewTransactionWithMap(types.TxTypeFeeDelegatedSmartContractExecution, map[types.TxValueKeyType]interface{}{ 465 types.TxValueKeyNonce: n, 466 types.TxValueKeyFeePayer: *bcdata.addrs[1], 467 types.TxValueKeyGasPrice: big.NewInt(0), 468 types.TxValueKeyGasLimit: uint64(5000000), 469 types.TxValueKeyFrom: *bcdata.addrs[0], 470 types.TxValueKeyAmount: big.NewInt(0), 471 types.TxValueKeyTo: c.address, 472 types.TxValueKeyData: data, 473 }) 474 require.Equal(t, nil, err) 475 476 err = tx.Sign(signer, bcdata.privKeys[0]) 477 require.Equal(t, nil, err) 478 479 err = tx.SignFeePayer(signer, bcdata.privKeys[1]) 480 require.Equal(t, nil, err) 481 482 ret, err := callContract(bcdata, tx) 483 require.Equal(t, nil, err) 484 485 // Check the returned value. 486 var result [32]byte 487 if err := abii.UnpackIntoInterface(&result, fn, ret); err != nil { 488 t.Fatal(err) 489 } 490 require.Equal(t, hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000000001"), result[:]) 491 } 492 }