diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 9a0309f9e..000000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -Cargo.lock linguist-generated=true -diff diff --git a/CHANGES.md b/CHANGES.md index 00b2ecab1..5aa303a27 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.4.0] - 2022-02-16 + +### Changes + +- Performance improvements by [@birchmd] and [@matklad]; the engine should now consume much less NEAR gas: ([#427]) ([#438]) ([#439]) ([#445]) ([#446]) +- Security improvment: only Engine contract owner can use the `deploy_upgrade` method by [@birchmd]. ([#410]) +- Bug fix: Engine now returns the error message in the case of a revert during an EVM contract deploy, previously it would always return an address (even when the deploy failed) by [@birchmd]. ([#424]) +- Security improvment: Engine will no longer accept EVM transactions without a chain ID as part of their signature by [@birchmd]. This should have no impact on users as all modern Ethereum tooling includes the chain ID. ([#432]) +- Improvements to code quality by [@mrLSD]: ([#386]) ([#387]) +- Improvements and additions to internal tests and benchmarks by [@birchmd]: ([#408]) ([#415]) ([#429]) + +[#386]: https://github.com/aurora-is-near/aurora-engine/pull/386 +[#387]: https://github.com/aurora-is-near/aurora-engine/pull/387 +[#408]: https://github.com/aurora-is-near/aurora-engine/pull/408 +[#410]: https://github.com/aurora-is-near/aurora-engine/pull/410 +[#415]: https://github.com/aurora-is-near/aurora-engine/pull/415 +[#424]: https://github.com/aurora-is-near/aurora-engine/pull/424 +[#427]: https://github.com/aurora-is-near/aurora-engine/pull/427 +[#429]: https://github.com/aurora-is-near/aurora-engine/pull/429 +[#432]: https://github.com/aurora-is-near/aurora-engine/pull/432 +[#438]: https://github.com/aurora-is-near/aurora-engine/pull/438 +[#439]: https://github.com/aurora-is-near/aurora-engine/pull/439 +[#445]: https://github.com/aurora-is-near/aurora-engine/pull/445 +[#446]: https://github.com/aurora-is-near/aurora-engine/pull/446 + ## [2.3.0] - 2021-12-10 ### Added @@ -180,7 +205,8 @@ struct SubmitResult { ## [1.0.0] - 2021-05-12 -[Unreleased]: https://github.com/aurora-is-near/aurora-engine/compare/2.3.0...master +[Unreleased]: https://github.com/aurora-is-near/aurora-engine/compare/2.4.0...master +[2.4.0]: https://github.com/aurora-is-near/aurora-engine/compare/2.3.0...2.4.0 [2.3.0]: https://github.com/aurora-is-near/aurora-engine/compare/2.2.0...2.3.0 [2.2.0]: https://github.com/aurora-is-near/aurora-engine/compare/2.1.0...2.2.0 [2.1.0]: https://github.com/aurora-is-near/aurora-engine/compare/2.0.2...2.1.0 @@ -209,3 +235,4 @@ struct SubmitResult { [@mfornet]: https://github.com/mfornet [@mrLSD]: https://github.com/mrLSD [@sept-en]: https://github.com/sept-en +[@matklad]: https://github.com/matklad diff --git a/Cargo.lock b/Cargo.lock index 34cae1abe..1959b9b08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,11 +19,11 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.15.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03345e98af8f3d786b6d9f656ccfa6ac316d954e92bc4841f0bba20789d5fb5a" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" dependencies = [ - "gimli 0.24.0", + "gimli 0.26.1", ] [[package]] @@ -38,6 +38,17 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" +[[package]] +name = "ahash" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98" +dependencies = [ + "getrandom 0.2.2", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "0.7.18" @@ -120,9 +131,9 @@ dependencies = [ "aurora-bn", "aurora-engine-precompiles", "aurora-engine-sdk", + "aurora-engine-transactions", "aurora-engine-types", "base64 0.13.0", - "blake2 0.9.1 (git+https://github.com/near/near-blake2.git)", "borsh 0.8.2", "byte-slice-cast", "ethabi", @@ -131,6 +142,7 @@ dependencies = [ "hex", "libsecp256k1", "logos", + "near-blake2", "num", "primitive-types 0.10.1", "rand 0.7.3", @@ -151,25 +163,21 @@ dependencies = [ "aurora-engine-sdk", "aurora-engine-types", "base64 0.13.0", - "blake2 0.9.1 (git+https://github.com/near/near-blake2.git)", "borsh 0.8.2", "ethabi", "evm", "evm-core", "hex", "libsecp256k1", - "logos", + "near-blake2", "num", "primitive-types 0.10.1", "rand 0.7.3", "ripemd160", - "rjson", - "rlp", "serde", "serde_json", "sha2 0.9.5", "sha3 0.9.1", - "wee_alloc", ] [[package]] @@ -189,6 +197,7 @@ dependencies = [ "aurora-engine", "aurora-engine-precompiles", "aurora-engine-sdk", + "aurora-engine-transactions", "aurora-engine-types", "base64 0.13.0", "borsh 0.8.2", @@ -204,20 +213,32 @@ dependencies = [ "git2", "hex", "libsecp256k1", - "near-crypto 0.1.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", - "near-primitives 0.1.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", - "near-primitives-core 0.1.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", + "near-crypto 0.0.0", + "near-primitives 0.0.0", + "near-primitives-core 0.0.0", "near-sdk", "near-sdk-sim", - "near-vm-logic 3.0.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", - "near-vm-runner 3.0.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", + "near-vm-logic 0.0.0", + "near-vm-runner 0.0.0", "rand 0.7.3", "rlp", "serde", "serde_json", "sha3 0.9.1", "tempfile", - "wasmer-near", + "walrus", +] + +[[package]] +name = "aurora-engine-transactions" +version = "1.0.0" +dependencies = [ + "aurora-engine-precompiles", + "aurora-engine-sdk", + "aurora-engine-types", + "evm", + "hex", + "rlp", ] [[package]] @@ -235,6 +256,18 @@ dependencies = [ "sha3 0.9.1", ] +[[package]] +name = "auto_impl" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7862e21c893d65a1650125d157eaeec691439379a1cee17ee49031b79236ada4" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.0.1" @@ -243,16 +276,16 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.59" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744" +checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" dependencies = [ - "addr2line 0.15.1", + "addr2line 0.17.0", "cc", "cfg-if 1.0.0", "libc", "miniz_oxide", - "object 0.24.0", + "object 0.27.1", "rustc-demangle", ] @@ -331,16 +364,6 @@ dependencies = [ "opaque-debug 0.3.0", ] -[[package]] -name = "blake2" -version = "0.9.1" -source = "git+https://github.com/near/near-blake2.git#736ff607cc8160af87ffa697c14ebef85050138f" -dependencies = [ - "crypto-mac 0.8.0", - "digest 0.9.0", - "opaque-debug 0.3.0", -] - [[package]] name = "blake3" version = "0.3.7" @@ -400,7 +423,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09a7111f797cc721407885a323fb071636aee57f750b1a4ddc27397eba168a74" dependencies = [ "borsh-derive 0.8.2", - "hashbrown", + "hashbrown 0.9.1", ] [[package]] @@ -410,7 +433,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18dda7dc709193c0d86a1a51050a926dc3df1cf262ec46a23a25dba421ea1924" dependencies = [ "borsh-derive 0.9.1", - "hashbrown", + "hashbrown 0.9.1", ] [[package]] @@ -519,6 +542,27 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +[[package]] +name = "bytecheck" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "314889ea31cda264cb7c3d6e6e5c9415a987ecb0e72c17c00d36fbb881d34abe" +dependencies = [ + "bytecheck_derive", + "ptr_meta", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a2b3b92c135dae665a6f760205b89187638e83bed17ef3e44e83c712cf30600" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "byteorder" version = "1.4.3" @@ -533,9 +577,9 @@ checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" [[package]] name = "bytesize" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da" +checksum = "6c58ec36aac5066d5ca17df51b3e70279f5670a72102f5752cb7e7c856adfc70" [[package]] name = "c2-chacha" @@ -558,7 +602,7 @@ dependencies = [ "cached_proc_macro", "cached_proc_macro_types", "futures", - "hashbrown", + "hashbrown 0.9.1", "once_cell", ] @@ -1149,7 +1193,7 @@ checksum = "42276e3f205fe63887cca255aa9a65a63fb72764c30b9a6252a7c7e46994f689" dependencies = [ "byteorder", "dynasm", - "memmap2", + "memmap2 0.2.2", ] [[package]] @@ -1200,27 +1244,13 @@ dependencies = [ "heapsize", ] -[[package]] -name = "engine-standalone" -version = "0.1.0" -dependencies = [ - "aurora-engine", - "aurora-engine-sdk", - "aurora-engine-types", - "borsh 0.8.2", - "engine-standalone-storage", - "engine-standalone-tracing", - "evm-core", - "libc", - "rocksdb", -] - [[package]] name = "engine-standalone-storage" version = "0.1.0" dependencies = [ "aurora-engine", "aurora-engine-sdk", + "aurora-engine-transactions", "aurora-engine-types", "base64 0.13.0", "borsh 0.8.2", @@ -1273,9 +1303,9 @@ checksum = "68b91989ae21441195d7d9b9993a2f9295c7e1a8c96255d8b729accddc124797" [[package]] name = "errno" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa68f2fb9cae9d37c9b2b3584aba698a2e97f72d7aef7b9f7aa71d8b54ce46fe" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" dependencies = [ "errno-dragonfly", "libc", @@ -1377,9 +1407,10 @@ checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" [[package]] name = "evm" -version = "0.31.1" -source = "git+https://github.com/aurora-is-near/sputnikvm.git#0fbde9fa7797308290f89111c6abe5cee55a5eac" +version = "0.33.1" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?rev=f4ee520254856898d451c7225851520a35c97cea#f4ee520254856898d451c7225851520a35c97cea" dependencies = [ + "auto_impl", "environmental", "ethereum", "evm-core", @@ -1396,8 +1427,8 @@ dependencies = [ [[package]] name = "evm-core" -version = "0.31.0" -source = "git+https://github.com/aurora-is-near/sputnikvm.git#0fbde9fa7797308290f89111c6abe5cee55a5eac" +version = "0.33.0" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?rev=f4ee520254856898d451c7225851520a35c97cea#f4ee520254856898d451c7225851520a35c97cea" dependencies = [ "funty", "parity-scale-codec", @@ -1408,8 +1439,8 @@ dependencies = [ [[package]] name = "evm-gasometer" -version = "0.31.0" -source = "git+https://github.com/aurora-is-near/sputnikvm.git#0fbde9fa7797308290f89111c6abe5cee55a5eac" +version = "0.33.0" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?rev=f4ee520254856898d451c7225851520a35c97cea#f4ee520254856898d451c7225851520a35c97cea" dependencies = [ "environmental", "evm-core", @@ -1419,9 +1450,10 @@ dependencies = [ [[package]] name = "evm-runtime" -version = "0.31.0" -source = "git+https://github.com/aurora-is-near/sputnikvm.git#0fbde9fa7797308290f89111c6abe5cee55a5eac" +version = "0.33.0" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?rev=f4ee520254856898d451c7225851520a35c97cea#f4ee520254856898d451c7225851520a35c97cea" dependencies = [ + "auto_impl", "environmental", "evm-core", "primitive-types 0.10.1", @@ -1657,9 +1689,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.24.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" [[package]] name = "git2" @@ -1709,7 +1741,16 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" dependencies = [ - "ahash", + "ahash 0.4.7", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash 0.7.4", ] [[package]] @@ -1776,6 +1817,12 @@ dependencies = [ "hmac 0.7.1", ] +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + [[package]] name = "ident_case" version = "1.0.1" @@ -1838,7 +1885,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.9.1", "serde", ] @@ -1951,9 +1998,9 @@ checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" [[package]] name = "libc" -version = "0.2.108" +version = "0.2.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119" +checksum = "0a8d982fa7a96a000f6ec4cfe966de9703eccde29750df2bb8949da91b0e818d" [[package]] name = "libgit2-sys" @@ -2115,6 +2162,15 @@ dependencies = [ "syn", ] +[[package]] +name = "lru" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "274353858935c992b13c0ca408752e2121da852d07dec7ce5f108c77dfa14d1f" +dependencies = [ + "hashbrown 0.11.2", +] + [[package]] name = "mach" version = "0.3.2" @@ -2155,9 +2211,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "memmap" @@ -2178,6 +2234,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memmap2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe3179b85e1fd8b14447cbebadb75e45a1002f541b925f0bfec366d56a81c56d" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.6.3" @@ -2233,8 +2298,8 @@ checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" [[package]] name = "near-account-id" -version = "0.1.0" -source = "git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228#0c9ad79a18e431f843e6123cf4559f9c2c5dd228" +version = "0.0.0" +source = "git+https://github.com/near/nearcore.git?rev=83fc0f7d6b212bacc49f058e7400743de3e59783#83fc0f7d6b212bacc49f058e7400743de3e59783" dependencies = [ "borsh 0.9.1", "serde", @@ -2249,6 +2314,24 @@ dependencies = [ "serde", ] +[[package]] +name = "near-blake2" +version = "0.9.1" +source = "git+https://github.com/near/near-blake2.git#cebb7df79608a7058017940830d37c37d55d21fe" +dependencies = [ + "crypto-mac 0.8.0", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "near-cache" +version = "0.0.0" +source = "git+https://github.com/near/nearcore.git?rev=83fc0f7d6b212bacc49f058e7400743de3e59783#83fc0f7d6b212bacc49f058e7400743de3e59783" +dependencies = [ + "lru", +] + [[package]] name = "near-chain-configs" version = "0.1.0" @@ -2267,20 +2350,20 @@ dependencies = [ [[package]] name = "near-crypto" -version = "0.1.0" -source = "git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228#0c9ad79a18e431f843e6123cf4559f9c2c5dd228" +version = "0.0.0" +source = "git+https://github.com/near/nearcore.git?rev=83fc0f7d6b212bacc49f058e7400743de3e59783#83fc0f7d6b212bacc49f058e7400743de3e59783" dependencies = [ "arrayref", - "blake2 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2", "borsh 0.9.1", "bs58", "c2-chacha", "curve25519-dalek", "derive_more", "ed25519-dalek", - "lazy_static", "libc", - "near-account-id 0.1.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", + "near-account-id 0.0.0", + "once_cell", "parity-secp256k1", "primitive-types 0.10.1", "rand 0.7.3", @@ -2297,7 +2380,7 @@ version = "0.1.0" source = "git+https://github.com/near/nearcore.git?rev=8a377fda0b4ce319385c463f1ae46e4b0b29dcd9#8a377fda0b4ce319385c463f1ae46e4b0b29dcd9" dependencies = [ "arrayref", - "blake2 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2", "borsh 0.8.2", "bs58", "c2-chacha", @@ -2306,7 +2389,7 @@ dependencies = [ "ed25519-dalek", "lazy_static", "libc", - "near-account-id 0.1.0 (git+https://github.com/near/nearcore.git?rev=8a377fda0b4ce319385c463f1ae46e4b0b29dcd9)", + "near-account-id 0.1.0", "parity-secp256k1", "primitive-types 0.10.1", "rand 0.7.3", @@ -2323,7 +2406,7 @@ version = "0.1.0" source = "git+https://github.com/near/nearcore.git?rev=8a37d39629885a41dde58b60642bcf1e99407d90#8a37d39629885a41dde58b60642bcf1e99407d90" dependencies = [ "arrayref", - "blake2 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2", "borsh 0.8.2", "bs58", "c2-chacha", @@ -2365,32 +2448,27 @@ dependencies = [ [[package]] name = "near-primitives" -version = "0.1.0" -source = "git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228#0c9ad79a18e431f843e6123cf4559f9c2c5dd228" +version = "0.0.0" +source = "git+https://github.com/near/nearcore.git?rev=83fc0f7d6b212bacc49f058e7400743de3e59783#83fc0f7d6b212bacc49f058e7400743de3e59783" dependencies = [ - "base64 0.13.0", "borsh 0.9.1", - "bs58", "byteorder", "bytesize", "chrono", "derive_more", "easy-ext", "hex", - "near-crypto 0.1.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", - "near-primitives-core 0.1.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", - "near-rpc-error-macro 0.1.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", - "near-vm-errors 3.0.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", + "near-crypto 0.0.0", + "near-primitives-core 0.0.0", + "near-rpc-error-macro 0.0.0", + "near-vm-errors 0.0.0", "num-rational 0.3.2", "primitive-types 0.10.1", "rand 0.7.3", "reed-solomon-erasure", - "regex", "serde", "serde_json", - "sha2 0.9.5", "smart-default", - "validator", ] [[package]] @@ -2455,19 +2533,16 @@ dependencies = [ [[package]] name = "near-primitives-core" -version = "0.1.0" -source = "git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228#0c9ad79a18e431f843e6123cf4559f9c2c5dd228" +version = "0.0.0" +source = "git+https://github.com/near/nearcore.git?rev=83fc0f7d6b212bacc49f058e7400743de3e59783#83fc0f7d6b212bacc49f058e7400743de3e59783" dependencies = [ "base64 0.11.0", "borsh 0.9.1", "bs58", "derive_more", - "hex", - "lazy_static", - "near-account-id 0.1.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", + "near-account-id 0.0.0", "num-rational 0.3.2", "serde", - "serde_json", "sha2 0.9.5", ] @@ -2482,7 +2557,7 @@ dependencies = [ "derive_more", "hex", "lazy_static", - "near-account-id 0.1.0 (git+https://github.com/near/nearcore.git?rev=8a377fda0b4ce319385c463f1ae46e4b0b29dcd9)", + "near-account-id 0.1.0", "num-rational 0.3.2", "serde", "serde_json", @@ -2508,10 +2583,9 @@ dependencies = [ [[package]] name = "near-rpc-error-core" -version = "0.1.0" -source = "git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228#0c9ad79a18e431f843e6123cf4559f9c2c5dd228" +version = "0.0.0" +source = "git+https://github.com/near/nearcore.git?rev=83fc0f7d6b212bacc49f058e7400743de3e59783#83fc0f7d6b212bacc49f058e7400743de3e59783" dependencies = [ - "proc-macro2", "quote", "serde", "syn", @@ -2541,14 +2615,11 @@ dependencies = [ [[package]] name = "near-rpc-error-macro" -version = "0.1.0" -source = "git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228#0c9ad79a18e431f843e6123cf4559f9c2c5dd228" +version = "0.0.0" +source = "git+https://github.com/near/nearcore.git?rev=83fc0f7d6b212bacc49f058e7400743de3e59783#83fc0f7d6b212bacc49f058e7400743de3e59783" dependencies = [ - "near-rpc-error-core 0.1.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", - "proc-macro2", - "quote", + "near-rpc-error-core 0.0.0", "serde", - "serde_json", "syn", ] @@ -2645,8 +2716,8 @@ dependencies = [ [[package]] name = "near-stable-hasher" -version = "0.1.0" -source = "git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228#0c9ad79a18e431f843e6123cf4559f9c2c5dd228" +version = "0.0.0" +source = "git+https://github.com/near/nearcore.git?rev=83fc0f7d6b212bacc49f058e7400743de3e59783#83fc0f7d6b212bacc49f058e7400743de3e59783" [[package]] name = "near-store" @@ -2676,13 +2747,12 @@ dependencies = [ [[package]] name = "near-vm-errors" -version = "3.0.0" -source = "git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228#0c9ad79a18e431f843e6123cf4559f9c2c5dd228" +version = "0.0.0" +source = "git+https://github.com/near/nearcore.git?rev=83fc0f7d6b212bacc49f058e7400743de3e59783#83fc0f7d6b212bacc49f058e7400743de3e59783" dependencies = [ "borsh 0.9.1", - "hex", - "near-account-id 0.1.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", - "near-rpc-error-macro 0.1.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", + "near-account-id 0.0.0", + "near-rpc-error-macro 0.0.0", "serde", ] @@ -2693,7 +2763,7 @@ source = "git+https://github.com/near/nearcore.git?rev=8a377fda0b4ce319385c463f1 dependencies = [ "borsh 0.8.2", "hex", - "near-account-id 0.1.0 (git+https://github.com/near/nearcore.git?rev=8a377fda0b4ce319385c463f1ae46e4b0b29dcd9)", + "near-account-id 0.1.0", "near-rpc-error-macro 0.1.0 (git+https://github.com/near/nearcore.git?rev=8a377fda0b4ce319385c463f1ae46e4b0b29dcd9)", "serde", ] @@ -2711,21 +2781,21 @@ dependencies = [ [[package]] name = "near-vm-logic" -version = "3.0.0" -source = "git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228#0c9ad79a18e431f843e6123cf4559f9c2c5dd228" +version = "0.0.0" +source = "git+https://github.com/near/nearcore.git?rev=83fc0f7d6b212bacc49f058e7400743de3e59783#83fc0f7d6b212bacc49f058e7400743de3e59783" dependencies = [ "base64 0.13.0", "borsh 0.9.1", "bs58", "byteorder", - "near-account-id 0.1.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", - "near-crypto 0.1.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", - "near-primitives 0.1.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", - "near-primitives-core 0.1.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", - "near-vm-errors 3.0.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", + "near-account-id 0.0.0", + "near-crypto 0.0.0", + "near-primitives 0.0.0", + "near-primitives-core 0.0.0", + "near-vm-errors 0.0.0", "ripemd160", "serde", - "sha2 0.9.5", + "sha2 0.8.2", "sha3 0.9.1", ] @@ -2738,7 +2808,7 @@ dependencies = [ "borsh 0.8.2", "bs58", "byteorder", - "near-account-id 0.1.0 (git+https://github.com/near/nearcore.git?rev=8a377fda0b4ce319385c463f1ae46e4b0b29dcd9)", + "near-account-id 0.1.0", "near-crypto 0.1.0 (git+https://github.com/near/nearcore.git?rev=8a377fda0b4ce319385c463f1ae46e4b0b29dcd9)", "near-primitives 0.1.0 (git+https://github.com/near/nearcore.git?rev=8a377fda0b4ce319385c463f1ae46e4b0b29dcd9)", "near-primitives-core 0.1.0 (git+https://github.com/near/nearcore.git?rev=8a377fda0b4ce319385c463f1ae46e4b0b29dcd9)", @@ -2771,30 +2841,31 @@ dependencies = [ [[package]] name = "near-vm-runner" -version = "3.0.0" -source = "git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228#0c9ad79a18e431f843e6123cf4559f9c2c5dd228" +version = "0.0.0" +source = "git+https://github.com/near/nearcore.git?rev=83fc0f7d6b212bacc49f058e7400743de3e59783#83fc0f7d6b212bacc49f058e7400743de3e59783" dependencies = [ - "anyhow", "borsh 0.9.1", - "cached", - "near-primitives 0.1.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", + "loupe", + "memoffset", + "near-cache", + "near-primitives 0.0.0", "near-stable-hasher", - "near-vm-errors 3.0.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", - "near-vm-logic 3.0.0 (git+https://github.com/near/nearcore.git?rev=0c9ad79a18e431f843e6123cf4559f9c2c5dd228)", - "parity-wasm", - "pwasm-utils", + "near-vm-errors 0.0.0", + "near-vm-logic 0.0.0", + "once_cell", + "parity-wasm 0.41.0", + "pwasm-utils 0.12.0", + "pwasm-utils 0.18.2", "serde", "threadpool", "tracing", + "wasmer-compiler-near", "wasmer-compiler-singlepass-near", + "wasmer-engine-near", "wasmer-engine-universal-near", - "wasmer-near", - "wasmer-runtime-core-near", - "wasmer-runtime-near", "wasmer-types-near", "wasmer-vm-near", - "wasmparser 0.51.4", - "wasmtime", + "wasmparser 0.78.2", ] [[package]] @@ -2808,8 +2879,8 @@ dependencies = [ "near-primitives 0.1.0 (git+https://github.com/near/nearcore.git?rev=8a377fda0b4ce319385c463f1ae46e4b0b29dcd9)", "near-vm-errors 3.0.0 (git+https://github.com/near/nearcore.git?rev=8a377fda0b4ce319385c463f1ae46e4b0b29dcd9)", "near-vm-logic 3.0.0 (git+https://github.com/near/nearcore.git?rev=8a377fda0b4ce319385c463f1ae46e4b0b29dcd9)", - "parity-wasm", - "pwasm-utils", + "parity-wasm 0.41.0", + "pwasm-utils 0.12.0", "serde", "threadpool", "tracing", @@ -2819,8 +2890,8 @@ dependencies = [ "wasmer-engine-native", "wasmer-runtime-core-near", "wasmer-runtime-near", - "wasmer-types 1.0.2", - "wasmer-vm 1.0.2", + "wasmer-types", + "wasmer-vm", "wasmparser 0.51.4", "wasmtime", ] @@ -2855,7 +2926,7 @@ dependencies = [ "near-store", "near-vm-errors 3.0.0 (git+https://github.com/near/nearcore.git?rev=8a377fda0b4ce319385c463f1ae46e4b0b29dcd9)", "near-vm-logic 3.0.0 (git+https://github.com/near/nearcore.git?rev=8a377fda0b4ce319385c463f1ae46e4b0b29dcd9)", - "near-vm-runner 3.0.0 (git+https://github.com/near/nearcore.git?rev=8a377fda0b4ce319385c463f1ae46e4b0b29dcd9)", + "near-vm-runner 3.0.0", "num-bigint 0.3.2", "num-rational 0.3.2", "num-traits", @@ -3018,18 +3089,10 @@ dependencies = [ [[package]] name = "object" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170" - -[[package]] -name = "object" -version = "0.25.3" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7" +checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" dependencies = [ - "crc32fast", - "indexmap", "memchr", ] @@ -3130,6 +3193,12 @@ version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865" +[[package]] +name = "parity-wasm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be5e13c266502aadf83426d87d81a0f5d1ef45b8027f5a471c360abfe4bfae92" + [[package]] name = "parking_lot" version = "0.10.2" @@ -3458,7 +3527,18 @@ checksum = "4f7a12f176deee919f4ba55326ee17491c8b707d0987aed822682c821b660192" dependencies = [ "byteorder", "log", - "parity-wasm", + "parity-wasm 0.41.0", +] + +[[package]] +name = "pwasm-utils" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "880b3384fb00b8f6ecccd5d358b93bd2201900ae3daad213791d1864f6441f5c" +dependencies = [ + "byteorder", + "log", + "parity-wasm 0.42.2", ] [[package]] @@ -3677,6 +3757,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "rend" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79af64b4b6362ffba04eef3a4e10829718a4896dac19daa741851c86781edf95" +dependencies = [ + "bytecheck", +] + [[package]] name = "ripemd160" version = "0.9.1" @@ -3695,21 +3784,23 @@ source = "git+https://github.com/aurora-is-near/rjson?rev=cc3da949#cc3da9495e7e5 [[package]] name = "rkyv" -version = "0.6.7" +version = "0.7.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb135b3e5e3311f0a254bfb00333f4bac9ef1d89888b84242a89eb8722b09a07" +checksum = "439655b8d657bcb28264da8e5380d55549e34ffc4149bea9e3521890a122a7bd" dependencies = [ - "memoffset", + "bytecheck", + "hashbrown 0.11.2", "ptr_meta", + "rend", "rkyv_derive", "seahash", ] [[package]] name = "rkyv_derive" -version = "0.6.7" +version = "0.7.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba8f489f6b6d8551bb15904293c1ad58a6abafa7d8390d15f7ed05a2afcd87d5" +checksum = "cded413ad606a80291ca84bedba137093807cf4f5b36be8c60f57a7e790d48f6" dependencies = [ "proc-macro2", "quote", @@ -4445,6 +4536,32 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "walrus" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb08e48cde54c05f363d984bb54ce374f49e242def9468d2e1b6c2372d291f8" +dependencies = [ + "anyhow", + "id-arena", + "leb128", + "log", + "walrus-macro", + "wasmparser 0.77.0", +] + +[[package]] +name = "walrus-macro" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e5bd22c71e77d60140b0bd5be56155a37e5bd14e24f5f87298040d0cc40d7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -4522,14 +4639,14 @@ dependencies = [ "more-asserts", "target-lexicon 0.11.2", "thiserror", - "wasmer-compiler 1.0.2", + "wasmer-compiler", "wasmer-compiler-cranelift", "wasmer-derive", - "wasmer-engine 1.0.2", + "wasmer-engine", "wasmer-engine-jit", "wasmer-engine-native", - "wasmer-types 1.0.2", - "wasmer-vm 1.0.2", + "wasmer-types", + "wasmer-vm", "wat", "winapi", ] @@ -4546,30 +4663,11 @@ dependencies = [ "smallvec", "target-lexicon 0.11.2", "thiserror", - "wasmer-types 1.0.2", - "wasmer-vm 1.0.2", + "wasmer-types", + "wasmer-vm", "wasmparser 0.65.0", ] -[[package]] -name = "wasmer-compiler" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc86dda6f715f03104800be575a38382b35c3962953af9e9d8722dcf0bd2458f" -dependencies = [ - "enumset", - "loupe", - "rkyv", - "serde", - "serde_bytes", - "smallvec", - "target-lexicon 0.12.2", - "thiserror", - "wasmer-types 2.0.0", - "wasmer-vm 2.0.0", - "wasmparser 0.78.2", -] - [[package]] name = "wasmer-compiler-cranelift" version = "1.0.2" @@ -4584,16 +4682,16 @@ dependencies = [ "serde", "smallvec", "tracing", - "wasmer-compiler 1.0.2", - "wasmer-types 1.0.2", - "wasmer-vm 1.0.2", + "wasmer-compiler", + "wasmer-types", + "wasmer-vm", ] [[package]] name = "wasmer-compiler-near" -version = "2.0.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a031e2aa4c253cd1a0f61f9b66dc1fdbe5ef7ff79d5e9eace40c8cac2d9ce337" +checksum = "c11074b5b8f4170b5ebf0744e811728befb01a70757395c43b528b6441e9c924" dependencies = [ "enumset", "loupe", @@ -4622,22 +4720,23 @@ dependencies = [ "rayon", "serde", "smallvec", - "wasmer-compiler 1.0.2", - "wasmer-types 1.0.2", - "wasmer-vm 1.0.2", + "wasmer-compiler", + "wasmer-types", + "wasmer-vm", ] [[package]] name = "wasmer-compiler-singlepass-near" -version = "2.0.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b36773b8efc498c764aa82ea0335a5d58e4578b451c1116cda3a7bbf42c74d1" +checksum = "c95dc7a193f0b607ce19c3a71418ea0d325696087a53755b4610b5b5b02b335b" dependencies = [ "byteorder", "dynasm", "dynasmrt", "lazy_static", "loupe", + "memoffset", "more-asserts", "rayon", "smallvec", @@ -4658,18 +4757,6 @@ dependencies = [ "syn", ] -[[package]] -name = "wasmer-derive-near" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e784e640f63c09f8bb236e58469e136ebe6f46fbe5cc58e046efc4804a34da50" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "wasmer-engine" version = "1.0.2" @@ -4679,59 +4766,16 @@ dependencies = [ "backtrace", "bincode", "lazy_static", - "memmap2", + "memmap2 0.2.2", "more-asserts", "rustc-demangle", "serde", "serde_bytes", "target-lexicon 0.11.2", "thiserror", - "wasmer-compiler 1.0.2", - "wasmer-types 1.0.2", - "wasmer-vm 1.0.2", -] - -[[package]] -name = "wasmer-engine" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8454ead320a4017ba36ddd9ab4fbf7776fceea6ab0b79b5e53664a1682569fc3" -dependencies = [ - "backtrace", - "lazy_static", - "loupe", - "memmap2", - "more-asserts", - "rustc-demangle", - "serde", - "serde_bytes", - "target-lexicon 0.12.2", - "thiserror", - "wasmer-compiler 2.0.0", - "wasmer-types 2.0.0", - "wasmer-vm 2.0.0", -] - -[[package]] -name = "wasmer-engine-dylib" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aa390d123ebe23d5315c39f6063fcc18319661d03c8000f23d0fe1c011e8135" -dependencies = [ - "cfg-if 1.0.0", - "leb128", - "libloading 0.7.0", - "loupe", - "rkyv", - "serde", - "tempfile", - "tracing", - "wasmer-compiler 2.0.0", - "wasmer-engine 2.0.0", - "wasmer-object 2.0.0", - "wasmer-types 2.0.0", - "wasmer-vm 2.0.0", - "which", + "wasmer-compiler", + "wasmer-types", + "wasmer-vm", ] [[package]] @@ -4745,10 +4789,10 @@ dependencies = [ "region 2.2.0", "serde", "serde_bytes", - "wasmer-compiler 1.0.2", - "wasmer-engine 1.0.2", - "wasmer-types 1.0.2", - "wasmer-vm 1.0.2", + "wasmer-compiler", + "wasmer-engine", + "wasmer-types", + "wasmer-vm", "winapi", ] @@ -4765,24 +4809,25 @@ dependencies = [ "serde", "tempfile", "tracing", - "wasmer-compiler 1.0.2", - "wasmer-engine 1.0.2", - "wasmer-object 1.0.2", - "wasmer-types 1.0.2", - "wasmer-vm 1.0.2", + "wasmer-compiler", + "wasmer-engine", + "wasmer-object", + "wasmer-types", + "wasmer-vm", "which", ] [[package]] name = "wasmer-engine-near" -version = "2.0.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd68343185cb15bb3668a2d2f6103e474553cc35a33346a0d8abdab2467ddeb6" +checksum = "55090b4c4cffc8460478fa0b0355d81044750655986a8be93e769f9df3caa6bf" dependencies = [ "backtrace", + "enumset", "lazy_static", "loupe", - "memmap2", + "memmap2 0.5.2", "more-asserts", "rustc-demangle", "serde", @@ -4796,11 +4841,12 @@ dependencies = [ [[package]] name = "wasmer-engine-universal-near" -version = "2.0.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d23b38bf74d16a4b00f9a26627ce008578b9c48b9a3ac7586b992f875cbf2b7" +checksum = "37d2a5c1153cf6d9441e3d05101559071a3fb7f44e343f398d5ec89f2f5748f4" dependencies = [ "cfg-if 1.0.0", + "enumset", "leb128", "loupe", "region 3.0.0", @@ -4812,31 +4858,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "wasmer-near" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595ddd94dbb327d564c14342ceebc48fae50f81a3ae4b65a0159e43c4e626d39" -dependencies = [ - "cfg-if 1.0.0", - "indexmap", - "js-sys", - "loupe", - "more-asserts", - "target-lexicon 0.12.2", - "thiserror", - "wasm-bindgen", - "wasmer-compiler-near", - "wasmer-compiler-singlepass-near", - "wasmer-derive-near", - "wasmer-engine-dylib", - "wasmer-engine-near", - "wasmer-engine-universal-near", - "wasmer-types-near", - "wasmer-vm-near", - "winapi", -] - [[package]] name = "wasmer-object" version = "1.0.2" @@ -4845,27 +4866,15 @@ checksum = "abf8e0c12b82ff81ebecd30d7e118be5fec871d6de885a90eeb105df0a769a7b" dependencies = [ "object 0.22.0", "thiserror", - "wasmer-compiler 1.0.2", - "wasmer-types 1.0.2", -] - -[[package]] -name = "wasmer-object" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c541c985799fc1444702501c15d41becfb066c92d9673defc1c7417fd8739e15" -dependencies = [ - "object 0.25.3", - "thiserror", - "wasmer-compiler 2.0.0", - "wasmer-types 2.0.0", + "wasmer-compiler", + "wasmer-types", ] [[package]] name = "wasmer-runtime-core-near" -version = "0.18.2" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cf26de331c8ef4257bef33649b4665535b105c927ab2e00715f17891362efe8" +checksum = "5a3fac37da3c625e98708c5dd92d3f642aaf700fd077168d3d0fff277ec6a165" dependencies = [ "bincode", "blake3", @@ -4936,24 +4945,11 @@ dependencies = [ "thiserror", ] -[[package]] -name = "wasmer-types" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91f75d3c31f8b1f8d818ff49624fc974220243cbc07a2252f408192e97c6b51" -dependencies = [ - "indexmap", - "loupe", - "rkyv", - "serde", - "thiserror", -] - [[package]] name = "wasmer-types-near" -version = "2.0.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00310b8d7167ec0aa2df888d7803fa17239a958c6dee3137313e8d1b96036b61" +checksum = "b4fae5b0041c76c1b114b3286503a54d42c38eb88146724919b5610c66ecd548" dependencies = [ "indexmap", "loupe", @@ -4978,37 +4974,15 @@ dependencies = [ "region 2.2.0", "serde", "thiserror", - "wasmer-types 1.0.2", - "winapi", -] - -[[package]] -name = "wasmer-vm" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469a12346a4831e7dac639b9646d8c9b24c7d2cf0cf458b77f489edb35060c1f" -dependencies = [ - "backtrace", - "cc", - "cfg-if 1.0.0", - "indexmap", - "libc", - "loupe", - "memoffset", - "more-asserts", - "region 2.2.0", - "rkyv", - "serde", - "thiserror", - "wasmer-types 2.0.0", + "wasmer-types", "winapi", ] [[package]] name = "wasmer-vm-near" -version = "2.0.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e862c259e2acb433a9185dd4be9f43726d3ac45ada2d8432f29e0e0d65e33847" +checksum = "db06e0c8e20945000c075237f1b5afb682bf80e2bec875ed9b9a633ef41960c7" dependencies = [ "backtrace", "cc", @@ -5044,6 +5018,12 @@ version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "755a9a4afe3f6cccbbe6d7e965eef44cf260b001f93e547eba84255c1d0187d8" +[[package]] +name = "wasmparser" +version = "0.77.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35c86d22e720a07d954ebbed772d01180501afe7d03d464f413bb5f8914a8d6" + [[package]] name = "wasmparser" version = "0.78.2" diff --git a/Cargo.toml b/Cargo.toml index 9095e16bc..b2298f22d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,10 +32,10 @@ members = [ "engine", "engine-precompiles", "engine-sdk", - "engine-standalone", "engine-standalone-storage", "engine-standalone-tracing", "engine-tests", + "engine-transactions", "engine-types", ] exclude = [ diff --git a/README.md b/README.md index cdc6e532e..de64dbfe5 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,9 @@ documentation. Network | Contract ID | Chain ID | Version ------- | ------------------- | ---------- | ------ -Mainnet | [`aurora`][Mainnet] | 1313161554 | 2.2.0 -Testnet | [`aurora`][Testnet] | 1313161555 | 2.3.0 -Local | `aurora.test.near` | 1313161556 | 2.3.0 +Mainnet | [`aurora`][Mainnet] | 1313161554 | 2.3.0 +Testnet | [`aurora`][Testnet] | 1313161555 | 2.4.0 +Local | `aurora.test.near` | 1313161556 | 2.4.0 [Mainnet]: https://explorer.near.org/accounts/aurora [Testnet]: https://explorer.testnet.near.org/accounts/aurora diff --git a/VERSION b/VERSION index 276cbf9e2..197c4d5c2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.3.0 +2.4.0 diff --git a/engine-precompiles/Cargo.toml b/engine-precompiles/Cargo.toml index 1bc39e484..09b77c230 100644 --- a/engine-precompiles/Cargo.toml +++ b/engine-precompiles/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "aurora-engine-precompiles" version = "1.0.0" -authors = ["NEAR "] -edition = "2018" +authors = ["Aurora Labs "] +edition = "2021" description = "" documentation = "" readme = true @@ -16,23 +16,19 @@ autobenches = false aurora-engine-types = { path = "../engine-types", default-features = false } aurora-engine-sdk = { path = "../engine-sdk", default-features = false } base64 = { version = "0.13.0", default-features = false, features = ["alloc"] } -blake2 = { git = "https://github.com/near/near-blake2.git", version = "0.9.1", default-features = false } +near-blake2 = { git = "https://github.com/near/near-blake2.git", version = "0.9.1", default-features = false } borsh = { version = "0.8.2", default-features = false } bn = { package = "aurora-bn", git = "https://github.com/aurora-is-near/aurora-bn.git", default-features = false } -evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", default-features = false } -evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", default-features = false } +evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "f4ee520254856898d451c7225851520a35c97cea", default-features = false } +evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "f4ee520254856898d451c7225851520a35c97cea", default-features = false } libsecp256k1 = { version = "0.3.5", default-features = false } num = { version = "0.4.0", default-features = false, features = ["alloc"] } primitive-types = { version = "0.10.0", default-features = false, features = ["rlp"] } ripemd160 = { version = "0.9.1", default-features = false } -rlp = { version = "0.5.0", default-features = false } sha2 = { version = "0.9.3", default-features = false } sha3 = { version = "0.9.1", default-features = false } -wee_alloc = { version = "0.4.5", default-features = false } -logos = { version = "0.12", default-features = false, features = ["export_derive"] } ethabi = { git = "https://github.com/darwinia-network/ethabi", branch = "xavier-no-std", default-features = false } hex = { version = "0.4", default-features = false, features = ["alloc"] } -rjson = { git = "https://github.com/aurora-is-near/rjson", rev = "cc3da949", default-features = false, features = ["integer"] } [dev-dependencies] serde = { version = "1", features = ["derive"] } @@ -40,6 +36,7 @@ serde_json = "1" rand = "0.7.3" [features] +std = ["aurora-engine-types/std", "aurora-engine-sdk/std", "borsh/std", "near-blake2/std", "bn/std", "evm/std", "evm-core/std", "libsecp256k1/std", "ripemd160/std", "sha2/std", "sha3/std", "ethabi/std"] contract = [] log = [] error_refund = [] diff --git a/engine-precompiles/src/blake2.rs b/engine-precompiles/src/blake2.rs index a6a300e03..470f2544c 100644 --- a/engine-precompiles/src/blake2.rs +++ b/engine-precompiles/src/blake2.rs @@ -1,7 +1,7 @@ use evm::{Context, ExitError}; use crate::prelude::types::EthGas; -use crate::prelude::{mem, Address, Borrowed, TryInto}; +use crate::prelude::{mem, types::Address, Borrowed}; use crate::{EvmPrecompileResult, Precompile, PrecompileOutput}; /// Blake2 costs. @@ -94,7 +94,7 @@ impl Precompile for Blake2F { } let finished = input[212] != 0; - let output = blake2::blake2b_f(rounds, h, m, t, finished).to_vec(); + let output = near_blake2::blake2b_f(rounds, h, m, t, finished).to_vec(); Ok(PrecompileOutput::without_logs(cost, output).into()) } } diff --git a/engine-precompiles/src/bn128.rs b/engine-precompiles/src/bn128.rs index 5422ed2cd..ccb5073a4 100644 --- a/engine-precompiles/src/bn128.rs +++ b/engine-precompiles/src/bn128.rs @@ -1,5 +1,5 @@ -use crate::prelude::types::EthGas; -use crate::prelude::{Address, Borrowed, PhantomData, Vec}; +use crate::prelude::types::{Address, EthGas}; +use crate::prelude::{Borrowed, PhantomData, Vec}; use crate::{Byzantium, EvmPrecompileResult, HardFork, Istanbul, Precompile, PrecompileOutput}; use evm::{Context, ExitError}; diff --git a/engine-precompiles/src/hash.rs b/engine-precompiles/src/hash.rs index d096c3cb8..6a545f145 100644 --- a/engine-precompiles/src/hash.rs +++ b/engine-precompiles/src/hash.rs @@ -1,7 +1,7 @@ #[cfg(feature = "contract")] use crate::prelude::sdk; -use crate::prelude::types::EthGas; -use crate::prelude::{vec, Address}; +use crate::prelude::types::{Address, EthGas}; +use crate::prelude::vec; use crate::{EvmPrecompileResult, Precompile, PrecompileOutput}; use evm::{Context, ExitError}; diff --git a/engine-precompiles/src/identity.rs b/engine-precompiles/src/identity.rs index 371d7747b..27e2b31a5 100644 --- a/engine-precompiles/src/identity.rs +++ b/engine-precompiles/src/identity.rs @@ -1,5 +1,4 @@ -use crate::prelude::types::EthGas; -use crate::prelude::Address; +use crate::prelude::types::{Address, EthGas}; use crate::{EvmPrecompileResult, Precompile, PrecompileOutput}; use evm::{Context, ExitError}; diff --git a/engine-precompiles/src/lib.rs b/engine-precompiles/src/lib.rs index 22acf4d5b..b2cb3530a 100644 --- a/engine-precompiles/src/lib.rs +++ b/engine-precompiles/src/lib.rs @@ -1,5 +1,4 @@ #![allow(dead_code)] -#![feature(array_methods)] #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), feature(alloc_error_handler))] #![cfg_attr(feature = "log", feature(panic_info_message))] @@ -23,10 +22,10 @@ use crate::identity::Identity; use crate::modexp::ModExp; use crate::native::{ExitToEthereum, ExitToNear}; use crate::prelude::types::EthGas; -use crate::prelude::{Vec, H256}; +use crate::prelude::{Vec, H160, H256}; use crate::random::RandomSeed; use crate::secp256k1::ECRecover; -use aurora_engine_types::{account_id::AccountId, vec, Address, BTreeMap, Box}; +use aurora_engine_types::{account_id::AccountId, types::Address, vec, BTreeMap, Box}; use evm::backend::Log; use evm::executor; use evm::{Context, ExitError, ExitSucceed}; @@ -48,18 +47,18 @@ impl PrecompileOutput { } } -impl From for evm::executor::PrecompileOutput { +impl From for executor::stack::PrecompileOutput { fn from(output: PrecompileOutput) -> Self { - evm::executor::PrecompileOutput { + executor::stack::PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: output.cost.into_u64(), + cost: output.cost.as_u64(), output: output.output, logs: output.logs, } } } -type EvmPrecompileResult = Result; +type EvmPrecompileResult = Result; /// A precompiled function for use in the EVM. pub trait Precompile { @@ -103,23 +102,23 @@ impl HardFork for Berlin {} pub struct Precompiles(pub prelude::BTreeMap>); -impl executor::PrecompileSet for Precompiles { +impl executor::stack::PrecompileSet for Precompiles { fn execute( &self, - address: prelude::Address, + address: prelude::H160, input: &[u8], gas_limit: Option, context: &Context, is_static: bool, - ) -> Option> { - self.0.get(&address).map(|p| { + ) -> Option> { + self.0.get(&Address::new(address)).map(|p| { p.run(input, gas_limit.map(EthGas::new), context, is_static) - .map_err(|exit_status| executor::PrecompileFailure::Error { exit_status }) + .map_err(|exit_status| executor::stack::PrecompileFailure::Error { exit_status }) }) } - fn is_precompile(&self, address: prelude::Address) -> bool { - self.0.contains_key(&address) + fn is_precompile(&self, address: prelude::H160) -> bool { + self.0.contains_key(&Address::new(address)) } } @@ -259,13 +258,13 @@ impl Precompiles { } } -/// const fn for making an address by concatenating the bytes from two given numbers, +/// fn for making an address by concatenating the bytes from two given numbers, /// Note that 32 + 128 = 160 = 20 bytes (the length of an address). This function is used /// as a convenience for specifying the addresses of the various precompiles. -pub const fn make_address(x: u32, y: u128) -> prelude::Address { +pub const fn make_address(x: u32, y: u128) -> prelude::types::Address { let x_bytes = x.to_be_bytes(); let y_bytes = y.to_be_bytes(); - prelude::Address([ + prelude::types::Address::new(H160([ x_bytes[0], x_bytes[1], x_bytes[2], @@ -286,7 +285,7 @@ pub const fn make_address(x: u32, y: u128) -> prelude::Address { y_bytes[13], y_bytes[14], y_bytes[15], - ]) + ])) } const fn make_h256(x: u128, y: u128) -> prelude::H256 { @@ -330,7 +329,9 @@ const fn make_h256(x: u128, y: u128) -> prelude::H256 { #[cfg(test)] mod tests { + use crate::prelude::H160; use crate::{prelude, Byzantium, Istanbul}; + use prelude::types::Address; use rand::Rng; #[test] @@ -354,25 +355,25 @@ mod tests { let mut rng = rand::thread_rng(); for _ in 0..u8::MAX { - let address: prelude::Address = prelude::Address(rng.gen()); + let address = Address::new(H160(rng.gen())); let (x, y) = split_address(address); assert_eq!(address, super::make_address(x, y)) } } - fn u8_to_address(x: u8) -> prelude::Address { + fn u8_to_address(x: u8) -> Address { let mut bytes = [0u8; 20]; bytes[19] = x; - prelude::Address(bytes) + Address::new(H160(bytes)) } // Inverse function of `super::make_address`. - fn split_address(a: prelude::Address) -> (u32, u128) { + fn split_address(a: Address) -> (u32, u128) { let mut x_bytes = [0u8; 4]; let mut y_bytes = [0u8; 16]; - x_bytes.copy_from_slice(&a[0..4]); - y_bytes.copy_from_slice(&a[4..20]); + x_bytes.copy_from_slice(&a.raw()[0..4]); + y_bytes.copy_from_slice(&a.raw()[4..20]); (u32::from_be_bytes(x_bytes), u128::from_be_bytes(y_bytes)) } diff --git a/engine-precompiles/src/modexp.rs b/engine-precompiles/src/modexp.rs index eac9735df..d4605e8d4 100644 --- a/engine-precompiles/src/modexp.rs +++ b/engine-precompiles/src/modexp.rs @@ -1,7 +1,7 @@ -use crate::prelude::{Address, PhantomData, Vec, U256}; +use crate::prelude::{PhantomData, Vec, U256}; use crate::{Berlin, Byzantium, EvmPrecompileResult, HardFork, Precompile, PrecompileOutput}; -use crate::prelude::types::EthGas; +use crate::prelude::types::{Address, EthGas}; use evm::{Context, ExitError}; use num::{BigUint, Integer}; @@ -131,7 +131,7 @@ impl ModExp { // output bounded by 2^122 fn mul_complexity(base_len: u64, mod_len: u64) -> U256 { let max_len = core::cmp::max(mod_len, base_len); - let words = U256::from(max_len.div_ceil(&8)); + let words = U256::from(Integer::div_ceil(&max_len, &8)); words * words } } diff --git a/engine-precompiles/src/native.rs b/engine-precompiles/src/native.rs index 8cf4bf58e..8cea60da4 100644 --- a/engine-precompiles/src/native.rs +++ b/engine-precompiles/src/native.rs @@ -5,7 +5,8 @@ use crate::prelude::{ parameters::{PromiseArgs, PromiseCreateArgs, WithdrawCallArgs}, sdk, storage::{bytes_to_key, KeyPrefix}, - vec, BorshSerialize, Cow, String, ToString, TryFrom, TryInto, Vec, H160, U256, + types::Yocto, + vec, BorshSerialize, Cow, String, ToString, Vec, U256, }; #[cfg(all(feature = "error_refund", feature = "contract"))] use crate::prelude::{ @@ -13,8 +14,7 @@ use crate::prelude::{ types, }; -use crate::prelude::types::EthGas; -use crate::prelude::Address; +use crate::prelude::types::{Address, EthGas}; use crate::PrecompileOutput; use aurora_engine_types::account_id::AccountId; #[cfg(feature = "contract")] @@ -24,7 +24,7 @@ use evm::{Context, ExitError}; const ERR_TARGET_TOKEN_NOT_FOUND: &str = "Target token not found"; mod costs { - use crate::prelude::types::EthGas; + use crate::prelude::types::{EthGas, NearGas}; // TODO(#51): Determine the correct amount of gas pub(super) const EXIT_TO_NEAR_GAS: EthGas = EthGas::new(0); @@ -33,18 +33,18 @@ mod costs { pub(super) const EXIT_TO_ETHEREUM_GAS: EthGas = EthGas::new(0); // TODO(#332): Determine the correct amount of gas - pub(super) const FT_TRANSFER_GAS: EthGas = EthGas::new(100_000_000_000_000); + pub(super) const FT_TRANSFER_GAS: NearGas = NearGas::new(100_000_000_000_000); // TODO(#332): Determine the correct amount of gas #[cfg(feature = "error_refund")] - pub(super) const REFUND_ON_ERROR_GAS: EthGas = EthGas::new(60_000_000_000_000); + pub(super) const REFUND_ON_ERROR_GAS: NearGas = NearGas::new(60_000_000_000_000); // TODO(#332): Determine the correct amount of gas - pub(super) const WITHDRAWAL_GAS: EthGas = EthGas::new(100_000_000_000_000); + pub(super) const WITHDRAWAL_GAS: NearGas = NearGas::new(100_000_000_000_000); } pub mod events { - use crate::prelude::{vec, Address, String, ToString, H256, U256}; + use crate::prelude::{types::Address, vec, String, ToString, H160, H256, U256}; /// Derived from event signature (see tests::test_exit_signatures) pub const EXIT_TO_NEAR_SIGNATURE: H256 = crate::make_h256( @@ -61,7 +61,7 @@ pub mod events { /// which ERC-20 token is being withdrawn. However, ETH is not an ERC-20 token /// So we need to have some other address to fill this field. This constant is /// used for this purpose. - pub const ETH_ADDRESS: Address = Address([0; 20]); + pub const ETH_ADDRESS: Address = Address::new(H160([0; 20])); /// ExitToNear( /// Address indexed sender, @@ -127,7 +127,7 @@ pub mod events { fn encode_address(a: Address) -> H256 { let mut result = [0u8; 32]; - result[12..].copy_from_slice(a.as_ref()); + result[12..].copy_from_slice(a.as_bytes()); H256(result) } @@ -252,7 +252,7 @@ impl Precompile for ExitToNear { ) -> EvmPrecompileResult { #[cfg(feature = "error_refund")] fn parse_input(input: &[u8]) -> (Address, &[u8]) { - let refund_address = Address::from_slice(&input[1..21]); + let refund_address = Address::from_array(&input[1..21]); (refund_address, &input[21..]) } #[cfg(not(feature = "error_refund"))] @@ -301,7 +301,7 @@ impl Precompile for ExitToNear { context.apparent_value.as_u128() ), events::ExitToNear { - sender: context.caller, + sender: Address::new(context.caller), erc20_address: events::ETH_ADDRESS, dest: dest_account.to_string(), amount: context.apparent_value, @@ -345,8 +345,8 @@ impl Precompile for ExitToNear { amount.as_u128() ), events::ExitToNear { - sender: erc20_address, - erc20_address, + sender: Address::new(erc20_address), + erc20_address: Address::new(erc20_address), dest: receiver_account_id.to_string(), amount, }, @@ -364,11 +364,11 @@ impl Precompile for ExitToNear { let erc20_address = if flag == 0 { None } else { - Some(exit_event.erc20_address.0) + Some(exit_event.erc20_address) }; #[cfg(feature = "error_refund")] let refund_args = RefundCallArgs { - recipient_address: refund_address.0, + recipient_address: refund_address, erc20_address, amount: types::u256_to_arr(&exit_event.amount), }; @@ -377,15 +377,15 @@ impl Precompile for ExitToNear { target_account_id: refund_on_error_target, method: "refund_on_error".to_string(), args: refund_args.try_to_vec().unwrap(), - attached_balance: 0, - attached_gas: costs::REFUND_ON_ERROR_GAS.into_u64(), + attached_balance: Yocto::new(0), + attached_gas: costs::REFUND_ON_ERROR_GAS, }; let transfer_promise = PromiseCreateArgs { target_account_id: nep141_address, method: "ft_transfer".to_string(), args: args.as_bytes().to_vec(), - attached_balance: 1, - attached_gas: costs::FT_TRANSFER_GAS.into_u64(), + attached_balance: Yocto::new(1), + attached_gas: costs::FT_TRANSFER_GAS, }; #[cfg(feature = "error_refund")] @@ -397,13 +397,13 @@ impl Precompile for ExitToNear { let promise = PromiseArgs::Create(transfer_promise); let promise_log = Log { - address: Self::ADDRESS, + address: Self::ADDRESS.raw(), topics: Vec::new(), data: promise.try_to_vec().unwrap(), }; let exit_event_log = exit_event.encode(); let exit_event_log = Log { - address: Self::ADDRESS, + address: Self::ADDRESS.raw(), topics: exit_event_log.topics, data: exit_event_log.data, }; @@ -463,6 +463,7 @@ impl Precompile for ExitToEthereum { context: &Context, is_static: bool, ) -> EvmPrecompileResult { + use crate::prelude::types::NEP141Wei; if let Some(target_gas) = target_gas { if Self::required_gas(input)? > target_gas { return Err(ExitError::OutOfGas); @@ -487,7 +488,7 @@ impl Precompile for ExitToEthereum { // // Input slice format: // eth_recipient (20 bytes) - the address of recipient which will receive ETH on Ethereum - let recipient_address = input + let recipient_address: Address = input .try_into() .map_err(|_| ExitError::Other(Cow::from("ERR_INVALID_RECIPIENT_ADDRESS")))?; ( @@ -496,14 +497,14 @@ impl Precompile for ExitToEthereum { // as decimal and hexadecimal respectively. WithdrawCallArgs { recipient_address, - amount: context.apparent_value.as_u128(), + amount: NEP141Wei::new(context.apparent_value.as_u128()), } .try_to_vec() .map_err(|_| ExitError::Other(Cow::from("ERR_INVALID_AMOUNT")))?, events::ExitToEth { - sender: context.caller, + sender: Address::new(context.caller), erc20_address: events::ETH_ADDRESS, - dest: H160(recipient_address), + dest: recipient_address, amount: context.apparent_value, }, ) @@ -532,9 +533,11 @@ impl Precompile for ExitToEthereum { if input.len() == 20 { // Parse ethereum address in hex - let eth_recipient: String = hex::encode(input.to_vec()); + let eth_recipient: String = hex::encode(input); // unwrap cannot fail since we checked the length already - let recipient_address = input.try_into().unwrap(); + let recipient_address = Address::try_from_slice(input).map_err(|_| { + ExitError::Other(crate::prelude::Cow::from("ERR_WRONG_ADDRESS")) + })?; ( nep141_address, @@ -545,12 +548,11 @@ impl Precompile for ExitToEthereum { amount.as_u128(), eth_recipient ) - .as_bytes() - .to_vec(), + .into_bytes(), events::ExitToEth { - sender: erc20_address, - erc20_address, - dest: H160(recipient_address), + sender: Address::new(erc20_address), + erc20_address: Address::new(erc20_address), + dest: recipient_address, amount, }, ) @@ -569,19 +571,19 @@ impl Precompile for ExitToEthereum { target_account_id: nep141_address, method: "withdraw".to_string(), args: serialized_args, - attached_balance: 1, - attached_gas: costs::WITHDRAWAL_GAS.into_u64(), + attached_balance: Yocto::new(1), + attached_gas: costs::WITHDRAWAL_GAS, }; let promise = PromiseArgs::Create(withdraw_promise).try_to_vec().unwrap(); let promise_log = Log { - address: Self::ADDRESS, + address: Self::ADDRESS.raw(), topics: Vec::new(), data: promise, }; let exit_event_log = exit_event.encode(); let exit_event_log = Log { - address: Self::ADDRESS, + address: Self::ADDRESS.raw(), topics: exit_event_log.topics, data: exit_event_log.data, }; diff --git a/engine-precompiles/src/random.rs b/engine-precompiles/src/random.rs index 014b7ee8a..b71f2509e 100644 --- a/engine-precompiles/src/random.rs +++ b/engine-precompiles/src/random.rs @@ -1,6 +1,6 @@ use super::{EvmPrecompileResult, Precompile}; -use crate::prelude::types::EthGas; -use crate::prelude::{Address, H256}; +use crate::prelude::types::{Address, EthGas}; +use crate::prelude::H256; use crate::PrecompileOutput; use evm::{Context, ExitError}; diff --git a/engine-precompiles/src/secp256k1.rs b/engine-precompiles/src/secp256k1.rs index 14f11d87c..3ef3cd7e8 100644 --- a/engine-precompiles/src/secp256k1.rs +++ b/engine-precompiles/src/secp256k1.rs @@ -1,7 +1,6 @@ -use crate::prelude::types::EthGas; +use crate::prelude::types::{Address, EthGas}; use crate::prelude::{sdk, vec, Borrowed, H256}; use crate::{EvmPrecompileResult, Precompile, PrecompileOutput}; -use ethabi::Address; use evm::{Context, ExitError}; mod costs { @@ -45,7 +44,8 @@ fn internal_impl(hash: H256, signature: &[u8]) -> Result { if let Ok(public_key) = secp256k1::recover(&hash, &signature, &recovery_id) { // recover returns a 65-byte key, but addresses come from the raw 64-byte key let r = sha3::Keccak256::digest(&public_key.serialize()[1..]); - return Ok(Address::from_slice(&r[12..])); + return Address::try_from_slice(&r[12..]) + .map_err(|_| ExitError::Other(Borrowed("ERR_INCORRECT_ADDRESS"))); } } @@ -132,8 +132,10 @@ mod tests { let signature = &hex::decode("b9f0bb08640d3c1c00761cdd0121209268f6fd3816bc98b9e6f3cc77bf82b69812ac7a61788a0fdc0e19180f14c945a8e1088a27d92a74dce81c0981fb6447441b") .unwrap(); - let signer = - Address::from_slice(&hex::decode("1563915e194D8CfBA1943570603F7606A3115508").unwrap()); + let signer = Address::try_from_slice( + &hex::decode("1563915e194D8CfBA1943570603F7606A3115508").unwrap(), + ) + .unwrap(); assert!(ecverify(hash, &signature, signer)); } diff --git a/engine-sdk/Cargo.toml b/engine-sdk/Cargo.toml index 3dd87c491..6db4a2a7e 100644 --- a/engine-sdk/Cargo.toml +++ b/engine-sdk/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "aurora-engine-sdk" version = "1.0.0" -authors = ["NEAR "] -edition = "2018" +authors = ["Aurora Labs "] +edition = "2021" description = "" documentation = "" readme = true diff --git a/engine-sdk/src/dup_cache.rs b/engine-sdk/src/dup_cache.rs new file mode 100644 index 000000000..67be908e5 --- /dev/null +++ b/engine-sdk/src/dup_cache.rs @@ -0,0 +1,41 @@ +/// The intention of this struct is to prevent repeating duplicate computations/IO with the +/// same input (key). However, unlike memoization or typical caching, this only remembers the +/// most recent key-value pair. This means it is optimized for consecutive duplicate lookups, +/// as opposed to general duplicated lookups. The benefit is that its memory footprint and +/// internal logic are both minimal, and the drawback is that its use case is very narrow. +#[derive(Default)] +pub struct DupCache { + key: K, + value: V, +} + +impl DupCache { + pub fn get_or_insert_with V>(&mut self, k: &K, f: F) -> &mut V { + if &self.key != k { + let new_value = f(); + self.value = new_value; + self.key = *k; + } + + &mut self.value + } +} + +/// Same as `DupCache` but optimized for the case that `K = (K1, K2)`. +#[derive(Default)] +pub struct PairDupCache { + key: (K1, K2), + value: V, +} + +impl PairDupCache { + pub fn get_or_insert_with V>(&mut self, k: (&K1, &K2), f: F) -> &mut V { + if (&self.key.0 != k.0) || (&self.key.1 != k.1) { + let new_value = f(); + self.value = new_value; + self.key = (*k.0, *k.1); + } + + &mut self.value + } +} diff --git a/engine-sdk/src/lib.rs b/engine-sdk/src/lib.rs index e4d256cc5..b0c18fafe 100644 --- a/engine-sdk/src/lib.rs +++ b/engine-sdk/src/lib.rs @@ -1,4 +1,3 @@ -#![feature(array_methods)] #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), feature(alloc_error_handler))] #![cfg_attr(feature = "log", feature(panic_info_message))] @@ -8,6 +7,7 @@ use crate::prelude::Address; use crate::prelude::{H256, STORAGE_PRICE_PER_BYTE}; pub use types::keccak; +pub mod dup_cache; pub mod env; pub mod error; pub mod io; @@ -97,7 +97,7 @@ pub fn ecrecover(hash: H256, signature: &[u8]) -> Result exports::keccak256(u64::MAX, RECOVER_REGISTER_ID, KECCACK_REGISTER_ID); let keccak_hash_bytes = [0u8; 32]; exports::read_register(KECCACK_REGISTER_ID, keccak_hash_bytes.as_ptr() as u64); - Ok(Address::from_slice(&keccak_hash_bytes[12..])) + Ok(Address::try_from_slice(&keccak_hash_bytes[12..]).map_err(|_| ECRecoverErr)?) } else { Err(ECRecoverErr) } diff --git a/engine-sdk/src/near_runtime.rs b/engine-sdk/src/near_runtime.rs index 00926399f..72213bbf8 100644 --- a/engine-sdk/src/near_runtime.rs +++ b/engine-sdk/src/near_runtime.rs @@ -4,7 +4,7 @@ use crate::promise::PromiseId; use aurora_engine_types::account_id::AccountId; use aurora_engine_types::parameters::{PromiseAction, PromiseBatchAction, PromiseCreateArgs}; use aurora_engine_types::types::PromiseResult; -use aurora_engine_types::{TryFrom, H256}; +use aurora_engine_types::H256; /// Wrapper type for indices in NEAR's register API. pub struct RegisterIndex(u64); @@ -40,7 +40,7 @@ impl Runtime { b"state_migration", &[], 0, - Self::GAS_FOR_STATE_MIGRATION.into_u64(), + Self::GAS_FOR_STATE_MIGRATION.as_u64(), ) } } @@ -266,8 +266,8 @@ impl crate::promise::PromiseHandler for Runtime { let account_id = args.target_account_id.as_bytes(); let method_name = args.method.as_bytes(); let arguments = args.args.as_slice(); - let amount = args.attached_balance; - let gas = args.attached_gas; + let amount = args.attached_balance.as_u128(); + let gas = args.attached_gas.as_u64(); let id = unsafe { exports::promise_create( @@ -292,8 +292,8 @@ impl crate::promise::PromiseHandler for Runtime { let account_id = callback.target_account_id.as_bytes(); let method_name = callback.method.as_bytes(); let arguments = callback.args.as_slice(); - let amount = callback.attached_balance; - let gas = callback.attached_gas; + let amount = callback.attached_balance.as_u128(); + let gas = callback.attached_gas.as_u64(); let id = unsafe { exports::promise_then( @@ -322,7 +322,7 @@ impl crate::promise::PromiseHandler for Runtime { for action in args.actions.iter() { match action { PromiseAction::Transfer { amount } => unsafe { - let amount = *amount; + let amount = amount.as_u128(); exports::promise_batch_action_transfer(id, &amount as *const u128 as _); }, PromiseAction::DeployConotract { code } => unsafe { @@ -341,7 +341,7 @@ impl crate::promise::PromiseHandler for Runtime { } => unsafe { let method_name = name.as_bytes(); let arguments = args.as_slice(); - let amount = *attached_yocto; + let amount = attached_yocto.as_u128(); exports::promise_batch_action_function_call( id, method_name.len() as _, @@ -349,7 +349,7 @@ impl crate::promise::PromiseHandler for Runtime { arguments.len() as _, arguments.as_ptr() as _, &amount as *const u128 as _, - *gas, + gas.as_u64(), ) }, } diff --git a/engine-sdk/src/prelude.rs b/engine-sdk/src/prelude.rs index 359551455..799b5ec86 100644 --- a/engine-sdk/src/prelude.rs +++ b/engine-sdk/src/prelude.rs @@ -1,3 +1,3 @@ -pub use aurora_engine_types::types::{NearGas, PromiseResult, STORAGE_PRICE_PER_BYTE}; -pub use aurora_engine_types::{vec, Address, Vec, H256}; +pub use aurora_engine_types::types::{Address, NearGas, PromiseResult, STORAGE_PRICE_PER_BYTE}; +pub use aurora_engine_types::{vec, Vec, H256}; pub use borsh::{BorshDeserialize, BorshSerialize}; diff --git a/engine-sdk/src/types.rs b/engine-sdk/src/types.rs index ce595ea69..571019922 100644 --- a/engine-sdk/src/types.rs +++ b/engine-sdk/src/types.rs @@ -23,7 +23,7 @@ pub fn keccak(data: &[u8]) -> H256 { } pub fn near_account_to_evm_address(addr: &[u8]) -> Address { - Address::from_slice(&keccak(addr)[12..]) + Address::try_from_slice(&keccak(addr)[12..]).unwrap() } #[cfg(feature = "contract")] diff --git a/engine-standalone-storage/Cargo.toml b/engine-standalone-storage/Cargo.toml index 7ae5e3786..5fd15a1ea 100644 --- a/engine-standalone-storage/Cargo.toml +++ b/engine-standalone-storage/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "engine-standalone-storage" version = "0.1.0" -edition = "2018" -authors = ["Aurora "] +edition = "2021" +authors = ["Aurora Labs "] description = "Aurora engine standalone storage library. Provides the storage backend used by the standalone engine." homepage = "https://github.com/aurora-is-near/aurora-engine" repository = "https://github.com/aurora-is-near/aurora-engine" @@ -17,8 +17,9 @@ crate-type = ["lib"] aurora-engine = { path = "../engine", default-features = false, features = ["std"] } aurora-engine-types = { path = "../engine-types", default-features = false, features = ["std"] } aurora-engine-sdk = { path = "../engine-sdk", default-features = false, features = ["std"] } +aurora-engine-transactions = { path = "../engine-transactions", default-features = false, features = ["std"] } borsh = { version = "0.8.2" } -evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", default-features = false } +evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "f4ee520254856898d451c7225851520a35c97cea", default-features = false } rocksdb = "0.16.0" postgres = "0.19.2" serde = "1.0.130" diff --git a/engine-standalone-storage/src/relayer_db/mod.rs b/engine-standalone-storage/src/relayer_db/mod.rs index 6b838a616..42f779e97 100644 --- a/engine-standalone-storage/src/relayer_db/mod.rs +++ b/engine-standalone-storage/src/relayer_db/mod.rs @@ -1,6 +1,6 @@ use aurora_engine::engine; -use aurora_engine::transaction::EthTransactionKind; use aurora_engine_sdk::env::{self, Env, DEFAULT_PREPAID_GAS}; +use aurora_engine_transactions::EthTransactionKind; use aurora_engine_types::account_id::AccountId; use aurora_engine_types::H256; use postgres::fallible_iterator::FallibleIterator; @@ -166,16 +166,19 @@ pub mod error { Self::Storage(e) } } + impl From for Error { fn from(e: postgres::Error) -> Self { Self::Postgres(e) } } + impl From for Error { fn from(e: engine::EngineStateError) -> Self { Self::EngineState(e) } } + impl From for Error { fn from(e: engine::EngineError) -> Self { Self::Engine(e) diff --git a/engine-standalone-storage/src/relayer_db/types.rs b/engine-standalone-storage/src/relayer_db/types.rs index 0fdc1dc9b..e7abc12ca 100644 --- a/engine-standalone-storage/src/relayer_db/types.rs +++ b/engine-standalone-storage/src/relayer_db/types.rs @@ -1,8 +1,9 @@ -use aurora_engine::transaction::{ +use aurora_engine_transactions::{ legacy::{LegacyEthSignedTransaction, TransactionLegacy}, EthTransactionKind, }; -use aurora_engine_types::{types::Wei, Address, H256, U256}; +use aurora_engine_types::types::{Address, Wei}; +use aurora_engine_types::{H256, U256}; use std::convert::TryFrom; use std::io::{Cursor, Read}; use std::time::SystemTime; @@ -177,18 +178,18 @@ impl From for TransactionRow { near_hash, near_receipt_hash, from, - to: to.map(Address::from_slice), + to: to.map(|arr| Address::try_from_slice(arr).unwrap()), nonce, gas_price, gas_limit, gas_used: gas_used.low_u64(), value: Wei::new(value), - input: input.unwrap_or_else(Vec::new), + input: input.unwrap_or_default(), v: v.low_u64(), r, s, status, - output: output.unwrap_or_else(Vec::new), + output: output.unwrap_or_default(), } } } @@ -225,7 +226,7 @@ fn get_hash(row: &postgres::Row, field: &str) -> H256 { fn get_address(row: &postgres::Row, field: &str) -> Address { let value: &[u8] = row.get(field); - Address::from_slice(value) + Address::try_from_slice(value).unwrap() } fn get_timestamp(row: &postgres::Row, field: &str) -> Option { diff --git a/engine-standalone-storage/src/sync/mod.rs b/engine-standalone-storage/src/sync/mod.rs index 4c4ce3b19..8a16deee7 100644 --- a/engine-standalone-storage/src/sync/mod.rs +++ b/engine-standalone-storage/src/sync/mod.rs @@ -1,6 +1,5 @@ use aurora_engine::{connector, engine, parameters}; use aurora_engine_sdk::env::{self, Env, DEFAULT_PREPAID_GAS}; -use aurora_engine_types::TryFrom; use borsh::BorshDeserialize; pub mod types; diff --git a/engine-standalone-storage/src/sync/types.rs b/engine-standalone-storage/src/sync/types.rs index 0080b95a6..75c65ce62 100644 --- a/engine-standalone-storage/src/sync/types.rs +++ b/engine-standalone-storage/src/sync/types.rs @@ -1,5 +1,5 @@ use aurora_engine::parameters; -use aurora_engine::transaction::EthTransactionKind; +use aurora_engine_transactions::EthTransactionKind; use aurora_engine_types::account_id::AccountId; use aurora_engine_types::H256; @@ -40,6 +40,7 @@ pub struct TransactionMessage { } #[derive(Debug, Clone)] +#[allow(clippy::large_enum_variant)] pub enum TransactionKind { /// Raw Ethereum transaction submitted to the engine Submit(EthTransactionKind), diff --git a/engine-standalone-tracing/Cargo.toml b/engine-standalone-tracing/Cargo.toml index 9d5f504e2..36eac31ca 100644 --- a/engine-standalone-tracing/Cargo.toml +++ b/engine-standalone-tracing/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "engine-standalone-tracing" version = "0.1.0" -edition = "2018" -authors = ["Aurora "] +edition = "2021" +authors = ["Aurora Labs "] description = "Aurora engine standalone tracing library. Provides functions and types for extracing geth-like traces from standalone engine execution." homepage = "https://github.com/aurora-is-near/aurora-engine" repository = "https://github.com/aurora-is-near/aurora-engine" @@ -17,10 +17,10 @@ crate-type = ["lib"] aurora-engine = { path = "../engine", default-features = false, features = ["std"] } aurora-engine-types = { path = "../engine-types", default-features = false, features = ["std"] } aurora-engine-sdk = { path = "../engine-sdk", default-features = false, features = ["std"] } -evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", default-features = false, features = ["std"] } -evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", default-features = false, features = ["std", "tracing"] } -evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", default-features = false, features = ["std", "tracing"] } -evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", default-features = false, features = ["std", "tracing"] } +evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "f4ee520254856898d451c7225851520a35c97cea", default-features = false, features = ["std"] } +evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "f4ee520254856898d451c7225851520a35c97cea", default-features = false, features = ["std", "tracing"] } +evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "f4ee520254856898d451c7225851520a35c97cea", default-features = false, features = ["std", "tracing"] } +evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "f4ee520254856898d451c7225851520a35c97cea", default-features = false, features = ["std", "tracing"] } [features] default = [] diff --git a/engine-standalone-tracing/src/sputnik.rs b/engine-standalone-tracing/src/sputnik.rs index 799b59194..e1ce326ea 100644 --- a/engine-standalone-tracing/src/sputnik.rs +++ b/engine-standalone-tracing/src/sputnik.rs @@ -48,14 +48,18 @@ impl evm_gasometer::tracing::EventListener for TransactionTraceBuilder { fn event(&mut self, event: evm_gasometer::tracing::Event) { use evm_gasometer::tracing::Event; match event { - Event::RecordCost { cost, snapshot: _ } => { + Event::RecordCost { cost, snapshot } => { self.current.gas_cost = EthGas::new(cost); + if let Some(snapshot) = snapshot { + self.current.gas = + EthGas::new(snapshot.gas_limit - snapshot.used_gas - snapshot.memory_gas); + } } Event::RecordDynamicCost { gas_cost, memory_gas, gas_refund: _, - snapshot: _, + snapshot, } => { // In SputnikVM memory gas is cumulative (ie this event always shows the total) gas // spent on memory up to this point. But geth traces simply show how much gas each step @@ -68,6 +72,10 @@ impl evm_gasometer::tracing::EventListener for TransactionTraceBuilder { }; self.current_memory_gas = memory_gas; self.current.gas_cost = EthGas::new(gas_cost + memory_cost_diff); + if let Some(snapshot) = snapshot { + self.current.gas = + EthGas::new(snapshot.gas_limit - snapshot.used_gas - snapshot.memory_gas); + } } Event::RecordRefund { refund: _, @@ -100,7 +108,15 @@ impl evm_runtime::tracing::EventListener for TransactionTraceBuilder { if let Ok(pc) = position { self.current.program_counter = ProgramCounter(*pc as u32); } - self.current.stack = stack.data().as_slice().into(); + self.current.stack = stack + .data() + .iter() + .map(|x| { + let mut buf = [0u8; 32]; + x.to_big_endian(&mut buf); + buf + }) + .collect(); self.current.memory = memory.data().as_slice().into(); } diff --git a/engine-standalone-tracing/src/types.rs b/engine-standalone-tracing/src/types.rs index 69b885593..716c79df7 100644 --- a/engine-standalone-tracing/src/types.rs +++ b/engine-standalone-tracing/src/types.rs @@ -1,5 +1,5 @@ use aurora_engine_types::types::EthGas; -use aurora_engine_types::{BTreeMap, H256}; +use aurora_engine_types::BTreeMap; use evm_core::Opcode; use std::ops::Index; @@ -85,9 +85,9 @@ impl LogStack { } } -impl From<&[H256]> for LogStack { - fn from(stack: &[H256]) -> Self { - let vec = stack.iter().map(|bytes| bytes.0).collect(); +impl std::iter::FromIterator<[u8; 32]> for LogStack { + fn from_iter>(iter: T) -> Self { + let vec = iter.into_iter().collect(); Self(vec) } } @@ -151,9 +151,9 @@ pub struct TraceLog { pub depth: Depth, /// Any errors that may have occurred during execution. pub error: Option, - /// Gas used to execute the transaction. + /// Remaining (unused) gas. pub gas: EthGas, - /// Gas cost for the transaction. + /// Gas cost for the opcode at this step. pub gas_cost: EthGas, /// The bounded memory. pub memory: LogMemory, @@ -218,6 +218,7 @@ impl IntoIterator for Logs { } #[derive(Debug, Default)] +#[allow(dead_code)] pub struct TransactionTrace { /// The total gas cost of the transaction. gas: EthGas, @@ -231,7 +232,6 @@ pub struct TransactionTrace { impl TransactionTrace { /// Constructs a new TransactionTrace with a given gas, return, and logs. - #[allow(dead_code)] pub fn new( gas: EthGas, failed: bool, diff --git a/engine-standalone/Cargo.toml b/engine-standalone/Cargo.toml deleted file mode 100644 index d55bbfe9e..000000000 --- a/engine-standalone/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "engine-standalone" -version = "0.1.0" -edition = "2018" -authors = ["Aurora "] -description = "Aurora engine standalone library. Provides debugging capabilities." -homepage = "https://github.com/aurora-is-near/aurora-engine" -repository = "https://github.com/aurora-is-near/aurora-engine" -license = "CC0-1.0" -publish = false -autobenches = false - -[dependencies] -aurora-engine = { path = "../engine", default-features = false, features = ["std", "tracing"] } -aurora-engine-types = { path = "../engine-types", default-features = false, features = ["std"] } -aurora-engine-sdk = { path = "../engine-sdk", default-features = false, features = ["std"] } -engine-standalone-storage = { path = "../engine-standalone-storage", default-features = false } -engine-standalone-tracing = { path = "../engine-standalone-tracing", default-features = false } -borsh = { version = "0.8.2" } -evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", default-features = false, features = ["std"] } -libc = "0.2" -rocksdb = "0.16.0" - -[features] -default = [] -mainnet = [] -testnet = [] diff --git a/engine-standalone/LICENSE b/engine-standalone/LICENSE deleted file mode 100644 index 670154e35..000000000 --- a/engine-standalone/LICENSE +++ /dev/null @@ -1,116 +0,0 @@ -CC0 1.0 Universal - -Statement of Purpose - -The laws of most jurisdictions throughout the world automatically confer -exclusive Copyright and Related Rights (defined below) upon the creator and -subsequent owner(s) (each and all, an "owner") of an original work of -authorship and/or a database (each, a "Work"). - -Certain owners wish to permanently relinquish those rights to a Work for the -purpose of contributing to a commons of creative, cultural and scientific -works ("Commons") that the public can reliably and without fear of later -claims of infringement build upon, modify, incorporate in other works, reuse -and redistribute as freely as possible in any form whatsoever and for any -purposes, including without limitation commercial purposes. These owners may -contribute to the Commons to promote the ideal of a free culture and the -further production of creative, cultural and scientific works, or to gain -reputation or greater distribution for their Work in part through the use and -efforts of others. - -For these and/or other purposes and motivations, and without any expectation -of additional consideration or compensation, the person associating CC0 with a -Work (the "Affirmer"), to the extent that he or she is an owner of Copyright -and Related Rights in the Work, voluntarily elects to apply CC0 to the Work -and publicly distribute the Work under its terms, with knowledge of his or her -Copyright and Related Rights in the Work and the meaning and intended legal -effect of CC0 on those rights. - -1. Copyright and Related Rights. A Work made available under CC0 may be -protected by copyright and related or neighboring rights ("Copyright and -Related Rights"). Copyright and Related Rights include, but are not limited -to, the following: - - i. the right to reproduce, adapt, distribute, perform, display, communicate, - and translate a Work; - - ii. moral rights retained by the original author(s) and/or performer(s); - - iii. publicity and privacy rights pertaining to a person's image or likeness - depicted in a Work; - - iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; - - v. rights protecting the extraction, dissemination, use and reuse of data in - a Work; - - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation thereof, - including any amended or successor version of such directive); and - - vii. other similar, equivalent or corresponding rights throughout the world - based on applicable law or treaty, and any national implementations thereof. - -2. Waiver. To the greatest extent permitted by, but not in contravention of, -applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and -unconditionally waives, abandons, and surrenders all of Affirmer's Copyright -and Related Rights and associated claims and causes of action, whether now -known or unknown (including existing as well as future claims and causes of -action), in the Work (i) in all territories worldwide, (ii) for the maximum -duration provided by applicable law or treaty (including future time -extensions), (iii) in any current or future medium and for any number of -copies, and (iv) for any purpose whatsoever, including without limitation -commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes -the Waiver for the benefit of each member of the public at large and to the -detriment of Affirmer's heirs and successors, fully intending that such Waiver -shall not be subject to revocation, rescission, cancellation, termination, or -any other legal or equitable action to disrupt the quiet enjoyment of the Work -by the public as contemplated by Affirmer's express Statement of Purpose. - -3. Public License Fallback. Should any part of the Waiver for any reason be -judged legally invalid or ineffective under applicable law, then the Waiver -shall be preserved to the maximum extent permitted taking into account -Affirmer's express Statement of Purpose. In addition, to the extent the Waiver -is so judged Affirmer hereby grants to each affected person a royalty-free, -non transferable, non sublicensable, non exclusive, irrevocable and -unconditional license to exercise Affirmer's Copyright and Related Rights in -the Work (i) in all territories worldwide, (ii) for the maximum duration -provided by applicable law or treaty (including future time extensions), (iii) -in any current or future medium and for any number of copies, and (iv) for any -purpose whatsoever, including without limitation commercial, advertising or -promotional purposes (the "License"). The License shall be deemed effective as -of the date CC0 was applied by Affirmer to the Work. Should any part of the -License for any reason be judged legally invalid or ineffective under -applicable law, such partial invalidity or ineffectiveness shall not -invalidate the remainder of the License, and in such case Affirmer hereby -affirms that he or she will not (i) exercise any of his or her remaining -Copyright and Related Rights in the Work or (ii) assert any associated claims -and causes of action with respect to the Work, in either case contrary to -Affirmer's express Statement of Purpose. - -4. Limitations and Disclaimers. - - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - - b. Affirmer offers the Work as-is and makes no representations or warranties - of any kind concerning the Work, express, implied, statutory or otherwise, - including without limitation warranties of title, merchantability, fitness - for a particular purpose, non infringement, or the absence of latent or - other defects, accuracy, or the present or absence of errors, whether or not - discoverable, all to the greatest extent permissible under applicable law. - - c. Affirmer disclaims responsibility for clearing rights of other persons - that may apply to the Work or any use thereof, including without limitation - any person's Copyright and Related Rights in the Work. Further, Affirmer - disclaims responsibility for obtaining any necessary consents, permissions - or other rights required for any use of the Work. - - d. Affirmer understands and acknowledges that Creative Commons is not a - party to this document and has no duty or obligation with respect to this - CC0 or use of the Work. - -For more information, please see - diff --git a/engine-standalone/src/ffi.rs b/engine-standalone/src/ffi.rs deleted file mode 100644 index 83d5c82bc..000000000 --- a/engine-standalone/src/ffi.rs +++ /dev/null @@ -1,209 +0,0 @@ -use engine_standalone_tracing::{TraceLog, TransactionTrace}; -use libc::{c_uchar, c_uint, c_ushort, size_t, uintmax_t}; -use std::ffi::CString; - -/// Translates a struct into a C struct. -pub trait IntoC { - /// A method used to consume a struct and convert it into a C-compatible - /// struct. - fn into_c(self) -> T; -} - -#[repr(C)] -/// The C trace log of an execution on the EVM. -pub struct CTraceLog { - /// The depth of the log. - depth: c_uint, - /// Any errors that may have occurred during execution. - /// - /// Empty if none. - error: CString, - /// Gas used to execute the transaction. - gas: uintmax_t, - /// Gas cost for the transaction. - gas_cost: uintmax_t, - /// The bounded memory. - memory_ptr: *const [c_uchar; 32], - /// The length of the memory vector. - memory_len: size_t, - /// The opcode as a byte. - opcode: c_uchar, // opcode as byte - /// The current program counter of the transaction. - program_counter: c_uint, - /// The local stack. - stack_ptr: *const [c_uchar; 32], - /// The length of the stack vector. - stack_len: size_t, - /// The storage of the logs as a set of tuples. - storage_ptr: *const ([c_uchar; 32], [c_uchar; 32]), - /// The length of the storage. - storage_len: size_t, -} - -impl From for CTraceLog { - fn from(log: TraceLog) -> Self { - let error = match &log.error { - Some(err) => CString::new(err.to_string()), - None => CString::new(""), - } - .expect("CString::new failed"); - let (memory_ptr, memory_len) = { - let len = log.memory.len(); - let memory = log.memory.clone(); - - (memory.into_raw().as_ptr(), len) - }; - let (stack_ptr, stack_len) = { - let len = log.stack.len(); - let stack = log.stack.clone(); - - (stack.into_raw().as_ptr(), len) - }; - let (storage_ptr, storage_len) = { - let storage_map = log.storage.clone(); - let storage: Vec<([u8; 32], [u8; 32])> = storage_map - .into_iter() - .map(|(key, value)| (key.into_raw(), value.into_raw())) - .collect(); - - (storage.as_ptr(), storage.len()) - }; - - Self { - depth: log.depth.into_u32(), - error, - gas: log.gas.into_u64(), - gas_cost: log.gas_cost.into_u64(), - memory_ptr, - memory_len, - opcode: log.opcode.as_u8(), - program_counter: log.program_counter.into_u32(), - stack_ptr, - stack_len, - storage_ptr, - storage_len, - } - } -} - -#[repr(C)] -pub struct CTransactionTrace { - /// The total gas cost of the transaction. - gas: uintmax_t, - /// The return of the operation. - result: CString, - /// The collection of traces. - logs_ptr: *const CTraceLog, - /// The length of the logs vector. - logs_len: size_t, -} - -impl From for CTransactionTrace { - fn from(trace: TransactionTrace) -> Self { - let logs = trace.logs().clone(); - let c_logs: Vec = logs.into_iter().map(CTraceLog::from).collect(); - let (logs_ptr, logs_len) = { - let len = c_logs.len(); - (c_logs.as_ptr(), len) - }; - - Self { - gas: trace.gas().into_u64(), - result: CString::new(trace.result()).expect("CString::new failed"), - logs_ptr, - logs_len, - } - } -} - -// Debug methods - -/// Takes in a transaction hash and returns a `TransactionTrace`. -#[no_mangle] -pub extern "C" fn trace_transaction(_tx_hash: *const [c_uchar; 32]) -> *const CTransactionTrace { - todo!() -} - -// Storage getters - -/// Gets the nonce of an Ethereum address at a given block. -/// Returns 0 on success, 1 on failure (block hash not found); the nonce variable is overwritten -/// with the requested nonce iff 0 is returned. -#[no_mangle] -pub extern "C" fn get_nonce( - _block_hash: *const [c_uchar; 32], - _address: *const [c_uchar; 20], - _nonce_out: *mut uintmax_t, -) -> c_uchar { - todo!() -} - -/// Gets the balance of an Ethereum address at a given block. -/// -/// Returns 0 on success, 1 on failure (block hash not found); the balance variable is overwritten -/// with the requested balance (big endian encoded) iff 0 is returned. -#[no_mangle] -pub extern "C" fn get_balance( - _block_hash: *const [c_uchar; 32], - _address: *const [c_uchar; 20], - _balance_out: *mut [c_uchar; 32], -) -> c_uchar { - todo!() -} - -/// Returns the size of the EVM bytecode (in bytes) for the specified account at a given block. -/// -/// Returns 0 on success, 1 on failure (block hash not found); the size variable is overwritten -/// with the requested balance (big endian encoded) iff 0 is returned. -#[no_mangle] -pub extern "C" fn get_code_size( - _block_hash: *const [c_uchar; 32], - _address: *const [c_uchar; 20], - _size_out: *const c_uint, -) -> c_uchar { - todo!() -} - -/// Returns the byte slice with the code for the specified account at a given block. -/// -/// Returns 0 on success, 1 on failure (block hash not found); the code variable is overwritten -/// with the requested balance (big endian encoded) iff 0 is returned. The size of the output slice -/// needed should be determined from `get_code_size`. -#[no_mangle] -pub extern "C" fn get_code( - _block_hash: *const [c_uchar; 32], - _address: *const [c_uchar; 20], - _code_out: *mut c_uchar, - _code_out_len: *mut c_uint, -) -> c_uchar { - todo!() -} - -/// Gets the state value for the provided address and key values at a given block. -/// Returns 0 on success, 1 on failure (block hash not found); the value variable is overwritten -/// with the requested balance (big endian encoded) iff 0 is returned. -#[no_mangle] -pub extern "C" fn get_state( - _block_hash: *const [c_uchar; 32], - _address: *const [c_uchar; 20], - _key: *const [c_uchar; 32], - _value_out: *mut [c_uchar; 32], -) -> c_uchar { - todo!() -} - -// Storage setters - -/// Submit a transaction which was included in the given block. The transaction is RPL encoded. -/// This will update the storage to include the transaction, the diff it generated, and other state metadata (see storage details). -/// The return value is 0 on success. Non-zero return values will correspond to different errors that may occur (exact errors TBD). -#[no_mangle] -pub extern "C" fn submit_transaction( - _block_hash: *const [c_uchar; 32], - _block_height: *const uintmax_t, - _transaction: *const c_uchar, - _transaction_len: *const c_uint, - _tx_position: *const c_ushort, -) -> c_uchar { - todo!() -} diff --git a/engine-standalone/src/main.rs b/engine-standalone/src/main.rs deleted file mode 100644 index f0f7c4ed6..000000000 --- a/engine-standalone/src/main.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod ffi; - -fn main() { - println!("Hello, World!"); -} diff --git a/engine-tests/Cargo.toml b/engine-tests/Cargo.toml index 12c348f36..76ae94fa9 100644 --- a/engine-tests/Cargo.toml +++ b/engine-tests/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "aurora-engine-tests" version = "1.0.0" -authors = ["NEAR "] -edition = "2018" +authors = ["Aurora Labs "] +edition = "2021" description = "" documentation = "" readme = true @@ -16,14 +16,15 @@ autobenches = false aurora-engine = { path = "../engine", default-features = false, features = ["std", "tracing"] } aurora-engine-types = { path = "../engine-types", default-features = false, features = ["std"] } aurora-engine-sdk = { path = "../engine-sdk", default-features = false, features = ["std"] } -aurora-engine-precompiles = { path = "../engine-precompiles", default-features = false } +aurora-engine-precompiles = { path = "../engine-precompiles", default-features = false, features = ["std"] } +aurora-engine-transactions = { path = "../engine-transactions", default-features = false, features = ["std"] } engine-standalone-storage = { path = "../engine-standalone-storage", default-features = false } engine-standalone-tracing = { path = "../engine-standalone-tracing", default-features = false } borsh = { version = "0.8.2", default-features = false } sha3 = { version = "0.9.1", default-features = false } -evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", default-features = false, features = ["std", "tracing"] } -evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", default-features = false, features = ["std", "tracing"] } -evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", default-features = false, features = ["std", "tracing"] } +evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "f4ee520254856898d451c7225851520a35c97cea", default-features = false, features = ["std", "tracing"] } +evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "f4ee520254856898d451c7225851520a35c97cea", default-features = false, features = ["std", "tracing"] } +evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "f4ee520254856898d451c7225851520a35c97cea", default-features = false, features = ["std", "tracing"] } rlp = { version = "0.5.0", default-features = false } [dev-dependencies] @@ -36,17 +37,17 @@ serde_json = "1" hex = { version = "0.4.3", default-features = false } near-sdk = { git = "https://github.com/aurora-is-near/near-sdk-rs.git", rev = "5e58722bd61d9d24ae6293326146c751f0a814fb" } near-sdk-sim = { git = "https://github.com/aurora-is-near/near-sdk-rs.git", rev = "5e58722bd61d9d24ae6293326146c751f0a814fb" } -near-crypto = { git = "https://github.com/near/nearcore.git", rev = "0c9ad79a18e431f843e6123cf4559f9c2c5dd228" } -near-vm-runner = { git = "https://github.com/near/nearcore.git", rev = "0c9ad79a18e431f843e6123cf4559f9c2c5dd228" } -near-vm-logic = { git = "https://github.com/near/nearcore.git", rev = "0c9ad79a18e431f843e6123cf4559f9c2c5dd228" } -near-primitives-core = { git = "https://github.com/near/nearcore.git", rev = "0c9ad79a18e431f843e6123cf4559f9c2c5dd228" } -near-primitives = { git = "https://github.com/near/nearcore.git", rev = "0c9ad79a18e431f843e6123cf4559f9c2c5dd228" } -wasmer = { package = "wasmer-near", version = "2.0.1", default-features = false, features = ["singlepass", "universal"] } +near-crypto = { git = "https://github.com/near/nearcore.git", rev = "83fc0f7d6b212bacc49f058e7400743de3e59783" } +near-vm-runner = { git = "https://github.com/near/nearcore.git", rev = "83fc0f7d6b212bacc49f058e7400743de3e59783", default-features = false, features = [ "wasmer2_vm" ] } +near-vm-logic = { git = "https://github.com/near/nearcore.git", rev = "83fc0f7d6b212bacc49f058e7400743de3e59783" } +near-primitives-core = { git = "https://github.com/near/nearcore.git", rev = "83fc0f7d6b212bacc49f058e7400743de3e59783" } +near-primitives = { git = "https://github.com/near/nearcore.git", rev = "83fc0f7d6b212bacc49f058e7400743de3e59783" } libsecp256k1 = "0.3.5" rand = "0.7.3" criterion = "0.3.4" git2 = "0.13" tempfile = "3.2.0" +walrus = "0.19" [features] meta-call = ["aurora-engine/meta-call"] diff --git a/engine-tests/src/benches/eth_deploy_code.rs b/engine-tests/src/benches/eth_deploy_code.rs index 6a7311a56..2c83d28b0 100644 --- a/engine-tests/src/benches/eth_deploy_code.rs +++ b/engine-tests/src/benches/eth_deploy_code.rs @@ -1,7 +1,7 @@ use criterion::{BatchSize, BenchmarkId, Criterion, Throughput}; use secp256k1::SecretKey; -use crate::prelude::types::Wei; +use crate::prelude::Wei; use crate::test_utils::{ address_from_secret_key, create_deploy_transaction, deploy_evm, sign_transaction, SUBMIT, }; diff --git a/engine-tests/src/benches/eth_erc20.rs b/engine-tests/src/benches/eth_erc20.rs index 369307298..137a16c7b 100644 --- a/engine-tests/src/benches/eth_erc20.rs +++ b/engine-tests/src/benches/eth_erc20.rs @@ -15,7 +15,7 @@ pub(crate) fn eth_erc20_benchmark(c: &mut Criterion) { let source_account = SecretKey::random(&mut rng); runner.create_address( address_from_secret_key(&source_account), - crate::prelude::types::Wei::new_u64(INITIAL_BALANCE), + crate::prelude::Wei::new_u64(INITIAL_BALANCE), INITIAL_NONCE.into(), ); let calling_account_id = "some-account.near"; diff --git a/engine-tests/src/benches/eth_standard_precompiles.rs b/engine-tests/src/benches/eth_standard_precompiles.rs index 2aeea79f1..e07fa1c27 100644 --- a/engine-tests/src/benches/eth_standard_precompiles.rs +++ b/engine-tests/src/benches/eth_standard_precompiles.rs @@ -2,7 +2,7 @@ use crate::prelude::U256; use criterion::{BatchSize, BenchmarkId, Criterion}; use secp256k1::SecretKey; -use crate::prelude::types::Wei; +use crate::prelude::Wei; use crate::test_utils::standard_precompiles::{PrecompilesConstructor, PrecompilesContract}; use crate::test_utils::{address_from_secret_key, deploy_evm, sign_transaction, SUBMIT}; diff --git a/engine-tests/src/benches/eth_transfer.rs b/engine-tests/src/benches/eth_transfer.rs index 8aa443a24..3aa7fdf45 100644 --- a/engine-tests/src/benches/eth_transfer.rs +++ b/engine-tests/src/benches/eth_transfer.rs @@ -1,7 +1,7 @@ use criterion::{BatchSize, Criterion}; use secp256k1::SecretKey; -use crate::prelude::types::Wei; +use crate::prelude::Wei; use crate::test_utils::{address_from_secret_key, create_eth_transaction, deploy_evm, SUBMIT}; const INITIAL_BALANCE: Wei = Wei::new_u64(1000); diff --git a/engine-tests/src/benches/nft_pagination.rs b/engine-tests/src/benches/nft_pagination.rs index 8d8e38d65..61c90e54b 100644 --- a/engine-tests/src/benches/nft_pagination.rs +++ b/engine-tests/src/benches/nft_pagination.rs @@ -1,7 +1,6 @@ -use crate::prelude::types::Wei; -use crate::prelude::{Address, U256}; +use crate::prelude::{Address, Wei, U256}; use crate::test_utils::{self, solidity}; -use aurora_engine::transaction::legacy::TransactionLegacy; +use aurora_engine_transactions::legacy::TransactionLegacy; use secp256k1::SecretKey; use std::path::{Path, PathBuf}; use std::process::Command; @@ -55,6 +54,7 @@ pub(crate) fn measure_gas_usage( } struct MarketPlaceConstructor(solidity::ContractConstructor); + struct MarketPlace(solidity::DeployedContract); impl MarketPlaceConstructor { @@ -134,7 +134,7 @@ impl MarketPlace { self.0.call_method_with_args( "minar", &[ - ethabi::Token::Address(recipient), + ethabi::Token::Address(recipient.raw()), ethabi::Token::String(data), ethabi::Token::Uint(price.raw()), ], @@ -171,7 +171,6 @@ fn initialize_evm() -> (test_utils::AuroraRunner, test_utils::Signer, Address) { signer.nonce = INITIAL_NONCE; runner.wasm_config.limit_config.max_gas_burnt = u64::MAX; - runner.wasm_config.limit_config.max_gas_burnt_view = u64::MAX; (runner, signer, dest_address) } diff --git a/engine-tests/src/prelude.rs b/engine-tests/src/prelude.rs index d83b02aae..9c36fdfa5 100644 --- a/engine-tests/src/prelude.rs +++ b/engine-tests/src/prelude.rs @@ -4,12 +4,13 @@ mod v0 { #[cfg(feature = "meta-call")] pub use aurora_engine::meta_parsing; pub use aurora_engine::parameters; - pub use aurora_engine::transaction; pub use aurora_engine_sdk as sdk; + pub use aurora_engine_transactions as transactions; pub use aurora_engine_types::parameters::*; pub use aurora_engine_types::storage; pub use aurora_engine_types::types::*; pub use aurora_engine_types::*; pub use borsh::{BorshDeserialize, BorshSerialize}; } + pub use v0::*; diff --git a/engine-tests/src/test_utils/erc20.rs b/engine-tests/src/test_utils/erc20.rs index 57cc38f69..22ef14d69 100644 --- a/engine-tests/src/test_utils/erc20.rs +++ b/engine-tests/src/test_utils/erc20.rs @@ -1,4 +1,4 @@ -use crate::prelude::{transaction::legacy::TransactionLegacy, Address, U256}; +use crate::prelude::{transactions::legacy::TransactionLegacy, Address, U256}; use crate::test_utils::solidity; use std::path::{Path, PathBuf}; use std::sync::Once; @@ -78,7 +78,7 @@ impl ERC20 { .function("mint") .unwrap() .encode_input(&[ - ethabi::Token::Address(recipient), + ethabi::Token::Address(recipient.raw()), ethabi::Token::Uint(amount), ]) .unwrap(); @@ -100,7 +100,7 @@ impl ERC20 { .function("transfer") .unwrap() .encode_input(&[ - ethabi::Token::Address(recipient), + ethabi::Token::Address(recipient.raw()), ethabi::Token::Uint(amount), ]) .unwrap(); @@ -120,7 +120,10 @@ impl ERC20 { .abi .function("approve") .unwrap() - .encode_input(&[ethabi::Token::Address(spender), ethabi::Token::Uint(amount)]) + .encode_input(&[ + ethabi::Token::Address(spender.raw()), + ethabi::Token::Uint(amount), + ]) .unwrap(); TransactionLegacy { nonce, @@ -138,7 +141,7 @@ impl ERC20 { .abi .function("balanceOf") .unwrap() - .encode_input(&[ethabi::Token::Address(address)]) + .encode_input(&[ethabi::Token::Address(address.raw())]) .unwrap(); TransactionLegacy { nonce, diff --git a/engine-tests/src/test_utils/exit_precompile.rs b/engine-tests/src/test_utils/exit_precompile.rs index 76484930e..177f8822f 100644 --- a/engine-tests/src/test_utils/exit_precompile.rs +++ b/engine-tests/src/test_utils/exit_precompile.rs @@ -1,5 +1,5 @@ use crate::prelude::{ - parameters::SubmitResult, transaction::legacy::TransactionLegacy, Address, Wei, U256, + parameters::SubmitResult, transactions::legacy::TransactionLegacy, Address, Wei, U256, }; use crate::test_utils::{self, solidity, AuroraRunner, Signer}; @@ -30,7 +30,7 @@ impl TesterConstructor { .abi .constructor() .unwrap() - .encode_input(self.0.code.clone(), &[ethabi::Token::Address(token)]) + .encode_input(self.0.code.clone(), &[ethabi::Token::Address(token.raw())]) .unwrap(); TransactionLegacy { @@ -200,7 +200,7 @@ impl Tester { signer, "withdrawEthToEthereum", amount, - &[ethabi::Token::Address(DEST_ADDRESS)], + &[ethabi::Token::Address(DEST_ADDRESS.raw())], ) } } diff --git a/engine-tests/src/test_utils/mocked_external.rs b/engine-tests/src/test_utils/mocked_external.rs new file mode 100644 index 000000000..4f6e9180f --- /dev/null +++ b/engine-tests/src/test_utils/mocked_external.rs @@ -0,0 +1,175 @@ +use near_vm_logic::mocks::mock_external::MockedExternal; + +pub const MAINNET_AVERAGE_TRIE_DEPTH: u64 = 10; + +#[derive(Clone)] +pub(crate) struct MockedExternalWithTrie { + pub underlying: MockedExternal, + trie_node_count: std::cell::Cell, +} + +impl MockedExternalWithTrie { + pub fn new(ext: MockedExternal) -> Self { + Self { + underlying: ext, + trie_node_count: std::cell::Cell::new(0), + } + } + + fn increment_trie_node_count(&self, amount: u64) { + let cell_value = self.trie_node_count.get(); + self.trie_node_count.set(cell_value + amount); + } +} + +impl near_vm_logic::External for MockedExternalWithTrie { + fn storage_set(&mut self, key: &[u8], value: &[u8]) -> Result<(), near_vm_logic::VMLogicError> { + self.increment_trie_node_count(MAINNET_AVERAGE_TRIE_DEPTH); + self.underlying.storage_set(key, value) + } + + fn storage_get<'a>( + &'a self, + key: &[u8], + ) -> Result>, near_vm_logic::VMLogicError> { + self.increment_trie_node_count(MAINNET_AVERAGE_TRIE_DEPTH); + self.underlying.storage_get(key) + } + + fn storage_remove(&mut self, key: &[u8]) -> Result<(), near_vm_logic::VMLogicError> { + self.increment_trie_node_count(MAINNET_AVERAGE_TRIE_DEPTH); + self.underlying.storage_remove(key) + } + + fn storage_remove_subtree(&mut self, prefix: &[u8]) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying.storage_remove_subtree(prefix) + } + + fn storage_has_key(&mut self, key: &[u8]) -> Result { + self.underlying.storage_has_key(key) + } + + fn create_receipt( + &mut self, + receipt_indices: Vec, + receiver_id: near_primitives::types::AccountId, + ) -> Result { + self.underlying.create_receipt(receipt_indices, receiver_id) + } + + fn append_action_create_account( + &mut self, + receipt_index: near_vm_logic::types::ReceiptIndex, + ) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying.append_action_create_account(receipt_index) + } + + fn append_action_deploy_contract( + &mut self, + receipt_index: near_vm_logic::types::ReceiptIndex, + code: Vec, + ) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying + .append_action_deploy_contract(receipt_index, code) + } + + fn append_action_function_call( + &mut self, + receipt_index: near_vm_logic::types::ReceiptIndex, + method_name: Vec, + arguments: Vec, + attached_deposit: near_primitives::types::Balance, + prepaid_gas: near_primitives::types::Gas, + ) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying.append_action_function_call( + receipt_index, + method_name, + arguments, + attached_deposit, + prepaid_gas, + ) + } + + fn append_action_transfer( + &mut self, + receipt_index: near_vm_logic::types::ReceiptIndex, + amount: near_primitives::types::Balance, + ) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying + .append_action_transfer(receipt_index, amount) + } + + fn append_action_stake( + &mut self, + receipt_index: near_vm_logic::types::ReceiptIndex, + stake: near_primitives::types::Balance, + public_key: near_vm_logic::types::PublicKey, + ) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying + .append_action_stake(receipt_index, stake, public_key) + } + + fn append_action_add_key_with_full_access( + &mut self, + receipt_index: near_vm_logic::types::ReceiptIndex, + public_key: near_vm_logic::types::PublicKey, + nonce: u64, + ) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying + .append_action_add_key_with_full_access(receipt_index, public_key, nonce) + } + + fn append_action_add_key_with_function_call( + &mut self, + receipt_index: near_vm_logic::types::ReceiptIndex, + public_key: near_vm_logic::types::PublicKey, + nonce: u64, + allowance: Option, + receiver_id: near_primitives::types::AccountId, + method_names: Vec>, + ) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying.append_action_add_key_with_function_call( + receipt_index, + public_key, + nonce, + allowance, + receiver_id, + method_names, + ) + } + + fn append_action_delete_key( + &mut self, + receipt_index: near_vm_logic::types::ReceiptIndex, + public_key: near_vm_logic::types::PublicKey, + ) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying + .append_action_delete_key(receipt_index, public_key) + } + + fn append_action_delete_account( + &mut self, + receipt_index: near_vm_logic::types::ReceiptIndex, + beneficiary_id: near_primitives::types::AccountId, + ) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying + .append_action_delete_account(receipt_index, beneficiary_id) + } + + fn get_touched_nodes_count(&self) -> u64 { + self.trie_node_count.get() + } + + fn validator_stake( + &self, + account_id: &near_primitives::types::AccountId, + ) -> Result, near_vm_logic::VMLogicError> { + self.underlying.validator_stake(account_id) + } + + fn validator_total_stake( + &self, + ) -> Result { + self.underlying.validator_total_stake() + } +} diff --git a/engine-tests/src/test_utils/mod.rs b/engine-tests/src/test_utils/mod.rs index 50c141073..3771d30da 100644 --- a/engine-tests/src/test_utils/mod.rs +++ b/engine-tests/src/test_utils/mod.rs @@ -1,10 +1,13 @@ +use aurora_engine::parameters::ViewCallArgs; use aurora_engine_types::account_id::AccountId; +use aurora_engine_types::types::NEP141Wei; use borsh::{BorshDeserialize, BorshSerialize}; +use near_primitives::runtime::config_store::RuntimeConfigStore; +use near_primitives::version::PROTOCOL_VERSION; use near_primitives_core::config::VMConfig; use near_primitives_core::contract::ContractCode; use near_primitives_core::profile::ProfileData; use near_primitives_core::runtime::fees::RuntimeFeesConfig; -use near_vm_logic::mocks::mock_external::MockedExternal; use near_vm_logic::types::ReturnData; use near_vm_logic::{VMContext, VMOutcome}; use near_vm_runner::{MockCompiledContractCache, VMError}; @@ -12,10 +15,8 @@ use rlp::RlpStream; use secp256k1::{self, Message, PublicKey, SecretKey}; use crate::prelude::fungible_token::{FungibleToken, FungibleTokenMetadata}; -use crate::prelude::parameters::{ - InitCallArgs, NewCallArgs, SubmitResult, TransactionStatus, ViewCallArgs, -}; -use crate::prelude::transaction::{ +use crate::prelude::parameters::{InitCallArgs, NewCallArgs, SubmitResult, TransactionStatus}; +use crate::prelude::transactions::{ eip_1559::{self, SignedTransaction1559, Transaction1559}, eip_2930::{self, SignedTransaction2930, Transaction2930}, legacy::{LegacyEthSignedTransaction, TransactionLegacy}, @@ -35,6 +36,7 @@ pub(crate) const DEPLOY_ERC20: &str = "deploy_erc20_token"; pub(crate) mod erc20; pub(crate) mod exit_precompile; +pub(crate) mod mocked_external; pub(crate) mod one_inch; pub(crate) mod random; pub(crate) mod rust; @@ -76,7 +78,7 @@ pub(crate) struct AuroraRunner { pub chain_id: u64, pub code: ContractCode, pub cache: MockCompiledContractCache, - pub ext: MockedExternal, + pub ext: mocked_external::MockedExternalWithTrie, pub context: VMContext, pub wasm_config: VMConfig, pub fees_config: RuntimeFeesConfig, @@ -92,7 +94,7 @@ pub(crate) struct AuroraRunner { #[derive(Clone)] pub(crate) struct OneShotAuroraRunner<'a> { pub base: &'a AuroraRunner, - pub ext: MockedExternal, + pub ext: mocked_external::MockedExternalWithTrie, pub context: VMContext, } @@ -239,7 +241,7 @@ impl AuroraRunner { init_nonce: U256, code: Option>, ) { - let trie = &mut self.ext.fake_trie; + let trie = &mut self.ext.underlying.fake_trie; let balance_key = crate::prelude::storage::address_to_key( crate::prelude::storage::KeyPrefix::Balance, @@ -270,7 +272,8 @@ impl AuroraRunner { .get(&ft_key) .map(|bytes| FungibleToken::try_from_slice(&bytes).unwrap()) .unwrap_or_default(); - current_ft.total_eth_supply_on_near += init_balance.raw().as_u128(); + current_ft.total_eth_supply_on_near = + current_ft.total_eth_supply_on_near + NEP141Wei::new(init_balance.raw().as_u128()); current_ft }; @@ -375,7 +378,7 @@ impl AuroraRunner { assert!(maybe_err.is_none()); let submit_result = SubmitResult::try_from_slice(&output.unwrap().return_data.as_value().unwrap()).unwrap(); - let address = Address::from_slice(&unwrap_success(submit_result)); + let address = Address::try_from_slice(&unwrap_success(submit_result)).unwrap(); let contract_constructor: ContractConstructor = contract_constructor.into(); DeployedContract { abi: contract_constructor.abi, @@ -419,7 +422,7 @@ impl AuroraRunner { pub fn get_storage(&self, address: Address, key: H256) -> H256 { let input = aurora_engine::parameters::GetStorageAtArgs { - address: address.0, + address, key: key.0, }; let (outcome, maybe_error) = @@ -469,9 +472,9 @@ impl AuroraRunner { let standalone_state = standalone_runner.get_current_state(); // The number of keys in standalone_state may be larger because values are never deleted // (they are replaced with a Deleted identifier instead; this is important for replaying transactions). - assert!(self.ext.fake_trie.len() <= standalone_state.iter().count()); + assert!(self.ext.underlying.fake_trie.len() <= standalone_state.iter().count()); for (key, value) in standalone_state.iter() { - let trie_value = self.ext.fake_trie.get(key).map(|v| v.as_slice()); + let trie_value = self.ext.underlying.fake_trie.get(key).map(|v| v.as_slice()); let standalone_value = value.value(); if trie_value != standalone_value { panic!( @@ -494,16 +497,18 @@ impl Default for AuroraRunner { } else { panic!("AuroraRunner requires mainnet-test or testnet-test feature enabled.") }; - let mut wasm_config = VMConfig::default(); - // See https://github.com/near/nearcore/pull/4979/ - wasm_config.regular_op_cost = 2207874; + + // Fetch config (mainly costs) for the latest protocol version. + let runtime_config_store = RuntimeConfigStore::new(None); + let runtime_config = runtime_config_store.get_config(PROTOCOL_VERSION); + let wasm_config = runtime_config.wasm_config.clone(); Self { aurora_account_id: aurora_account_id.clone(), chain_id: 1313161556, // NEAR localnet, code: ContractCode::new(evm_wasm_bytes, None), cache: Default::default(), - ext: Default::default(), + ext: mocked_external::MockedExternalWithTrie::new(Default::default()), context: VMContext { current_account_id: as_account_id(&aurora_account_id), signer_account_id: as_account_id(&aurora_account_id), @@ -535,7 +540,7 @@ impl Default for AuroraRunner { /// (which was removed in https://github.com/near/nearcore/pull/4438). #[derive(Default, Clone)] pub(crate) struct ExecutionProfile { - host_breakdown: ProfileData, + pub host_breakdown: ProfileData, wasm_gas: u64, } @@ -653,8 +658,8 @@ pub(crate) fn create_eth_transaction( pub(crate) fn as_view_call(tx: TransactionLegacy, sender: Address) -> ViewCallArgs { ViewCallArgs { - sender: sender.0, - address: tx.to.unwrap().0, + sender, + address: tx.to.unwrap(), amount: tx.value.to_bytes(), input: tx.data, } @@ -732,7 +737,7 @@ pub(crate) fn sign_eip_1559_transaction( pub(crate) fn address_from_secret_key(sk: &SecretKey) -> Address { let pk = PublicKey::from_secret_key(sk); let hash = sdk::keccak(&pk.serialize()[1..]); - Address::from_slice(&hash[12..]) + Address::try_from_slice(&hash[12..]).unwrap() } pub(crate) fn parse_eth_gas(output: &VMOutcome) -> u64 { @@ -761,7 +766,7 @@ pub(crate) fn address_from_hex(address: &str) -> Address { hex::decode(address).unwrap() }; - Address::from_slice(&bytes) + Address::try_from_slice(&bytes).unwrap() } pub(crate) fn as_account_id(account_id: &str) -> near_primitives_core::types::AccountId { diff --git a/engine-tests/src/test_utils/one_inch/liquidity_protocol.rs b/engine-tests/src/test_utils/one_inch/liquidity_protocol.rs index 4de97a372..913d3ae43 100644 --- a/engine-tests/src/test_utils/one_inch/liquidity_protocol.rs +++ b/engine-tests/src/test_utils/one_inch/liquidity_protocol.rs @@ -27,7 +27,7 @@ impl<'a> Helper<'a> { let (result, profile) = self .runner .submit_with_signer_profiled(self.signer, |nonce| { - crate::prelude::transaction::legacy::TransactionLegacy { + crate::prelude::transactions::legacy::TransactionLegacy { nonce, gas_price: Default::default(), gas_limit: u64::MAX.into(), @@ -38,7 +38,8 @@ impl<'a> Helper<'a> { }) .unwrap(); - let deployer_address = Address::from_slice(test_utils::unwrap_success_slice(&result)); + let deployer_address = + Address::try_from_slice(test_utils::unwrap_success_slice(&result)).unwrap(); let deployer = PoolDeployer(solidity::DeployedContract { abi, address: deployer_address, @@ -63,15 +64,15 @@ impl<'a> Helper<'a> { constructor.deploy_with_args( nonce, &[ - ethabi::Token::Address(signer_address), - ethabi::Token::Address(pool_deployer.0.address), - ethabi::Token::Address(signer_address), + ethabi::Token::Address(signer_address.raw()), + ethabi::Token::Address(pool_deployer.0.address.raw()), + ethabi::Token::Address(signer_address.raw()), ], ) }) .unwrap(); - let address = Address::from_slice(test_utils::unwrap_success_slice(&result)); + let address = Address::try_from_slice(test_utils::unwrap_success_slice(&result)).unwrap(); let pool_factory = PoolFactory(constructor.deployed_at(address)); (result, profile, pool_factory) @@ -94,15 +95,16 @@ impl<'a> Helper<'a> { pool_factory.0.call_method_with_args( "deploy", &[ - ethabi::Token::Address(token_a), - ethabi::Token::Address(token_b), + ethabi::Token::Address(token_a.raw()), + ethabi::Token::Address(token_b.raw()), ], nonce, ) }) .unwrap(); - let address = Address::from_slice(&test_utils::unwrap_success_slice(&result)[12..32]); + let address = + Address::try_from_slice(&test_utils::unwrap_success_slice(&result)[12..32]).unwrap(); let pool = Pool(constructor.deployed_at(address)); (result, profile, pool) @@ -178,11 +180,11 @@ impl<'a> Helper<'a> { pool, "swap", &[ - ethabi::Token::Address(args.src_token), - ethabi::Token::Address(args.dst_token), + ethabi::Token::Address(args.src_token.raw()), + ethabi::Token::Address(args.dst_token.raw()), ethabi::Token::Uint(args.amount), ethabi::Token::Uint(args.min_amount), - ethabi::Token::Address(args.referral), + ethabi::Token::Address(args.referral.raw()), ], ) } diff --git a/engine-tests/src/test_utils/random.rs b/engine-tests/src/test_utils/random.rs index 4d4505d08..531606af2 100644 --- a/engine-tests/src/test_utils/random.rs +++ b/engine-tests/src/test_utils/random.rs @@ -1,6 +1,6 @@ use crate::prelude::U256; use crate::test_utils::{self, solidity, AuroraRunner, Signer}; -use aurora_engine::transaction::legacy::TransactionLegacy; +use aurora_engine_transactions::legacy::TransactionLegacy; use aurora_engine_types::H256; use ethabi::Constructor; diff --git a/engine-tests/src/test_utils/self_destruct.rs b/engine-tests/src/test_utils/self_destruct.rs index a4acb6947..751ff0751 100644 --- a/engine-tests/src/test_utils/self_destruct.rs +++ b/engine-tests/src/test_utils/self_destruct.rs @@ -1,10 +1,9 @@ use crate::prelude::{ - parameters::CallArgs, parameters::FunctionCallArgsV2, transaction::legacy::TransactionLegacy, + parameters::CallArgs, parameters::FunctionCallArgsV2, transactions::legacy::TransactionLegacy, Address, WeiU256, U256, }; use crate::test_utils::{self, solidity, AuroraRunner, Signer}; use borsh::BorshSerialize; -use std::convert::TryInto; pub(crate) struct SelfDestructFactoryConstructor(pub solidity::ContractConstructor); @@ -75,7 +74,7 @@ impl SelfDestructFactory { let result = runner.submit_transaction(&signer.secret_key, tx).unwrap(); let result = test_utils::unwrap_success(result); - Address::from_slice(&result[12..]) + Address::try_from_slice(&result[12..]).unwrap() } } diff --git a/engine-tests/src/test_utils/solidity.rs b/engine-tests/src/test_utils/solidity.rs index 4ced046cc..53434a2ae 100644 --- a/engine-tests/src/test_utils/solidity.rs +++ b/engine-tests/src/test_utils/solidity.rs @@ -1,4 +1,4 @@ -use crate::prelude::{transaction::legacy::TransactionLegacy, Address, U256}; +use crate::prelude::{transactions::legacy::TransactionLegacy, Address, U256}; use near_sdk::serde_json; use serde::Deserialize; use std::fs; @@ -22,6 +22,27 @@ struct ExtendedJsonSolidityArtifact { } impl ContractConstructor { + /// Same as `compile_from_source` but always recompiles instead of reusing artifacts when they exist. + pub fn force_compile( + sources_root: P1, + artifacts_base_path: P2, + contract_file: P3, + contract_name: &str, + ) -> Self + where + P1: AsRef, + P2: AsRef, + P3: AsRef, + { + compile(&sources_root, &contract_file, &artifacts_base_path); + Self::compile_from_source( + sources_root, + artifacts_base_path, + contract_file, + contract_name, + ) + } + // Note: `contract_file` must be relative to `sources_root` pub fn compile_from_source( sources_root: P1, diff --git a/engine-tests/src/test_utils/standalone/mocks/block.rs b/engine-tests/src/test_utils/standalone/mocks/block.rs index 3a4d5366f..2ca2c3092 100644 --- a/engine-tests/src/test_utils/standalone/mocks/block.rs +++ b/engine-tests/src/test_utils/standalone/mocks/block.rs @@ -1,4 +1,4 @@ -use aurora_engine::transaction::legacy::LegacyEthSignedTransaction; +use aurora_engine_transactions::legacy::LegacyEthSignedTransaction; /// A vastly simplified block structure pub struct Block { diff --git a/engine-tests/src/test_utils/standalone/mocks/mod.rs b/engine-tests/src/test_utils/standalone/mocks/mod.rs index 07a5d5355..f71f2fc75 100644 --- a/engine-tests/src/test_utils/standalone/mocks/mod.rs +++ b/engine-tests/src/test_utils/standalone/mocks/mod.rs @@ -1,15 +1,14 @@ +use crate::test_utils; use aurora_engine::engine; use aurora_engine::fungible_token::FungibleTokenMetadata; use aurora_engine::parameters::{FinishDepositCallArgs, InitCallArgs, NewCallArgs}; use aurora_engine_sdk::env::{Env, DEFAULT_PREPAID_GAS}; use aurora_engine_sdk::io::IO; -use aurora_engine_types::types::NearGas; -use aurora_engine_types::{account_id::AccountId, types::Wei, Address, H256, U256}; +use aurora_engine_types::types::{Address, NEP141Wei, NearGas, Wei}; +use aurora_engine_types::{account_id::AccountId, H256, U256}; use engine_standalone_storage::{BlockMetadata, Storage}; use near_sdk_sim::DEFAULT_GAS; -use crate::test_utils; - pub mod block; pub mod promise; pub mod storage; @@ -62,7 +61,7 @@ pub fn init_evm(mut io: I, env: &E, chain_id: u64) { let connector_args = InitCallArgs { prover_account: test_utils::str_to_account_id("prover.near"), - eth_custodian_address: hex::encode(Ð_CUSTODIAN_ADDRESS), + eth_custodian_address: ETH_CUSTODIAN_ADDRESS.encode(), metadata: FungibleTokenMetadata::default(), }; @@ -88,7 +87,7 @@ pub fn mint_evm_account( let aurora_account_id = env.current_account_id(); let mut engine = engine::Engine::new(address, aurora_account_id.clone(), io, env).unwrap(); let state_change = evm::backend::Apply::Modify { - address, + address: address.raw(), basic: evm::backend::Basic { balance: balance.raw(), nonce, @@ -101,7 +100,7 @@ pub fn mint_evm_account( let deposit_args = FinishDepositCallArgs { new_owner_id: aurora_account_id.clone(), - amount: balance.raw().low_u128(), + amount: NEP141Wei::new(balance.raw().as_u128()), proof_key: String::new(), relayer_id: aurora_account_id.clone(), fee: 0.into(), diff --git a/engine-tests/src/test_utils/standalone/mod.rs b/engine-tests/src/test_utils/standalone/mod.rs index f2f3b59ac..076b53335 100644 --- a/engine-tests/src/test_utils/standalone/mod.rs +++ b/engine-tests/src/test_utils/standalone/mod.rs @@ -1,9 +1,9 @@ use aurora_engine::engine; use aurora_engine::parameters::{CallArgs, DeployErc20TokenArgs, SubmitResult, TransactionStatus}; -use aurora_engine::transaction::legacy::{LegacyEthSignedTransaction, TransactionLegacy}; use aurora_engine_sdk::env::{self, Env}; -use aurora_engine_types::types::NearGas; -use aurora_engine_types::{types::Wei, Address, H256, U256}; +use aurora_engine_transactions::legacy::{LegacyEthSignedTransaction, TransactionLegacy}; +use aurora_engine_types::types::{Address, NearGas, Wei}; +use aurora_engine_types::{H256, U256}; use borsh::BorshDeserialize; use engine_standalone_storage::engine_state; use engine_standalone_storage::{BlockMetadata, Diff, Storage}; @@ -50,7 +50,7 @@ impl StandaloneRunner { let env = &mut self.env; let transaction_hash = { let bytes = [ - address.as_ref(), + address.raw().as_ref(), &balance.to_bytes(), &aurora_engine_types::types::u256_to_arr(&nonce), ] @@ -184,7 +184,7 @@ impl StandaloneRunner { .unwrap(); io.finish().commit(storage, &mut self.cumulative_diff); Ok(SubmitResult::new( - TransactionStatus::Succeed(address.as_ref().to_vec()), + TransactionStatus::Succeed(address.raw().as_ref().to_vec()), 0, Vec::new(), )) diff --git a/engine-tests/src/test_utils/standard_precompiles.rs b/engine-tests/src/test_utils/standard_precompiles.rs index 7404b4452..1468bc0a0 100644 --- a/engine-tests/src/test_utils/standard_precompiles.rs +++ b/engine-tests/src/test_utils/standard_precompiles.rs @@ -1,4 +1,4 @@ -use crate::prelude::{transaction::legacy::TransactionLegacy, U256}; +use crate::prelude::{transactions::legacy::TransactionLegacy, U256}; use crate::test_utils::solidity; use std::path::{Path, PathBuf}; diff --git a/engine-tests/src/test_utils/uniswap.rs b/engine-tests/src/test_utils/uniswap.rs index 4d951ade8..88a42d848 100644 --- a/engine-tests/src/test_utils/uniswap.rs +++ b/engine-tests/src/test_utils/uniswap.rs @@ -1,6 +1,6 @@ use crate::prelude::{Address, U256}; use crate::test_utils::solidity; -use aurora_engine::transaction::legacy::TransactionLegacy; +use aurora_engine_transactions::legacy::TransactionLegacy; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; @@ -112,9 +112,9 @@ impl PositionManagerConstructor { .encode_input( self.0.code.clone(), &[ - ethabi::Token::Address(factory), - ethabi::Token::Address(wrapped_eth), - ethabi::Token::Address(token_descriptor), + ethabi::Token::Address(factory.raw()), + ethabi::Token::Address(wrapped_eth.raw()), + ethabi::Token::Address(token_descriptor.raw()), ], ) .unwrap(); @@ -143,8 +143,8 @@ impl Factory { .function("createPool") .unwrap() .encode_input(&[ - ethabi::Token::Address(token_a), - ethabi::Token::Address(token_b), + ethabi::Token::Address(token_a.raw()), + ethabi::Token::Address(token_b.raw()), ethabi::Token::Uint(fee), ]) .unwrap(); @@ -213,8 +213,8 @@ impl PositionManager { .function("mint") .unwrap() .encode_input(&[ethabi::Token::Tuple(vec![ - ethabi::Token::Address(params.token0), - ethabi::Token::Address(params.token1), + ethabi::Token::Address(params.token0.raw()), + ethabi::Token::Address(params.token1.raw()), ethabi::Token::Uint(params.fee.into()), ethabi::Token::Int(tick_lower), ethabi::Token::Int(tick_upper), @@ -222,7 +222,7 @@ impl PositionManager { ethabi::Token::Uint(params.amount1_desired), ethabi::Token::Uint(params.amount0_min), ethabi::Token::Uint(params.amount1_min), - ethabi::Token::Address(params.recipient), + ethabi::Token::Address(params.recipient.raw()), ethabi::Token::Uint(params.deadline), ])]) .unwrap(); @@ -276,8 +276,8 @@ impl SwapRouterConstructor { .encode_input( self.0.code.clone(), &[ - ethabi::Token::Address(factory), - ethabi::Token::Address(wrapped_eth), + ethabi::Token::Address(factory.raw()), + ethabi::Token::Address(wrapped_eth.raw()), ], ) .unwrap(); @@ -303,6 +303,16 @@ pub struct ExactOutputSingleParams { pub price_limit: U256, } +pub struct ExactInputParams { + pub token_in: Address, + // Vec of poolFee + tokenAddress + pub path: Vec<(u64, Address)>, + pub recipient: Address, + pub deadline: U256, + pub amount_in: U256, + pub amount_out_min: U256, +} + impl SwapRouter { pub fn exact_output_single( &self, @@ -315,10 +325,10 @@ impl SwapRouter { .function("exactOutputSingle") .unwrap() .encode_input(&[ethabi::Token::Tuple(vec![ - ethabi::Token::Address(params.token_in), - ethabi::Token::Address(params.token_out), + ethabi::Token::Address(params.token_in.raw()), + ethabi::Token::Address(params.token_out.raw()), ethabi::Token::Uint(params.fee.into()), - ethabi::Token::Address(params.recipient), + ethabi::Token::Address(params.recipient.raw()), ethabi::Token::Uint(params.deadline), ethabi::Token::Uint(params.amount_out), ethabi::Token::Uint(params.amount_in_max), @@ -335,6 +345,42 @@ impl SwapRouter { data, } } + + pub fn exact_input(&self, params: ExactInputParams, nonce: U256) -> TransactionLegacy { + let path: Vec = { + // The encoding here is 32-byte address, then 3-byte (24-bit) fee, alternating + let mut result = Vec::with_capacity(32 + 35 * params.path.len()); + result.extend_from_slice(params.token_in.as_bytes()); + for (fee, token) in params.path.iter() { + let fee_bytes = fee.to_be_bytes(); + result.extend_from_slice(&fee_bytes[5..8]); + result.extend_from_slice(token.as_bytes()); + } + result + }; + let data = self + .0 + .abi + .function("exactInput") + .unwrap() + .encode_input(&[ethabi::Token::Tuple(vec![ + ethabi::Token::Bytes(path), + ethabi::Token::Address(params.recipient.raw()), + ethabi::Token::Uint(params.deadline), + ethabi::Token::Uint(params.amount_in), + ethabi::Token::Uint(params.amount_out_min), + ])]) + .unwrap(); + + TransactionLegacy { + nonce, + gas_price: Default::default(), + gas_limit: u64::MAX.into(), + to: Some(self.0.address), + value: Default::default(), + data, + } + } } fn load_constructor(artifact_path: PathBuf) -> solidity::ContractConstructor { diff --git a/engine-tests/src/test_utils/weth.rs b/engine-tests/src/test_utils/weth.rs index da5390cf6..63ff6cc17 100644 --- a/engine-tests/src/test_utils/weth.rs +++ b/engine-tests/src/test_utils/weth.rs @@ -1,5 +1,6 @@ -use aurora_engine::transaction::legacy::TransactionLegacy; -use aurora_engine_types::{types::Wei, Address, U256}; +use aurora_engine_transactions::legacy::TransactionLegacy; +use aurora_engine_types::types::{Address, Wei}; +use aurora_engine_types::U256; use crate::test_utils::solidity; diff --git a/engine-tests/src/tests/access_lists.rs b/engine-tests/src/tests/access_lists.rs index 93ef7f779..4e44678c4 100644 --- a/engine-tests/src/tests/access_lists.rs +++ b/engine-tests/src/tests/access_lists.rs @@ -1,8 +1,8 @@ +use crate::prelude::transactions::eip_2930::{self, AccessTuple, Transaction2930}; +use crate::prelude::transactions::EthTransactionKind; use crate::prelude::Wei; use crate::prelude::{H256, U256}; use crate::test_utils; -use aurora_engine::transaction::eip_2930::{self, AccessTuple, Transaction2930}; -use aurora_engine::transaction::EthTransactionKind; use std::convert::TryFrom; use std::iter; @@ -26,11 +26,13 @@ fn test_access_list_tx_encoding_decoding() { data: vec![0], access_list: vec![ AccessTuple { - address: test_utils::address_from_hex("0x095e7baea6a6c7c4c2dfeb977efac326af552d87"), + address: test_utils::address_from_hex("0x095e7baea6a6c7c4c2dfeb977efac326af552d87") + .raw(), storage_keys: vec![H256::zero(), one()], }, AccessTuple { - address: test_utils::address_from_hex("0x195e7baea6a6c7c4c2dfeb977efac326af552d87"), + address: test_utils::address_from_hex("0x195e7baea6a6c7c4c2dfeb977efac326af552d87") + .raw(), storage_keys: vec![H256::zero()], }, ], diff --git a/engine-tests/src/tests/contract_call.rs b/engine-tests/src/tests/contract_call.rs index f52572461..83c219f10 100644 --- a/engine-tests/src/tests/contract_call.rs +++ b/engine-tests/src/tests/contract_call.rs @@ -4,7 +4,7 @@ use crate::test_utils::{origin, AuroraRunner, Signer}; use crate::test_utils; use crate::test_utils::exit_precompile::{Tester, TesterConstructor, DEST_ACCOUNT, DEST_ADDRESS}; -fn setup_test() -> (AuroraRunner, Signer, [u8; 20], Tester) { +fn setup_test() -> (AuroraRunner, Signer, Address, Tester) { let mut runner = AuroraRunner::new(); let token = runner.deploy_erc20_token(&"tt.testnet".to_string()); let mut signer = test_utils::Signer::random(); @@ -49,7 +49,6 @@ fn hello_world_solidity() { #[test] fn withdraw() { let (mut runner, mut signer, token, tester) = setup_test(); - let token = Address(token); let test_data = vec![ (true, "call_contract tt.testnet.ft_transfer"), @@ -86,20 +85,20 @@ fn withdraw() { } else { // transferred to 0xE0f5206BBD039e7b0592d8918820024e2a7437b9 (defined in Tester.sol) let address = hex::decode("E0f5206BBD039e7b0592d8918820024e2a7437b9").unwrap(); - let address = Address::from_slice(&address); + let address = Address::try_from_slice(&address).unwrap(); ethabi::LogParam { name: "dest".to_string(), - value: ethabi::Token::Address(address), + value: ethabi::Token::Address(address.raw()), } }; let expected_event = vec![ ethabi::LogParam { name: "sender".to_string(), - value: ethabi::Token::Address(token), + value: ethabi::Token::Address(token.raw()), }, ethabi::LogParam { name: "erc20_address".to_string(), - value: ethabi::Token::Address(token), + value: ethabi::Token::Address(token.raw()), }, dest, ethabi::LogParam { @@ -188,11 +187,13 @@ fn withdraw_eth() { let mut expected_event = vec![ ethabi::LogParam { name: "sender".to_string(), - value: ethabi::Token::Address(tester.contract.address), + value: ethabi::Token::Address(tester.contract.address.raw()), }, ethabi::LogParam { name: "erc20_address".to_string(), - value: ethabi::Token::Address(aurora_engine_precompiles::native::events::ETH_ADDRESS), + value: ethabi::Token::Address( + aurora_engine_precompiles::native::events::ETH_ADDRESS.raw(), + ), }, ethabi::LogParam { name: "dest".to_string(), @@ -215,7 +216,7 @@ fn withdraw_eth() { .unwrap(); expected_event[2] = ethabi::LogParam { name: "dest".to_string(), - value: ethabi::Token::Address(DEST_ADDRESS), + value: ethabi::Token::Address(DEST_ADDRESS.raw()), }; expected_event[3] = ethabi::LogParam { name: "amount".to_string(), diff --git a/engine-tests/src/tests/eip1559.rs b/engine-tests/src/tests/eip1559.rs index 239c5b33b..84693ca02 100644 --- a/engine-tests/src/tests/eip1559.rs +++ b/engine-tests/src/tests/eip1559.rs @@ -1,10 +1,10 @@ +use crate::prelude::transactions::eip_1559::{self, SignedTransaction1559, Transaction1559}; +use crate::prelude::transactions::eip_2930::AccessTuple; +use crate::prelude::transactions::EthTransactionKind; use crate::prelude::Wei; use crate::prelude::{H256, U256}; use crate::test_utils; use aurora_engine::parameters::SubmitResult; -use aurora_engine::transaction::eip_1559::{self, SignedTransaction1559, Transaction1559}; -use aurora_engine::transaction::eip_2930::AccessTuple; -use aurora_engine::transaction::EthTransactionKind; use borsh::BorshDeserialize; use std::convert::TryFrom; use std::iter; @@ -132,7 +132,7 @@ fn example_transaction() -> Transaction1559 { value: Wei::zero(), data: vec![0], access_list: vec![AccessTuple { - address: test_utils::address_from_hex(CONTRACT_ADDRESS), + address: test_utils::address_from_hex(CONTRACT_ADDRESS).raw(), storage_keys: vec![H256::zero(), one()], }], } diff --git a/engine-tests/src/tests/erc20.rs b/engine-tests/src/tests/erc20.rs index 24ce19697..c91f54fd0 100644 --- a/engine-tests/src/tests/erc20.rs +++ b/engine-tests/src/tests/erc20.rs @@ -107,13 +107,13 @@ fn profile_erc20_get_balance() { runner.profiled_view_call(test_utils::as_view_call(balance_tx, source_address)); assert!(result.is_ok()); - // call costs less than 4 Tgas - test_utils::assert_gas_bound(profile.all_gas(), 4); + // call costs less than 3 Tgas + test_utils::assert_gas_bound(profile.all_gas(), 3); // at least 70% of the cost is spent on wasm computation (as opposed to host functions) let wasm_fraction = (100 * profile.wasm_gas()) / profile.all_gas(); assert!( - wasm_fraction >= 68, - "{}% is not greater than 68%", + 15 <= wasm_fraction && wasm_fraction <= 20, + "{}% is not between 15% and 20%", wasm_fraction ); } @@ -225,7 +225,7 @@ fn deploy_erc_20_out_of_gas() { assert!(error_message.contains("ERR_INTRINSIC_GAS")); // not enough gas to complete transaction - deploy_transaction.gas_limit = U256::from(3_200_000); + deploy_transaction.gas_limit = U256::from(intrinsic_gas + 1); let outcome = runner.submit_transaction(&source_account, deploy_transaction); let error = outcome.unwrap(); assert_eq!(error.status, TransactionStatus::OutOfGas); diff --git a/engine-tests/src/tests/erc20_connector.rs b/engine-tests/src/tests/erc20_connector.rs index df18be73e..68c642fc0 100644 --- a/engine-tests/src/tests/erc20_connector.rs +++ b/engine-tests/src/tests/erc20_connector.rs @@ -1,8 +1,8 @@ -use crate::prelude::{Address, Balance, RawAddress, TryInto, Wei, WeiU256, U256}; +use crate::prelude::{Address, Balance, Wei, WeiU256, U256}; use crate::test_utils; use crate::test_utils::{create_eth_transaction, origin, AuroraRunner}; use aurora_engine::parameters::{CallArgs, FunctionCallArgsV2, SubmitResult}; -use aurora_engine::transaction::legacy::LegacyEthSignedTransaction; +use aurora_engine_transactions::legacy::LegacyEthSignedTransaction; use borsh::{BorshDeserialize, BorshSerialize}; use ethabi::Token; use near_vm_logic::VMOutcome; @@ -61,7 +61,7 @@ fn create_ethereum_address() -> Address { pub struct EthereumAddress { pub secret_key: SecretKey, - pub address: RawAddress, + pub address: Address, } impl test_utils::AuroraRunner { @@ -91,7 +91,7 @@ impl test_utils::AuroraRunner { CallResult { outcome, error } } - pub fn evm_call(&mut self, contract: RawAddress, input: Vec, origin: String) -> CallResult { + pub fn evm_call(&mut self, contract: Address, input: Vec, origin: String) -> CallResult { self.make_call( "call", origin, @@ -109,15 +109,16 @@ impl test_utils::AuroraRunner { self.make_call("submit", origin, rlp::encode(&input).to_vec()) } - pub fn deploy_erc20_token(&mut self, nep141: &String) -> RawAddress { + pub fn deploy_erc20_token(&mut self, nep141: &String) -> Address { let result = self.make_call("deploy_erc20_token", origin(), nep141.try_to_vec().unwrap()); result.check_ok(); - Vec::::try_from_slice(result.value().as_slice()) + let raw_address: [u8; 20] = Vec::::try_from_slice(result.value().as_slice()) .unwrap() .try_into() - .unwrap() + .unwrap(); + Address::try_from_slice(&raw_address).unwrap() } pub fn create_account(&mut self) -> EthereumAddress { @@ -131,8 +132,8 @@ impl test_utils::AuroraRunner { } } - pub fn balance_of(&mut self, token: RawAddress, target: RawAddress, origin: String) -> U256 { - let input = build_input("balanceOf(address)", &[Token::Address(target.into())]); + pub fn balance_of(&mut self, token: Address, target: Address, origin: String) -> U256 { + let input = build_input("balanceOf(address)", &[Token::Address(target.raw())]); let result = self.evm_call(token, input, origin); result.check_ok(); let output = test_utils::unwrap_success(result.submit_result()); @@ -141,15 +142,15 @@ impl test_utils::AuroraRunner { pub fn mint( &mut self, - token: RawAddress, - target: RawAddress, + token: Address, + target: Address, amount: u64, origin: String, ) -> CallResult { let input = build_input( "mint(address,uint256)", &[ - Token::Address(target.into()), + Token::Address(target.raw()), Token::Uint(U256::from(amount).into()), ], ); @@ -159,7 +160,7 @@ impl test_utils::AuroraRunner { } #[allow(dead_code)] - pub fn admin(&mut self, token: RawAddress, origin: String) -> CallResult { + pub fn admin(&mut self, token: Address, origin: String) -> CallResult { let input = build_input("admin()", &[]); let result = self.evm_call(token, input, origin); result.check_ok(); @@ -168,9 +169,9 @@ impl test_utils::AuroraRunner { pub fn transfer_erc20( &mut self, - token: RawAddress, + token: Address, sender: SecretKey, - receiver: RawAddress, + receiver: Address, amount: u64, origin: String, ) -> CallResult { @@ -178,12 +179,14 @@ impl test_utils::AuroraRunner { let input = build_input( "transfer(address,uint256)", &[ - Token::Address(receiver.into()), + Token::Address(receiver.raw()), Token::Uint(U256::from(amount)), ], ); - let input = create_eth_transaction(Some(token.into()), Wei::zero(), input, None, &sender); + let chain_id = Some(self.chain_id); + let input = + create_eth_transaction(Some(token.into()), Wei::zero(), input, chain_id, &sender); let result = self.evm_submit(input, origin); // create_eth_transaction() result.check_ok(); @@ -222,7 +225,7 @@ impl test_utils::AuroraRunner { self.make_call( "register_relayer", relayer_account_id, - relayer_address.as_fixed_bytes().try_to_vec().unwrap(), + relayer_address.try_to_vec().unwrap(), ) } } @@ -267,18 +270,18 @@ fn test_ft_on_transfer() { let nep141 = "tt.testnet".to_string(); let alice = "alice".to_string(); let token = runner.deploy_erc20_token(&nep141); - let amount = 10; + let amount = Balance::new(10); let recipient = runner.create_account().address; let balance = runner.balance_of(token, recipient, origin()); assert_eq!(balance, U256::from(0)); - let res = runner.ft_on_transfer(nep141, alice.clone(), alice, amount, hex::encode(recipient)); + let res = runner.ft_on_transfer(nep141, alice.clone(), alice, amount, recipient.encode()); // Transaction should succeed so return amount is 0 assert_eq!(res, "\"0\""); let balance = runner.balance_of(token, recipient, origin()); - assert_eq!(balance, U256::from(amount)); + assert_eq!(balance, U256::from(amount.as_u128())); } #[test] @@ -286,11 +289,11 @@ fn test_ft_on_transfer_fail() { let mut runner = AuroraRunner::new(); let nep141 = "tt.testnet".to_string(); let alice = "alice".to_string(); - let amount = 10; + let amount = Balance::new(10); let recipient = runner.create_account().address; - let res = runner.ft_on_transfer(nep141, alice.clone(), alice, amount, hex::encode(recipient)); + let res = runner.ft_on_transfer(nep141, alice.clone(), alice, amount, recipient.encode()); // Transaction should fail so it must return everything assert_eq!(res, format!("\"{}\"", amount.to_string())); @@ -301,7 +304,7 @@ fn test_relayer_charge_fee() { let mut runner = AuroraRunner::new(); // Standalone runner presently does not support ft_on_transfer runner.standalone_runner = None; - let amount = 10; + let amount = Balance::new(10); let fee = 51; let nep141 = "tt.testnet".to_string(); let alice = "alice".to_string(); @@ -327,7 +330,7 @@ fn test_relayer_charge_fee() { alice.clone(), alice, amount, - hex::encode(recipient) + &hex::encode(fee_encoded), + recipient.encode() + &hex::encode(fee_encoded), ); let recipient_balance_end = runner.get_balance(recipient.into()); @@ -339,7 +342,7 @@ fn test_relayer_charge_fee() { assert_eq!(relayer_balance, Wei::new_u64(fee)); let balance = runner.balance_of(token, recipient, origin()); - assert_eq!(balance, U256::from(amount)); + assert_eq!(balance, U256::from(amount.as_u128())); } #[test] @@ -390,7 +393,7 @@ fn test_transfer_erc20_token() { // Note: `AuroraRunner` is not suitable for these tests because // it does not execute promises; but `near-sdk-sim` does. mod sim_tests { - use crate::prelude::{types::Wei, Address, WeiU256, U256}; + use crate::prelude::{Wei, WeiU256, U256}; use crate::test_utils; use crate::test_utils::erc20::{ERC20Constructor, ERC20}; use crate::test_utils::exit_precompile::TesterConstructor; @@ -398,6 +401,7 @@ mod sim_tests { use aurora_engine::parameters::{ CallArgs, DeployErc20TokenArgs, FunctionCallArgsV2, SubmitResult, }; + use aurora_engine_types::types::Address; use borsh::BorshSerialize; use near_sdk_sim::UserAccount; use serde_json::json; @@ -518,13 +522,13 @@ mod sim_tests { nep_141_balance_of( aurora.contract.account_id.as_str(), &aurora.contract, - &aurora + &aurora, ), - (INITIAL_ETH_BALANCE - ETH_EXIT_AMOUNT).into() + (INITIAL_ETH_BALANCE - ETH_EXIT_AMOUNT) as u128 ); assert_eq!( nep_141_balance_of(exit_account_id.as_str(), &aurora.contract, &aurora), - ETH_EXIT_AMOUNT.into() + ETH_EXIT_AMOUNT as u128 ); assert_eq!( eth_balance_of(signer_address, &aurora), @@ -603,7 +607,7 @@ mod sim_tests { aurora .call( "mint_account", - &(signer_address.0, signer.nonce, INITIAL_ETH_BALANCE) + &(signer_address, signer.nonce, INITIAL_ETH_BALANCE) .try_to_vec() .unwrap(), ) @@ -613,9 +617,9 @@ mod sim_tests { nep_141_balance_of( aurora.contract.account_id.as_str(), &aurora.contract, - &aurora + &aurora, ), - INITIAL_ETH_BALANCE.into() + INITIAL_ETH_BALANCE as u128 ); assert_eq!( eth_balance_of(signer_address, &aurora), @@ -626,7 +630,8 @@ mod sim_tests { let constructor = TesterConstructor::load(); let deploy_data = constructor.deploy(0, Address::zero()).data; let submit_result: SubmitResult = aurora.call("deploy_code", &deploy_data).unwrap_borsh(); - let tester_address = Address::from_slice(&test_utils::unwrap_success(submit_result)); + let tester_address = + Address::try_from_slice(&test_utils::unwrap_success(submit_result)).unwrap(); TestExitToNearEthContext { signer, @@ -651,7 +656,7 @@ mod sim_tests { aurora .call( "mint_account", - &(ft_owner_address.0, 0u64, INITIAL_ETH_BALANCE) + &(ft_owner_address, 0u64, INITIAL_ETH_BALANCE) .try_to_vec() .unwrap(), ) @@ -718,7 +723,7 @@ mod sim_tests { ], ); let call_args = CallArgs::V2(FunctionCallArgsV2 { - contract: erc20.0.address.0, + contract: erc20.0.address, value: WeiU256::default(), input, }); @@ -758,7 +763,7 @@ mod sim_tests { let mint_tx = erc20.mint(dest, amount.into(), 0.into()); let call_args = CallArgs::V2(FunctionCallArgsV2 { - contract: erc20.0.address.0, + contract: erc20.0.address, value: WeiU256::default(), input: mint_tx.data, }); @@ -789,7 +794,7 @@ mod sim_tests { fn erc20_balance(erc20: &ERC20, address: Address, aurora: &AuroraAccount) -> U256 { let balance_tx = erc20.balance_of(address, 0.into()); let call_args = CallArgs::V2(FunctionCallArgsV2 { - contract: erc20.0.address.0, + contract: erc20.0.address, value: WeiU256::default(), input: balance_tx.data, }); @@ -807,7 +812,7 @@ mod sim_tests { }; let result = aurora.call("deploy_erc20_token", &args.try_to_vec().unwrap()); let addr_bytes: Vec = result.unwrap_borsh(); - let address = Address::from_slice(&addr_bytes); + let address = Address::try_from_slice(&addr_bytes).unwrap(); let abi = ERC20Constructor::load().0.abi; ERC20(crate::test_utils::solidity::DeployedContract { abi, address }) } diff --git a/engine-tests/src/tests/eth_connector.rs b/engine-tests/src/tests/eth_connector.rs index 7f1de673c..3882dd12b 100644 --- a/engine-tests/src/tests/eth_connector.rs +++ b/engine-tests/src/tests/eth_connector.rs @@ -1,4 +1,4 @@ -use crate::prelude::EthAddress; +use crate::prelude::Address; use crate::prelude::WithdrawCallArgs; use crate::test_utils::str_to_account_id; use aurora_engine::admin_controlled::{PausedMask, ERR_PAUSED}; @@ -9,7 +9,7 @@ use aurora_engine::fungible_token::FungibleTokenMetadata; use aurora_engine::parameters::{ InitCallArgs, NewCallArgs, RegisterRelayerCallArgs, WithdrawResult, }; -use aurora_engine_types::types::Fee; +use aurora_engine_types::types::{Fee, NEP141Wei}; use borsh::{BorshDeserialize, BorshSerialize}; use byte_slice_cast::AsByteSlice; use ethabi::ethereum_types::U256; @@ -98,12 +98,8 @@ fn init_contract( contract_account } -fn validate_eth_address(address: &str) -> EthAddress { - let data = hex::decode(address).unwrap(); - assert_eq!(data.len(), 20); - let mut result = [0u8; 20]; - result.copy_from_slice(&data); - result +fn validate_eth_address(address: &str) -> Address { + Address::decode(address).unwrap() } fn call_deposit_eth_to_near( @@ -192,10 +188,10 @@ fn get_eth_on_near_balance(master_account: &UserAccount, acc: &str, contract: &s val.parse().unwrap() } -fn get_eth_balance(master_account: &UserAccount, address: EthAddress, contract: &str) -> u128 { +fn get_eth_balance(master_account: &UserAccount, address: Address, contract: &str) -> u128 { #[derive(BorshSerialize, BorshDeserialize)] pub struct BalanceOfEthCallArgs { - pub address: EthAddress, + pub address: Address, } let balance = master_account.view( @@ -306,7 +302,7 @@ fn test_withdraw_eth_from_near() { let (master_account, contract) = init(CUSTODIAN_ADDRESS); call_deposit_eth_to_near(&contract, CONTRACT_ACC); - let withdraw_amount = 100; + let withdraw_amount = NEP141Wei::new(100); let recipient_addr = validate_eth_address(RECIPIENT_ETH_ADDRESS); let res = contract.call( CONTRACT_ACC.parse().unwrap(), @@ -336,13 +332,13 @@ fn test_withdraw_eth_from_near() { } let balance = get_eth_on_near_balance(&master_account, CONTRACT_ACC, CONTRACT_ACC); - assert_eq!(balance, DEPOSITED_FEE - withdraw_amount as u128); + assert_eq!(balance, DEPOSITED_FEE - withdraw_amount.as_u128()); let balance = get_eth_on_near_balance(&master_account, DEPOSITED_RECIPIENT, CONTRACT_ACC); assert_eq!(balance, DEPOSITED_AMOUNT - DEPOSITED_FEE); let balance = total_supply(&master_account, CONTRACT_ACC); - assert_eq!(balance, DEPOSITED_AMOUNT - withdraw_amount as u128); + assert_eq!(balance, DEPOSITED_AMOUNT - withdraw_amount.as_u128()); } #[test] @@ -412,7 +408,11 @@ fn test_ft_transfer_call_eth() { let transfer_amount = 50; let fee: u128 = 30; let mut msg = U256::from(fee).as_byte_slice().to_vec(); - msg.append(&mut validate_eth_address(RECIPIENT_ETH_ADDRESS).to_vec()); + msg.append( + &mut validate_eth_address(RECIPIENT_ETH_ADDRESS) + .as_bytes() + .to_vec(), + ); let message = [CONTRACT_ACC, hex::encode(msg).as_str()].join(":"); let res = contract.call( @@ -597,28 +597,23 @@ fn test_deposit_with_0x_prefix() { use aurora_engine::deposit_event::TokenMessageData; let (master_account, contract) = init(CUSTODIAN_ADDRESS); - let eth_custodian_address: [u8; 20] = { - let mut buf = [0u8; 20]; - let bytes = hex::decode(CUSTODIAN_ADDRESS).unwrap(); - buf.copy_from_slice(&bytes); - buf - }; - let recipient_address = [10u8; 20]; + let eth_custodian_address: Address = Address::decode(&CUSTODIAN_ADDRESS.to_string()).unwrap(); + let recipient_address = Address::from_array([10u8; 20]); let deposit_amount = 17; - let recipient_address_encoded = hex::encode(&recipient_address); + let recipient_address_encoded = recipient_address.encode(); // Note the 0x prefix before the deposit address. let message = [CONTRACT_ACC, ":", "0x", &recipient_address_encoded].concat(); - let fee: Fee = 0.into(); + let fee: Fee = Fee::new(NEP141Wei::new(0)); let token_message_data = TokenMessageData::parse_event_message_and_prepare_token_message_data(&message, fee) .unwrap(); let deposit_event = aurora_engine::deposit_event::DepositedEvent { eth_custodian_address, - sender: [0u8; 20], + sender: Address::zero(), token_message_data, - amount: deposit_amount, + amount: NEP141Wei::new(deposit_amount), fee, }; @@ -628,7 +623,7 @@ fn test_deposit_with_0x_prefix() { anonymous: false, }; let log_entry = aurora_engine::log_entry::LogEntry { - address: eth_custodian_address.into(), + address: eth_custodian_address.raw(), topics: vec![ event_schema.signature(), // the sender is not important @@ -636,8 +631,8 @@ fn test_deposit_with_0x_prefix() { ], data: ethabi::encode(&[ ethabi::Token::String(message), - ethabi::Token::Uint(U256::from(deposit_event.amount)), - ethabi::Token::Uint(U256::from(deposit_event.fee.into_u128())), + ethabi::Token::Uint(U256::from(deposit_event.amount.as_u128())), + ethabi::Token::Uint(U256::from(deposit_event.fee.as_u128())), ]), }; let proof = Proof { @@ -718,7 +713,11 @@ fn test_ft_transfer_call_without_relayer() { let transfer_amount = 50; let fee: u128 = 30; let mut msg = U256::from(fee).as_byte_slice().to_vec(); - msg.append(&mut validate_eth_address(RECIPIENT_ETH_ADDRESS).to_vec()); + msg.append( + &mut validate_eth_address(RECIPIENT_ETH_ADDRESS) + .as_bytes() + .to_vec(), + ); let relayer_id = "relayer.root"; let message = [relayer_id, hex::encode(msg).as_str()].join(":"); let res = contract.call( @@ -774,7 +773,11 @@ fn test_ft_transfer_call_fee_greater_than_amount() { let transfer_amount = 10; let fee: u128 = transfer_amount + 10; let mut msg = fee.to_be_bytes().to_vec(); - msg.append(&mut validate_eth_address(RECIPIENT_ETH_ADDRESS).to_vec()); + msg.append( + &mut validate_eth_address(RECIPIENT_ETH_ADDRESS) + .as_bytes() + .to_vec(), + ); let relayer_id = "relayer.root"; let message = [relayer_id, hex::encode(msg).as_str()].join(":"); let res = contract.call( @@ -895,7 +898,7 @@ fn test_admin_controlled_admin_can_peform_actions_when_paused() { p.assert_success() } - let withdraw_amount = 100; + let withdraw_amount = NEP141Wei::new(100); let recipient_addr = validate_eth_address(RECIPIENT_ETH_ADDRESS); // 1st withdraw call when unpaused - should succeed @@ -1008,7 +1011,7 @@ fn test_withdraw_from_near_pausability() { call_deposit_eth_to_near(&contract, CONTRACT_ACC); - let withdraw_amount = 100; + let withdraw_amount = NEP141Wei::new(100); let recipient_addr = validate_eth_address(RECIPIENT_ETH_ADDRESS); // 1st withdraw - should succeed let res = user_account.call( diff --git a/engine-tests/src/tests/meta_parsing.rs b/engine-tests/src/tests/meta_parsing.rs index 5648cc771..2c6689018 100644 --- a/engine-tests/src/tests/meta_parsing.rs +++ b/engine-tests/src/tests/meta_parsing.rs @@ -47,8 +47,8 @@ fn encode_meta_call_function_args( v: 27, nonce: u256_to_arr(&nonce), fee_amount: fee_amount.to_bytes(), - fee_address: fee_address.0, - contract_address: contract_address.0, + fee_address, + contract_address, value: value.to_bytes(), method_def: method_def.to_string(), args, @@ -65,9 +65,7 @@ fn public_key_to_address(public_key: PublicKey) -> Address { PublicKey::SECP256K1(pubkey) => { let pk: [u8; 64] = pubkey.into(); let bytes = keccak(&pk.to_vec()); - let mut result = Address::zero(); - result.as_bytes_mut().copy_from_slice(&bytes[12..]); - result + Address::try_from_slice(&bytes[12..]).unwrap() } } } @@ -84,7 +82,7 @@ fn test_meta_parsing() { chain_id, U256::from(14), Wei::new_u64(6), - Address::from_slice(&[0u8; 20]), + Address::try_from_slice(&[0u8; 20]).unwrap(), signer_addr.clone(), Wei::zero(), "adopt(uint256 petId)", @@ -104,7 +102,7 @@ fn test_meta_parsing() { chain_id, U256::from(14), Wei::new_u64(6), - Address::from_slice(&[0u8; 20]), + Address::try_from_slice(&[0u8; 20]).unwrap(), signer_addr.clone(), Wei::zero(), "adopt(uint256 petId,PetObj petObject)PetObj(string petName,address owner)", diff --git a/engine-tests/src/tests/one_inch.rs b/engine-tests/src/tests/one_inch.rs index fac18a3a3..65c605c37 100644 --- a/engine-tests/src/tests/one_inch.rs +++ b/engine-tests/src/tests/one_inch.rs @@ -23,11 +23,11 @@ fn test_1inch_liquidity_protocol() { let (result, profile, deployer_address) = helper.create_mooniswap_deployer(); assert!(result.gas_used >= 5_100_000); // more than 5.1M EVM gas used - assert_gas_bound(profile.all_gas(), 28); // less than 28 NEAR Tgas used + assert_gas_bound(profile.all_gas(), 12); // less than 12 NEAR Tgas used let (result, profile, pool_factory) = helper.create_pool_factory(&deployer_address); assert!(result.gas_used >= 2_800_000); // more than 2.8M EVM gas used - assert_gas_bound(profile.all_gas(), 22); // less than 22 NEAR Tgas used + assert_gas_bound(profile.all_gas(), 12); // less than 12 NEAR Tgas used // create some ERC-20 tokens to have a liquidity pool for let signer_address = test_utils::address_from_secret_key(&helper.signer.secret_key); @@ -39,7 +39,7 @@ fn test_1inch_liquidity_protocol() { let (result, profile, pool) = helper.create_pool(&pool_factory, token_a.0.address, token_b.0.address); assert!(result.gas_used >= 4_500_000); // more than 4.5M EVM gas used - assert_gas_bound(profile.all_gas(), 67); // less than 67 NEAR Tgas used + assert_gas_bound(profile.all_gas(), 34); // less than 34 NEAR Tgas used // Approve giving ERC-20 tokens to the pool helper.approve_erc20_tokens(&token_a, pool.address()); @@ -58,7 +58,7 @@ fn test_1inch_liquidity_protocol() { }, ); assert!(result.gas_used >= 302_000); // more than 302k EVM gas used - assert_gas_bound(profile.all_gas(), 82); // less than 82 NEAR Tgas used + assert_gas_bound(profile.all_gas(), 45); // less than 45 NEAR Tgas used // Same here helper.runner.context.block_timestamp += 10_000_000 * 1_000_000_000; @@ -73,7 +73,7 @@ fn test_1inch_liquidity_protocol() { }, ); assert!(result.gas_used >= 210_000); // more than 210k EVM gas used - assert_gas_bound(profile.all_gas(), 90); // less than 90 NEAR Tgas used + assert_gas_bound(profile.all_gas(), 48); // less than 48 NEAR Tgas used let (result, profile) = helper.pool_withdraw( &pool, @@ -84,7 +84,7 @@ fn test_1inch_liquidity_protocol() { }, ); assert!(result.gas_used >= 150_000); // more than 150k EVM gas used - assert_gas_bound(profile.all_gas(), 69); // less than 69 NEAR Tgas used + assert_gas_bound(profile.all_gas(), 39); // less than 39 NEAR Tgas used } #[test] @@ -100,13 +100,13 @@ fn test_1_inch_limit_order_deploy() { // more than 3.5 million Ethereum gas used assert!(result.gas_used > 3_500_000); - // less than 27 NEAR Tgas used - assert_gas_bound(profile.all_gas(), 28); - // at least 70% of which is from wasm execution + // less than 12 NEAR Tgas used + assert_gas_bound(profile.all_gas(), 12); + // at least 45% of which is from wasm execution let wasm_fraction = 100 * profile.wasm_gas() / profile.all_gas(); assert!( - wasm_fraction > 65, - "{}% is not greater than 65%", + 40 <= wasm_fraction && wasm_fraction <= 50, + "{}% is not between 40% and 50%", wasm_fraction ); } @@ -125,7 +125,7 @@ fn deploy_1_inch_limit_order_contract( test_utils::solidity::ContractConstructor::compile_from_extended_json(contract_path); let nonce = signer.use_nonce(); - let deploy_tx = crate::prelude::transaction::legacy::TransactionLegacy { + let deploy_tx = crate::prelude::transactions::legacy::TransactionLegacy { nonce: nonce.into(), gas_price: Default::default(), gas_limit: u64::MAX.into(), diff --git a/engine-tests/src/tests/res/bench.sol b/engine-tests/src/tests/res/bench.sol new file mode 100644 index 000000000..1eeae7caa --- /dev/null +++ b/engine-tests/src/tests/res/bench.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract Bencher { + function cpu_ram_soak_test(uint32 loop_limit) public pure { + uint8[102400] memory buf; + uint32 len = 102400; + for (uint32 i=0; i < loop_limit; i++) { + uint32 j = (i * 7 + len / 2) % len; + uint32 k = (i * 3) % len; + uint8 tmp = buf[k]; + buf[k] = buf[j]; + buf[j] = tmp; + } + } +} diff --git a/engine-tests/src/tests/res/reverter.sol b/engine-tests/src/tests/res/reverter.sol new file mode 100644 index 000000000..f2957d7ed --- /dev/null +++ b/engine-tests/src/tests/res/reverter.sol @@ -0,0 +1,9 @@ +pragma solidity ^0.8.0; + +contract ReverterByDefault { + uint256 y = 0; + constructor(uint256 x) public { + require (x < y, "Revert message"); + y = x; + } +} diff --git a/engine-tests/src/tests/sanity.rs b/engine-tests/src/tests/sanity.rs index cd9435ca4..7098768df 100644 --- a/engine-tests/src/tests/sanity.rs +++ b/engine-tests/src/tests/sanity.rs @@ -5,7 +5,7 @@ use crate::tests::state_migration; use aurora_engine::fungible_token::FungibleTokenMetadata; use aurora_engine::parameters::{SubmitResult, TransactionStatus}; use aurora_engine_sdk as sdk; -use borsh::{BorshDeserialize, BorshSerialize}; +use borsh::BorshSerialize; use rand::RngCore; use secp256k1::SecretKey; use std::path::{Path, PathBuf}; @@ -57,7 +57,7 @@ fn test_deploy_contract() { test_utils::create_deploy_transaction(code.clone(), nonce) }) .unwrap(); - let address = Address::from_slice(test_utils::unwrap_success_slice(&result)); + let address = Address::try_from_slice(test_utils::unwrap_success_slice(&result)).unwrap(); // Confirm the code stored at that address is equal to the input code. let stored_code = runner.get_code(address); @@ -92,8 +92,8 @@ fn test_deploy_largest_contract() { result.gas_used, ); - // Less than 28 NEAR Tgas - test_utils::assert_gas_bound(profile.all_gas(), 28); + // Less than 12 NEAR Tgas + test_utils::assert_gas_bound(profile.all_gas(), 12); } #[test] @@ -123,7 +123,7 @@ fn test_log_address() { .submit_with_signer(&mut signer, |nonce| { caller_contract.call_method_with_args( "greet", - &[ethabi::Token::Address(greet_contract.address)], + &[ethabi::Token::Address(greet_contract.address.raw())], nonce, ) }) @@ -132,7 +132,80 @@ fn test_log_address() { // Address included in the log should come from the contract emitting the log, // not the contract that invoked the call. let log_address = result.logs.first().unwrap().address; - assert_eq!(Address(log_address), greet_contract.address); + assert_eq!(log_address, greet_contract.address); +} + +#[test] +fn test_solidity_pure_bench() { + let (mut runner, mut signer, _) = initialize_transfer(); + runner.wasm_config.limit_config.max_gas_burnt = u64::MAX; + + let constructor = test_utils::solidity::ContractConstructor::force_compile( + "src/tests/res", + "target/solidity_build", + "bench.sol", + "Bencher", + ); + + let nonce = signer.use_nonce(); + let contract = runner.deploy_contract( + &signer.secret_key, + |c| c.deploy_without_constructor(nonce.into()), + constructor, + ); + + // Number of iterations to do + let loop_limit = 10_000; + let (result, profile) = runner + .submit_with_signer_profiled(&mut signer, |nonce| { + contract.call_method_with_args( + "cpu_ram_soak_test", + &[ethabi::Token::Uint(loop_limit.into())], + nonce, + ) + }) + .unwrap(); + + assert!( + result.gas_used > 38_000_000, + "Over 38 million EVM gas is used" + ); + assert!( + profile.all_gas() > 2200 * 1_000_000_000_000, + "Over 2200 NEAR Tgas is used" + ); +} + +#[test] +fn test_revert_during_contract_deploy() { + let (mut runner, mut signer, _) = initialize_transfer(); + + let constructor = test_utils::solidity::ContractConstructor::compile_from_source( + "src/tests/res", + "target/solidity_build", + "reverter.sol", + "ReverterByDefault", + ); + + let nonce = signer.use_nonce(); + let deploy_tx = + constructor.deploy_with_args(nonce.into(), &[ethabi::Token::Uint(U256::zero())]); + let submit_result = runner + .submit_transaction(&signer.secret_key, deploy_tx) + .unwrap(); + + let revert_bytes = crate::test_utils::unwrap_revert(submit_result); + // First 4 bytes is a function selector with signature `Error(string)` + assert_eq!(&revert_bytes[0..4], &[8, 195, 121, 160]); + // Remaining data is an ABI-encoded string + let revert_message = ethabi::decode(&[ethabi::ParamType::String], &revert_bytes[4..]) + .unwrap() + .pop() + .unwrap() + .into_string() + .unwrap(); + + assert_eq!(revert_message.as_str(), "Revert message"); } #[test] @@ -194,7 +267,7 @@ fn test_override_state() { // deploy contract let result = runner .submit_with_signer(&mut account1, |nonce| { - crate::prelude::transaction::legacy::TransactionLegacy { + crate::prelude::transactions::legacy::TransactionLegacy { nonce, gas_price: Default::default(), gas_limit: u64::MAX.into(), @@ -204,7 +277,7 @@ fn test_override_state() { } }) .unwrap(); - let address = Address::from_slice(&test_utils::unwrap_success(result)); + let address = Address::try_from_slice(&test_utils::unwrap_success(result)).unwrap(); let contract = contract.deployed_at(address); // define functions to interact with the contract @@ -217,7 +290,7 @@ fn test_override_state() { .unwrap(); match result { crate::prelude::parameters::TransactionStatus::Succeed(bytes) => { - Address::from_slice(&bytes[12..32]) + Address::try_from_slice(&bytes[12..32]).unwrap() } _ => panic!("tx failed"), } @@ -237,7 +310,7 @@ fn test_override_state() { }; // Assert the initial state is 0 - assert_eq!(get_address(&runner), Address([0; 20])); + assert_eq!(get_address(&runner), Address::new(H160([0; 20]))); post_address(&mut runner, &mut account1); // Assert the address matches the first caller assert_eq!(get_address(&runner), account1_address); @@ -251,9 +324,10 @@ fn test_num_wasm_functions() { // Counts the number of functions in our wasm output. // See https://github.com/near/nearcore/issues/4814 for context let runner = test_utils::deploy_evm(); - let artifact = get_compiled_artifact(&runner); - let module_info = artifact.info(); - let num_functions = module_info.functions.len(); + let module = walrus::ModuleConfig::default() + .parse(runner.code.code()) + .unwrap(); + let num_functions = module.funcs.iter().count(); assert!( num_functions <= 1440, "{} is not less than 1440", @@ -517,6 +591,7 @@ fn initialize_transfer() -> (test_utils::AuroraRunner, test_utils::Signer, Addre (runner, signer, dest_address) } +use aurora_engine_types::H160; use sha3::Digest; #[test] @@ -621,7 +696,7 @@ fn test_eth_transfer_insufficient_balance_sim() { // Run transaction which will fail (transfer more than current balance) let nonce = signer.use_nonce(); let tx = test_utils::transfer( - Address([1; 20]), + Address::new(H160([1; 20])), INITIAL_BALANCE + INITIAL_BALANCE, nonce.into(), ); @@ -652,7 +727,7 @@ fn test_eth_transfer_charging_gas_not_enough_balance_sim() { // Run transaction which will fail (not enough balance to cover gas) let nonce = signer.use_nonce(); - let mut tx = test_utils::transfer(Address([1; 20]), TRANSFER_AMOUNT, nonce.into()); + let mut tx = test_utils::transfer(Address::new(H160([1; 20])), TRANSFER_AMOUNT, nonce.into()); tx.gas_limit = 3_000_000.into(); tx.gas_price = GAS_PRICE.into(); let signed_tx = test_utils::sign_transaction( @@ -680,7 +755,7 @@ fn initialize_evm_sim() -> (state_migration::AuroraAccount, test_utils::Signer, let signer = test_utils::Signer::random(); let address = test_utils::address_from_secret_key(&signer.secret_key); - let args = (address.0, INITIAL_NONCE, INITIAL_BALANCE.raw().low_u64()); + let args = (address, INITIAL_NONCE, INITIAL_BALANCE.raw().low_u64()); aurora .call("mint_account", &args.try_to_vec().unwrap()) .assert_success(); @@ -703,31 +778,9 @@ fn query_address_sim( method: &str, aurora: &state_migration::AuroraAccount, ) -> U256 { - let x = aurora.call(method, &address.0); + let x = aurora.call(method, address.as_bytes()); match &x.outcome().status { near_sdk_sim::transaction::ExecutionStatus::SuccessValue(b) => U256::from_big_endian(&b), other => panic!("Unexpected outcome: {:?}", other), } } - -fn get_compiled_artifact(runner: &test_utils::AuroraRunner) -> wasmer::Module { - use near_primitives::types::CompiledContractCache; - - let current_protocol_version = u32::MAX; - let vm_kind = near_vm_runner::VMKind::for_protocol_version(current_protocol_version); - near_vm_runner::precompile_contract( - &runner.code, - &runner.wasm_config, - current_protocol_version, - Some(&runner.cache), - ) - .unwrap() - .unwrap(); - let cache_key = - near_vm_runner::get_contract_cache_key(&runner.code, vm_kind, &runner.wasm_config); - let cache_record = - Vec::try_from_slice(&runner.cache.get(cache_key.as_ref()).unwrap().unwrap()[1..]).unwrap(); - let store = wasmer::Store::new(&wasmer::Universal::new(wasmer::Singlepass::new()).engine()); - - unsafe { wasmer::Module::deserialize(&store, &cache_record).unwrap() } -} diff --git a/engine-tests/src/tests/standalone/json_snapshot.rs b/engine-tests/src/tests/standalone/json_snapshot.rs index 45e191089..0325cd799 100644 --- a/engine-tests/src/tests/standalone/json_snapshot.rs +++ b/engine-tests/src/tests/standalone/json_snapshot.rs @@ -1,5 +1,6 @@ use crate::test_utils::standalone; -use aurora_engine_types::{Address, U256}; +use aurora_engine_types::types::Address; +use aurora_engine_types::{H160, U256}; use engine_standalone_storage::json_snapshot; const NONCE_PREFIX: [u8; 2] = [0x07, 0x01]; @@ -40,5 +41,5 @@ fn test_consume_snapshot() { fn address_from_key(key: &[u8]) -> Address { let mut result = [0u8; 20]; result.copy_from_slice(&key[2..22]); - Address(result) + Address::new(H160(result)) } diff --git a/engine-tests/src/tests/standalone/sanity.rs b/engine-tests/src/tests/standalone/sanity.rs index b043e6607..f537951d5 100644 --- a/engine-tests/src/tests/standalone/sanity.rs +++ b/engine-tests/src/tests/standalone/sanity.rs @@ -1,8 +1,8 @@ use crate::test_utils::standalone::mocks::{promise, storage}; use aurora_engine::engine; use aurora_engine_sdk::env::DEFAULT_PREPAID_GAS; -use aurora_engine_types::types::Wei; -use aurora_engine_types::{account_id::AccountId, Address, H256, U256}; +use aurora_engine_types::types::{Address, Wei}; +use aurora_engine_types::{account_id::AccountId, H160, H256, U256}; use std::sync::RwLock; #[test] @@ -20,7 +20,7 @@ fn test_deploy_code() { bridge_prover_id: "mr_the_prover".parse().unwrap(), upgrade_delay_blocks: 0, }; - let origin = Address([0u8; 20]); + let origin = Address::new(H160([0u8; 20])); let storage = RwLock::new(storage::Storage::default()); let io = storage::StoragePointer(&storage); let env = aurora_engine_sdk::env::Fixed { @@ -50,7 +50,9 @@ fn test_deploy_code() { // execution was successful let contract_address = match result.unwrap().status { - aurora_engine::parameters::TransactionStatus::Succeed(bytes) => Address::from_slice(&bytes), + aurora_engine::parameters::TransactionStatus::Succeed(bytes) => { + Address::try_from_slice(&bytes).unwrap() + } other => panic!("Unexpected status: {:?}", other), }; diff --git a/engine-tests/src/tests/standalone/storage.rs b/engine-tests/src/tests/standalone/storage.rs index 5fd0606d4..7c963591f 100644 --- a/engine-tests/src/tests/standalone/storage.rs +++ b/engine-tests/src/tests/standalone/storage.rs @@ -1,6 +1,7 @@ use aurora_engine::engine; use aurora_engine_sdk::env::Timestamp; -use aurora_engine_types::{types::Wei, Address, H256, U256}; +use aurora_engine_types::types::{Address, Wei}; +use aurora_engine_types::{H256, U256}; use engine_standalone_storage::BlockMetadata; use crate::test_utils::standalone::{mocks, storage::create_db}; @@ -236,9 +237,7 @@ fn test_transaction_index() { aurora_engine_types::storage::KeyPrefix::Balance, &[1u8; 20], ); - let value = aurora_engine_types::types::Wei::new_u64(159) - .to_bytes() - .to_vec(); + let value = crate::prelude::Wei::new_u64(159).to_bytes().to_vec(); tmp.modify(key, value); tmp }; diff --git a/engine-tests/src/tests/standalone/sync.rs b/engine-tests/src/tests/standalone/sync.rs index 00c6de10f..6ac01594d 100644 --- a/engine-tests/src/tests/standalone/sync.rs +++ b/engine-tests/src/tests/standalone/sync.rs @@ -1,7 +1,7 @@ use aurora_engine::deposit_event::TokenMessageData; use aurora_engine_sdk::env::{Env, Timestamp}; -use aurora_engine_types::types::Fee; -use aurora_engine_types::{account_id::AccountId, types::Wei, Address, H256, U256}; +use aurora_engine_types::types::{Address, Balance, Fee, NEP141Wei, Wei}; +use aurora_engine_types::{account_id::AccountId, H160, H256, U256}; use borsh::BorshSerialize; use engine_standalone_storage::sync; @@ -40,7 +40,7 @@ fn test_consume_block_message() { fn test_consume_deposit_message() { let (mut runner, block_message) = initialize(); - let recipient_address = Address([22u8; 20]); + let recipient_address = Address::new(H160([22u8; 20])); let deposit_amount = Wei::new_u64(123_456_789); let proof = mock_proof(recipient_address, deposit_amount); @@ -97,11 +97,11 @@ fn test_consume_deploy_message() { position: 0, }) .unwrap(); - let mut deployed_address = Address([0u8; 20]); + let mut deployed_address = Address::zero(); for (key, value) in diff.iter() { match value.value() { Some(bytes) if bytes == code.as_slice() => { - deployed_address.0.copy_from_slice(&key[2..22]); + deployed_address = Address::try_from_slice(&key[2..22]).unwrap(); break; } _ => continue, @@ -119,7 +119,7 @@ fn test_consume_deploy_erc20_message() { let token: AccountId = "some_nep141.near".parse().unwrap(); let mint_amount: u128 = 555_555; - let dest_address = Address([170u8; 20]); + let dest_address = Address::new(H160([170u8; 20])); let args = aurora_engine::parameters::DeployErc20TokenArgs { nep141: token.clone(), @@ -155,7 +155,7 @@ fn test_consume_deploy_erc20_message() { let args = aurora_engine::parameters::NEP141FtOnTransferArgs { sender_id: "mr_money_bags.near".parse().unwrap(), - amount: mint_amount, + amount: Balance::new(mint_amount), msg: hex::encode(dest_address.as_bytes()), }; let transaction_message = sync::types::TransactionMessage { @@ -180,7 +180,7 @@ fn test_consume_deploy_erc20_message() { let deployed_token = test_utils::erc20::ERC20( test_utils::erc20::ERC20Constructor::load() .0 - .deployed_at(Address::from_slice(&erc20_address)), + .deployed_at(Address::try_from_slice(&erc20_address).unwrap()), ); let signer = test_utils::Signer::random(); let tx = deployed_token.balance_of(dest_address, signer.nonce.into()); @@ -200,12 +200,12 @@ fn test_consume_ft_on_transfer_message() { let mint_amount = 8_675_309; let fee = Wei::zero(); - let dest_address = Address([221u8; 20]); + let dest_address = Address::new(H160([221u8; 20])); // Mint ETH on Aurora per the bridge workflow let args = aurora_engine::parameters::NEP141FtOnTransferArgs { sender_id: "mr_money_bags.near".parse().unwrap(), - amount: mint_amount, + amount: Balance::new(mint_amount), msg: [ "relayer.near", ":", @@ -245,7 +245,7 @@ fn test_consume_call_message() { let initial_balance = Wei::new_u64(800_000); let transfer_amount = Wei::new_u64(115_321); let caller_address = aurora_engine_sdk::types::near_account_to_evm_address(caller.as_bytes()); - let recipient_address = Address([1u8; 20]); + let recipient_address = Address::new(H160([1u8; 20])); runner.mint_account(caller_address, initial_balance, U256::zero(), None); runner.env.block_height += 1; @@ -290,7 +290,7 @@ fn test_consume_submit_message() { let initial_balance = Wei::new_u64(800_000); let transfer_amount = Wei::new_u64(115_321); let signer_address = test_utils::address_from_secret_key(&signer.secret_key); - let recipient_address = Address([1u8; 20]); + let recipient_address = Address::new(H160([1u8; 20])); runner.mint_account(signer_address, initial_balance, signer.nonce.into(), None); runner.env.block_height += 1; @@ -304,7 +304,7 @@ fn test_consume_submit_message() { let signed_transaction = test_utils::sign_transaction(transaction, Some(runner.chain_id), &signer.secret_key); let eth_transaction = - aurora_engine::transaction::EthTransactionKind::Legacy(signed_transaction); + crate::prelude::transactions::EthTransactionKind::Legacy(signed_transaction); let transaction_message = sync::types::TransactionMessage { block_hash, @@ -334,17 +334,17 @@ fn test_consume_submit_message() { fn mock_proof(recipient_address: Address, deposit_amount: Wei) -> aurora_engine::proof::Proof { let eth_custodian_address = test_utils::standalone::mocks::ETH_CUSTODIAN_ADDRESS; - let fee = Fee::new(0); - let message = ["aurora", ":", hex::encode(&recipient_address).as_str()].concat(); + let fee = Fee::new(NEP141Wei::new(0)); + let message = ["aurora", ":", recipient_address.encode().as_str()].concat(); let token_message_data: TokenMessageData = TokenMessageData::parse_event_message_and_prepare_token_message_data(&message, fee) .unwrap(); let deposit_event = aurora_engine::deposit_event::DepositedEvent { - eth_custodian_address: eth_custodian_address.0, - sender: [0u8; 20], + eth_custodian_address, + sender: Address::new(H160([0u8; 20])), token_message_data, - amount: deposit_amount.raw().as_u128(), + amount: NEP141Wei::new(deposit_amount.raw().as_u128()), fee, }; @@ -354,7 +354,7 @@ fn mock_proof(recipient_address: Address, deposit_amount: Wei) -> aurora_engine: anonymous: false, }; let log_entry = aurora_engine::log_entry::LogEntry { - address: eth_custodian_address, + address: eth_custodian_address.raw(), topics: vec![ event_schema.signature(), // the sender is not important @@ -362,8 +362,8 @@ fn mock_proof(recipient_address: Address, deposit_amount: Wei) -> aurora_engine: ], data: ethabi::encode(&[ ethabi::Token::String(message), - ethabi::Token::Uint(U256::from(deposit_event.amount)), - ethabi::Token::Uint(U256::from(deposit_event.fee.into_u128())), + ethabi::Token::Uint(U256::from(deposit_event.amount.as_u128())), + ethabi::Token::Uint(U256::from(deposit_event.fee.as_u128())), ]), }; aurora_engine::proof::Proof { @@ -382,7 +382,7 @@ fn simple_transfer_args( transfer_amount: Wei, ) -> aurora_engine::parameters::CallArgs { aurora_engine::parameters::CallArgs::V2(aurora_engine::parameters::FunctionCallArgsV2 { - contract: dest_address.0, + contract: dest_address, value: transfer_amount.to_bytes(), input: Vec::new(), }) diff --git a/engine-tests/src/tests/standalone/tracing.rs b/engine-tests/src/tests/standalone/tracing.rs index f6da0e8ee..641a89f34 100644 --- a/engine-tests/src/tests/standalone/tracing.rs +++ b/engine-tests/src/tests/standalone/tracing.rs @@ -1,5 +1,6 @@ use aurora_engine_sdk::env::Env; -use aurora_engine_types::{types::Wei, Address, H256, U256}; +use aurora_engine_types::types::{Address, Wei}; +use aurora_engine_types::{H256, U256}; use engine_standalone_tracing::{sputnik, types::TransactionTrace}; use serde::Deserialize; use std::path::Path; @@ -20,9 +21,9 @@ fn test_evm_tracing_with_storage() { let mut signer = test_utils::Signer::random(); let signer_address = test_utils::address_from_secret_key(&signer.secret_key); let sender_address = - Address::from_slice(&hex::decode("304ee8ae14eceb3a544dff53a27eb1bb1aaa471f").unwrap()); + Address::decode(&"304ee8ae14eceb3a544dff53a27eb1bb1aaa471f".to_string()).unwrap(); let weth_address = - Address::from_slice(&hex::decode("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2").unwrap()); + Address::decode(&"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2".to_string()).unwrap(); // Initialize EVM runner.init_evm_with_chain_id(1); @@ -34,7 +35,8 @@ fn test_evm_tracing_with_storage() { let result = runner .submit_transaction(&signer.secret_key, deploy_tx) .unwrap(); - let contract_address = Address::from_slice(test_utils::unwrap_success_slice(&result)); + let contract_address = + Address::try_from_slice(test_utils::unwrap_success_slice(&result)).unwrap(); // Move it over to the same address as it exists on mainnet let mut diff = engine_standalone_storage::Diff::default(); @@ -128,7 +130,7 @@ fn test_evm_tracing() { runner.init_evm(); // Deploy contract - let deploy_tx = aurora_engine::transaction::legacy::TransactionLegacy { + let deploy_tx = aurora_engine_transactions::legacy::TransactionLegacy { nonce: signer.use_nonce().into(), gas_price: U256::zero(), gas_limit: u64::MAX.into(), @@ -139,10 +141,11 @@ fn test_evm_tracing() { let result = runner .submit_transaction(&signer.secret_key, deploy_tx) .unwrap(); - let contract_address = Address::from_slice(test_utils::unwrap_success_slice(&result)); + let contract_address = + Address::try_from_slice(test_utils::unwrap_success_slice(&result)).unwrap(); // Interact with contract (and trace execution) - let tx = aurora_engine::transaction::legacy::TransactionLegacy { + let tx = aurora_engine_transactions::legacy::TransactionLegacy { nonce: signer.use_nonce().into(), gas_price: U256::zero(), gas_limit: 90_000.into(), @@ -170,7 +173,7 @@ fn test_evm_tracing() { .logs() .0 .iter() - .map(|l| l.gas_cost.into_u64() as u32) + .map(|l| l.gas_cost.as_u64() as u32) .collect(); assert_eq!(costs.as_slice(), &EXPECTED_COSTS); @@ -210,7 +213,7 @@ fn check_transaction_trace>(trace: TransactionTrace, expected_tra assert_eq!(log.depth.into_u32(), step.depth, "Depths should match"); assert_eq!(log.opcode.as_u8(), step.op, "opcodes should match"); assert_eq!( - log.gas_cost.into_u64(), + log.gas_cost.as_u64(), step.gas_cost, "gas costs should match" ); diff --git a/engine-tests/src/tests/uniswap.rs b/engine-tests/src/tests/uniswap.rs index ba4a2d94e..49fdb41f2 100644 --- a/engine-tests/src/tests/uniswap.rs +++ b/engine-tests/src/tests/uniswap.rs @@ -3,12 +3,14 @@ use crate::test_utils::{ self, erc20::{ERC20Constructor, ERC20}, uniswap::{ - ExactOutputSingleParams, Factory, FactoryConstructor, MintParams, Pool, PositionManager, - PositionManagerConstructor, SwapRouter, SwapRouterConstructor, + ExactInputParams, ExactOutputSingleParams, Factory, FactoryConstructor, MintParams, Pool, + PositionManager, PositionManagerConstructor, SwapRouter, SwapRouterConstructor, }, AuroraRunner, ExecutionProfile, Signer, }; use aurora_engine_types::types::Wei; +use aurora_engine_types::H160; +use rand::SeedableRng; use secp256k1::SecretKey; const INITIAL_BALANCE: u64 = 1000; @@ -16,9 +18,33 @@ const INITIAL_NONCE: u64 = 0; // The "fee" can only be specific values, see // https://github.com/Uniswap/uniswap-v3-core/blob/main/contracts/UniswapV3Factory.sol#L26 const POOL_FEE: u64 = 500; -const MINT_AMOUNT: u64 = 1_000_000_000; -const LIQUIDITY_AMOUNT: u64 = MINT_AMOUNT / 2; +const MINT_AMOUNT: u64 = 1_000_000_000_000; +const LIQUIDITY_AMOUNT: u64 = MINT_AMOUNT / 5; const OUTPUT_AMOUNT: u64 = LIQUIDITY_AMOUNT / 100; +const INPUT_AMOUNT: u64 = LIQUIDITY_AMOUNT / 100; + +#[test] +fn test_uniswap_input_multihop() { + let mut context = UniswapTestContext::new("uniswap"); + + // evm_gas = 970k + // near total gas = 214 Tgas + // Wish: optimize so that this transaction costs less than 200 Tgas. + // For now we just have to increase the burnt gas limit to make it run to completion. + context.runner.wasm_config.limit_config.max_gas_burnt = 500_000_000_000_000; + + let tokens = context.create_tokens(10, MINT_AMOUNT.into()); + for (token_a, token_b) in tokens.iter().zip(tokens.iter().skip(1)) { + context.create_pool(token_a, token_b); + context.add_equal_liquidity(LIQUIDITY_AMOUNT.into(), &token_a, &token_b); + } + + let (_amount_out, _evm_gas, profile) = context.exact_input(&tokens, INPUT_AMOUNT.into()); + + println!("{:?}", profile.host_breakdown); + println!("NEAR_GAS_WASM {:?}", profile.wasm_gas()); + println!("NEAR_GAS_TOTAL {:?}", profile.all_gas()); +} #[test] fn test_uniswap_exact_output() { @@ -28,15 +54,23 @@ fn test_uniswap_exact_output() { let (_result, profile) = context.add_equal_liquidity(LIQUIDITY_AMOUNT.into(), &token_a, &token_b); - test_utils::assert_gas_bound(profile.all_gas(), 114); + test_utils::assert_gas_bound(profile.all_gas(), 58); let wasm_fraction = 100 * profile.wasm_gas() / profile.all_gas(); - assert!(wasm_fraction >= 68, "{}% not more than 68%", wasm_fraction); + assert!( + 20 <= wasm_fraction && wasm_fraction <= 30, + "{}% is not between 20% and 30%", + wasm_fraction + ); let (_amount_in, profile) = context.exact_output_single(&token_a, &token_b, OUTPUT_AMOUNT.into()); - test_utils::assert_gas_bound(profile.all_gas(), 68); + test_utils::assert_gas_bound(profile.all_gas(), 32); let wasm_fraction = 100 * profile.wasm_gas() / profile.all_gas(); - assert!(wasm_fraction >= 72, "{}% not more than 72%", wasm_fraction); + assert!( + 25 <= wasm_fraction && wasm_fraction <= 35, + "{}% is not between 25% and 35%", + wasm_fraction + ); } #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -59,7 +93,7 @@ pub(crate) struct UniswapTestContext { impl UniswapTestContext { pub fn new(name: &str) -> Self { let mut runner = test_utils::deploy_evm(); - let mut rng = rand::thread_rng(); + let mut rng = rand::rngs::StdRng::seed_from_u64(414243); let source_account = SecretKey::random(&mut rng); let source_address = test_utils::address_from_secret_key(&source_account); runner.create_address( @@ -96,7 +130,7 @@ impl UniswapTestContext { c.deploy( factory.0.address, weth_address, - Address([0; 20]), + Address::new(H160([0; 20])), nonce.into(), ) }, @@ -124,6 +158,18 @@ impl UniswapTestContext { self.runner.wasm_config.regular_op_cost = 0; } + pub fn create_tokens(&mut self, n: usize, mint_amount: U256) -> Vec { + let names = ('a'..'z').into_iter().map(|c| format!("token_{}", c)); + let symbols = ('A'..'Z').into_iter().map(|c| format!("{}{}{}", c, c, c)); + let mut result: Vec = names + .zip(symbols) + .take(n) + .map(|(name, symbol)| self.create_token(&name, &symbol, mint_amount)) + .collect(); + result.sort_by_key(|t| t.0.address); + result + } + pub fn create_token_pair(&mut self, mint_amount: U256) -> (ERC20, ERC20) { let token_a = self.create_token("token_a", "A", mint_amount); let token_b = self.create_token("token_b", "B", mint_amount); @@ -147,9 +193,8 @@ impl UniswapTestContext { .unwrap(); assert!(result.status.is_ok(), "Failed to create pool"); - let mut address = [0u8; 20]; - address.copy_from_slice(&test_utils::unwrap_success(result)[12..]); - let pool = Pool::from_address(Address(address)); + let address = Address::try_from_slice(&test_utils::unwrap_success(result)[12..]).unwrap(); + let pool = Pool::from_address(address); // 2^96 corresponds to a price ratio of 1 let result = self @@ -222,6 +267,46 @@ impl UniswapTestContext { (result, profile) } + pub fn exact_input_params(&self, amount_in: U256, token_path: &[ERC20]) -> ExactInputParams { + let path = token_path + .iter() + .skip(1) + .map(|t| (POOL_FEE, t.0.address)) + .collect(); + ExactInputParams { + token_in: token_path[0].0.address, + path, + + recipient: Address::new(H160([0; 20])), + deadline: U256::MAX, + amount_in, + amount_out_min: U256::one(), + } + } + + pub fn exact_input( + &mut self, + token_path: &[ERC20], + amount_in: U256, + ) -> (U256, u64, ExecutionProfile) { + for token in token_path.iter() { + self.approve_erc20(token, self.swap_router.0.address, U256::MAX); + } + let params = self.exact_input_params(amount_in, token_path); + let swap_router = &self.swap_router; + let (result, profile) = self + .runner + .submit_with_signer_profiled(&mut self.signer, |nonce| { + swap_router.exact_input(params, nonce) + }) + .unwrap(); + assert!(result.status.is_ok(), "Swap failed"); + + let evm_gas = result.gas_used; + let amount_out = U256::from_big_endian(&test_utils::unwrap_success(result)); + (amount_out, evm_gas, profile) + } + pub fn exact_output_single_params( &self, amount_out: U256, @@ -232,7 +317,8 @@ impl UniswapTestContext { token_in: token_in.0.address, token_out: token_out.0.address, fee: POOL_FEE, - recipient: Address([0; 20]), + + recipient: Address::new(H160([0; 20])), deadline: U256::MAX, amount_out, amount_in_max: U256::from(100) * amount_out, diff --git a/engine-transactions/Cargo.toml b/engine-transactions/Cargo.toml new file mode 100644 index 000000000..8f29d04f3 --- /dev/null +++ b/engine-transactions/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "aurora-engine-transactions" +version = "1.0.0" +authors = ["Aurora Labs "] +edition = "2021" +description = "" +documentation = "" +readme = true +homepage = "https://github.com/aurora-is-near/aurora-engine" +repository = "https://github.com/aurora-is-near/aurora-engine" +license = "CC0-1.0" +publish = false +autobenches = false + +[dependencies] +aurora-engine-types = { path = "../engine-types", default-features = false } +aurora-engine-sdk = { path = "../engine-sdk", default-features = false } +aurora-engine-precompiles = { path = "../engine-precompiles", default-features = false } +evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "f4ee520254856898d451c7225851520a35c97cea", default-features = false } +rlp = { version = "0.5.0", default-features = false } +hex = { version = "0.4", default-features = false, features = ["alloc"] } + +[features] +std = ["aurora-engine-types/std", "aurora-engine-precompiles/std", "evm/std", "rlp/std", "hex/std"] diff --git a/engine/src/transaction/eip_1559.rs b/engine-transactions/src/eip_1559.rs similarity index 94% rename from engine/src/transaction/eip_1559.rs rename to engine-transactions/src/eip_1559.rs index 22a9ec539..8eaefbf43 100644 --- a/engine/src/transaction/eip_1559.rs +++ b/engine-transactions/src/eip_1559.rs @@ -1,8 +1,7 @@ -use crate::prelude::precompiles::secp256k1::ecrecover; -use crate::prelude::{Vec, U256}; -use crate::transaction::eip_2930::AccessTuple; -use aurora_engine_types::types::Wei; -use ethabi::Address; +use crate::eip_2930::AccessTuple; +use aurora_engine_precompiles::secp256k1::ecrecover; +use aurora_engine_types::types::{Address, Wei}; +use aurora_engine_types::{Vec, U256}; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; /// Type indicator (per EIP-1559) @@ -45,7 +44,7 @@ impl Transaction1559 { s.append(&self.gas_limit); match self.to.as_ref() { None => s.append(&""), - Some(address) => s.append(address), + Some(address) => s.append(&address.raw()), }; s.append(&self.value.raw()); s.append(&self.data); diff --git a/engine/src/transaction/eip_2930.rs b/engine-transactions/src/eip_2930.rs similarity index 93% rename from engine/src/transaction/eip_2930.rs rename to engine-transactions/src/eip_2930.rs index 72aa564ae..48a83f6a3 100644 --- a/engine/src/transaction/eip_2930.rs +++ b/engine-transactions/src/eip_2930.rs @@ -1,5 +1,7 @@ -use crate::prelude::precompiles::secp256k1::ecrecover; -use crate::prelude::{sdk, Address, Vec, Wei, H256, U256}; +use aurora_engine_precompiles::secp256k1::ecrecover; +use aurora_engine_sdk as sdk; +use aurora_engine_types::types::{Address, Wei}; +use aurora_engine_types::{Vec, H160, H256, U256}; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; /// Type indicator (per EIP-2718) for access list transactions @@ -7,7 +9,7 @@ pub const TYPE_BYTE: u8 = 0x01; #[derive(Debug, Eq, PartialEq, Clone)] pub struct AccessTuple { - pub address: Address, + pub address: H160, pub storage_keys: Vec, } @@ -55,7 +57,7 @@ impl Transaction2930 { s.append(&self.gas_limit); match self.to.as_ref() { None => s.append(&""), - Some(address) => s.append(address), + Some(address) => s.append(&address.raw()), }; s.append(&self.value.raw()); s.append(&self.data); diff --git a/engine/src/transaction/legacy.rs b/engine-transactions/src/legacy.rs similarity index 95% rename from engine/src/transaction/legacy.rs rename to engine-transactions/src/legacy.rs index 124830383..ff3afaac4 100644 --- a/engine/src/transaction/legacy.rs +++ b/engine-transactions/src/legacy.rs @@ -1,5 +1,7 @@ -use crate::prelude::precompiles::secp256k1::ecrecover; -use crate::prelude::{sdk, Address, Vec, Wei, U256}; +use aurora_engine_precompiles::secp256k1::ecrecover; +use aurora_engine_sdk as sdk; +use aurora_engine_types::types::{Address, Wei}; +use aurora_engine_types::{Vec, U256}; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; #[derive(Debug, Eq, PartialEq, Clone)] @@ -26,7 +28,7 @@ impl TransactionLegacy { s.append(&self.gas_limit); match self.to.as_ref() { None => s.append(&""), - Some(address) => s.append(address), + Some(address) => s.append(&address.raw()), }; s.append(&self.value.raw()); s.append(&self.data); @@ -40,7 +42,6 @@ impl TransactionLegacy { /// Returns self.gas as a u64, or None if self.gas > u64::MAX #[allow(unused)] pub fn get_gas_limit(&self) -> Option { - use crate::prelude::TryInto; self.gas_limit.try_into().ok() } @@ -106,7 +107,7 @@ impl Encodable for LegacyEthSignedTransaction { s.append(&self.transaction.gas_limit); match self.transaction.to.as_ref() { None => s.append(&""), - Some(address) => s.append(address), + Some(address) => s.append(&address.raw()), }; s.append(&self.transaction.value.raw()); s.append(&self.transaction.data); @@ -149,6 +150,7 @@ impl Decodable for LegacyEthSignedTransaction { #[cfg(test)] mod tests { use super::*; + use aurora_engine_types::vec; #[test] fn test_eth_signed_no_chain_sender() { @@ -199,8 +201,6 @@ mod tests { fn address_from_arr(arr: &[u8]) -> Address { assert_eq!(arr.len(), 20); - let mut address = [0u8; 20]; - address.copy_from_slice(&arr); - Address::from(address) + Address::try_from_slice(arr).unwrap() } } diff --git a/engine/src/transaction/mod.rs b/engine-transactions/src/lib.rs similarity index 95% rename from engine/src/transaction/mod.rs rename to engine-transactions/src/lib.rs index 7a16af021..05b2c1115 100644 --- a/engine/src/transaction/mod.rs +++ b/engine-transactions/src/lib.rs @@ -1,13 +1,15 @@ -use crate::prelude::{vec, Address, TryFrom, Vec, U256}; +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(not(feature = "std"), feature(alloc_error_handler))] + +use aurora_engine_types::types::{Address, Wei}; +use aurora_engine_types::{vec, Vec, H160, U256}; +use eip_2930::AccessTuple; use rlp::{Decodable, DecoderError, Rlp}; pub mod eip_1559; pub mod eip_2930; pub mod legacy; -use aurora_engine_types::types::Wei; -use eip_2930::AccessTuple; - /// Typed Transaction Envelope (see https://eips.ethereum.org/EIPS/eip-2718) #[derive(Debug, Eq, PartialEq, Clone)] pub enum EthTransactionKind { @@ -189,11 +191,12 @@ fn rlp_extract_to(rlp: &Rlp<'_>, index: usize) -> Result, Decode Err(rlp::DecoderError::RlpExpectedToBeData) } } else { - let v: Address = value.as_val()?; - if v == Address::zero() { + let v: H160 = value.as_val()?; + let addr = Address::new(v); + if addr == Address::zero() { Ok(None) } else { - Ok(Some(v)) + Ok(Some(addr)) } } } diff --git a/engine-types/Cargo.toml b/engine-types/Cargo.toml index 3b2a73a0e..275ec026d 100644 --- a/engine-types/Cargo.toml +++ b/engine-types/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "aurora-engine-types" version = "1.0.0" -authors = ["NEAR "] -edition = "2018" +authors = ["Aurora Labs "] +edition = "2021" description = "" documentation = "" readme = true diff --git a/engine-types/src/account_id.rs b/engine-types/src/account_id.rs index f42b536d4..4998d6a90 100644 --- a/engine-types/src/account_id.rs +++ b/engine-types/src/account_id.rs @@ -2,7 +2,7 @@ //! //! Inpired by: https://github.com/near/nearcore/tree/master/core/account-id -use crate::{fmt, str, str::FromStr, Box, String, TryFrom, Vec}; +use crate::{fmt, str, str::FromStr, Box, String, Vec}; use borsh::{BorshDeserialize, BorshSerialize}; pub const MIN_ACCOUNT_ID_LEN: usize = 2; diff --git a/engine-types/src/lib.rs b/engine-types/src/lib.rs index ae35c46f9..7250dab40 100644 --- a/engine-types/src/lib.rs +++ b/engine-types/src/lib.rs @@ -1,4 +1,3 @@ -#![feature(array_methods)] #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), feature(alloc_error_handler))] #![cfg_attr(feature = "log", feature(panic_info_message))] @@ -9,12 +8,9 @@ pub mod storage; pub mod types; mod v0 { - #[cfg(not(feature = "std"))] extern crate alloc; - #[cfg(not(feature = "std"))] extern crate core; - #[cfg(not(feature = "std"))] pub use alloc::{ borrow::ToOwned, borrow::{Cow, Cow::*}, @@ -27,28 +23,11 @@ mod v0 { vec, vec::Vec, }; - #[cfg(not(feature = "std"))] pub use core::{ - cmp::Ordering, convert::TryFrom, convert::TryInto, fmt::Display, marker::PhantomData, mem, - ops::Add, ops::Div, ops::Mul, ops::Sub, + cmp::Ordering, fmt::Display, marker::PhantomData, mem, ops::Add, ops::Div, ops::Mul, + ops::Sub, ops::SubAssign, }; pub use primitive_types::{H160, H256, U256}; - #[cfg(feature = "std")] - pub use std::{ - borrow::Cow, borrow::Cow::Borrowed, borrow::ToOwned, boxed::Box, cmp::Ordering, - collections::BTreeMap, collections::HashMap, convert::TryFrom, convert::TryInto, - error::Error, fmt, fmt::Display, format, marker::PhantomData, mem, ops::Add, ops::Div, - ops::Mul, ops::Sub, str, string::String, string::ToString, vec, vec::Vec, - }; } pub use v0::*; - -/// See: https://ethereum-magicians.org/t/increasing-address-size-from-20-to-32-bytes/5485 -pub type Address = H160; - -#[allow(non_snake_case, dead_code)] -// Gets around the fact that you can't contract pub fields with types. -pub const fn Address(input: [u8; 20]) -> Address { - H160(input) -} diff --git a/engine-types/src/parameters.rs b/engine-types/src/parameters.rs index 417326874..7781d1936 100644 --- a/engine-types/src/parameters.rs +++ b/engine-types/src/parameters.rs @@ -16,8 +16,8 @@ pub struct PromiseCreateArgs { pub target_account_id: AccountId, pub method: String, pub args: Vec, - pub attached_balance: u128, - pub attached_gas: u64, + pub attached_balance: Yocto, + pub attached_gas: NearGas, } #[must_use] @@ -30,7 +30,7 @@ pub struct PromiseWithCallbackArgs { #[derive(Debug, BorshSerialize, BorshDeserialize, Clone)] pub enum PromiseAction { Transfer { - amount: u128, + amount: Yocto, }, DeployConotract { code: Vec, @@ -38,8 +38,8 @@ pub enum PromiseAction { FunctionCall { name: String, args: Vec, - attached_yocto: u128, - gas: u64, + attached_yocto: Yocto, + gas: NearGas, }, } @@ -53,14 +53,14 @@ pub struct PromiseBatchAction { /// withdraw NEAR eth-connector call args #[derive(Debug, BorshSerialize, BorshDeserialize)] pub struct WithdrawCallArgs { - pub recipient_address: EthAddress, - pub amount: Balance, + pub recipient_address: Address, + pub amount: NEP141Wei, } /// withdraw NEAR eth-connector call args #[derive(BorshSerialize, BorshDeserialize)] pub struct RefundCallArgs { - pub recipient_address: EthAddress, - pub erc20_address: Option, + pub recipient_address: Address, + pub erc20_address: Option
, pub amount: RawU256, } diff --git a/engine-types/src/storage.rs b/engine-types/src/storage.rs index 9a6827a96..ce287542b 100644 --- a/engine-types/src/storage.rs +++ b/engine-types/src/storage.rs @@ -1,3 +1,4 @@ +use crate::types::Address; use crate::*; use borsh::{BorshDeserialize, BorshSerialize}; @@ -65,7 +66,7 @@ pub fn address_to_key(prefix: KeyPrefix, address: &Address) -> [u8; 22] { let mut result = [0u8; 22]; result[0] = VersionPrefix::V1 as u8; result[1] = prefix as u8; - result[2..22].copy_from_slice(&address.0); + result[2..22].copy_from_slice(address.as_bytes()); result } @@ -77,9 +78,9 @@ pub enum StorageKeyKind { impl AsRef<[u8]> for StorageKeyKind { fn as_ref(&self) -> &[u8] { use StorageKeyKind::*; - match self { - Normal(v) => v.as_slice(), - Generation(v) => v.as_slice(), + match &self { + Normal(v) => v, + Generation(v) => v, } } } @@ -97,7 +98,7 @@ fn normal_storage_key(address: &Address, key: &H256) -> [u8; 54] { let mut result = [0u8; 54]; result[0] = VersionPrefix::V1 as u8; result[1] = KeyPrefix::Storage as u8; - result[2..22].copy_from_slice(&address.0); + result[2..22].copy_from_slice(address.as_bytes()); result[22..54].copy_from_slice(&key.0); result } @@ -107,7 +108,7 @@ fn generation_storage_key(address: &Address, key: &H256, generation: u32) -> [u8 let mut result = [0u8; 58]; result[0] = VersionPrefix::V1 as u8; result[1] = KeyPrefix::Storage as u8; - result[2..22].copy_from_slice(&address.0); + result[2..22].copy_from_slice(address.as_bytes()); result[22..26].copy_from_slice(&generation.to_le_bytes()); result[26..58].copy_from_slice(&key.0); result diff --git a/engine-types/src/types.rs b/engine-types/src/types.rs deleted file mode 100644 index e37f04b8d..000000000 --- a/engine-types/src/types.rs +++ /dev/null @@ -1,515 +0,0 @@ -use crate::{str, vec, Add, Address, Display, Div, Mul, String, Sub, Vec, U256}; -use borsh::{BorshDeserialize, BorshSerialize}; - -use crate::fmt::Formatter; - -// TODO: introduce new Balance type for more strict typing -pub type Balance = u128; -pub type RawAddress = [u8; 20]; -pub type RawU256 = [u8; 32]; -// Big-endian large integer type. -pub type RawH256 = [u8; 32]; // Unformatted binary data of fixed length. - -// TODO: introduce new type. Add encode/decode/validation methods -pub type EthAddress = [u8; 20]; -pub type StorageUsage = u64; -/// Wei compatible Borsh-encoded raw value to attach an ETH balance to the transaction -pub type WeiU256 = [u8; 32]; - -#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] -/// Near gas type which wraps an underlying u64. -pub struct NearGas(u64); - -impl Sub for NearGas { - type Output = NearGas; - - fn sub(self, rhs: NearGas) -> Self::Output { - Self(self.0 - rhs.0) - } -} - -impl Display for NearGas { - fn fmt(&self, f: &mut Formatter<'_>) -> crate::fmt::Result { - self.0.fmt(f) - } -} - -impl NearGas { - /// Constructs a new `NearGas` with a given u64 value. - pub const fn new(gas: u64) -> NearGas { - Self(gas) - } - - /// Consumes `NearGas` and returns the underlying type. - pub fn into_u64(self) -> u64 { - self.0 - } -} - -#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] -/// Ethereum gas type which wraps an underlying u64. -pub struct EthGas(u64); - -impl Display for EthGas { - fn fmt(&self, f: &mut Formatter<'_>) -> crate::fmt::Result { - self.0.fmt(f) - } -} - -impl EthGas { - /// Constructs a new `EthGas` with a given u64 value. - pub const fn new(gas: u64) -> EthGas { - Self(gas) - } - - /// Consumes `EthGas` and returns the underlying type. - pub fn into_u64(self) -> u64 { - self.0 - } -} - -impl Add for EthGas { - type Output = EthGas; - - fn add(self, rhs: EthGas) -> Self::Output { - EthGas(self.0 + rhs.0) - } -} - -impl Div for EthGas { - type Output = EthGas; - - fn div(self, rhs: usize) -> Self::Output { - EthGas(self.0 / rhs as u64) - } -} - -impl Mul for u32 { - type Output = EthGas; - - fn mul(self, rhs: EthGas) -> Self::Output { - EthGas(self as u64 * rhs.0) - } -} - -impl Mul for EthGas { - type Output = EthGas; - - fn mul(self, rhs: u32) -> Self::Output { - EthGas(self.0 * rhs as u64) - } -} - -impl Mul for EthGas { - type Output = EthGas; - - fn mul(self, rhs: usize) -> Self::Output { - EthGas(self.0 * rhs as u64) - } -} - -impl Mul for u64 { - type Output = EthGas; - - fn mul(self, rhs: EthGas) -> Self::Output { - EthGas(self * rhs.0) - } -} - -#[derive( - Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, BorshSerialize, BorshDeserialize, -)] -/// Engine `fee` type which wraps an underlying u128. -pub struct Fee(u128); - -impl Display for Fee { - fn fmt(&self, f: &mut Formatter<'_>) -> crate::fmt::Result { - self.0.fmt(f) - } -} - -impl Fee { - /// Constructs a new `Fee` with a given u128 value. - pub const fn new(fee: u128) -> Fee { - Self(fee) - } - - /// Consumes `Fee` and returns the underlying type. - pub fn into_u128(self) -> u128 { - self.0 - } -} - -impl Add for Fee { - type Output = Fee; - - fn add(self, rhs: Fee) -> Self::Output { - Fee(self.0 + rhs.0) - } -} - -impl From for Fee { - fn from(fee: u128) -> Self { - Self(fee) - } -} - -/// Selector to call mint function in ERC 20 contract -/// -/// keccak("mint(address,uint256)".as_bytes())[..4]; -#[allow(dead_code)] -pub const ERC20_MINT_SELECTOR: &[u8] = &[64, 193, 15, 25]; - -#[derive(Debug)] -pub enum AddressValidationError { - FailedDecodeHex, - IncorrectLength, -} - -impl AsRef<[u8]> for AddressValidationError { - fn as_ref(&self) -> &[u8] { - match self { - Self::FailedDecodeHex => b"FAILED_DECODE_ETH_ADDRESS", - Self::IncorrectLength => b"ETH_WRONG_ADDRESS_LENGTH", - } - } -} - -/// Validate Ethereum address from string and return Result data EthAddress or Error data -pub fn validate_eth_address(address: String) -> Result { - let data = hex::decode(address).map_err(|_| AddressValidationError::FailedDecodeHex)?; - if data.len() != 20 { - return Err(AddressValidationError::IncorrectLength); - } - let mut result = [0u8; 20]; - result.copy_from_slice(&data); - Ok(result) -} - -/// Newtype to distinguish balances (denominated in Wei) from other U256 types. -#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] -pub struct Wei(U256); - -impl Wei { - const ETH_TO_WEI: U256 = U256([1_000_000_000_000_000_000, 0, 0, 0]); - - pub const fn zero() -> Self { - Self(U256([0, 0, 0, 0])) - } - - pub const fn new(amount: U256) -> Self { - Self(amount) - } - - // Purposely not implementing `From` because I want the call site to always - // say `Wei::`. If `From` is implemented then the caller might write - // `amount.into()` without thinking too hard about the units. Explicitly writing - // `Wei` reminds the developer to think about whether the amount they enter is really - // in units of `Wei` or not. - pub const fn new_u64(amount: u64) -> Self { - Self(U256([amount, 0, 0, 0])) - } - - pub fn from_eth(amount: U256) -> Option { - amount.checked_mul(Self::ETH_TO_WEI).map(Self) - } - - pub fn to_bytes(self) -> [u8; 32] { - u256_to_arr(&self.0) - } - - pub fn is_zero(&self) -> bool { - self.0.is_zero() - } - - pub fn raw(self) -> U256 { - self.0 - } - - pub fn checked_sub(self, rhs: Self) -> Option { - self.0.checked_sub(rhs.0).map(Self) - } - - pub fn checked_add(self, rhs: Self) -> Option { - self.0.checked_add(rhs.0).map(Self) - } - - /// Try convert U256 to u128 with checking overflow. - /// NOTICE: Error can contain only overflow - pub fn try_into_u128(self) -> Result { - use crate::TryInto; - self.0.try_into().map_err(|_| error::BalanceOverflowError) - } -} - -impl Display for Wei { - fn fmt(&self, f: &mut Formatter<'_>) -> crate::fmt::Result { - self.0.fmt(f) - } -} - -impl Add for Wei { - type Output = Wei; - - fn add(self, rhs: Self) -> Self::Output { - Self(self.0 + rhs.0) - } -} - -impl Sub for Wei { - type Output = Wei; - - fn sub(self, rhs: Self) -> Self::Output { - Self(self.0 - rhs.0) - } -} - -/// Type casting from Wei compatible Borsh-encoded raw value into the Wei value, to attach an ETH balance to the transaction -impl From for Wei { - fn from(value: WeiU256) -> Self { - Wei(U256::from_big_endian(&value)) - } -} - -pub const STORAGE_PRICE_PER_BYTE: u128 = 10_000_000_000_000_000_000; -// 1e19yN, 0.00001N -pub const ERR_FAILED_PARSE: &str = "ERR_FAILED_PARSE"; -pub const ERR_INVALID_ETH_ADDRESS: &str = "ERR_INVALID_ETH_ADDRESS"; - -/// Internal args format for meta call. -#[derive(Debug)] -pub struct InternalMetaCallArgs { - pub sender: Address, - pub nonce: U256, - pub fee_amount: Wei, - pub fee_address: Address, - pub contract_address: Address, - pub value: Wei, - pub input: Vec, -} - -pub struct StorageBalanceBounds { - pub min: Balance, - pub max: Option, -} - -/// promise results structure -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum PromiseResult { - NotReady, - Successful(Vec), - Failed, -} - -/// ft_resolve_transfer result of eth-connector -pub struct FtResolveTransferResult { - pub amount: Balance, - pub refund_amount: Balance, -} - -/// Internal errors to propagate up and format in the single place. -pub enum ErrorKind { - ArgumentParseError, - InvalidMetaTransactionMethodName, - InvalidMetaTransactionFunctionArg, - InvalidEcRecoverSignature, -} - -#[allow(dead_code)] -pub fn u256_to_arr(value: &U256) -> [u8; 32] { - let mut result = [0u8; 32]; - value.to_big_endian(&mut result); - result -} - -const HEX_ALPHABET: &[u8; 16] = b"0123456789abcdef"; - -#[allow(dead_code)] -pub fn bytes_to_hex(v: &[u8]) -> String { - let mut result = String::new(); - for x in v { - result.push(HEX_ALPHABET[(x / 16) as usize] as char); - result.push(HEX_ALPHABET[(x % 16) as usize] as char); - } - result -} - -#[derive(Default)] -pub struct Stack { - stack: Vec, - boundaries: Vec, -} - -impl Stack { - pub fn new() -> Self { - Self { - stack: Vec::new(), - boundaries: vec![0], - } - } - - pub fn enter(&mut self) { - self.boundaries.push(self.stack.len()); - } - - pub fn commit(&mut self) { - self.boundaries.pop().unwrap(); - } - - pub fn discard(&mut self) { - let boundary = self.boundaries.pop().unwrap(); - self.stack.truncate(boundary); - } - - pub fn push(&mut self, value: T) { - self.stack.push(value); - } - - pub fn into_vec(self) -> Vec { - self.stack - } -} - -pub fn str_from_slice(inp: &[u8]) -> &str { - str::from_utf8(inp).unwrap() -} - -pub mod error { - use crate::{fmt, String}; - - #[derive(Eq, Hash, Clone, Debug, PartialEq)] - pub struct BalanceOverflowError; - - impl AsRef<[u8]> for BalanceOverflowError { - fn as_ref(&self) -> &[u8] { - b"ERR_BALANCE_OVERFLOW" - } - } - - impl fmt::Display for BalanceOverflowError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let msg = String::from_utf8(self.as_ref().to_vec()).unwrap(); - write!(f, "{}", msg) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_hex() { - assert_eq!( - bytes_to_hex(&[0u8, 1u8, 255u8, 16u8]), - "0001ff10".to_string() - ); - } - - /// Build view of the stack. Intervals between None values are scopes. - fn view_stack(stack: &Stack) -> Vec> { - let mut res = vec![]; - let mut pnt = 0; - - for &pos in stack.boundaries.iter() { - while pnt < pos { - res.push(Some(stack.stack[pnt])); - pnt += 1; - } - res.push(None); - } - - while pnt < stack.stack.len() { - res.push(Some(stack.stack[pnt])); - pnt += 1; - } - - res - } - - fn check_stack(stack: &Stack, expected: Vec>) { - if let Some(&last) = stack.boundaries.last() { - assert!(last <= stack.stack.len()); - } - assert_eq!(view_stack(stack), expected); - } - - #[test] - fn test_stack() { - let mut stack = Stack::new(); // [ $ ] - check_stack(&stack, vec![None]); - - stack.push(1); // [ $, 1] - check_stack(&stack, vec![None, Some(1)]); - stack.push(2); // [ $, 1, 2 ] - check_stack(&stack, vec![None, Some(1), Some(2)]); - stack.enter(); // [$, 1, 2, $] - check_stack(&stack, vec![None, Some(1), Some(2), None]); - stack.push(3); // [$, 1, 2, $, 3] - check_stack(&stack, vec![None, Some(1), Some(2), None, Some(3)]); - stack.discard(); // [$, 1, 2] - check_stack(&stack, vec![None, Some(1), Some(2)]); - stack.enter(); - check_stack(&stack, vec![None, Some(1), Some(2), None]); - stack.push(4); // [$, 1, 2, $, 4] - check_stack(&stack, vec![None, Some(1), Some(2), None, Some(4)]); - stack.enter(); // [$, 1, 2, $, 4, $] - check_stack(&stack, vec![None, Some(1), Some(2), None, Some(4), None]); - stack.push(5); // [$, 1, 2, $, 4, $, 5] - check_stack( - &stack, - vec![None, Some(1), Some(2), None, Some(4), None, Some(5)], - ); - stack.commit(); // [$, 1, 2, $, 4, 5] - check_stack(&stack, vec![None, Some(1), Some(2), None, Some(4), Some(5)]); - stack.discard(); // [$, 1, 2] - check_stack(&stack, vec![None, Some(1), Some(2)]); - stack.push(6); // [$, 1, 2, 6] - check_stack(&stack, vec![None, Some(1), Some(2), Some(6)]); - stack.enter(); // [$, 1, 2, 6, $] - check_stack(&stack, vec![None, Some(1), Some(2), Some(6), None]); - stack.enter(); // [$, 1, 2, 6, $, $] - check_stack(&stack, vec![None, Some(1), Some(2), Some(6), None, None]); - stack.enter(); // [$, 1, 2, 6, $, $, $] - check_stack( - &stack, - vec![None, Some(1), Some(2), Some(6), None, None, None], - ); - stack.commit(); // [$, 1, 2, 6, $, $] - check_stack(&stack, vec![None, Some(1), Some(2), Some(6), None, None]); - stack.discard(); // [$, 1, 2, 6, $] - check_stack(&stack, vec![None, Some(1), Some(2), Some(6), None]); - stack.push(7); // [$, 1, 2, 6, $, 7] - - assert_eq!(stack.into_vec(), vec![1, 2, 6, 7]); - } - - #[test] - fn test_wei_from_u64() { - let x: u64 = rand::random(); - assert_eq!(Wei::new_u64(x).raw().as_u64(), x); - } - - #[test] - fn test_wei_from_eth() { - let eth_amount: u64 = rand::random(); - let wei_amount = U256::from(eth_amount) * U256::from(10).pow(18.into()); - assert_eq!(Wei::from_eth(eth_amount.into()), Some(Wei::new(wei_amount))); - } - - #[test] - fn test_fee_add() { - let fee = Fee::new(100); - assert_eq!(fee + fee, Fee::new(200)); - assert_eq!(fee.add(200.into()), Fee::new(300)); - } - - #[test] - fn test_fee_from() { - let fee = Fee::new(100); - let fee2 = Fee::from(100u128); - assert_eq!(fee, fee2); - let res: u128 = fee.into_u128(); - assert_eq!(res, 100); - } -} diff --git a/engine-types/src/types/address.rs b/engine-types/src/types/address.rs new file mode 100755 index 000000000..78d0b6673 --- /dev/null +++ b/engine-types/src/types/address.rs @@ -0,0 +1,172 @@ +use crate::{format, String, H160}; +use borsh::maybestd::io; +use borsh::{BorshDeserialize, BorshSerialize}; + +/// Base Eth Address type +#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] +pub struct Address(H160); + +impl Address { + /// Construct Address from H160 + pub const fn new(val: H160) -> Self { + Self(val) + } + + /// Get raw H160 data + pub fn raw(&self) -> H160 { + self.0 + } + + /// Encode address to string + pub fn encode(&self) -> String { + hex::encode(self.0.as_bytes()) + } + + pub fn decode(address: &str) -> Result { + if address.len() != 40 { + return Err(error::AddressError::IncorrectLength); + } + let mut result = [0u8; 20]; + hex::decode_to_slice(address, &mut result) + .map_err(|_| error::AddressError::FailedDecodeHex)?; + Ok(Address::new(H160(result))) + } + + pub fn as_bytes(&self) -> &[u8] { + self.0.as_bytes() + } + + pub fn try_from_slice(raw_addr: &[u8]) -> Result { + if raw_addr.len() != 20 { + return Err(error::AddressError::IncorrectLength); + } + Ok(Self::new(H160::from_slice(raw_addr))) + } + + pub fn from_array(array: [u8; 20]) -> Self { + Self(H160(array)) + } + + pub const fn zero() -> Self { + Address::new(H160([0u8; 20])) + } +} + +impl TryFrom<&[u8]> for Address { + type Error = error::AddressError; + + fn try_from(raw_addr: &[u8]) -> Result { + Self::try_from_slice(raw_addr).map_err(|_| error::AddressError::IncorrectLength) + } +} + +impl BorshSerialize for Address { + fn serialize(&self, writer: &mut W) -> io::Result<()> { + writer.write_all(self.0.as_bytes()) + } +} + +impl BorshDeserialize for Address { + fn deserialize(buf: &mut &[u8]) -> io::Result { + if buf.len() < 20 { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("{}", error::AddressError::IncorrectLength), + )); + } + // Guaranty no panics. The length checked early + let address = Self(H160::from_slice(&buf[..20])); + *buf = &buf[20..]; + Ok(address) + } +} + +impl Default for Address { + fn default() -> Self { + Address::zero() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_address_serializer() { + let eth_address = "096DE9C2B8A5B8c22cEe3289B101f6960d68E51E"; + // borsh serialize + let serialized_addr = + Address::new(H160::from_slice(&hex::decode(eth_address).unwrap()[..])) + .try_to_vec() + .unwrap(); + assert_eq!(serialized_addr.len(), 20); + + let addr = Address::try_from_slice(&serialized_addr).unwrap(); + assert_eq!( + addr.encode(), + "096DE9C2B8A5B8c22cEe3289B101f6960d68E51E".to_lowercase() + ); + } + + #[test] + fn test_address_decode() { + // Test compatibility with previous typ RawAddress. + // It was: type RawAddress = [u8;20]; + let eth_address_vec = + hex::decode("096DE9C2B8A5B8c22cEe3289B101f6960d68E51E".to_string()).unwrap(); + let mut eth_address = [0u8; 20]; + eth_address.copy_from_slice(ð_address_vec[..]); + + let aurora_eth_address = + Address::decode(&"096DE9C2B8A5B8c22cEe3289B101f6960d68E51E".to_string()).unwrap(); + assert_eq!(eth_address, aurora_eth_address.as_bytes()); + + let serialized_addr = eth_address.try_to_vec().unwrap(); + let aurora_serialized_addr = aurora_eth_address.try_to_vec().unwrap(); + + assert_eq!(serialized_addr.len(), 20); + assert_eq!(aurora_serialized_addr.len(), 20); + assert_eq!(serialized_addr, aurora_serialized_addr); + + // Used serialized data from `RawAddress` + let addr = Address::try_from_slice(&serialized_addr).unwrap(); + assert_eq!( + addr.encode(), + "096DE9C2B8A5B8c22cEe3289B101f6960d68E51E".to_lowercase() + ); + } + + #[test] + fn test_wrong_address_19() { + let serialized_addr = [0u8; 19]; + let addr = Address::try_from_slice(&serialized_addr); + let err = addr.unwrap_err(); + matches!(err, error::AddressError::IncorrectLength); + } +} + +pub mod error { + use crate::{fmt, String}; + + #[derive(Eq, Hash, Clone, Debug, PartialEq)] + pub enum AddressError { + FailedDecodeHex, + IncorrectLength, + } + + impl AsRef<[u8]> for AddressError { + fn as_ref(&self) -> &[u8] { + match self { + Self::FailedDecodeHex => b"FAILED_DECODE_ETH_ADDRESS", + Self::IncorrectLength => b"ETH_WRONG_ADDRESS_LENGTH", + } + } + } + + impl fmt::Display for AddressError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let msg = String::from_utf8(self.as_ref().to_vec()).unwrap(); + write!(f, "{}", msg) + } + } +} diff --git a/engine-types/src/types/balance.rs b/engine-types/src/types/balance.rs new file mode 100644 index 000000000..92c985f1c --- /dev/null +++ b/engine-types/src/types/balance.rs @@ -0,0 +1,94 @@ +use crate::fmt::Formatter; +use crate::{Add, Display, Sub}; +use borsh::{BorshDeserialize, BorshSerialize}; + +pub const ZERO_BALANCE: Balance = Balance::new(0); +pub const ZERO_YOCTO: Yocto = Yocto::new(0); + +#[derive( + Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, BorshSerialize, BorshDeserialize, +)] +/// A generic type for 128-bit balances, especially for NEP-141 tokens. This generic type should not be used +/// to represent NEAR balances (`Yocto` is designed for this purpose) or for eth-connector balances (`NEP141Wei` +/// is designed for this purpose). The reason we have specific types for NEAR and eth-connector is because of the +/// significant role they play in our system; therefore we do not want to mix them up with generic token balances. +pub struct Balance(u128); + +impl Display for Balance { + fn fmt(&self, f: &mut Formatter<'_>) -> crate::fmt::Result { + self.0.fmt(f) + } +} + +impl Balance { + /// Constructs a new `Balance` with a given u128 value. + pub const fn new(amount: u128) -> Balance { + Self(amount) + } + + /// Consumes `Balance` and returns the underlying type. + pub fn as_u128(self) -> u128 { + self.0 + } +} + +#[derive( + Default, BorshSerialize, BorshDeserialize, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, +)] +/// Near Yocto type which wraps an underlying u128. +/// 1 NEAR = 10^24 yoctoNEAR +pub struct Yocto(u128); + +impl Display for Yocto { + fn fmt(&self, f: &mut Formatter<'_>) -> crate::fmt::Result { + self.0.fmt(f) + } +} + +impl Yocto { + /// Constructs a new `Yocto NEAR` with a given u128 value. + pub const fn new(yocto: u128) -> Yocto { + Self(yocto) + } + + /// Consumes `Yocto NEAR` and returns the underlying type. + pub fn as_u128(self) -> u128 { + self.0 + } +} + +impl Add for Yocto { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0) + } +} + +impl Sub for Yocto { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0 - rhs.0) + } +} + +pub mod error { + use crate::{fmt, String}; + + #[derive(Eq, Hash, Clone, Debug, PartialEq)] + pub struct BalanceOverflowError; + + impl AsRef<[u8]> for BalanceOverflowError { + fn as_ref(&self) -> &[u8] { + b"ERR_BALANCE_OVERFLOW" + } + } + + impl fmt::Display for BalanceOverflowError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let msg = String::from_utf8(self.as_ref().to_vec()).unwrap(); + write!(f, "{}", msg) + } + } +} diff --git a/engine-types/src/types/fee.rs b/engine-types/src/types/fee.rs new file mode 100644 index 000000000..1de4e3816 --- /dev/null +++ b/engine-types/src/types/fee.rs @@ -0,0 +1,63 @@ +use crate::fmt::Formatter; +use crate::types::NEP141Wei; +use crate::{Add, Display}; +use borsh::{BorshDeserialize, BorshSerialize}; + +#[derive( + Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, BorshSerialize, BorshDeserialize, +)] +/// Engine `fee` type which wraps an underlying u128. +pub struct Fee(NEP141Wei); + +impl Display for Fee { + fn fmt(&self, f: &mut Formatter<'_>) -> crate::fmt::Result { + self.0.fmt(f) + } +} + +impl Fee { + /// Constructs a new `Fee` with a given u128 value. + pub const fn new(fee: NEP141Wei) -> Fee { + Self(fee) + } + + /// Consumes `Fee` and returns the underlying type. + pub fn as_u128(self) -> u128 { + self.0.as_u128() + } +} + +impl Add for Fee { + type Output = Fee; + + fn add(self, rhs: Fee) -> Self::Output { + Fee(self.0 + rhs.0) + } +} + +impl From for Fee { + fn from(fee: u128) -> Self { + Self(NEP141Wei::new(fee)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_fee_add() { + let fee = Fee::new(NEP141Wei::new(100)); + assert_eq!(fee + fee, Fee::from(200)); + assert_eq!(fee.add(200.into()), Fee::from(300)); + } + + #[test] + fn test_fee_from() { + let fee = Fee::new(NEP141Wei::new(100)); + let fee2 = Fee::from(100u128); + assert_eq!(fee, fee2); + let res: u128 = fee.as_u128(); + assert_eq!(res, 100); + } +} diff --git a/engine-types/src/types/gas.rs b/engine-types/src/types/gas.rs new file mode 100644 index 000000000..a689e3678 --- /dev/null +++ b/engine-types/src/types/gas.rs @@ -0,0 +1,105 @@ +use crate::fmt::Formatter; +use crate::{Add, Display, Div, Mul, Sub}; +use borsh::{BorshDeserialize, BorshSerialize}; + +#[derive( + Default, BorshSerialize, BorshDeserialize, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, +)] +/// Near gas type which wraps an underlying u64. +pub struct NearGas(u64); + +impl Display for NearGas { + fn fmt(&self, f: &mut Formatter<'_>) -> crate::fmt::Result { + self.0.fmt(f) + } +} + +impl Sub for NearGas { + type Output = NearGas; + + fn sub(self, rhs: NearGas) -> Self::Output { + Self(self.0 - rhs.0) + } +} + +impl NearGas { + /// Constructs a new `NearGas` with a given u64 value. + pub const fn new(gas: u64) -> NearGas { + Self(gas) + } + + /// Consumes `NearGas` and returns the underlying type. + pub fn as_u64(self) -> u64 { + self.0 + } +} + +#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] +/// Ethereum gas type which wraps an underlying u64. +pub struct EthGas(u64); + +impl Display for EthGas { + fn fmt(&self, f: &mut Formatter<'_>) -> crate::fmt::Result { + self.0.fmt(f) + } +} + +impl EthGas { + /// Constructs a new `EthGas` with a given u64 value. + pub const fn new(gas: u64) -> EthGas { + Self(gas) + } + + /// Consumes `EthGas` and returns the underlying type. + pub fn as_u64(self) -> u64 { + self.0 + } +} + +impl Add for EthGas { + type Output = EthGas; + + fn add(self, rhs: EthGas) -> Self::Output { + EthGas(self.0 + rhs.0) + } +} + +impl Div for EthGas { + type Output = EthGas; + + fn div(self, rhs: usize) -> Self::Output { + EthGas(self.0 / rhs as u64) + } +} + +impl Mul for u32 { + type Output = EthGas; + + fn mul(self, rhs: EthGas) -> Self::Output { + EthGas(self as u64 * rhs.0) + } +} + +impl Mul for EthGas { + type Output = EthGas; + + fn mul(self, rhs: u32) -> Self::Output { + EthGas(self.0 * rhs as u64) + } +} + +impl Mul for EthGas { + type Output = EthGas; + + fn mul(self, rhs: usize) -> Self::Output { + EthGas(self.0 * rhs as u64) + } +} + +impl Mul for u64 { + type Output = EthGas; + + fn mul(self, rhs: EthGas) -> Self::Output { + EthGas(self * rhs.0) + } +} diff --git a/engine-types/src/types/mod.rs b/engine-types/src/types/mod.rs new file mode 100644 index 000000000..f33b8c7d9 --- /dev/null +++ b/engine-types/src/types/mod.rs @@ -0,0 +1,227 @@ +use crate::{str, vec, String, Vec, U256}; + +pub mod address; +pub mod balance; +pub mod fee; +pub mod gas; +pub mod wei; + +pub use address::*; +pub use balance::*; +pub use fee::*; +pub use gas::*; +pub use wei::*; + +pub type RawU256 = [u8; 32]; +// Big-endian large integer type. +pub type RawH256 = [u8; 32]; // Unformatted binary data of fixed length. + +pub type StorageUsage = u64; + +/// Selector to call mint function in ERC 20 contract +/// +/// keccak("mint(address,uint256)".as_bytes())[..4]; +#[allow(dead_code)] +pub const ERC20_MINT_SELECTOR: &[u8] = &[64, 193, 15, 25]; + +#[derive(Debug)] +pub enum AddressValidationError { + FailedDecodeHex, + IncorrectLength, +} + +impl AsRef<[u8]> for AddressValidationError { + fn as_ref(&self) -> &[u8] { + match self { + Self::FailedDecodeHex => b"FAILED_DECODE_ETH_ADDRESS", + Self::IncorrectLength => b"ETH_WRONG_ADDRESS_LENGTH", + } + } +} + +pub const STORAGE_PRICE_PER_BYTE: u128 = 10_000_000_000_000_000_000; +// 1e19yN, 0.00001N +pub const ERR_FAILED_PARSE: &str = "ERR_FAILED_PARSE"; +pub const ERR_INVALID_ETH_ADDRESS: &str = "ERR_INVALID_ETH_ADDRESS"; + +/// Internal args format for meta call. +#[derive(Debug)] +pub struct InternalMetaCallArgs { + pub sender: Address, + pub nonce: U256, + pub fee_amount: Wei, + pub fee_address: Address, + pub contract_address: Address, + pub value: Wei, + pub input: Vec, +} + +pub struct StorageBalanceBounds { + pub min: Yocto, + pub max: Option, +} + +/// promise results structure +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum PromiseResult { + NotReady, + Successful(Vec), + Failed, +} + +/// ft_resolve_transfer result of eth-connector +pub struct FtResolveTransferResult { + pub amount: Balance, + pub refund_amount: Balance, +} + +/// Internal errors to propagate up and format in the single place. +pub enum ErrorKind { + ArgumentParseError, + InvalidMetaTransactionMethodName, + InvalidMetaTransactionFunctionArg, + InvalidEcRecoverSignature, +} + +const HEX_ALPHABET: &[u8; 16] = b"0123456789abcdef"; + +#[allow(dead_code)] +pub fn bytes_to_hex(v: &[u8]) -> String { + let mut result = String::new(); + for x in v { + result.push(HEX_ALPHABET[(x / 16) as usize] as char); + result.push(HEX_ALPHABET[(x % 16) as usize] as char); + } + result +} + +#[derive(Default)] +pub struct Stack { + stack: Vec, + boundaries: Vec, +} + +impl Stack { + pub fn new() -> Self { + Self { + stack: Vec::new(), + boundaries: vec![0], + } + } + + pub fn enter(&mut self) { + self.boundaries.push(self.stack.len()); + } + + pub fn commit(&mut self) { + self.boundaries.pop().unwrap(); + } + + pub fn discard(&mut self) { + let boundary = self.boundaries.pop().unwrap(); + self.stack.truncate(boundary); + } + + pub fn push(&mut self, value: T) { + self.stack.push(value); + } + + pub fn into_vec(self) -> Vec { + self.stack + } +} + +pub fn str_from_slice(inp: &[u8]) -> &str { + str::from_utf8(inp).unwrap() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_hex() { + assert_eq!( + bytes_to_hex(&[0u8, 1u8, 255u8, 16u8]), + "0001ff10".to_string() + ); + } + + /// Build view of the stack. Intervals between None values are scopes. + fn view_stack(stack: &Stack) -> Vec> { + let mut res = vec![]; + let mut pnt = 0; + + for &pos in stack.boundaries.iter() { + while pnt < pos { + res.push(Some(stack.stack[pnt])); + pnt += 1; + } + res.push(None); + } + + while pnt < stack.stack.len() { + res.push(Some(stack.stack[pnt])); + pnt += 1; + } + + res + } + + fn check_stack(stack: &Stack, expected: Vec>) { + if let Some(&last) = stack.boundaries.last() { + assert!(last <= stack.stack.len()); + } + assert_eq!(view_stack(stack), expected); + } + + #[test] + fn test_stack() { + let mut stack = Stack::new(); // [ $ ] + check_stack(&stack, vec![None]); + + stack.push(1); // [ $, 1] + check_stack(&stack, vec![None, Some(1)]); + stack.push(2); // [ $, 1, 2 ] + check_stack(&stack, vec![None, Some(1), Some(2)]); + stack.enter(); // [$, 1, 2, $] + check_stack(&stack, vec![None, Some(1), Some(2), None]); + stack.push(3); // [$, 1, 2, $, 3] + check_stack(&stack, vec![None, Some(1), Some(2), None, Some(3)]); + stack.discard(); // [$, 1, 2] + check_stack(&stack, vec![None, Some(1), Some(2)]); + stack.enter(); + check_stack(&stack, vec![None, Some(1), Some(2), None]); + stack.push(4); // [$, 1, 2, $, 4] + check_stack(&stack, vec![None, Some(1), Some(2), None, Some(4)]); + stack.enter(); // [$, 1, 2, $, 4, $] + check_stack(&stack, vec![None, Some(1), Some(2), None, Some(4), None]); + stack.push(5); // [$, 1, 2, $, 4, $, 5] + check_stack( + &stack, + vec![None, Some(1), Some(2), None, Some(4), None, Some(5)], + ); + stack.commit(); // [$, 1, 2, $, 4, 5] + check_stack(&stack, vec![None, Some(1), Some(2), None, Some(4), Some(5)]); + stack.discard(); // [$, 1, 2] + check_stack(&stack, vec![None, Some(1), Some(2)]); + stack.push(6); // [$, 1, 2, 6] + check_stack(&stack, vec![None, Some(1), Some(2), Some(6)]); + stack.enter(); // [$, 1, 2, 6, $] + check_stack(&stack, vec![None, Some(1), Some(2), Some(6), None]); + stack.enter(); // [$, 1, 2, 6, $, $] + check_stack(&stack, vec![None, Some(1), Some(2), Some(6), None, None]); + stack.enter(); // [$, 1, 2, 6, $, $, $] + check_stack( + &stack, + vec![None, Some(1), Some(2), Some(6), None, None, None], + ); + stack.commit(); // [$, 1, 2, 6, $, $] + check_stack(&stack, vec![None, Some(1), Some(2), Some(6), None, None]); + stack.discard(); // [$, 1, 2, 6, $] + check_stack(&stack, vec![None, Some(1), Some(2), Some(6), None]); + stack.push(7); // [$, 1, 2, 6, $, 7] + + assert_eq!(stack.into_vec(), vec![1, 2, 6, 7]); + } +} diff --git a/engine-types/src/types/wei.rs b/engine-types/src/types/wei.rs new file mode 100644 index 000000000..b70b00e5e --- /dev/null +++ b/engine-types/src/types/wei.rs @@ -0,0 +1,186 @@ +use crate::fmt::Formatter; +use crate::types::balance::error; +use crate::types::Fee; +use crate::{Add, Display, Sub, SubAssign, U256}; +use borsh::{BorshDeserialize, BorshSerialize}; + +pub const ZERO_NEP141_WEI: NEP141Wei = NEP141Wei::new(0); +pub const ZERO_WEI: Wei = Wei::new_u64(0); + +/// Wei compatible Borsh-encoded raw value to attach an ETH balance to the transaction +pub type WeiU256 = [u8; 32]; + +// Type representing the NEP-141 balances of the eth-connector (ie Wei amounts that have been bridged to Near) +#[derive( + Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, BorshSerialize, BorshDeserialize, +)] +pub struct NEP141Wei(u128); + +impl Display for NEP141Wei { + fn fmt(&self, f: &mut Formatter<'_>) -> crate::fmt::Result { + self.0.fmt(f) + } +} + +impl NEP141Wei { + /// Constructs a new `NEP141Wei` with a given u128 value. + pub const fn new(amount: u128) -> Self { + Self(amount) + } + + pub fn checked_sub(self, rhs: Self) -> Option { + self.0.checked_sub(rhs.0).map(Self) + } + + pub fn checked_add(self, rhs: Self) -> Option { + self.0.checked_add(rhs.0).map(Self) + } + + /// Consumes `NEP141Wei` and returns the underlying type. + pub fn as_u128(self) -> u128 { + self.0 + } +} + +impl Sub for NEP141Wei { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0 - rhs.0) + } +} + +impl Add for NEP141Wei { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0) + } +} + +impl SubAssign for NEP141Wei { + fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; + } +} + +/// Newtype to distinguish balances (denominated in Wei) from other U256 types. +#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] +pub struct Wei(U256); + +impl Wei { + const ETH_TO_WEI: U256 = U256([1_000_000_000_000_000_000, 0, 0, 0]); + + pub const fn zero() -> Self { + Self(U256([0, 0, 0, 0])) + } + + pub const fn new(amount: U256) -> Self { + Self(amount) + } + + // Purposely not implementing `From` because I want the call site to always + // say `Wei::`. If `From` is implemented then the caller might write + // `amount.into()` without thinking too hard about the units. Explicitly writing + // `Wei` reminds the developer to think about whether the amount they enter is really + // in units of `Wei` or not. + pub const fn new_u64(amount: u64) -> Self { + Self(U256([amount, 0, 0, 0])) + } + + pub fn from_eth(amount: U256) -> Option { + amount.checked_mul(Self::ETH_TO_WEI).map(Self) + } + + pub fn to_bytes(self) -> [u8; 32] { + u256_to_arr(&self.0) + } + + pub fn is_zero(&self) -> bool { + self.0.is_zero() + } + + pub fn raw(self) -> U256 { + self.0 + } + + pub fn checked_sub(self, rhs: Self) -> Option { + self.0.checked_sub(rhs.0).map(Self) + } + + pub fn checked_add(self, rhs: Self) -> Option { + self.0.checked_add(rhs.0).map(Self) + } + + /// Try convert U256 to u128 with checking overflow. + /// NOTICE: Error can contain only overflow + pub fn try_into_u128(self) -> Result { + self.0.try_into().map_err(|_| error::BalanceOverflowError) + } +} + +impl Display for Wei { + fn fmt(&self, f: &mut Formatter<'_>) -> crate::fmt::Result { + self.0.fmt(f) + } +} + +impl Add for Wei { + type Output = Wei; + + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0) + } +} + +impl Sub for Wei { + type Output = Wei; + + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0 - rhs.0) + } +} + +/// Type casting from Wei compatible Borsh-encoded raw value into the Wei value, to attach an ETH balance to the transaction +impl From for Wei { + fn from(value: WeiU256) -> Self { + Wei(U256::from_big_endian(&value)) + } +} + +impl From for Wei { + fn from(value: Fee) -> Self { + Wei(U256::from(value.as_u128())) + } +} + +impl From for Wei { + fn from(value: NEP141Wei) -> Self { + Wei(U256::from(value.as_u128())) + } +} + +#[allow(dead_code)] +pub fn u256_to_arr(value: &U256) -> [u8; 32] { + let mut result = [0u8; 32]; + value.to_big_endian(&mut result); + result +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_wei_from_eth() { + let eth_amount: u64 = rand::random(); + let wei_amount = U256::from(eth_amount) * U256::from(10).pow(18.into()); + assert_eq!(Wei::from_eth(eth_amount.into()), Some(Wei::new(wei_amount))); + } + + #[test] + fn test_wei_from_u64() { + let x: u64 = rand::random(); + assert_eq!(Wei::new_u64(x).raw().as_u64(), x); + } +} diff --git a/engine/Cargo.toml b/engine/Cargo.toml index a4952c19c..df90aeb36 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "aurora-engine" version = "2.1.0" -authors = ["NEAR "] -edition = "2018" +authors = ["Aurora Labs "] +edition = "2021" description = "" documentation = "" readme = true @@ -19,12 +19,13 @@ crate-type = ["cdylib", "rlib"] aurora-engine-types = { path = "../engine-types", default-features = false } aurora-engine-sdk = { path = "../engine-sdk", default-features = false } aurora-engine-precompiles = { path = "../engine-precompiles", default-features = false } +aurora-engine-transactions = { path = "../engine-transactions", default-features = false } base64 = { version = "0.13.0", default-features = false, features = ["alloc"] } -blake2 = { git = "https://github.com/near/near-blake2.git", version = "0.9.1", default-features = false } +near-blake2 = { git = "https://github.com/near/near-blake2.git", version = "0.9.1", default-features = false } borsh = { version = "0.8.2", default-features = false } bn = { package = "aurora-bn", git = "https://github.com/aurora-is-near/aurora-bn.git", default-features = false } -evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", default-features = false } -evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", default-features = false } +evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "f4ee520254856898d451c7225851520a35c97cea", default-features = false } +evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "f4ee520254856898d451c7225851520a35c97cea", default-features = false } libsecp256k1 = { version = "0.3.5", default-features = false } num = { version = "0.4.0", default-features = false, features = ["alloc"] } primitive-types = { version = "0.10.0", default-features = false, features = ["rlp"] } @@ -45,7 +46,7 @@ rand = "0.7.3" [features] default = ["std"] -std = ["borsh/std", "evm/std", "primitive-types/std", "rlp/std", "sha3/std", "ethabi/std", "logos/std", "bn/std", "aurora-engine-types/std"] +std = ["borsh/std", "evm/std", "primitive-types/std", "rlp/std", "sha3/std", "ethabi/std", "logos/std", "bn/std", "aurora-engine-types/std", "rjson/std", "aurora-engine-precompiles/std", "aurora-engine-transactions/std"] contract = ["aurora-engine-sdk/contract", "aurora-engine-precompiles/contract"] evm_bully = [] log = ["aurora-engine-sdk/log", "aurora-engine-precompiles/log"] diff --git a/engine/src/connector.rs b/engine/src/connector.rs index 959dd8e7d..50a20f11c 100644 --- a/engine/src/connector.rs +++ b/engine/src/connector.rs @@ -9,20 +9,20 @@ use crate::parameters::{ StorageWithdrawCallArgs, TransferCallArgs, TransferCallCallArgs, WithdrawResult, }; use crate::prelude::{ - format, sdk, str, validate_eth_address, AccountId, Address, Balance, BorshDeserialize, - BorshSerialize, EthAddress, EthConnectorStorageId, KeyPrefix, NearGas, PromiseResult, ToString, - Vec, WithdrawCallArgs, ERR_FAILED_PARSE, H160, + address::error::AddressError, NEP141Wei, Wei, U256, ZERO_NEP141_WEI, ZERO_WEI, }; use crate::prelude::{ - AddressValidationError, PromiseBatchAction, PromiseCreateArgs, PromiseWithCallbackArgs, + format, sdk, str, AccountId, Address, BorshDeserialize, BorshSerialize, EthConnectorStorageId, + KeyPrefix, NearGas, PromiseResult, ToString, Vec, WithdrawCallArgs, Yocto, ERR_FAILED_PARSE, }; +use crate::prelude::{PromiseBatchAction, PromiseCreateArgs, PromiseWithCallbackArgs}; use crate::proof::Proof; use aurora_engine_sdk::env::Env; use aurora_engine_sdk::io::{StorageIntermediate, IO}; pub const ERR_NOT_ENOUGH_BALANCE_FOR_FEE: &str = "ERR_NOT_ENOUGH_BALANCE_FOR_FEE"; /// Indicate zero attached balance for promise call -pub const ZERO_ATTACHED_BALANCE: Balance = 0; +pub const ZERO_ATTACHED_BALANCE: Yocto = Yocto::new(0); /// NEAR Gas for calling `fininsh_deposit` promise. Used in the `deposit` logic. pub const GAS_FOR_FINISH_DEPOSIT: NearGas = NearGas::new(50_000_000_000_000); /// NEAR Gas for calling `verify_log_entry` promise. Used in the `deposit` logic. @@ -55,7 +55,7 @@ pub struct EthConnector { /// It used in the Deposit flow, to verify log entry form incoming proof. pub prover_account: AccountId, /// It is Eth address, used in the Deposit and Withdraw logic. - pub eth_custodian_address: EthAddress, + pub eth_custodian_address: Address, } impl EthConnectorContract { @@ -144,7 +144,7 @@ impl EthConnectorContract { sdk::log!(&format!( "Deposit started: from {} to recipient {:?} with amount: {:?} and fee {:?}", - hex::encode(event.sender), + event.sender.encode(), event.token_message_data.get_recipient(), event.amount, event.fee @@ -152,15 +152,15 @@ impl EthConnectorContract { sdk::log!(&format!( "Event's address {}, custodian address {}", - hex::encode(&event.eth_custodian_address), - hex::encode(&self.contract.eth_custodian_address), + event.eth_custodian_address.encode(), + self.contract.eth_custodian_address.encode(), )); if event.eth_custodian_address != self.contract.eth_custodian_address { return Err(error::DepositError::CustodianAddressMismatch); } - if event.fee.into_u128() >= event.amount { + if NEP141Wei::new(event.fee.as_u128()) >= event.amount { return Err(error::DepositError::InsufficientAmountForFee); } @@ -180,7 +180,7 @@ impl EthConnectorContract { method: "verify_log_entry".to_string(), args: proof_to_verify, attached_balance: ZERO_ATTACHED_BALANCE, - attached_gas: GAS_FOR_VERIFY_LOG_ENTRY.into_u64(), + attached_gas: GAS_FOR_VERIFY_LOG_ENTRY, }; // Finalize deposit @@ -232,7 +232,7 @@ impl EthConnectorContract { method: "finish_deposit".to_string(), args: data, attached_balance: ZERO_ATTACHED_BALANCE, - attached_gas: GAS_FOR_FINISH_DEPOSIT.into_u64(), + attached_gas: GAS_FOR_FINISH_DEPOSIT, }; Ok(PromiseWithCallbackArgs { base: verify_call, @@ -274,9 +274,9 @@ impl EthConnectorContract { // Mint - calculate new balances self.mint_eth_on_near( data.new_owner_id.clone(), - data.amount - data.fee.into_u128(), + data.amount - NEP141Wei::new(data.fee.as_u128()), )?; - self.mint_eth_on_near(data.relayer_id, data.fee.into_u128())?; + self.mint_eth_on_near(data.relayer_id, NEP141Wei::new(data.fee.as_u128()))?; // Store proof only after `mint` calculations self.record_proof(&data.proof_key)?; // Save new contract data @@ -289,9 +289,9 @@ impl EthConnectorContract { pub(crate) fn internal_remove_eth( &mut self, address: &Address, - amount: Balance, + amount: Wei, ) -> Result<(), fungible_token::error::WithdrawError> { - self.burn_eth_on_aurora(address.0, amount)?; + self.burn_eth_on_aurora(address, amount)?; self.save_ft_contract(); Ok(()) } @@ -312,12 +312,12 @@ impl EthConnectorContract { fn mint_eth_on_near( &mut self, owner_id: AccountId, - amount: Balance, + amount: NEP141Wei, ) -> Result<(), fungible_token::error::DepositError> { sdk::log!(&format!("Mint {} nETH tokens for: {}", amount, owner_id)); if self.ft.get_account_eth_balance(&owner_id).is_none() { - self.ft.accounts_insert(&owner_id, 0); + self.ft.accounts_insert(&owner_id, ZERO_NEP141_WEI); } self.ft.internal_deposit_eth_to_near(&owner_id, amount) } @@ -325,13 +325,13 @@ impl EthConnectorContract { /// Mint ETH tokens fn mint_eth_on_aurora( &mut self, - owner_id: EthAddress, - amount: Balance, + owner_id: Address, + amount: Wei, ) -> Result<(), fungible_token::error::DepositError> { sdk::log!(&format!( "Mint {} ETH tokens for: {}", amount, - hex::encode(owner_id) + owner_id.encode() )); self.ft.internal_deposit_eth_to_aurora(owner_id, amount) } @@ -339,13 +339,13 @@ impl EthConnectorContract { /// Burn ETH tokens fn burn_eth_on_aurora( &mut self, - address: EthAddress, - amount: Balance, + address: &Address, + amount: Wei, ) -> Result<(), fungible_token::error::WithdrawError> { sdk::log!(&format!( "Burn {} ETH tokens for: {}", amount, - hex::encode(address) + address.encode() )); self.ft.internal_withdraw_eth_from_aurora(address, amount) } @@ -382,7 +382,7 @@ impl EthConnectorContract { let total_supply = self.ft.ft_total_eth_supply_on_near(); sdk::log!(&format!("Total ETH supply on NEAR: {}", total_supply)); self.io - .return_output(format!("\"{}\"", total_supply.to_string()).as_bytes()); + .return_output(format!("\"{}\"", total_supply).as_bytes()); } /// Returns total ETH supply on Aurora (ETH in Aurora EVM) @@ -390,7 +390,7 @@ impl EthConnectorContract { let total_supply = self.ft.ft_total_eth_supply_on_aurora(); sdk::log!(&format!("Total ETH supply on Aurora: {}", total_supply)); self.io - .return_output(format!("\"{}\"", total_supply.to_string()).as_bytes()); + .return_output(format!("\"{}\"", total_supply).as_bytes()); } /// Return balance of nETH (ETH on Near) @@ -401,25 +401,23 @@ impl EthConnectorContract { args.account_id, balance )); - self.io - .return_output(format!("\"{}\"", balance.to_string()).as_bytes()); + self.io.return_output(format!("\"{}\"", balance).as_bytes()); } /// Return balance of ETH (ETH in Aurora EVM) pub fn ft_balance_of_eth_on_aurora( &mut self, args: BalanceOfEthCallArgs, - ) -> Result<(), crate::prelude::types::error::BalanceOverflowError> { + ) -> Result<(), crate::prelude::types::balance::error::BalanceOverflowError> { let balance = self .ft - .internal_unwrap_balance_of_eth_on_aurora(args.address)?; + .internal_unwrap_balance_of_eth_on_aurora(&args.address); sdk::log!(&format!( "Balance of ETH [{}]: {}", - hex::encode(args.address), + args.address.encode(), balance )); - self.io - .return_output(format!("\"{}\"", balance.to_string()).as_bytes()); + self.io.return_output(format!("\"{}\"", balance).as_bytes()); Ok(()) } @@ -461,8 +459,7 @@ impl EthConnectorContract { )); // `ft_resolve_transfer` can change `total_supply` so we should save the contract self.save_ft_contract(); - self.io - .return_output(format!("\"{}\"", amount.to_string()).as_bytes()); + self.io.return_output(format!("\"{}\"", amount).as_bytes()); } /// FT transfer call from sender account (invoker account) to receiver @@ -487,7 +484,7 @@ impl EthConnectorContract { let message_data = FtTransferMessageData::parse_on_transfer_message(&args.msg) .map_err(error::FtTransferCallError::MessageParseFailed)?; // Check is transfer amount > fee - if message_data.fee.into_u128() >= args.amount { + if message_data.fee.as_u128() >= args.amount.as_u128() { return Err(error::FtTransferCallError::InsufficientAmountForFee); } @@ -496,9 +493,11 @@ impl EthConnectorContract { // Note: It can't overflow because the total supply doesn't change during transfer. let amount_for_check = self .ft - .internal_unwrap_balance_of_eth_on_aurora(message_data.recipient) - .map_err(error::FtTransferCallError::BalanceOverflow)?; - if amount_for_check.checked_add(args.amount).is_none() { + .internal_unwrap_balance_of_eth_on_aurora(&message_data.recipient); + if amount_for_check + .checked_add(Wei::from(args.amount)) + .is_none() + { return Err(error::FtTransferCallError::Transfer( fungible_token::error::TransferError::BalanceOverflow, )); @@ -506,7 +505,7 @@ impl EthConnectorContract { if self .ft .total_eth_supply_on_aurora - .checked_add(args.amount) + .checked_add(Wei::from(args.amount)) .is_none() { return Err(error::FtTransferCallError::Transfer( @@ -532,7 +531,7 @@ impl EthConnectorContract { pub fn storage_deposit( &mut self, predecessor_account_id: AccountId, - amount: Balance, + amount: Yocto, args: StorageDepositCallArgs, ) -> Result, fungible_token::error::StorageFundingError> { let account_id = args @@ -599,15 +598,21 @@ impl EthConnectorContract { .map_err(error::FtTransferCallError::MessageParseFailed)?; // Special case when predecessor_account_id is current_account_id - let fee = message_data.fee.into_u128(); + let wei_fee = Wei::from(message_data.fee); // Mint fee to relayer let relayer = engine.get_relayer(message_data.relayer.as_bytes()); - match (fee, relayer) { - (fee, Some(H160(evm_relayer_address))) if fee > 0 => { - self.mint_eth_on_aurora(message_data.recipient, args.amount - fee)?; + match (wei_fee, relayer) { + (fee, Some(evm_relayer_address)) if fee > ZERO_WEI => { + self.mint_eth_on_aurora( + message_data.recipient, + Wei::new(U256::from(args.amount.as_u128())) - fee, + )?; self.mint_eth_on_aurora(evm_relayer_address, fee)?; } - _ => self.mint_eth_on_aurora(message_data.recipient, args.amount)?, + _ => self.mint_eth_on_aurora( + message_data.recipient, + Wei::new(U256::from(args.amount.as_u128())), + )?, } self.save_ft_contract(); self.io.return_output("\"0\"".as_bytes()); @@ -693,11 +698,11 @@ fn get_contract_data(io: &I, suffix: &EthConnectorSt pub fn set_contract_data( io: &mut I, args: SetContractDataCallArgs, -) -> Result { +) -> Result { // Get initial contract arguments let contract_data = EthConnector { prover_account: args.prover_account, - eth_custodian_address: validate_eth_address(args.eth_custodian_address)?, + eth_custodian_address: Address::decode(&args.eth_custodian_address)?, }; // Save eth-connector specific data io.write_borsh( @@ -722,7 +727,8 @@ pub fn get_metadata(io: &I) -> Option { } pub mod error { - use crate::prelude::types::{error::BalanceOverflowError, AddressValidationError}; + use aurora_engine_types::types::address::error::AddressError; + use aurora_engine_types::types::balance::error::BalanceOverflowError; use crate::deposit_event::error::ParseOnTransferMessageError; use crate::{deposit_event, fungible_token}; @@ -736,7 +742,7 @@ pub mod error { EventParseFailed(deposit_event::error::ParseError), CustodianAddressMismatch, InsufficientAmountForFee, - InvalidAddress(AddressValidationError), + InvalidAddress(AddressError), } impl AsRef<[u8]> for DepositError { @@ -844,7 +850,7 @@ pub mod error { pub enum InitContractError { AlreadyInitialized, - InvalidCustodianAddress(AddressValidationError), + InvalidCustodianAddress(AddressError), } impl AsRef<[u8]> for InitContractError { diff --git a/engine/src/deposit_event.rs b/engine/src/deposit_event.rs index da1a9625f..815182f03 100644 --- a/engine/src/deposit_event.rs +++ b/engine/src/deposit_event.rs @@ -2,9 +2,9 @@ use crate::deposit_event::error::ParseEventMessageError; use crate::log_entry::LogEntry; use crate::prelude::account_id::AccountId; use crate::prelude::{ - validate_eth_address, vec, AddressValidationError, Balance, BorshDeserialize, BorshSerialize, - EthAddress, Fee, String, ToString, TryFrom, TryInto, Vec, U256, + vec, Address, BorshDeserialize, BorshSerialize, Fee, NEP141Wei, String, ToString, Vec, U256, }; +use aurora_engine_types::types::address::error::AddressError; use byte_slice_cast::AsByteSlice; use ethabi::{Event, EventParam, Hash, Log, ParamType, RawLog}; @@ -18,7 +18,7 @@ pub type EventParams = Vec; #[cfg_attr(not(target_arch = "wasm32"), derive(Debug))] pub struct FtTransferMessageData { pub relayer: AccountId, - pub recipient: EthAddress, + pub recipient: Address, pub fee: Fee, } @@ -58,8 +58,7 @@ impl FtTransferMessageData { let fee: Fee = fee_u128.into(); // Get recipient Eth address from message slice - let mut recipient: EthAddress = Default::default(); - recipient.copy_from_slice(&msg[32..52]); + let recipient = Address::try_from_slice(&msg[32..52]).unwrap(); Ok(FtTransferMessageData { relayer: account_id, @@ -73,9 +72,9 @@ impl FtTransferMessageData { // The first data section should contain fee data. // Pay attention, that for compatibility reasons we used U256 type // it means 32 bytes for fee data - let mut data = U256::from(self.fee.into_u128()).as_byte_slice().to_vec(); + let mut data = U256::from(self.fee.as_u128()).as_byte_slice().to_vec(); // Second data section should contain Eth address - data.extend(self.recipient); + data.extend(self.recipient.as_bytes()); // Add `:` separator between relayer_id and data message [self.relayer.as_ref(), &hex::encode(data)].join(":") } @@ -89,23 +88,23 @@ impl FtTransferMessageData { // The first data section should contain fee data. // Pay attention, that for compatibility reasons we used U256 type // it means 32 bytes for fee data - let mut data = U256::from(fee.into_u128()).as_byte_slice().to_vec(); + let mut data = U256::from(fee.as_u128()).as_byte_slice().to_vec(); // Check message length. let address = if recipient.len() == 42 { recipient .strip_prefix("0x") .ok_or(ParseEventMessageError::EthAddressValidationError( - AddressValidationError::FailedDecodeHex, + AddressError::FailedDecodeHex, ))? .to_string() } else { recipient }; - let recipient_address = validate_eth_address(address) - .map_err(ParseEventMessageError::EthAddressValidationError)?; + let recipient_address = + Address::decode(&address).map_err(ParseEventMessageError::EthAddressValidationError)?; // Second data section should contain Eth address - data.extend(recipient_address); + data.extend(recipient_address.as_bytes()); // Add `:` separator between relayer_id and data message //Ok([relayer_account_id.as_ref(), &hex::encode(data)].join(":")) Ok(Self { @@ -182,7 +181,7 @@ impl TokenMessageData { /// Ethereum event pub struct EthEvent { - pub eth_custodian_address: EthAddress, + pub eth_custodian_address: Address, pub log: Log, } @@ -200,7 +199,7 @@ impl EthEvent { anonymous: false, }; let log_entry: LogEntry = rlp::decode(data).map_err(|_| error::DecodeError::RlpFailed)?; - let eth_custodian_address = log_entry.address.0; + let eth_custodian_address = Address::new(log_entry.address); let topics = log_entry.topics.iter().map(|h| Hash::from(h.0)).collect(); let raw_log = RawLog { @@ -220,10 +219,10 @@ impl EthEvent { /// Data that was emitted by Deposited event. pub struct DepositedEvent { - pub eth_custodian_address: EthAddress, - pub sender: EthAddress, + pub eth_custodian_address: Address, + pub sender: Address, pub token_message_data: TokenMessageData, - pub amount: Balance, + pub amount: NEP141Wei, pub fee: Fee, } @@ -258,31 +257,33 @@ impl DepositedEvent { pub fn from_log_entry_data(data: &[u8]) -> Result { let event = EthEvent::fetch_log_entry_data(DEPOSITED_EVENT, Self::event_params(), data) .map_err(error::ParseError::LogParseFailed)?; - let sender = event.log.params[0] + let raw_sender = event.log.params[0] .value .clone() .into_address() .ok_or(error::ParseError::InvalidSender)? .0; + let sender = Address::from_array(raw_sender); // parse_event_message let event_message_data: String = event.log.params[1].value.clone().to_string(); - let amount: u128 = event.log.params[2] + let amount = event.log.params[2] .value .clone() .into_uint() .ok_or(error::ParseError::InvalidAmount)? .try_into() + .map(NEP141Wei::new) .map_err(|_| error::ParseError::OverflowNumber)?; - let raw_fee: u128 = event.log.params[3] + let fee = event.log.params[3] .value .clone() .into_uint() .ok_or(error::ParseError::InvalidFee)? .try_into() + .map(|v| Fee::new(NEP141Wei::new(v))) .map_err(|_| error::ParseError::OverflowNumber)?; - let fee: Fee = raw_fee.into(); let token_message_data = TokenMessageData::parse_event_message_and_prepare_token_message_data( @@ -321,7 +322,7 @@ pub mod error { pub enum ParseEventMessageError { TooManyParts, InvalidAccount, - EthAddressValidationError(AddressValidationError), + EthAddressValidationError(AddressError), ParseMessageError(ParseOnTransferMessageError), } diff --git a/engine/src/engine.rs b/engine/src/engine.rs index 1f1937410..2d1a9181f 100644 --- a/engine/src/engine.rs +++ b/engine/src/engine.rs @@ -6,6 +6,7 @@ use evm::{Config, CreateScheme, ExitError, ExitFatal, ExitReason}; use crate::connector::EthConnectorContract; use crate::map::BijectionMap; +use aurora_engine_sdk::dup_cache::{DupCache, PairDupCache}; use aurora_engine_sdk::env::Env; use aurora_engine_sdk::io::{StorageIntermediate, IO}; use aurora_engine_sdk::promise::{PromiseHandler, PromiseId}; @@ -13,13 +14,14 @@ use aurora_engine_sdk::promise::{PromiseHandler, PromiseId}; use crate::parameters::{DeployErc20TokenArgs, NewCallArgs, TransactionStatus}; use crate::prelude::precompiles::native::{ExitToEthereum, ExitToNear}; use crate::prelude::precompiles::Precompiles; +use crate::prelude::transactions::{EthTransactionKind, NormalizedEthTransaction}; use crate::prelude::{ address_to_key, bytes_to_key, sdk, storage_to_key, u256_to_arr, vec, AccountId, Address, - BorshDeserialize, BorshSerialize, KeyPrefix, PromiseArgs, PromiseCreateArgs, ToString, TryFrom, - TryInto, Vec, Wei, ERC20_MINT_SELECTOR, H256, U256, + BTreeMap, BorshDeserialize, BorshSerialize, KeyPrefix, PromiseArgs, PromiseCreateArgs, + ToString, Vec, Wei, ERC20_MINT_SELECTOR, H160, H256, U256, }; -use crate::transaction::{EthTransactionKind, NormalizedEthTransaction}; use aurora_engine_precompiles::PrecompileConstructorContext; +use core::cell::RefCell; /// Used as the first byte in the concatenation of data used to compute the blockhash. /// Could be useful in the future as a version byte, or to distinguish different types of blocks. @@ -82,7 +84,7 @@ pub enum EngineErrorKind { EvmFatal(ExitFatal), /// Incorrect nonce. IncorrectNonce, - FailedTransactionParse(crate::transaction::ParseTransactionError), + FailedTransactionParse(crate::prelude::transactions::ParseTransactionError), InvalidChainId, InvalidSignature, IntrinsicGasNotMet, @@ -215,6 +217,7 @@ pub enum DeployErc20Error { Engine(EngineError), Register(RegisterTokenError), } + impl AsRef<[u8]> for DeployErc20Error { fn as_ref(&self) -> &[u8] { match self { @@ -239,7 +242,9 @@ impl TryFrom> for ERC20Address { fn try_from(bytes: Vec) -> Result { if bytes.len() == 20 { - Ok(Self(Address::from_slice(&bytes))) + Ok(Self( + Address::try_from_slice(&bytes).map_err(|_| AddressParseError)?, + )) } else { Err(AddressParseError) } @@ -348,15 +353,15 @@ impl StackExecutorParams { fn make_executor<'a, 'env, I: IO + Copy, E: Env>( &'a self, engine: &'a Engine<'env, I, E>, - ) -> executor::StackExecutor< + ) -> executor::stack::StackExecutor< 'static, 'a, - executor::MemoryStackState>, + executor::stack::MemoryStackState>, Precompiles, > { - let metadata = executor::StackSubstateMetadata::new(self.gas_limit, CONFIG); - let state = executor::MemoryStackState::new(metadata, engine); - executor::StackExecutor::new_with_precompiles(state, CONFIG, &self.precompiles) + let metadata = executor::stack::StackSubstateMetadata::new(self.gas_limit, CONFIG); + let state = executor::stack::MemoryStackState::new(metadata, engine); + executor::stack::StackExecutor::new_with_precompiles(state, CONFIG, &self.precompiles) } } @@ -401,6 +406,9 @@ pub struct Engine<'env, I: IO, E: Env> { current_account_id: AccountId, io: I, env: &'env E, + generation_cache: RefCell>, + account_info_cache: RefCell>, + contract_storage_cache: RefCell>, } pub(crate) const CONFIG: &Config = &Config::london(); @@ -432,6 +440,9 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { current_account_id, io, env, + generation_cache: RefCell::new(BTreeMap::new()), + account_info_cache: RefCell::new(DupCache::default()), + contract_storage_cache: RefCell::new(PairDupCache::default()), } } @@ -474,7 +485,7 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { input: Vec, handler: &mut P, ) -> EngineResult { - let origin = self.origin(); + let origin = Address::new(self.origin()); let value = Wei::zero(); self.deploy_code(origin, value, input, u64::MAX, Vec::new(), handler) } @@ -485,7 +496,7 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { value: Wei, input: Vec, gas_limit: u64, - access_list: Vec<(Address, Vec)>, // See EIP-2930 + access_list: Vec<(H160, Vec)>, // See EIP-2930 handler: &mut P, ) -> EngineResult { let executor_params = StackExecutorParams::new( @@ -494,14 +505,19 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { self.env.random_seed(), ); let mut executor = executor_params.make_executor(self); - let address = executor.create_address(CreateScheme::Legacy { caller: origin }); - let (exit_reason, result) = ( - executor.transact_create(origin, value.raw(), input, gas_limit, access_list), - address, - ); + let address = executor.create_address(CreateScheme::Legacy { + caller: origin.raw(), + }); + let (exit_reason, return_value) = + executor.transact_create(origin.raw(), value.raw(), input, gas_limit, access_list); + let result = if exit_reason.is_succeed() { + address.0.to_vec() + } else { + return_value + }; let used_gas = executor.used_gas(); - let status = match exit_reason.into_result(result.0.to_vec()) { + let status = match exit_reason.into_result(result) { Ok(status) => status, Err(e) => { increment_nonce(&mut self.io, &origin); @@ -523,15 +539,15 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { args: CallArgs, handler: &mut P, ) -> EngineResult { - let origin = self.origin(); + let origin = Address::new(self.origin()); match args { CallArgs::V2(call_args) => { - let contract = Address(call_args.contract); + let contract = call_args.contract; let value = call_args.value.into(); let input = call_args.input; self.call( - origin, - contract, + &origin, + &contract, value, input, u64::MAX, @@ -540,12 +556,12 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { ) } CallArgs::V1(call_args) => { - let contract = Address(call_args.contract); + let contract = call_args.contract; let value = Wei::zero(); let input = call_args.input; self.call( - origin, - contract, + &origin, + &contract, value, input, u64::MAX, @@ -559,12 +575,12 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { #[allow(clippy::too_many_arguments)] pub fn call( &mut self, - origin: Address, - contract: Address, + origin: &Address, + contract: &Address, value: Wei, input: Vec, gas_limit: u64, - access_list: Vec<(Address, Vec)>, // See EIP-2930 + access_list: Vec<(H160, Vec)>, // See EIP-2930 handler: &mut P, ) -> EngineResult { let executor_params = StackExecutorParams::new( @@ -573,14 +589,20 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { self.env.random_seed(), ); let mut executor = executor_params.make_executor(self); - let (exit_reason, result) = - executor.transact_call(origin, contract, value.raw(), input, gas_limit, access_list); + let (exit_reason, result) = executor.transact_call( + origin.raw(), + contract.raw(), + value.raw(), + input, + gas_limit, + access_list, + ); let used_gas = executor.used_gas(); let status = match exit_reason.into_result(result) { Ok(status) => status, Err(e) => { - increment_nonce(&mut self.io, &origin); + increment_nonce(&mut self.io, origin); return Err(e.with_gas_used(used_gas)); } }; @@ -596,16 +618,16 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { } pub fn view_with_args(&self, args: ViewCallArgs) -> Result { - let origin = Address::from_slice(&args.sender); - let contract = Address::from_slice(&args.address); + let origin = &args.sender; + let contract = &args.address; let value = U256::from_big_endian(&args.amount); self.view(origin, contract, Wei::new(value), args.input, u64::MAX) } pub fn view( &self, - origin: Address, - contract: Address, + origin: &Address, + contract: &Address, value: Wei, input: Vec, gas_limit: u64, @@ -616,8 +638,14 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { self.env.random_seed(), ); let mut executor = executor_params.make_executor(self); - let (status, result) = - executor.transact_call(origin, contract, value.raw(), input, gas_limit, Vec::new()); + let (status, result) = executor.transact_call( + origin.raw(), + contract.raw(), + value.raw(), + input, + gas_limit, + Vec::new(), + ); status.into_result(result) } @@ -632,9 +660,8 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { pub fn get_relayer(&self, account_id: &[u8]) -> Option
{ let key = Self::relayer_key(account_id); - self.io - .read_storage(&key) - .map(|v| Address::from_slice(&v.to_vec())) + let raw_addr = self.io.read_storage(&key).map(|v| v.to_vec())?; + Address::try_from_slice(&raw_addr[..]).ok() } pub fn register_token( @@ -670,8 +697,8 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { handler: &mut P, ) -> EngineResult { self.call( - sender, - receiver, + &sender, + &receiver, value, Vec::new(), gas_limit, @@ -709,11 +736,11 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { let mut message = args.msg.as_bytes(); assert_or_finish!(message.len() >= 40, output_on_fail, self.io); - let recipient = Address(unwrap_res_or_finish!( + let recipient = Address::new(H160(unwrap_res_or_finish!( hex::decode(&message[..40]).unwrap().as_slice().try_into(), output_on_fail, self.io - )); + ))); message = &message[40..]; let fee = if message.is_empty() { @@ -728,7 +755,7 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { (recipient, fee) }; - let erc20_token = Address(unwrap_res_or_finish!( + let erc20_token = Address::from_array(unwrap_res_or_finish!( unwrap_res_or_finish!( get_erc20_from_nep141(&self.io, token), output_on_fail, @@ -762,15 +789,15 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { let selector = ERC20_MINT_SELECTOR; let tail = ethabi::encode(&[ - ethabi::Token::Address(recipient), - ethabi::Token::Uint(args.amount.into()), + ethabi::Token::Address(recipient.raw()), + ethabi::Token::Uint(U256::from(args.amount.as_u128())), ]); let erc20_admin_address = current_address(current_account_id); unwrap_res_or_finish!( self.call( - erc20_admin_address, - erc20_token, + &erc20_admin_address, + &erc20_token, Wei::zero(), [selector, tail.as_slice()].concat(), u64::MAX, @@ -838,6 +865,10 @@ pub fn submit( if U256::from(chain_id) != U256::from(state.chain_id) { return Err(EngineErrorKind::InvalidChainId.into()); } + } else { + // Do not allow missing chain_id in production + #[cfg(not(feature = "evm_bully"))] + return Err(EngineErrorKind::InvalidChainId.into()); } // Retrieve the signer of the transaction: @@ -888,8 +919,8 @@ pub fn submit( .collect(); let result = if let Some(receiver) = transaction.to { engine.call( - sender, - receiver, + &sender, + &receiver, transaction.value, transaction.data, gas_limit, @@ -1028,7 +1059,7 @@ pub fn deploy_erc20_token( ethabi::Token::String("Empty".to_string()), ethabi::Token::String("EMPTY".to_string()), ethabi::Token::Uint(ethabi::Uint::from(0)), - ethabi::Token::Address(erc20_admin_address), + ethabi::Token::Address(erc20_admin_address.raw()), ]); let address = match Engine::deploy_code_with_input( @@ -1037,7 +1068,9 @@ pub fn deploy_erc20_token( handler, ) { Ok(result) => match result.status { - TransactionStatus::Succeed(ret) => Address(ret.as_slice().try_into().unwrap()), + TransactionStatus::Succeed(ret) => { + Address::new(H160(ret.as_slice().try_into().unwrap())) + } other => return Err(DeployErc20Error::Failed(other)), }, Err(e) => return Err(DeployErc20Error::Engine(e)), @@ -1062,7 +1095,7 @@ pub fn remove_code(io: &mut I, address: &Address) { pub fn get_code(io: &I, address: &Address) -> Vec { io.read_storage(&address_to_key(KeyPrefix::Code, address)) .map(|s| s.to_vec()) - .unwrap_or_else(Vec::new) + .unwrap_or_default() } pub fn get_code_size(io: &I, address: &Address) -> usize { @@ -1142,9 +1175,7 @@ pub fn set_balance(io: &mut I, address: &Address, balance: &Wei) { } pub fn remove_balance(io: &mut I, address: &Address) { - // The `unwrap` is safe here because if the connector - // is implemented correctly then the "Eth on Aurora" wll never underflow. - let balance = get_balance(io, address).try_into_u128().unwrap(); + let balance = get_balance(io, address); // Apply changes for eth-connector. The `unwrap` is safe here because (a) if the connector // is implemented correctly then the total supply wll never underflow and (b) we are passing // in the balance directly so there will always be enough balance. @@ -1186,14 +1217,13 @@ pub fn get_storage(io: &I, address: &Address, key: &H256, generation: u32 None } }) - .unwrap_or_else(H256::default) + .unwrap_or_default() } pub fn is_account_empty(io: &I, address: &Address) -> bool { - let balance = get_balance(io, address); - let nonce = get_nonce(io, address); - let code_len = get_code_size(io, address); - balance.is_zero() && nonce.is_zero() && code_len == 0 + get_balance(io, address).is_zero() + && get_nonce(io, address).is_zero() + && get_code_size(io, address) == 0 } /// Increments storage generation for a given address. @@ -1242,7 +1272,9 @@ where { logs.into_iter() .filter_map(|log| { - if log.address == ExitToNear::ADDRESS || log.address == ExitToEthereum::ADDRESS { + if log.address == ExitToNear::ADDRESS.raw() + || log.address == ExitToEthereum::ADDRESS.raw() + { if log.topics.is_empty() { if let Ok(promise) = PromiseArgs::try_from_slice(&log.data) { match promise { @@ -1297,8 +1329,8 @@ impl<'env, I: IO + Copy, E: Env> evm::backend::Backend for Engine<'env, I, E> { } /// Returns the origin address that created the contract. - fn origin(&self) -> Address { - self.origin + fn origin(&self) -> H160 { + self.origin.raw() } /// Returns a block hash from a given index. @@ -1341,8 +1373,8 @@ impl<'env, I: IO + Copy, E: Env> evm::backend::Backend for Engine<'env, I, E> { /// account, being 0x4444588443C3a91288c5002483449Aba1054192b. /// /// See: https://doc.aurora.dev/develop/compat/evm#coinbase - fn block_coinbase(&self) -> Address { - Address([ + fn block_coinbase(&self) -> H160 { + H160([ 0x44, 0x44, 0x58, 0x84, 0x43, 0xC3, 0xa9, 0x12, 0x88, 0xc5, 0x00, 0x24, 0x83, 0x44, 0x9A, 0xba, 0x10, 0x54, 0x19, 0x2b, ]) @@ -1387,27 +1419,44 @@ impl<'env, I: IO + Copy, E: Env> evm::backend::Backend for Engine<'env, I, E> { } /// Checks if an address exists. - fn exists(&self, address: Address) -> bool { - !is_account_empty(&self.io, &address) + fn exists(&self, address: H160) -> bool { + !is_account_empty(&self.io, &Address::new(address)) } /// Returns basic account information. - fn basic(&self, address: Address) -> Basic { - Basic { - nonce: get_nonce(&self.io, &address), - balance: get_balance(&self.io, &address).raw(), - } + fn basic(&self, address: H160) -> Basic { + let address = Address::new(address); + let result = self + .account_info_cache + .borrow_mut() + .get_or_insert_with(&address, || Basic { + nonce: get_nonce(&self.io, &address), + balance: get_balance(&self.io, &address).raw(), + }) + .clone(); + result } /// Returns the code of the contract from an address. - fn code(&self, address: Address) -> Vec { - get_code(&self.io, &address) + fn code(&self, address: H160) -> Vec { + get_code(&self.io, &Address::new(address)) } /// Get storage value of address at index. - fn storage(&self, address: Address, index: H256) -> H256 { - let generation = get_generation(&self.io, &address); - get_storage(&self.io, &address, &index, generation) + fn storage(&self, address: H160, index: H256) -> H256 { + let address = Address::new(address); + let generation = *self + .generation_cache + .borrow_mut() + .entry(address) + .or_insert_with(|| get_generation(&self.io, &address)); + let result = *self + .contract_storage_cache + .borrow_mut() + .get_or_insert_with((&address, &index), || { + get_storage(&self.io, &address, &index, generation) + }); + result } /// Get original storage value of address at index, if available. @@ -1415,7 +1464,7 @@ impl<'env, I: IO + Copy, E: Env> evm::backend::Backend for Engine<'env, I, E> { /// Since SputnikVM collects storage changes in memory until the transaction is over, /// the "original storage" will always be the same as the storage because no values /// are written to storage until after the transaction is complete. - fn original_storage(&self, address: Address, index: H256) -> Option { + fn original_storage(&self, address: H160, index: H256) -> Option { Some(self.storage(address, index)) } } @@ -1438,6 +1487,7 @@ impl<'env, J: IO + Copy, E: Env> ApplyBackend for Engine<'env, J, E> { storage, reset_storage, } => { + let address = Address::new(address); let generation = get_generation(&self.io, &address); set_nonce(&mut self.io, &address, &basic.nonce); set_balance(&mut self.io, &address, &Wei::new(basic.balance)); @@ -1484,6 +1534,7 @@ impl<'env, J: IO + Copy, E: Env> ApplyBackend for Engine<'env, J, E> { } } Apply::Delete { address } => { + let address = Address::new(address); let generation = get_generation(&self.io, &address); remove_account(&mut self.io, &address, generation); writes_counter += 1; diff --git a/engine/src/fungible_token.rs b/engine/src/fungible_token.rs index 74f220ce2..adbfc665e 100644 --- a/engine/src/fungible_token.rs +++ b/engine/src/fungible_token.rs @@ -3,13 +3,14 @@ use crate::engine; use crate::json::{parse_json, JsonValue}; use crate::parameters::{NEP141FtOnTransferArgs, ResolveTransferCallArgs, StorageBalance}; use crate::prelude::account_id::AccountId; +use crate::prelude::Wei; use crate::prelude::{ - sdk, storage, vec, Address, BTreeMap, Balance, BorshDeserialize, BorshSerialize, EthAddress, - NearGas, PromiseAction, PromiseBatchAction, PromiseCreateArgs, PromiseResult, - PromiseWithCallbackArgs, StorageBalanceBounds, StorageUsage, String, ToString, TryInto, Vec, - Wei, U256, + sdk, storage, vec, Address, BTreeMap, Balance, BorshDeserialize, BorshSerialize, NearGas, + PromiseAction, PromiseBatchAction, PromiseCreateArgs, PromiseResult, PromiseWithCallbackArgs, + StorageBalanceBounds, StorageUsage, String, ToString, Vec, }; use aurora_engine_sdk::io::{StorageIntermediate, IO}; +use aurora_engine_types::types::{NEP141Wei, Yocto, ZERO_NEP141_WEI, ZERO_YOCTO}; /// Gas for `resolve_transfer`: 5 TGas const GAS_FOR_RESOLVE_TRANSFER: NearGas = NearGas::new(5_000_000_000_000); @@ -19,10 +20,12 @@ const GAS_FOR_FT_TRANSFER_CALL: NearGas = NearGas::new(35_000_000_000_000); #[derive(Debug, Default, BorshDeserialize, BorshSerialize)] pub struct FungibleToken { /// Total ETH supply on Near (nETH as NEP-141 token) - pub total_eth_supply_on_near: Balance, + pub total_eth_supply_on_near: NEP141Wei, /// Total ETH supply on Aurora (ETH in Aurora EVM) - pub total_eth_supply_on_aurora: Balance, + /// NOTE: For compatibility reasons, we do not use `Wei` (32 bytes) + /// buy `NEP141Wei` (16 bytes) + pub total_eth_supply_on_aurora: NEP141Wei, /// The storage size in bytes for one account. pub account_storage_usage: StorageUsage, @@ -32,7 +35,7 @@ impl FungibleToken { pub fn ops(self, io: I) -> FungibleTokenOps { FungibleTokenOps { total_eth_supply_on_near: self.total_eth_supply_on_near, - total_eth_supply_on_aurora: self.total_eth_supply_on_aurora, + total_eth_supply_on_aurora: Wei::from(self.total_eth_supply_on_aurora), account_storage_usage: self.account_storage_usage, io, } @@ -41,10 +44,10 @@ impl FungibleToken { pub struct FungibleTokenOps { /// Total ETH supply on Near (nETH as NEP-141 token) - pub total_eth_supply_on_near: Balance, + pub total_eth_supply_on_near: NEP141Wei, /// Total ETH supply on Aurora (ETH in Aurora EVM) - pub total_eth_supply_on_aurora: Balance, + pub total_eth_supply_on_aurora: Wei, /// The storage size in bytes for one account. pub account_storage_usage: StorageUsage, @@ -66,7 +69,7 @@ impl FungibleReferenceHash { impl AsRef<[u8]> for FungibleReferenceHash { fn as_ref(&self) -> &[u8] { - self.0.as_slice() + &self.0 } } @@ -139,26 +142,29 @@ impl FungibleTokenOps { pub fn data(&self) -> FungibleToken { FungibleToken { total_eth_supply_on_near: self.total_eth_supply_on_near, - total_eth_supply_on_aurora: self.total_eth_supply_on_aurora, + // TODO: both types should be same + // ut must never panic + total_eth_supply_on_aurora: NEP141Wei::new( + self.total_eth_supply_on_aurora.try_into_u128().unwrap(), + ), account_storage_usage: self.account_storage_usage, } } /// Balance of ETH (ETH on Aurora) - pub fn internal_unwrap_balance_of_eth_on_aurora( - &self, - address: EthAddress, - ) -> Result { - engine::get_balance(&self.io, &Address(address)).try_into_u128() + pub fn internal_unwrap_balance_of_eth_on_aurora(&self, address: &Address) -> Wei { + engine::get_balance(&self.io, address) } /// Internal ETH deposit to NEAR - nETH (NEP-141) pub fn internal_deposit_eth_to_near( &mut self, account_id: &AccountId, - amount: Balance, + amount: NEP141Wei, ) -> Result<(), error::DepositError> { - let balance = self.get_account_eth_balance(account_id).unwrap_or(0); + let balance = self + .get_account_eth_balance(account_id) + .unwrap_or(ZERO_NEP141_WEI); let new_balance = balance .checked_add(amount) .ok_or(error::DepositError::BalanceOverflow)?; @@ -173,20 +179,14 @@ impl FungibleTokenOps { /// Internal ETH deposit to Aurora pub fn internal_deposit_eth_to_aurora( &mut self, - address: EthAddress, - amount: Balance, + address: Address, + amount: Wei, ) -> Result<(), error::DepositError> { - let balance = self - .internal_unwrap_balance_of_eth_on_aurora(address) - .map_err(|_| error::DepositError::BalanceOverflow)?; + let balance = self.internal_unwrap_balance_of_eth_on_aurora(&address); let new_balance = balance .checked_add(amount) .ok_or(error::DepositError::BalanceOverflow)?; - engine::set_balance( - &mut self.io, - &Address(address), - &Wei::new(U256::from(new_balance)), - ); + engine::set_balance(&mut self.io, &address, &new_balance); self.total_eth_supply_on_aurora = self .total_eth_supply_on_aurora .checked_add(amount) @@ -198,9 +198,11 @@ impl FungibleTokenOps { pub fn internal_withdraw_eth_from_near( &mut self, account_id: &AccountId, - amount: Balance, + amount: NEP141Wei, ) -> Result<(), error::WithdrawError> { - let balance = self.get_account_eth_balance(account_id).unwrap_or(0); + let balance = self + .get_account_eth_balance(account_id) + .unwrap_or(ZERO_NEP141_WEI); let new_balance = balance .checked_sub(amount) .ok_or(error::WithdrawError::InsufficientFunds)?; @@ -215,20 +217,14 @@ impl FungibleTokenOps { /// Withdraw ETH tokens pub fn internal_withdraw_eth_from_aurora( &mut self, - address: EthAddress, - amount: Balance, + address: &Address, + amount: Wei, ) -> Result<(), error::WithdrawError> { - let balance = self - .internal_unwrap_balance_of_eth_on_aurora(address) - .map_err(error::WithdrawError::BalanceOverflow)?; + let balance = self.internal_unwrap_balance_of_eth_on_aurora(address); let new_balance = balance .checked_sub(amount) .ok_or(error::WithdrawError::InsufficientFunds)?; - engine::set_balance( - &mut self.io, - &Address(address), - &Wei::new(U256::from(new_balance)), - ); + engine::set_balance(&mut self.io, address, &new_balance); self.total_eth_supply_on_aurora = self .total_eth_supply_on_aurora .checked_sub(amount) @@ -241,13 +237,13 @@ impl FungibleTokenOps { &mut self, sender_id: &AccountId, receiver_id: &AccountId, - amount: Balance, + amount: NEP141Wei, #[allow(unused_variables)] memo: &Option, ) -> Result<(), error::TransferError> { if sender_id == receiver_id { return Err(error::TransferError::SelfTransfer); } - if amount == 0 { + if amount == ZERO_NEP141_WEI { return Err(error::TransferError::ZeroAmount); } @@ -274,19 +270,20 @@ impl FungibleTokenOps { } pub fn internal_register_account(&mut self, account_id: &AccountId) { - self.accounts_insert(account_id, 0) + self.accounts_insert(account_id, ZERO_NEP141_WEI) } - pub fn ft_total_eth_supply_on_near(&self) -> Balance { + pub fn ft_total_eth_supply_on_near(&self) -> NEP141Wei { self.total_eth_supply_on_near } - pub fn ft_total_eth_supply_on_aurora(&self) -> Balance { + pub fn ft_total_eth_supply_on_aurora(&self) -> Wei { self.total_eth_supply_on_aurora } - pub fn ft_balance_of(&self, account_id: &AccountId) -> Balance { - self.get_account_eth_balance(account_id).unwrap_or(0) + pub fn ft_balance_of(&self, account_id: &AccountId) -> NEP141Wei { + self.get_account_eth_balance(account_id) + .unwrap_or(ZERO_NEP141_WEI) } #[allow(clippy::too_many_arguments)] @@ -294,7 +291,7 @@ impl FungibleTokenOps { &mut self, sender_id: AccountId, receiver_id: AccountId, - amount: Balance, + amount: NEP141Wei, memo: &Option, msg: String, current_account_id: AccountId, @@ -305,7 +302,7 @@ impl FungibleTokenOps { self.internal_transfer_eth_on_near(&sender_id, &receiver_id, amount, memo)?; } let data1: String = NEP141FtOnTransferArgs { - amount, + amount: Balance::new(amount.as_u128()), msg, sender_id: sender_id.clone(), } @@ -325,15 +322,14 @@ impl FungibleTokenOps { method: "ft_on_transfer".to_string(), args: data1.into_bytes(), attached_balance: ZERO_ATTACHED_BALANCE, - attached_gas: (prepaid_gas - GAS_FOR_FT_TRANSFER_CALL - GAS_FOR_RESOLVE_TRANSFER) - .into_u64(), + attached_gas: prepaid_gas - GAS_FOR_FT_TRANSFER_CALL - GAS_FOR_RESOLVE_TRANSFER, }; let ft_resolve_transfer_call = PromiseCreateArgs { target_account_id: current_account_id, method: "ft_resolve_transfer".to_string(), args: data2, attached_balance: ZERO_ATTACHED_BALANCE, - attached_gas: GAS_FOR_RESOLVE_TRANSFER.into_u64(), + attached_gas: GAS_FOR_RESOLVE_TRANSFER, }; Ok(PromiseWithCallbackArgs { base: ft_on_transfer_call, @@ -346,15 +342,17 @@ impl FungibleTokenOps { promise_result: PromiseResult, sender_id: &AccountId, receiver_id: &AccountId, - amount: Balance, - ) -> (Balance, Balance) { + amount: NEP141Wei, + ) -> (NEP141Wei, NEP141Wei) { // Get the unused amount from the `ft_on_transfer` call result. let unused_amount = match promise_result { PromiseResult::NotReady => unreachable!(), PromiseResult::Successful(value) => { - if let Some(unused_amount) = + if let Some(raw_unused_amount) = parse_json(value.as_slice()).and_then(|x| (&x).try_into().ok()) { + let unused_amount = NEP141Wei::new(raw_unused_amount); + // let unused_amount = Balance::from(raw_unused_amount); if amount > unused_amount { unused_amount } else { @@ -367,14 +365,14 @@ impl FungibleTokenOps { PromiseResult::Failed => amount, }; - if unused_amount > 0 { + if unused_amount > ZERO_NEP141_WEI { let receiver_balance = self .get_account_eth_balance(receiver_id) .unwrap_or_else(|| { - self.accounts_insert(receiver_id, 0); - 0 + self.accounts_insert(receiver_id, ZERO_NEP141_WEI); + ZERO_NEP141_WEI }); - if receiver_balance > 0 { + if receiver_balance > ZERO_NEP141_WEI { let refund_amount = if receiver_balance > unused_amount { unused_amount } else { @@ -395,7 +393,7 @@ impl FungibleTokenOps { receiver_id, sender_id )); - (amount - refund_amount, 0) + (amount - refund_amount, ZERO_NEP141_WEI) } else { // Sender's account was deleted, so we need to burn tokens. self.total_eth_supply_on_near -= refund_amount; @@ -404,7 +402,7 @@ impl FungibleTokenOps { }; } } - (amount, 0) + (amount, ZERO_NEP141_WEI) } pub fn ft_resolve_transfer( @@ -412,8 +410,8 @@ impl FungibleTokenOps { promise_result: PromiseResult, sender_id: &AccountId, receiver_id: &AccountId, - amount: Balance, - ) -> Balance { + amount: NEP141Wei, + ) -> NEP141Wei { self.internal_ft_resolve_transfer(promise_result, sender_id, receiver_id, amount) .0 } @@ -422,16 +420,16 @@ impl FungibleTokenOps { &mut self, account_id: AccountId, force: Option, - ) -> Result<(Balance, PromiseBatchAction), error::StorageFundingError> { + ) -> Result<(NEP141Wei, PromiseBatchAction), error::StorageFundingError> { let force = force.unwrap_or(false); if let Some(balance) = self.get_account_eth_balance(&account_id) { - if balance == 0 || force { + if balance == ZERO_NEP141_WEI || force { self.accounts_remove(&account_id); self.total_eth_supply_on_near -= balance; let storage_deposit = self.storage_balance_of(&account_id); let action = PromiseAction::Transfer { // The `+ 1` is to cover the 1 yoctoNEAR necessary to call this function in the first place. - amount: storage_deposit.total + 1, + amount: storage_deposit.total + Yocto::new(1), }; let promise = PromiseBatchAction { target_account_id: account_id, @@ -452,7 +450,7 @@ impl FungibleTokenOps { pub fn storage_balance_bounds(&self) -> StorageBalanceBounds { let required_storage_balance = - Balance::from(self.account_storage_usage) * sdk::storage_byte_cost(); + Yocto::new(self.account_storage_usage as u128 * sdk::storage_byte_cost() as u128); StorageBalanceBounds { min: required_storage_balance, max: Some(required_storage_balance), @@ -463,7 +461,7 @@ impl FungibleTokenOps { if self.accounts_contains_key(account_id) { Some(StorageBalance { total: self.storage_balance_bounds().min, - available: 0, + available: ZERO_YOCTO, }) } else { None @@ -481,12 +479,12 @@ impl FungibleTokenOps { &mut self, predecessor_account_id: AccountId, account_id: &AccountId, - amount: Balance, + amount: Yocto, registration_only: Option, ) -> Result<(StorageBalance, Option), error::StorageFundingError> { let promise = if self.accounts_contains_key(account_id) { sdk::log!("The account is already registered, refunding the deposit"); - if amount > 0 { + if amount > ZERO_YOCTO { let action = PromiseAction::Transfer { amount }; let promise = PromiseBatchAction { target_account_id: predecessor_account_id, @@ -504,7 +502,7 @@ impl FungibleTokenOps { self.internal_register_account(account_id); let refund = amount - min_balance; - if refund > 0 { + if refund > ZERO_YOCTO { let action = PromiseAction::Transfer { amount: refund }; let promise = PromiseBatchAction { target_account_id: predecessor_account_id, @@ -522,11 +520,11 @@ impl FungibleTokenOps { pub fn storage_withdraw( &mut self, account_id: &AccountId, - amount: Option, + amount: Option, ) -> Result { if let Some(storage_balance) = self.internal_storage_balance_of(account_id) { match amount { - Some(amount) if amount > 0 => { + Some(amount) if amount > ZERO_YOCTO => { // The available balance is always zero because `StorageBalanceBounds::max` is // equal to `StorageBalanceBounds::min`. Therefore it is impossible to withdraw // a positive amount. @@ -541,7 +539,7 @@ impl FungibleTokenOps { /// Insert account. /// Calculate total unique accounts - pub fn accounts_insert(&mut self, account_id: &AccountId, amount: Balance) { + pub fn accounts_insert(&mut self, account_id: &AccountId, amount: NEP141Wei) { if !self.accounts_contains_key(account_id) { let key = Self::get_statistic_key(); let accounts_counter = self @@ -571,10 +569,10 @@ impl FungibleTokenOps { } /// Balance of nETH (ETH on NEAR token) - pub fn get_account_eth_balance(&self, account_id: &AccountId) -> Option { + pub fn get_account_eth_balance(&self, account_id: &AccountId) -> Option { self.io .read_storage(&Self::account_to_key(account_id)) - .and_then(|s| Balance::try_from_slice(&s.to_vec()).ok()) + .and_then(|s| NEP141Wei::try_from_slice(&s.to_vec()).ok()) } /// Fungible token key @@ -597,7 +595,7 @@ impl FungibleTokenOps { } pub mod error { - use crate::prelude::types::error::BalanceOverflowError; + use crate::prelude::types::balance::error::BalanceOverflowError; const TOTAL_SUPPLY_OVERFLOW: &[u8; 25] = b"ERR_TOTAL_SUPPLY_OVERFLOW"; const BALANCE_OVERFLOW: &[u8; 20] = b"ERR_BALANCE_OVERFLOW"; diff --git a/engine/src/json.rs b/engine/src/json.rs index 81616c2fd..7883e8239 100644 --- a/engine/src/json.rs +++ b/engine/src/json.rs @@ -1,4 +1,4 @@ -use crate::prelude::{BTreeMap, String, TryFrom, TryInto, Vec}; +use crate::prelude::{BTreeMap, String, Vec}; use core::convert::From; use rjson::{Array, Null, Object, Value}; @@ -274,7 +274,6 @@ impl core::fmt::Display for JsonValue { } } -#[allow(dead_code)] pub fn parse_json(data: &[u8]) -> Option { let data_array: Vec = data.iter().map(|b| *b as char).collect::>(); let mut index = 0; diff --git a/engine/src/lib.rs b/engine/src/lib.rs index 04dc19285..40f6f7685 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -1,4 +1,3 @@ -#![feature(array_methods)] #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), feature(alloc_error_handler))] #![cfg_attr(feature = "log", feature(panic_info_message))] @@ -15,7 +14,6 @@ mod map; pub mod meta_parsing; pub mod parameters; pub mod proof; -pub mod transaction; pub mod admin_controlled; #[cfg_attr(feature = "contract", allow(dead_code))] @@ -69,6 +67,7 @@ mod contract { use crate::connector::{self, EthConnectorContract}; use crate::engine::{self, current_address, Engine, EngineState}; use crate::fungible_token::FungibleTokenMetadata; + use crate::json::parse_json; use crate::parameters::{ self, CallArgs, DeployErc20TokenArgs, GetErc20FromNep141CallArgs, GetStorageAtArgs, InitCallArgs, IsUsedProofCallArgs, NEP141FtOnTransferArgs, NewCallArgs, @@ -77,23 +76,20 @@ mod contract { }; #[cfg(feature = "evm_bully")] use crate::parameters::{BeginBlockArgs, BeginChainArgs}; - use aurora_engine_sdk::env::Env; - use aurora_engine_sdk::io::{StorageIntermediate, IO}; - use aurora_engine_sdk::near_runtime::Runtime; - use aurora_engine_sdk::promise::PromiseHandler; - use aurora_engine_types::account_id::AccountId; - - use crate::json::parse_json; + use crate::prelude::account_id::AccountId; use crate::prelude::parameters::RefundCallArgs; use crate::prelude::sdk::types::{ near_account_to_evm_address, SdkExpect, SdkProcess, SdkUnwrap, }; use crate::prelude::storage::{bytes_to_key, KeyPrefix}; - use crate::prelude::types::{u256_to_arr, ERR_FAILED_PARSE}; use crate::prelude::{ - sdk, vec, Address, PromiseResult, ToString, TryFrom, TryInto, Vec, Wei, - ERC20_MINT_SELECTOR, H256, U256, + sdk, u256_to_arr, vec, Address, PromiseResult, ToString, Vec, Wei, Yocto, + ERC20_MINT_SELECTOR, ERR_FAILED_PARSE, H256, U256, }; + use aurora_engine_sdk::env::Env; + use aurora_engine_sdk::io::{StorageIntermediate, IO}; + use aurora_engine_sdk::near_runtime::Runtime; + use aurora_engine_sdk::promise::PromiseHandler; #[cfg(feature = "integration-test")] use crate::prelude::NearGas; @@ -180,6 +176,7 @@ mod contract { pub extern "C" fn deploy_upgrade() { let io = Runtime; let state = engine::get_state(&io).sdk_unwrap(); + require_owner_only(&state, &io.predecessor_account_id()); let index = internal_get_upgrade_index(); if io.block_height() <= index + state.upgrade_delay_blocks { sdk::panic_utf8(b"ERR_NOT_ALLOWED:TOO_EARLY"); @@ -282,8 +279,8 @@ mod contract { let mut engine = Engine::new_with_state(state, meta_call_args.sender, current_account_id, io, &io); let result = engine.call( - meta_call_args.sender, - meta_call_args.contract_address, + &meta_call_args.sender, + &meta_call_args.contract_address, meta_call_args.value, meta_call_args.input, u64::MAX, // TODO: is there a gas limit with meta calls? @@ -309,7 +306,10 @@ mod contract { &io, ) .sdk_unwrap(); - engine.register_relayer(predecessor_account_id.as_bytes(), Address(relayer_address)); + engine.register_relayer( + predecessor_account_id.as_bytes(), + Address::from_array(relayer_address), + ); } /// Allow receiving NEP141 tokens to the EVM contract. @@ -391,20 +391,20 @@ mod contract { let erc20_admin_address = current_address(¤t_account_id); let mut engine = Engine::new(erc20_admin_address, current_account_id, io, &io).sdk_unwrap(); - let erc20_address = Address(erc20_address); - let refund_address = Address(args.recipient_address); + let erc20_address = erc20_address; + let refund_address = args.recipient_address; let amount = U256::from_big_endian(&args.amount); let selector = ERC20_MINT_SELECTOR; let mint_args = ethabi::encode(&[ - ethabi::Token::Address(refund_address), + ethabi::Token::Address(refund_address.raw()), ethabi::Token::Uint(amount), ]); engine .call( - erc20_admin_address, - erc20_address, + &erc20_admin_address, + &erc20_address, Wei::zero(), [selector, mint_args.as_slice()].concat(), u64::MAX, @@ -418,16 +418,19 @@ mod contract { let exit_address = aurora_engine_precompiles::native::ExitToNear::ADDRESS; let mut engine = Engine::new(exit_address, current_account_id, io, &io).sdk_unwrap(); - let refund_address = Address(args.recipient_address); + let refund_address = args.recipient_address; let amount = Wei::new(U256::from_big_endian(&args.amount)); engine .call( - exit_address, - refund_address, + &exit_address, + &refund_address, amount, Vec::new(), u64::MAX, - vec![(exit_address, Vec::new()), (refund_address, Vec::new())], + vec![ + (exit_address.raw(), Vec::new()), + (refund_address.raw(), Vec::new()), + ], &mut Runtime, ) .sdk_unwrap() @@ -448,13 +451,7 @@ mod contract { let mut io = Runtime; let args: ViewCallArgs = io.read_input_borsh().sdk_unwrap(); let current_account_id = io.current_account_id(); - let engine = Engine::new( - Address::from_slice(&args.sender), - current_account_id, - io, - &io, - ) - .sdk_unwrap(); + let engine = Engine::new(args.sender, current_account_id, io, &io).sdk_unwrap(); let result = Engine::view_with_args(&engine, args).sdk_unwrap(); io.return_output(&result.try_to_vec().sdk_expect("ERR_SERIALIZE")); } @@ -476,7 +473,7 @@ mod contract { pub extern "C" fn get_code() { let mut io = Runtime; let address = io.read_input_arr20().sdk_unwrap(); - let code = engine::get_code(&io, &Address(address)); + let code = engine::get_code(&io, &Address::from_array(address)); io.return_output(&code) } @@ -484,7 +481,7 @@ mod contract { pub extern "C" fn get_balance() { let mut io = Runtime; let address = io.read_input_arr20().sdk_unwrap(); - let balance = engine::get_balance(&io, &Address(address)); + let balance = engine::get_balance(&io, &Address::from_array(address)); io.return_output(&balance.to_bytes()) } @@ -492,7 +489,7 @@ mod contract { pub extern "C" fn get_nonce() { let mut io = Runtime; let address = io.read_input_arr20().sdk_unwrap(); - let nonce = engine::get_nonce(&io, &Address(address)); + let nonce = engine::get_nonce(&io, &Address::from_array(address)); io.return_output(&u256_to_arr(&nonce)) } @@ -500,9 +497,9 @@ mod contract { pub extern "C" fn get_storage_at() { let mut io = Runtime; let args: GetStorageAtArgs = io.read_input_borsh().sdk_unwrap(); - let address = Address(args.address); + let address = args.address; let generation = engine::get_generation(&io, &address); - let value = engine::get_storage(&io, &Address(args.address), &H256(args.key), generation); + let value = engine::get_storage(&io, &args.address, &H256(args.key), generation); io.return_output(&value.0) } @@ -522,8 +519,8 @@ mod contract { for account_balance in args.genesis_alloc { engine::set_balance( &mut io, - &Address(account_balance.address), - &crate::prelude::types::Wei::new(U256::from(account_balance.balance)), + &account_balance.address, + &crate::prelude::Wei::new(U256::from(account_balance.balance)), ) } // return new chain ID @@ -732,7 +729,7 @@ mod contract { let mut io = Runtime; let args = StorageDepositCallArgs::from(parse_json(&io.read_input().to_vec()).sdk_unwrap()); let predecessor_account_id = io.predecessor_account_id(); - let amount = io.attached_deposit(); + let amount = Yocto::new(io.attached_deposit()); let maybe_promise = EthConnectorContract::init_instance(io) .storage_deposit(predecessor_account_id, amount, args) .sdk_unwrap(); @@ -846,20 +843,25 @@ mod contract { #[cfg(feature = "integration-test")] #[no_mangle] pub extern "C" fn mint_account() { + use crate::connector::ZERO_ATTACHED_BALANCE; + use crate::prelude::NEP141Wei; use evm::backend::ApplyBackend; const GAS_FOR_VERIFY: NearGas = NearGas::new(20_000_000_000_000); const GAS_FOR_FINISH: NearGas = NearGas::new(50_000_000_000_000); let mut io = Runtime; let args: ([u8; 20], u64, u64) = io.read_input_borsh().sdk_expect("ERR_ARGS"); - let address = Address(args.0); + let address = Address::from_array(args.0); let nonce = U256::from(args.1); - let balance = U256::from(args.2); + let balance = NEP141Wei::new(args.2 as u128); let current_account_id = io.current_account_id(); let mut engine = Engine::new(address, current_account_id, io, &io).sdk_unwrap(); let state_change = evm::backend::Apply::Modify { - address, - basic: evm::backend::Basic { balance, nonce }, + address: address.raw(), + basic: evm::backend::Basic { + balance: U256::from(balance.as_u128()), + nonce, + }, code: None, storage: core::iter::empty(), reset_storage: false, @@ -871,7 +873,7 @@ mod contract { let aurora_account_id = io.current_account_id(); let args = crate::parameters::FinishDepositCallArgs { new_owner_id: aurora_account_id.clone(), - amount: balance.low_u128(), + amount: balance, proof_key: crate::prelude::String::new(), relayer_id: aurora_account_id.clone(), fee: 0.into(), @@ -881,15 +883,15 @@ mod contract { target_account_id: aurora_account_id.clone(), method: "verify_log_entry".to_string(), args: Vec::new(), - attached_balance: 0, - attached_gas: GAS_FOR_VERIFY.into_u64(), + attached_balance: ZERO_ATTACHED_BALANCE, + attached_gas: GAS_FOR_VERIFY, }; let finish_call = aurora_engine_types::parameters::PromiseCreateArgs { target_account_id: aurora_account_id, method: "finish_deposit".to_string(), args: args.try_to_vec().unwrap(), - attached_balance: 0, - attached_gas: GAS_FOR_FINISH.into_u64(), + attached_balance: ZERO_ATTACHED_BALANCE, + attached_gas: GAS_FOR_FINISH, }; io.promise_crate_with_callback(&aurora_engine_types::parameters::PromiseWithCallbackArgs { base: verify_call, diff --git a/engine/src/map.rs b/engine/src/map.rs index faf69b69e..d3a54bea6 100644 --- a/engine/src/map.rs +++ b/engine/src/map.rs @@ -1,4 +1,4 @@ -pub use crate::prelude::{bytes_to_key, PhantomData, TryFrom, TryInto, Vec}; +pub use crate::prelude::{bytes_to_key, PhantomData, Vec}; use aurora_engine_sdk::io::{StorageIntermediate, IO}; use aurora_engine_types::storage::KeyPrefix; diff --git a/engine/src/meta_parsing.rs b/engine/src/meta_parsing.rs index 269ae454c..f464f36cc 100644 --- a/engine/src/meta_parsing.rs +++ b/engine/src/meta_parsing.rs @@ -2,7 +2,7 @@ use crate::parameters::MetaCallArgs; use crate::prelude::precompiles::secp256k1::ecrecover; use crate::prelude::{ keccak, u256_to_arr, vec, Address, BorshDeserialize, Box, HashMap, InternalMetaCallArgs, - RawU256, String, ToOwned, ToString, Vec, Wei, H256, U256, + RawU256, String, ToOwned, ToString, Vec, Wei, H160, H256, U256, }; use ethabi::{encode, Token as ABIToken}; use logos::Logos; @@ -160,7 +160,7 @@ pub fn method_sig_to_abi(method_sig: &str) -> [u8; 4] { pub fn encode_address(addr: Address) -> Vec { let mut bytes = vec![0u8; 12]; - bytes.extend_from_slice(&addr.0); + bytes.extend_from_slice(&addr.raw().as_bytes()); bytes } @@ -369,9 +369,11 @@ fn eip_712_hash_argument( ArgType::Uint | ArgType::Int | ArgType::Bool => eip_712_rlp_value(value, |b| { Ok(u256_to_arr(&U256::from_big_endian(b)).to_vec()) }), - ArgType::Address => { - eip_712_rlp_value(value, |b| Ok(encode_address(Address::from_slice(b)))) - } + ArgType::Address => eip_712_rlp_value(value, |b| { + Ok(encode_address( + Address::try_from_slice(b).map_err(|_| ParsingError::ArgumentParseError)?, + )) + }), ArgType::Array { inner, .. } => eip_712_rlp_list(value, |l| { let mut r = vec![]; for element in l { @@ -447,7 +449,7 @@ fn arg_to_abi_token( value_to_abi_token(arg, |b| Ok(ABIToken::Uint(U256::from_big_endian(b)))) } ArgType::Address => { - value_to_abi_token(arg, |b| Ok(ABIToken::Address(Address::from_slice(b)))) + value_to_abi_token(arg, |b| Ok(ABIToken::Address(H160::from_slice(&b[..])))) } ArgType::Array { inner, @@ -578,8 +580,8 @@ pub fn parse_meta_call( MetaCallArgs::try_from_slice(&args).map_err(|_| ParsingError::ArgumentParseError)?; let nonce = U256::from(meta_tx.nonce); let fee_amount = Wei::new(U256::from(meta_tx.fee_amount)); - let fee_address = Address::from(meta_tx.fee_address); - let contract_address = Address::from(meta_tx.contract_address); + let fee_address = meta_tx.fee_address; + let contract_address = meta_tx.contract_address; let value = Wei::new(U256::from(meta_tx.value)); let mut result = InternalMetaCallArgs { diff --git a/engine/src/parameters.rs b/engine/src/parameters.rs index d27ce394b..f0fcbcb8d 100644 --- a/engine/src/parameters.rs +++ b/engine/src/parameters.rs @@ -3,11 +3,11 @@ use crate::fungible_token::FungibleTokenMetadata; use crate::json::{JsonError, JsonValue}; use crate::prelude::account_id::AccountId; use crate::prelude::{ - format, Balance, BorshDeserialize, BorshSerialize, EthAddress, RawAddress, RawH256, RawU256, - String, ToString, TryFrom, Vec, WeiU256, + format, Address, Balance, BorshDeserialize, BorshSerialize, RawH256, RawU256, String, Vec, + WeiU256, }; use crate::proof::Proof; -use aurora_engine_types::types::Fee; +use aurora_engine_types::types::{Fee, NEP141Wei, Yocto}; use evm::backend::Log; /// Borsh-encoded parameters for the `new` function. @@ -32,8 +32,8 @@ pub struct MetaCallArgs { pub v: u8, pub nonce: RawU256, pub fee_amount: RawU256, - pub fee_address: RawAddress, - pub contract_address: RawAddress, + pub fee_address: Address, + pub contract_address: Address, pub value: RawU256, pub method_def: String, pub args: Vec, @@ -42,7 +42,7 @@ pub struct MetaCallArgs { /// Borsh-encoded log for use in a `SubmitResult`. #[derive(Debug, BorshSerialize, BorshDeserialize)] pub struct ResultLog { - pub address: RawAddress, + pub address: Address, pub topics: Vec, pub data: Vec, } @@ -55,7 +55,7 @@ impl From for ResultLog { .map(|topic| topic.0) .collect::>(); ResultLog { - address: log.address.0, + address: Address::new(log.address), topics, data: log.data, } @@ -134,7 +134,7 @@ impl SubmitResult { /// Borsh-encoded parameters for the engine `call` function. #[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq, Clone)] pub struct FunctionCallArgsV2 { - pub contract: RawAddress, + pub contract: Address, /// Wei compatible Borsh-encoded value field to attach an ETH balance to the transaction pub value: WeiU256, pub input: Vec, @@ -143,7 +143,7 @@ pub struct FunctionCallArgsV2 { /// Legacy Borsh-encoded parameters for the engine `call` function, to provide backward type compatibility #[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq, Clone)] pub struct FunctionCallArgsV1 { - pub contract: RawAddress, + pub contract: Address, pub input: Vec, } @@ -176,8 +176,8 @@ impl CallArgs { /// Borsh-encoded parameters for the `view` function. #[derive(BorshSerialize, BorshDeserialize, Debug, Eq, PartialEq)] pub struct ViewCallArgs { - pub sender: RawAddress, - pub address: RawAddress, + pub sender: Address, + pub address: Address, pub amount: RawU256, pub input: Vec, } @@ -194,7 +194,7 @@ pub type GetErc20FromNep141CallArgs = DeployErc20TokenArgs; /// Borsh-encoded parameters for the `get_storage_at` function. #[derive(BorshSerialize, BorshDeserialize)] pub struct GetStorageAtArgs { - pub address: RawAddress, + pub address: Address, pub key: RawH256, } @@ -202,7 +202,7 @@ pub struct GetStorageAtArgs { #[cfg(feature = "evm_bully")] #[derive(BorshSerialize, BorshDeserialize)] pub struct AccountBalance { - pub address: RawAddress, + pub address: Address, pub balance: RawU256, } @@ -221,7 +221,7 @@ pub struct BeginBlockArgs { /// The current block's hash (for replayer use). pub hash: RawU256, /// The current block's beneficiary address. - pub coinbase: RawAddress, + pub coinbase: Address, /// The current block's timestamp (in seconds since the Unix epoch). pub timestamp: RawU256, /// The current block's number (the genesis block is number zero). @@ -237,6 +237,8 @@ pub struct BeginBlockArgs { #[derive(Debug, Clone)] pub struct NEP141FtOnTransferArgs { pub sender_id: AccountId, + /// Balance can be for Eth on Near and for Eth to Aurora + /// `ft_on_transfer` can be called with arbitrary NEP-141 tokens attached, therefore we do not specify a particular type Wei. pub amount: Balance, pub msg: String, } @@ -248,7 +250,7 @@ impl TryFrom for NEP141FtOnTransferArgs { Ok(Self { sender_id: AccountId::try_from(value.string("sender_id")?) .map_err(|_| JsonError::InvalidString)?, - amount: value.u128("amount")?, + amount: Balance::new(value.u128("amount")?), msg: value.string("msg")?, }) } @@ -261,7 +263,7 @@ impl From for String { value.sender_id, value.amount, // Escape message to avoid json injection attacks - value.msg.replace("\\", "\\\\").replace("\"", "\\\"") + value.msg.replace('\\', "\\\\").replace('"', "\\\"") ) } } @@ -272,7 +274,7 @@ pub struct DepositCallArgs { /// Proof data pub proof: Proof, /// Optional relayer address - pub relayer_eth_account: Option, + pub relayer_eth_account: Option
, } /// Eth-connector isUsedProof arguments @@ -286,27 +288,25 @@ pub struct IsUsedProofCallArgs { #[derive(BorshSerialize)] #[cfg_attr(not(target_arch = "wasm32"), derive(BorshDeserialize))] pub struct WithdrawResult { - pub amount: Balance, - pub recipient_id: RawAddress, - pub eth_custodian_address: RawAddress, + pub amount: NEP141Wei, + pub recipient_id: Address, + pub eth_custodian_address: Address, } /// Fungible token storage balance #[derive(Default)] pub struct StorageBalance { - pub total: Balance, - pub available: Balance, + pub total: Yocto, + pub available: Yocto, } impl StorageBalance { pub fn to_json_bytes(&self) -> Vec { format!( "{{\"total\": \"{}\", \"available\": \"{}\"}}", - self.total.to_string(), - self.available.to_string() + self.total, self.available ) - .as_bytes() - .to_vec() + .into_bytes() } } @@ -314,7 +314,7 @@ impl StorageBalance { #[derive(BorshSerialize, BorshDeserialize)] pub struct ResolveTransferCallArgs { pub sender_id: AccountId, - pub amount: Balance, + pub amount: NEP141Wei, pub receiver_id: AccountId, } @@ -322,7 +322,7 @@ pub struct ResolveTransferCallArgs { #[derive(BorshSerialize, BorshDeserialize)] pub struct FinishDepositCallArgs { pub new_owner_id: AccountId, - pub amount: Balance, + pub amount: NEP141Wei, pub proof_key: String, pub relayer_id: AccountId, pub fee: Fee, @@ -333,14 +333,14 @@ pub struct FinishDepositCallArgs { #[derive(Default, BorshDeserialize, BorshSerialize, Clone)] pub struct DepositEthCallArgs { pub proof: Proof, - pub relayer_eth_account: EthAddress, + pub relayer_eth_account: Address, } /// Finish deposit NEAR eth-connector call args #[derive(BorshSerialize, BorshDeserialize)] pub struct FinishDepositEthCallArgs { - pub new_owner_id: EthAddress, - pub amount: Balance, + pub new_owner_id: Address, + pub amount: NEP141Wei, pub fee: Balance, pub relayer_eth_account: AccountId, pub proof: Proof, @@ -361,7 +361,7 @@ pub type SetContractDataCallArgs = InitCallArgs; #[derive(BorshSerialize, BorshDeserialize)] pub struct TransferCallCallArgs { pub receiver_id: AccountId, - pub amount: Balance, + pub amount: NEP141Wei, pub memo: Option, pub msg: String, } @@ -371,7 +371,7 @@ impl TryFrom for TransferCallCallArgs { fn try_from(v: JsonValue) -> Result { let receiver_id = AccountId::try_from(v.string("receiver_id")?)?; - let amount = v.u128("amount")?; + let amount = NEP141Wei::new(v.u128("amount")?); let memo = v.string("memo").ok(); let msg = v.string("msg")?; Ok(Self { @@ -419,13 +419,13 @@ impl From for StorageDepositCallArgs { /// storage_withdraw eth-connector call args #[derive(BorshSerialize, BorshDeserialize)] pub struct StorageWithdrawCallArgs { - pub amount: Option, + pub amount: Option, } impl From for StorageWithdrawCallArgs { fn from(v: JsonValue) -> Self { Self { - amount: v.u128("amount").ok(), + amount: v.u128("amount").map(Yocto::new).ok(), } } } @@ -434,7 +434,7 @@ impl From for StorageWithdrawCallArgs { #[derive(BorshSerialize, BorshDeserialize)] pub struct TransferCallArgs { pub receiver_id: AccountId, - pub amount: Balance, + pub amount: NEP141Wei, pub memo: Option, } @@ -444,7 +444,7 @@ impl TryFrom for TransferCallArgs { fn try_from(v: JsonValue) -> Result { Ok(Self { receiver_id: AccountId::try_from(v.string("receiver_id")?)?, - amount: v.u128("amount")?, + amount: NEP141Wei::new(v.u128("amount")?), memo: v.string("memo").ok(), }) } @@ -458,7 +458,7 @@ pub struct BalanceOfCallArgs { #[derive(BorshSerialize, BorshDeserialize)] pub struct BalanceOfEthCallArgs { - pub address: EthAddress, + pub address: Address, } impl TryFrom for BalanceOfCallArgs { @@ -473,7 +473,7 @@ impl TryFrom for BalanceOfCallArgs { #[derive(BorshSerialize, BorshDeserialize)] pub struct RegisterRelayerCallArgs { - pub address: EthAddress, + pub address: Address, } #[derive(BorshSerialize, BorshDeserialize)] @@ -488,7 +488,7 @@ impl TryFrom for ResolveTransferCallArgs { Ok(Self { sender_id: AccountId::try_from(v.string("sender_id")?)?, receiver_id: AccountId::try_from(v.string("receiver_id")?)?, - amount: v.u128("amount")?, + amount: NEP141Wei::new(v.u128("amount")?), }) } } @@ -537,8 +537,8 @@ mod tests { #[test] fn test_roundtrip_view_call() { let x = ViewCallArgs { - sender: [1; 20], - address: [2; 20], + sender: Address::from_array([1; 20]), + address: Address::from_array([2; 20]), amount: [3; 32], input: vec![1, 2, 3], }; @@ -550,12 +550,12 @@ mod tests { #[test] fn test_call_args_deserialize() { let new_input = FunctionCallArgsV2 { - contract: [0u8; 20], + contract: Address::from_array([0u8; 20]), value: WeiU256::default(), input: Vec::new(), }; let legacy_input = FunctionCallArgsV1 { - contract: [0u8; 20], + contract: Address::from_array([0u8; 20]), input: Vec::new(), }; diff --git a/engine/src/prelude.rs b/engine/src/prelude.rs index b8a4e1a3b..81c80363c 100644 --- a/engine/src/prelude.rs +++ b/engine/src/prelude.rs @@ -2,6 +2,7 @@ mod v0 { pub use aurora_engine_precompiles as precompiles; pub use aurora_engine_sdk as sdk; pub use aurora_engine_sdk::types::*; + pub use aurora_engine_transactions as transactions; pub use aurora_engine_types::account_id::*; pub use aurora_engine_types::parameters::*; pub use aurora_engine_types::storage::*; @@ -9,4 +10,5 @@ mod v0 { pub use aurora_engine_types::*; pub use borsh::{BorshDeserialize, BorshSerialize}; } + pub use v0::*; diff --git a/etc/ft-receiver/Cargo.toml b/etc/ft-receiver/Cargo.toml index 5659857a2..fd05e6f6a 100644 --- a/etc/ft-receiver/Cargo.toml +++ b/etc/ft-receiver/Cargo.toml @@ -2,7 +2,7 @@ name = "ft_receiver" version = "1.0.0" authors = ["Aurora "] -edition = "2018" +edition = "2021" [lib] crate-type = ["cdylib", "rlib"] @@ -10,4 +10,3 @@ crate-type = ["cdylib", "rlib"] [dependencies] near-sdk = "3.1.0" near-contract-standards = "3.2.0" - diff --git a/etc/state-migration-test/Cargo.lock b/etc/state-migration-test/Cargo.lock index c190f43cf..630cd3d04 100644 --- a/etc/state-migration-test/Cargo.lock +++ b/etc/state-migration-test/Cargo.lock @@ -42,9 +42,9 @@ dependencies = [ "aurora-bn", "aurora-engine-precompiles", "aurora-engine-sdk", + "aurora-engine-transactions", "aurora-engine-types", "base64", - "blake2", "borsh", "byte-slice-cast", "ethabi", @@ -53,6 +53,7 @@ dependencies = [ "hex", "libsecp256k1", "logos", + "near-blake2", "num", "primitive-types", "ripemd160", @@ -70,22 +71,18 @@ dependencies = [ "aurora-engine-sdk", "aurora-engine-types", "base64", - "blake2", "borsh", "ethabi", "evm", "evm-core", "hex", "libsecp256k1", - "logos", + "near-blake2", "num", "primitive-types", "ripemd160", - "rjson", - "rlp", "sha2", "sha3 0.9.1", - "wee_alloc", ] [[package]] @@ -108,6 +105,18 @@ dependencies = [ "borsh", ] +[[package]] +name = "aurora-engine-transactions" +version = "1.0.0" +dependencies = [ + "aurora-engine-precompiles", + "aurora-engine-sdk", + "aurora-engine-types", + "evm", + "hex", + "rlp", +] + [[package]] name = "aurora-engine-types" version = "1.0.0" @@ -119,6 +128,18 @@ dependencies = [ "sha3 0.9.1", ] +[[package]] +name = "auto_impl" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7862e21c893d65a1650125d157eaeec691439379a1cee17ee49031b79236ada4" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.0.1" @@ -137,16 +158,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6736e2428df2ca2848d846c43e88745121a6654696e349ce0054a420815a7409" -[[package]] -name = "blake2" -version = "0.9.1" -source = "git+https://github.com/near/near-blake2.git#736ff607cc8160af87ffa697c14ebef85050138f" -dependencies = [ - "crypto-mac", - "digest 0.9.0", - "opaque-debug 0.3.0", -] - [[package]] name = "block-buffer" version = "0.7.3" @@ -383,9 +394,10 @@ dependencies = [ [[package]] name = "evm" -version = "0.31.1" -source = "git+https://github.com/aurora-is-near/sputnikvm.git#0fbde9fa7797308290f89111c6abe5cee55a5eac" +version = "0.33.1" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?rev=f4ee520254856898d451c7225851520a35c97cea#f4ee520254856898d451c7225851520a35c97cea" dependencies = [ + "auto_impl", "ethereum", "evm-core", "evm-gasometer", @@ -398,8 +410,8 @@ dependencies = [ [[package]] name = "evm-core" -version = "0.31.0" -source = "git+https://github.com/aurora-is-near/sputnikvm.git#0fbde9fa7797308290f89111c6abe5cee55a5eac" +version = "0.33.0" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?rev=f4ee520254856898d451c7225851520a35c97cea#f4ee520254856898d451c7225851520a35c97cea" dependencies = [ "funty", "primitive-types", @@ -407,8 +419,8 @@ dependencies = [ [[package]] name = "evm-gasometer" -version = "0.31.0" -source = "git+https://github.com/aurora-is-near/sputnikvm.git#0fbde9fa7797308290f89111c6abe5cee55a5eac" +version = "0.33.0" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?rev=f4ee520254856898d451c7225851520a35c97cea#f4ee520254856898d451c7225851520a35c97cea" dependencies = [ "evm-core", "evm-runtime", @@ -417,9 +429,10 @@ dependencies = [ [[package]] name = "evm-runtime" -version = "0.31.0" -source = "git+https://github.com/aurora-is-near/sputnikvm.git#0fbde9fa7797308290f89111c6abe5cee55a5eac" +version = "0.33.0" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?rev=f4ee520254856898d451c7225851520a35c97cea#f4ee520254856898d451c7225851520a35c97cea" dependencies = [ + "auto_impl", "evm-core", "primitive-types", "sha3 0.8.2", @@ -618,6 +631,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" +[[package]] +name = "near-blake2" +version = "0.9.1" +source = "git+https://github.com/near/near-blake2.git#cebb7df79608a7058017940830d37c37d55d21fe" +dependencies = [ + "crypto-mac", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + [[package]] name = "num" version = "0.4.0" @@ -768,6 +791,30 @@ dependencies = [ "toml", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.26" diff --git a/etc/state-migration-test/Cargo.toml b/etc/state-migration-test/Cargo.toml index 8f7f85128..0c3f92502 100644 --- a/etc/state-migration-test/Cargo.toml +++ b/etc/state-migration-test/Cargo.toml @@ -2,7 +2,7 @@ name = "aurora-engine-state-migration-test" version = "1.0.0" authors = ["NEAR "] -edition = "2018" +edition = "2021" description = "" documentation = "" readme = true diff --git a/rust-toolchain b/rust-toolchain index d00399aad..2a84a09b7 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2021-08-01" +channel = "nightly-2022-01-26" components = [] targets = ["wasm32-unknown-unknown"]