From 2fd12731c140b0d0407f75eec565c49dbedb645a Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Fri, 21 Jul 2023 15:51:51 +0800 Subject: [PATCH 01/32] WIP: counter contract --- .gitignore | 3 + lib/Cargo.lock | 1544 ++++++++++++++++- lib/ain-evm/src/backend.rs | 47 + lib/ain-evm/src/evm.rs | 15 + lib/ain-evm/src/executor.rs | 10 + lib/ain-evm/src/lib.rs | 4 +- lib/ain-evm/src/transaction/mod.rs | 2 + lib/ain-evm/src/transaction/system.rs | 14 + lib/ain-evm/src/txqueue.rs | 3 + lib/ain-rs-exports/Cargo.toml | 7 + lib/ain-rs-exports/build.rs | 43 +- .../counter_contract/Counter.sol | 10 + lib/ain-rs-exports/src/counter_contract.rs | 75 + lib/ain-rs-exports/src/lib.rs | 3 + make.sh | 8 + src/masternodes/validation.cpp | 12 +- test/functional/feature_evm.py | 8 + 17 files changed, 1771 insertions(+), 37 deletions(-) create mode 100644 lib/ain-evm/src/transaction/system.rs create mode 100644 lib/ain-rs-exports/counter_contract/Counter.sol create mode 100644 lib/ain-rs-exports/src/counter_contract.rs diff --git a/.gitignore b/.gitignore index 33d619c7e44..76f895846d4 100644 --- a/.gitignore +++ b/.gitignore @@ -147,3 +147,6 @@ contrib/devtools/split-debug.sh # Rust local artifacts /lib/target *.bin + +/lib/ain-rs-exports/**/cache +/lib/ain-rs-exports/**/output \ No newline at end of file diff --git a/lib/Cargo.lock b/lib/Cargo.lock index c82fbe4bb50..c7b927d67ef 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -36,6 +36,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aes" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "ahash" version = "0.7.6" @@ -173,13 +184,18 @@ version = "0.1.0" dependencies = [ "ain-evm", "ain-grpc", + "anyhow", "cxx", "cxx-gen", "ethereum", + "ethers", + "ethers-solc", + "hex", "log", "primitive-types", "proc-macro2", "rlp", + "serde_json", ] [[package]] @@ -245,6 +261,15 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + [[package]] name = "async-trait" version = "0.1.68" @@ -256,6 +281,17 @@ dependencies = [ "syn 2.0.18", ] +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version", +] + [[package]] name = "atty" version = "0.2.14" @@ -340,11 +376,17 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.6.2", "object 0.30.4", "rustc-demangle", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base58" version = "0.2.0" @@ -363,6 +405,12 @@ version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bcs" version = "0.1.5" @@ -373,6 +421,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "bech32" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dabbe35f96fb9507f7330793dc490461b2962659ac5d427181e451a623751d1" + [[package]] name = "beef" version = "0.5.2" @@ -411,12 +465,37 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitvec" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" +dependencies = [ + "either", + "radium 0.3.0", +] + [[package]] name = "bitvec" version = "1.0.1" @@ -424,7 +503,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ "funty", - "radium", + "radium 0.7.0", "tap", "wyz", ] @@ -446,7 +525,7 @@ checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" dependencies = [ "arrayref", "arrayvec 0.7.4", - "constant_time_eq", + "constant_time_eq 0.2.6", ] [[package]] @@ -505,6 +584,9 @@ name = "bs58" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +dependencies = [ + "sha2 0.9.9", +] [[package]] name = "bstr" @@ -551,6 +633,19 @@ name = "bytes" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +dependencies = [ + "serde", +] + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] [[package]] name = "bzip2-sys" @@ -563,6 +658,38 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cc" version = "1.0.79" @@ -600,6 +727,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clang-sys" version = "1.6.1" @@ -636,6 +773,74 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "coins-bip32" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b30a84aab436fcb256a2ab3c80663d8aec686e6bae12827bb05fef3e1e439c9f" +dependencies = [ + "bincode", + "bs58", + "coins-core", + "digest 0.10.7", + "getrandom 0.2.10", + "hmac 0.12.1", + "k256", + "lazy_static", + "serde", + "sha2 0.10.7", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f4d04ee18e58356accd644896aeb2094ddeafb6a713e056cef0c0a8e468c15" +dependencies = [ + "bitvec 0.17.4", + "coins-bip32", + "getrandom 0.2.10", + "hmac 0.12.1", + "once_cell", + "pbkdf2 0.12.2", + "rand 0.8.5", + "sha2 0.10.7", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b949a1c63fb7eb591eb7ba438746326aedf0ae843e51ec92ba6bec5bb382c4f" +dependencies = [ + "base64 0.21.2", + "bech32", + "bs58", + "digest 0.10.7", + "generic-array 0.14.7", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2 0.10.7", + "sha3", + "thiserror", +] + +[[package]] +name = "const-oid" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "795bc6e66a8e340f075fcf6227e417a2dc976b92b91f3cdc778bb858778b6747" + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "constant_time_eq" version = "0.2.6" @@ -694,6 +899,27 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + [[package]] name = "crossbeam-epoch" version = "0.9.15" @@ -722,6 +948,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-bigint" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" +dependencies = [ + "generic-array 0.14.7", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -752,6 +990,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + [[package]] name = "curve25519-dalek" version = "2.1.3" @@ -869,6 +1116,22 @@ dependencies = [ "syn 2.0.18", ] +[[package]] +name = "data-encoding" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" + +[[package]] +name = "der" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7ed52955ce76b1554f509074bb357d3fb8ac9b51288a65a3fd480d1dfba946" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -880,6 +1143,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "digest" version = "0.8.1" @@ -905,16 +1174,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", + "const-oid", "crypto-common", "subtle", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "downcast-rs" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + [[package]] name = "dyn-clonable" version = "0.9.0" @@ -942,13 +1239,27 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" +[[package]] +name = "ecdsa" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature 2.1.0", + "spki", +] + [[package]] name = "ed25519" version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ - "signature", + "signature 1.6.4", ] [[package]] @@ -983,6 +1294,61 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +[[package]] +name = "elliptic-curve" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array 0.14.7", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ena" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +dependencies = [ + "log", +] + +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf56acd72bb22d2824e66ae8e9e5ada4d0de17a69c7fd35569dde2ada8ec9116" +dependencies = [ + "base64 0.13.1", + "bytes", + "hex", + "k256", + "log", + "rand 0.8.5", + "rlp", + "serde", + "sha3", + "zeroize", +] + [[package]] name = "env_logger" version = "0.10.0" @@ -1003,8 +1369,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" [[package]] -name = "erased-serde" -version = "0.3.25" +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "erased-serde" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f2b0c2380453a92ea8b6c8e5f64ecaafccddde8ceab55ff7a8ac1029f894569" dependencies = [ @@ -1032,6 +1404,45 @@ dependencies = [ "libc", ] +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes", + "ctr", + "digest 0.10.7", + "hex", + "hmac 0.12.1", + "pbkdf2 0.11.0", + "rand 0.8.5", + "scrypt", + "serde", + "serde_json", + "sha2 0.10.7", + "sha3", + "thiserror", + "uuid", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror", + "uint", +] + [[package]] name = "ethbloom" version = "0.13.0" @@ -1081,6 +1492,252 @@ dependencies = [ "uint", ] +[[package]] +name = "ethers" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b4026b97da8281276744741fac7eb385da905f6093c583331fa2953fdd4253" +dependencies = [ + "ethers-addressbook", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-middleware", + "ethers-providers", + "ethers-signers", + "ethers-solc", +] + +[[package]] +name = "ethers-addressbook" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edcb6ffefc230d8c42874c51b28dc11dbb8de50b27a8fdf92648439d6baa68dc" +dependencies = [ + "ethers-core", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "ethers-contract" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4719a44c3d37ab07c6dea99ab174068d8c35e441b60b6c20ce4e48357273e8" +dependencies = [ + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "ethers-providers", + "ethers-signers", + "futures-util", + "hex", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ethers-contract-abigen" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "155ea1b84d169d231317ed86e307af6f2bed6b40dd17e5e94bc84da21cadb21c" +dependencies = [ + "Inflector", + "dunce", + "ethers-core", + "ethers-etherscan", + "eyre", + "hex", + "prettyplease 0.2.8", + "proc-macro2", + "quote", + "regex", + "reqwest", + "serde", + "serde_json", + "syn 2.0.18", + "toml", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8567ff196c4a37c1a8c90ec73bda0ad2062e191e4f0a6dc4d943e2ec4830fc88" +dependencies = [ + "Inflector", + "ethers-contract-abigen", + "ethers-core", + "hex", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.18", +] + +[[package]] +name = "ethers-core" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60ca2514feb98918a0a31de7e1983c29f2267ebf61b2dc5d4294f91e5b866623" +dependencies = [ + "arrayvec 0.7.4", + "bytes", + "cargo_metadata", + "chrono", + "elliptic-curve", + "ethabi", + "generic-array 0.14.7", + "hex", + "k256", + "num_enum", + "once_cell", + "open-fastrlp", + "rand 0.8.5", + "rlp", + "serde", + "serde_json", + "strum", + "syn 2.0.18", + "tempfile", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "ethers-etherscan" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22b3a8269d3df0ed6364bc05b4735b95f4bf830ce3aef87d5e760fb0e93e5b91" +dependencies = [ + "ethers-core", + "reqwest", + "semver", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-middleware" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0c339aad74ae5c451d27e0e49c7a3c7d22620b119b4f9291d7aa21f72d7f366" +dependencies = [ + "async-trait", + "auto_impl", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-providers", + "ethers-signers", + "futures-channel", + "futures-locks", + "futures-util", + "instant", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", +] + +[[package]] +name = "ethers-providers" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b411b119f1cf0efb69e2190883dee731251882bb21270f893ee9513b3a697c48" +dependencies = [ + "async-trait", + "auto_impl", + "base64 0.21.2", + "bytes", + "enr", + "ethers-core", + "futures-core", + "futures-timer", + "futures-util", + "hashers", + "hex", + "http", + "instant", + "once_cell", + "pin-project", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-tungstenite", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-signers" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4864d387456a9c09a1157fa10e1528b29d90f1d859443acf06a1b23365fb518c" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "elliptic-curve", + "eth-keystore", + "ethers-core", + "hex", + "rand 0.8.5", + "sha2 0.10.7", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-solc" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6c2b9625a2c639d46625f88acc2092a3cb35786c37f7c2128b3ca20f639b3c" +dependencies = [ + "cfg-if", + "dunce", + "ethers-core", + "glob", + "hex", + "home", + "md-5", + "num_cpus", + "once_cell", + "path-slash", + "rayon", + "regex", + "semver", + "serde", + "serde_json", + "solang-parser", + "svm-rs", + "thiserror", + "tiny-keccak", + "tokio", + "tracing", + "walkdir", + "yansi", +] + [[package]] name = "evm" version = "0.39.1" @@ -1132,6 +1789,16 @@ dependencies = [ "sha3", ] +[[package]] +name = "eyre" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "fake" version = "2.6.1" @@ -1163,6 +1830,16 @@ dependencies = [ "instant", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "fixed-hash" version = "0.8.0" @@ -1181,6 +1858,16 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +[[package]] +name = "flate2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +dependencies = [ + "crc32fast", + "miniz_oxide 0.7.1", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1196,6 +1883,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "fs4" version = "0.5.4" @@ -1267,6 +1964,16 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +[[package]] +name = "futures-locks" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" +dependencies = [ + "futures-channel", + "futures-task", +] + [[package]] name = "futures-macro" version = "0.3.28" @@ -1290,6 +1997,16 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" +dependencies = [ + "gloo-timers", + "send_wrapper 0.4.0", +] + [[package]] name = "futures-util" version = "0.3.28" @@ -1334,6 +2051,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -1354,8 +2072,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -1393,6 +2113,29 @@ dependencies = [ "regex", ] +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "h2" version = "0.3.19" @@ -1405,7 +2148,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -1443,12 +2186,27 @@ dependencies = [ ] [[package]] -name = "hashbrown" -version = "0.13.2" +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.3", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "hashers" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" dependencies = [ - "ahash 0.8.3", + "fxhash", ] [[package]] @@ -1542,6 +2300,15 @@ dependencies = [ "hmac 0.8.1", ] +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "http" version = "0.2.9" @@ -1619,7 +2386,7 @@ dependencies = [ "rustls-native-certs", "tokio", "tokio-rustls 0.23.4", - "webpki-roots", + "webpki-roots 0.22.6", ] [[package]] @@ -1726,6 +2493,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + [[package]] name = "indexmap" version = "1.9.3" @@ -1737,6 +2510,25 @@ dependencies = [ "serde", ] +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array 0.14.7", +] + [[package]] name = "instant" version = "0.1.12" @@ -1757,6 +2549,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ipnet" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" + [[package]] name = "is-terminal" version = "0.4.7" @@ -1971,6 +2769,20 @@ dependencies = [ "tracing", ] +[[package]] +name = "k256" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2 0.10.7", + "signature 2.1.0", +] + [[package]] name = "keccak" version = "0.1.4" @@ -2022,6 +2834,34 @@ dependencies = [ "tonic-build", ] +[[package]] +name = "lalrpop" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da4081d44f4611b66c6dd725e6de3169f9f63905421e8626fcb86b6a898998b8" +dependencies = [ + "ascii-canvas", + "bit-set", + "diff", + "ena", + "is-terminal", + "itertools", + "lalrpop-util", + "petgraph", + "regex", + "regex-syntax 0.7.2", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "lalrpop-util" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f35c735096c0293d313e8f2a641627472b83d01b937177fe76e5e2708d31e0d" + [[package]] name = "lazy_static" version = "1.4.0" @@ -2213,6 +3053,15 @@ dependencies = [ "rawpointer", ] +[[package]] +name = "md-5" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "memchr" version = "2.5.0" @@ -2319,6 +3168,15 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.8" @@ -2365,6 +3223,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + [[package]] name = "nohash-hasher" version = "0.2.0" @@ -2478,6 +3342,27 @@ dependencies = [ "libc", ] +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.18", +] + [[package]] name = "object" version = "0.29.0" @@ -2486,7 +3371,7 @@ checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" dependencies = [ "crc32fast", "hashbrown 0.12.3", - "indexmap", + "indexmap 1.9.3", "memchr", ] @@ -2517,6 +3402,31 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec 0.7.4", + "auto_impl", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "openssl-probe" version = "0.1.5" @@ -2530,7 +3440,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2287753623c76f953acd29d15d8100bcab84d29db78fb6f352adb3c53e83b967" dependencies = [ "arrayvec 0.7.4", - "bitvec", + "bitvec 1.0.1", "byte-slice-cast", "bytes", "impl-trait-for-tuples", @@ -2574,17 +3484,34 @@ checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.3.5", "smallvec", "windows-targets 0.48.0", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "paste" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +[[package]] +name = "path-slash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" + [[package]] name = "pbkdf2" version = "0.8.0" @@ -2601,6 +3528,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ "digest 0.10.7", + "hmac 0.12.1", + "password-hash", + "sha2 0.10.7", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "hmac 0.12.1", ] [[package]] @@ -2622,7 +3562,68 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" dependencies = [ "fixedbitset", - "indexmap", + "indexmap 1.9.3", +] + +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", ] [[package]] @@ -2657,6 +3658,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.27" @@ -2669,6 +3680,12 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + [[package]] name = "prettyplease" version = "0.1.25" @@ -2818,6 +3835,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" + [[package]] name = "radium" version = "0.7.0" @@ -2939,6 +3962,28 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + [[package]] name = "rdrand" version = "0.4.0" @@ -2948,6 +3993,15 @@ dependencies = [ "rand_core 0.3.1", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_syscall" version = "0.3.5" @@ -2957,6 +4011,17 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom 0.2.10", + "redox_syscall 0.2.16", + "thiserror", +] + [[package]] name = "ref-cast" version = "1.0.16" @@ -3018,6 +4083,55 @@ dependencies = [ "winapi", ] +[[package]] +name = "reqwest" +version = "0.11.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +dependencies = [ + "base64 0.21.2", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls 0.24.0", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.2", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-rustls 0.24.1", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.22.6", + "winreg", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + [[package]] name = "ring" version = "0.16.20" @@ -3100,7 +4214,16 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" name = "rustc-hex" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] [[package]] name = "rustix" @@ -3206,13 +4329,31 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scale-info" version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b569c32c806ec3abdf3b5869fb8bf1e0d275a7c1c9b0b05603d9464632649edf" dependencies = [ - "bitvec", + "bitvec 1.0.1", "cfg-if", "derive_more", "parity-scale-codec", @@ -3281,6 +4422,18 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac 0.12.1", + "pbkdf2 0.11.0", + "salsa20", + "sha2 0.10.7", +] + [[package]] name = "sct" version = "0.7.0" @@ -3291,6 +4444,20 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array 0.14.7", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "secp256k1" version = "0.24.3" @@ -3341,6 +4508,27 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +dependencies = [ + "serde", +] + +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + [[package]] name = "serde" version = "1.0.164" @@ -3372,6 +4560,27 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_with" version = "3.0.0" @@ -3381,7 +4590,7 @@ dependencies = [ "base64 0.21.2", "chrono", "hex", - "indexmap", + "indexmap 1.9.3", "serde", "serde_json", "serde_with_macros", @@ -3400,6 +4609,17 @@ dependencies = [ "syn 2.0.18", ] +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "sha2" version = "0.8.2" @@ -3467,6 +4687,16 @@ version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + [[package]] name = "simba" version = "0.6.0" @@ -3480,6 +4710,12 @@ dependencies = [ "wide", ] +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + [[package]] name = "slab" version = "0.4.8" @@ -3505,6 +4741,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "solang-parser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c792fe9fae2a2f716846f214ca10d5a1e21133e0bf36cef34bcc4a852467b21" +dependencies = [ + "itertools", + "lalrpop", + "lalrpop-util", + "phf", + "thiserror", + "unicode-xid", +] + [[package]] name = "sp-core" version = "18.0.0" @@ -3889,6 +5139,16 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spki" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "ss58-registry" version = "1.40.0" @@ -3929,6 +5189,19 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared 0.10.0", + "precomputed-hash", +] + [[package]] name = "strsim" version = "0.8.0" @@ -3965,6 +5238,28 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6069ca09d878a33f883cc06aaa9718ede171841d3832450354410b718b097232" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.18", +] + [[package]] name = "substrate-bip39" version = "0.4.4" @@ -3997,6 +5292,26 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +[[package]] +name = "svm-rs" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a04fc4f5cd35c700153b233f5575ccb3237e0f941fa5049d9e98254d10bf2fe" +dependencies = [ + "fs2", + "hex", + "home", + "once_cell", + "reqwest", + "semver", + "serde", + "serde_json", + "sha2 0.10.7", + "thiserror", + "url", + "zip", +] + [[package]] name = "syn" version = "1.0.109" @@ -4056,11 +5371,22 @@ dependencies = [ "autocfg", "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.3.5", "rustix 0.37.20", "windows-sys 0.48.0", ] +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + [[package]] name = "termcolor" version = "1.2.0" @@ -4258,6 +5584,21 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-tungstenite" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec509ac96e9a0c43427c74f003127d953a265737636129424288d27cb5c4b12c" +dependencies = [ + "futures-util", + "log", + "rustls 0.21.2", + "tokio", + "tokio-rustls 0.24.1", + "tungstenite", + "webpki-roots 0.23.1", +] + [[package]] name = "tokio-util" version = "0.7.8" @@ -4272,19 +5613,36 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + [[package]] name = "toml_datetime" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" -version = "0.19.10" +version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ - "indexmap", + "indexmap 2.0.0", + "serde", + "serde_spanned", "toml_datetime", "winnow", ] @@ -4338,7 +5696,7 @@ checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ "futures-core", "futures-util", - "indexmap", + "indexmap 1.9.3", "pin-project", "pin-project-lite", "rand 0.8.5", @@ -4509,6 +5867,27 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "tungstenite" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15fba1a6d6bb030745759a9a2a588bfe8490fc8b4751a277db3a0be1c9ebbf67" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.8.5", + "rustls 0.21.2", + "sha1", + "thiserror", + "url", + "utf-8", + "webpki", +] + [[package]] name = "twox-hash" version = "1.6.3" @@ -4610,6 +5989,22 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom 0.2.10", + "serde", +] + [[package]] name = "valuable" version = "0.1.0" @@ -4704,6 +6099,16 @@ dependencies = [ "zstd", ] +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -4750,6 +6155,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.87" @@ -4818,7 +6235,7 @@ version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64b20236ab624147dfbb62cf12a19aaf66af0e41b8398838b66e997d07d269d4" dependencies = [ - "indexmap", + "indexmap 1.9.3", "url", ] @@ -4831,7 +6248,7 @@ dependencies = [ "anyhow", "bincode", "cfg-if", - "indexmap", + "indexmap 1.9.3", "libc", "log", "object 0.29.0", @@ -4865,7 +6282,7 @@ dependencies = [ "anyhow", "cranelift-entity", "gimli 0.26.2", - "indexmap", + "indexmap 1.9.3", "log", "object 0.29.0", "serde", @@ -4927,7 +6344,7 @@ dependencies = [ "anyhow", "cc", "cfg-if", - "indexmap", + "indexmap 1.9.3", "libc", "log", "mach", @@ -4983,6 +6400,15 @@ dependencies = [ "webpki", ] +[[package]] +name = "webpki-roots" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" +dependencies = [ + "rustls-webpki", +] + [[package]] name = "which" version = "4.4.0" @@ -5193,13 +6619,41 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.7" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7" dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "log", + "pharos", + "rustc_version", + "send_wrapper 0.6.0", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wyz" version = "0.5.1" @@ -5209,6 +6663,12 @@ dependencies = [ "tap", ] +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + [[package]] name = "zeroize" version = "1.6.0" @@ -5229,6 +6689,26 @@ dependencies = [ "syn 2.0.18", ] +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq 0.1.5", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac 0.12.1", + "pbkdf2 0.11.0", + "sha1", + "time", + "zstd", +] + [[package]] name = "zstd" version = "0.11.2+zstd.1.5.2" diff --git a/lib/ain-evm/src/backend.rs b/lib/ain-evm/src/backend.rs index 76ff9a12a83..2df89615c9b 100644 --- a/lib/ain-evm/src/backend.rs +++ b/lib/ain-evm/src/backend.rs @@ -187,6 +187,53 @@ impl EVMBackend { .map(|acc| acc.nonce) .unwrap_or_default() } + + pub fn get_account_storage(&self, contract: H160, storage_index: H256) -> Result { + let account = self.get_account(&contract).unwrap_or(Account { + nonce: U256::zero(), + balance: U256::zero(), + storage_root: H256::zero(), + code_hash: H256::zero(), + }); + + let state = self + .trie_store + .trie_db + .trie_restore( + contract.clone().as_bytes(), + None, + account.storage_root.into(), + ) + .map_err(|e| EVMBackendError::TrieRestoreFailed(e.to_string()))?; + + Ok(U256::from( + state + .get(storage_index.clone().as_bytes()) + .unwrap_or_default() + .unwrap_or_default() + .as_slice(), + )) + } + + pub fn deploy_contract( + &mut self, + address: &H160, + code: Vec, + storage: Vec<(H256, H256)>, + ) -> Result<()> { + self.apply( + *address, + Basic { + balance: U256::zero(), + nonce: U256::zero(), + }, + Some(code), + storage, + true, + )?; + + Ok(()) + } } impl Backend for EVMBackend { diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 199d92d70e3..7d07bbd654b 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -17,6 +17,7 @@ use crate::txqueue::QueueTx; use ethereum::{Block, PartialHeader, ReceiptV3, TransactionV2}; use ethereum_types::{Bloom, H160, H64, U256}; +use crate::transaction::system::{DeployContractData, SystemTx}; use anyhow::anyhow; use hex::FromHex; use log::debug; @@ -201,6 +202,20 @@ impl EVMServices { failed_transactions.push(hex::encode(hash)); } } + QueueTx::SystemTx(SystemTx::DeployContract(DeployContractData { + address, + storage, + bytecode, + })) => { + debug!( + "[finalize_block] DeployContract for address {}, storage {:#?}, bytecode {:#?}", + address, storage, bytecode + ); + + if let Err(e) = executor.deploy_contract(address, bytecode, storage) { + debug!("[finalize_block] DeployContract failed with {e}"); + } + } } executor.commit(); diff --git a/lib/ain-evm/src/executor.rs b/lib/ain-evm/src/executor.rs index ff1536804fc..d1af4ee64ed 100644 --- a/lib/ain-evm/src/executor.rs +++ b/lib/ain-evm/src/executor.rs @@ -1,5 +1,6 @@ use crate::precompiles::MetachainPrecompiles; +use crate::bytes::Bytes; use crate::{ backend::{EVMBackend, EVMBackendError}, core::EVMCoreService, @@ -34,6 +35,15 @@ impl<'backend> AinExecutor<'backend> { self.backend.sub_balance(address, amount) } + pub fn deploy_contract( + &mut self, + address: H160, + bytecode: Bytes, + storage: Vec<(H256, H256)>, + ) -> Result<(), EVMBackendError> { + self.backend.deploy_contract(&address, bytecode.0, storage) + } + pub fn commit(&mut self) -> H256 { self.backend.commit() } diff --git a/lib/ain-evm/src/lib.rs b/lib/ain-evm/src/lib.rs index ccde9adbf23..82cd6d8afe7 100644 --- a/lib/ain-evm/src/lib.rs +++ b/lib/ain-evm/src/lib.rs @@ -1,4 +1,4 @@ -mod backend; +pub mod backend; pub mod block; pub mod bytes; pub mod core; @@ -16,4 +16,4 @@ pub mod storage; pub mod traits; pub mod transaction; mod trie; -mod txqueue; +pub mod txqueue; diff --git a/lib/ain-evm/src/transaction/mod.rs b/lib/ain-evm/src/transaction/mod.rs index 114582dd52a..7dd833522c2 100644 --- a/lib/ain-evm/src/transaction/mod.rs +++ b/lib/ain-evm/src/transaction/mod.rs @@ -1,4 +1,6 @@ pub mod bridge; +pub mod system; + use crate::ecrecover::{public_key_to_address, recover_public_key}; use ethereum::{ AccessList, EnvelopedDecoderError, LegacyTransaction, TransactionAction, TransactionSignature, diff --git a/lib/ain-evm/src/transaction/system.rs b/lib/ain-evm/src/transaction/system.rs new file mode 100644 index 00000000000..cbb52b41ad3 --- /dev/null +++ b/lib/ain-evm/src/transaction/system.rs @@ -0,0 +1,14 @@ +use crate::bytes::Bytes; +use primitive_types::{H160, H256}; + +#[derive(Debug, Clone)] +pub struct DeployContractData { + pub bytecode: Bytes, + pub storage: Vec<(H256, H256)>, + pub address: H160, +} + +#[derive(Debug, Clone)] +pub enum SystemTx { + DeployContract(DeployContractData), +} diff --git a/lib/ain-evm/src/txqueue.rs b/lib/ain-evm/src/txqueue.rs index 74de48f17d9..0987a42f4b8 100644 --- a/lib/ain-evm/src/txqueue.rs +++ b/lib/ain-evm/src/txqueue.rs @@ -5,6 +5,7 @@ use std::{ sync::{Mutex, RwLock}, }; +use crate::transaction::system::SystemTx; use crate::{ core::NativeTxHash, transaction::{bridge::BridgeTx, SignedTx}, @@ -161,6 +162,7 @@ impl TransactionQueueMap { pub enum QueueTx { SignedTx(Box), BridgeTx(BridgeTx), + SystemTx(SystemTx), } type QueueTxWithNativeHash = (QueueTx, NativeTxHash); @@ -230,6 +232,7 @@ impl TransactionQueue { let tx_sender = match tx { QueueTx::SignedTx(tx) => tx.sender, QueueTx::BridgeTx(tx) => tx.sender(), + QueueTx::SystemTx(_) => H160::zero(), }; tx_sender != sender }); diff --git a/lib/ain-rs-exports/Cargo.toml b/lib/ain-rs-exports/Cargo.toml index 1b144bb1522..d1ae79ef332 100644 --- a/lib/ain-rs-exports/Cargo.toml +++ b/lib/ain-rs-exports/Cargo.toml @@ -17,6 +17,9 @@ ethereum = "0.14.0" rlp = "0.5.2" primitive-types = "0.12.1" log = { version = "0.4" } +hex = "0.4.3" +serde_json = "1.0" +anyhow = "1.0.71" # Build cxx = "1.0" @@ -24,3 +27,7 @@ cxx = "1.0" [build-dependencies] cxx-gen = "0.7" proc-macro2 = "1.0" +ethers = "2.0.7" +ethers-solc = "2.0.7" +serde_json = "1.0" +anyhow = "1.0" diff --git a/lib/ain-rs-exports/build.rs b/lib/ain-rs-exports/build.rs index 1e360b94c0c..b9450cd54eb 100644 --- a/lib/ain-rs-exports/build.rs +++ b/lib/ain-rs-exports/build.rs @@ -1,9 +1,11 @@ use proc_macro2::TokenStream; -use std::env; +use anyhow::anyhow; +use ethers_solc::{Project, ProjectPathsConfig}; use std::fs::File; use std::io::{Read, Write}; use std::path::PathBuf; +use std::{env, fs}; fn main() -> Result<(), Box> { let pkg_name = env::var("CARGO_PKG_NAME")?; @@ -55,5 +57,44 @@ fn main() -> Result<(), Box> { ); } + // compile solidity project + // configure `root` as our project root + let root = PathBuf::from("counter_contract"); + if !root.exists() { + return Err("Project root {root:?} does not exists!".into()); + } + + let paths = ProjectPathsConfig::builder() + .root(&root) + .sources(&root) + .build()?; + + let project = Project::builder() + .paths(paths) + .set_auto_detect(true) + .no_artifacts() + .build()?; + let output = project.compile().unwrap(); + let artifacts = output.into_artifacts(); + + for (id, artifact) in artifacts { + if id.name == "Counter" { + let abi = artifact.abi.ok_or_else(|| anyhow!("ABI not found"))?; + let bytecode = artifact.deployed_bytecode.expect("No bytecode found"); + + fs::create_dir_all("counter_contract/output/")?; + fs::write( + PathBuf::from("counter_contract/output/bytecode.json"), + serde_json::to_string(&bytecode).unwrap().as_bytes(), + )?; + fs::write( + PathBuf::from("counter_contract/output/abi.json"), + serde_json::to_string(&abi).unwrap().as_bytes(), + )?; + } + } + + project.rerun_if_sources_changed(); + Ok(()) } diff --git a/lib/ain-rs-exports/counter_contract/Counter.sol b/lib/ain-rs-exports/counter_contract/Counter.sol new file mode 100644 index 00000000000..9400207c376 --- /dev/null +++ b/lib/ain-rs-exports/counter_contract/Counter.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.8.2 <0.9.0; + +/** + * @title Storage + */ +contract Counter { + uint256 public number; +} \ No newline at end of file diff --git a/lib/ain-rs-exports/src/counter_contract.rs b/lib/ain-rs-exports/src/counter_contract.rs new file mode 100644 index 00000000000..8875da1207b --- /dev/null +++ b/lib/ain-rs-exports/src/counter_contract.rs @@ -0,0 +1,75 @@ +use crate::ffi::CrossBoundaryResult; +use crate::prelude::{cross_boundary_error_return, cross_boundary_success}; +use ain_evm::bytes::Bytes; +use ain_evm::services::SERVICES; +use ain_evm::transaction::system::{DeployContractData, SystemTx}; +use ain_evm::txqueue::QueueTx; +use anyhow::anyhow; +use primitive_types::{H160, H256, U256}; +use std::error::Error; +use std::str::FromStr; + +pub fn evm_deploy_counter_contract(result: &mut CrossBoundaryResult, context: u64) { + match deploy_counter_contract(context) { + Ok(_) => cross_boundary_success(result), + Err(e) => cross_boundary_error_return(result, e.to_string()), + } +} + +fn deploy_counter_contract(context: u64) -> Result<(), Box> { + let address = H160::from_str("0x0000000000000000000000000000000000000301").unwrap(); + let bytecode = get_bytecode(include_str!("../counter_contract/output/bytecode.json"))?; + let (_, latest_block_number) = SERVICES + .evm + .block + .get_latest_block_hash_and_number() + .unwrap_or_default(); + let count = U256::from( + SERVICES + .evm + .core + .get_storage_at(address, U256::one(), latest_block_number)? + .unwrap_or_default() + .as_slice(), + ); + + let system_tx = QueueTx::SystemTx(SystemTx::DeployContract(DeployContractData { + bytecode, + storage: vec![(H256::from_low_u64_be(1), u256_to_h256(count + U256::one()))], + address, + })); + + SERVICES + .evm + .queue_tx(context, system_tx, Default::default(), 0)?; + + Ok(()) +} + +fn u256_to_h256(input: U256) -> H256 { + let mut bytes = [0_u8; 32]; + input.to_big_endian(&mut bytes); + + H256::from(bytes) +} + +fn get_abi_encoded_string(input: &str) -> H256 { + let length = input.len(); + + let mut storage_value = H256::default(); + storage_value.0[31] = (length * 2) as u8; + storage_value.0[..length].copy_from_slice(input.as_bytes()); + + storage_value +} + +fn get_bytecode(input: &str) -> Result> { + let bytecode_json: serde_json::Value = serde_json::from_str(input)?; + let bytecode_raw = bytecode_json["object"] + .as_str() + .ok_or_else(|| anyhow!("Bytecode object not available".to_string()))?; + + Ok(Bytes::from( + hex::decode(&bytecode_raw[2..]).map_err(|e| anyhow!(e.to_string()))?, + )) +} diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index 163dff85f66..e45e2eb7aaa 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -1,8 +1,10 @@ mod core; +mod counter_contract; mod evm; mod prelude; use crate::core::*; +use crate::counter_contract::*; use crate::evm::*; #[cxx::bridge] @@ -112,5 +114,6 @@ pub mod ffi { result: &mut CrossBoundaryResult, hash: [u8; 32], ) -> u64; + fn evm_deploy_counter_contract(result: &mut CrossBoundaryResult, context: u64); } } diff --git a/make.sh b/make.sh index 06837031911..3addb8cb9b7 100755 --- a/make.sh +++ b/make.sh @@ -527,6 +527,13 @@ pkg_install_rust() { _fold_end } +pkg_install_solc_linux() { + _fold_start "pkg-install-solc" + add-apt-repository ppa:ethereum/ethereum -y + apt-get update + apt-get install solc -y +} + pkg_local_ensure_osx_sysroot() { local sdk_name="Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers" local pkg="${sdk_name}.tar.gz" @@ -949,6 +956,7 @@ ci_setup_deps() { DEBIAN_FRONTEND=noninteractive pkg_setup_locale DEBIAN_FRONTEND=noninteractive pkg_install_llvm DEBIAN_FRONTEND=noninteractive pkg_install_rust + DEBIAN_FRONTEND=noninteractive pkg_install_solc_linux } _ci_setup_deps_target() { diff --git a/src/masternodes/validation.cpp b/src/masternodes/validation.cpp index 7bf9f8fac2a..a21ff9bde92 100644 --- a/src/masternodes/validation.cpp +++ b/src/masternodes/validation.cpp @@ -2450,7 +2450,7 @@ static void ProcessEVMQueue(const CBlock &block, const CBlockIndex *pindex, CCus } } -static void ProcessChangiIntermediate4(const CBlockIndex* pindex, CCustomCSView& cache, const CChainParams& chainparams) { +static void ProcessChangiIntermediate4(const CBlockIndex* pindex, CCustomCSView& cache, const CChainParams& chainparams, const uint64_t evmContext) { if (pindex->nHeight != chainparams.GetConsensus().ChangiIntermediateHeight4 || IsRegtestNetwork()) { return; } @@ -2465,6 +2465,14 @@ static void ProcessChangiIntermediate4(const CBlockIndex* pindex, CCustomCSView& attributes->SetValue(dvm_evm, true); cache.SetVariable(*attributes); + + if (pindex->nHeight == chainparams.GetConsensus().ChangiIntermediateHeight4) { + // deploy counter contract + CrossBoundaryResult result; + evm_deploy_counter_contract(result, evmContext); + + assert(result.ok); + } } void ProcessDeFiEvent(const CBlock &block, const CBlockIndex* pindex, CCustomCSView& mnview, const CCoinsViewCache& view, const CChainParams& chainparams, const CreationTxs &creationTxs, const uint64_t evmContext, std::array& beneficiary) { @@ -2525,7 +2533,7 @@ void ProcessDeFiEvent(const CBlock &block, const CBlockIndex* pindex, CCustomCSV ProcessEVMQueue(block, pindex, cache, chainparams, evmContext, beneficiary); // Execute ChangiIntermediate4 Events. Delete when removing Changi forks - ProcessChangiIntermediate4(pindex, cache, chainparams); + ProcessChangiIntermediate4(pindex, cache, chainparams, evmContext); // construct undo auto& flushable = cache.GetStorage(); diff --git a/test/functional/feature_evm.py b/test/functional/feature_evm.py index 87fe2707bc7..82170a9ee8f 100755 --- a/test/functional/feature_evm.py +++ b/test/functional/feature_evm.py @@ -92,6 +92,14 @@ def run_test(self): self.nodes[0].setgov({"ATTRIBUTES": {'v0/params/feature/evm': 'true'}}) self.nodes[0].generate(1) + # check counter contract + from web3 import Web3 + w3 = Web3(Web3.HTTPProvider(self.nodes[0].get_evm_rpc())) + abi = open("./lib/ain-rs-exports/counter_contract/output/abi.json", encoding="utf-8").read() + counter = w3.eth.contract(address="0x0000000000000000000000000000000000000301", abi=abi) + + print(counter.functions.number().call()) + # Check error before transferdomain enabled assert_raises_rpc_error(-32600, "Cannot create tx, transfer domain is not enabled", self.nodes[0].transferdomain, [{"src": {"address":address, "amount":"100@DFI", "domain": 2}, "dst":{"address":eth_address, "amount":"100@DFI", "domain": 3}}]) From 2c293c6fa1f365bb0ebeefbbd3c1ac62bf12bf82 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Mon, 24 Jul 2023 13:21:22 +0800 Subject: [PATCH 02/32] Run code during finalize_block instead of through FFI --- lib/ain-evm/src/backend.rs | 15 ++++ lib/ain-evm/src/evm.rs | 85 +++++++++++++++++-- lib/ain-evm/src/executor.rs | 8 ++ src/masternodes/validation.cpp | 8 -- test/functional/feature_evm.py | 8 -- .../feature_evm_state_root_change.py | 38 +++++++++ test/functional/test_runner.py | 1 + 7 files changed, 140 insertions(+), 23 deletions(-) create mode 100644 test/functional/feature_evm_state_root_change.py diff --git a/lib/ain-evm/src/backend.rs b/lib/ain-evm/src/backend.rs index 2df89615c9b..2ffa8e861e9 100644 --- a/lib/ain-evm/src/backend.rs +++ b/lib/ain-evm/src/backend.rs @@ -234,6 +234,21 @@ impl EVMBackend { Ok(()) } + + pub fn update_storage(&mut self, address: &H160, storage: Vec<(H256, H256)>) -> Result<()> { + self.apply( + *address, + Basic { + balance: U256::zero(), + nonce: U256::zero(), + }, + None, + storage, + false, + )?; + + Ok(()) + } } impl Backend for EVMBackend { diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 7d07bbd654b..38603e2e68c 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -1,4 +1,4 @@ -use crate::backend::{EVMBackend, Vicinity}; +use crate::backend::{EVMBackend, EVMBackendError, Vicinity}; use crate::block::BlockService; use crate::core::{EVMCoreService, EVMError, NativeTxHash, MAX_GAS_PER_BLOCK}; use crate::executor::{AinExecutor, TxResponse}; @@ -17,6 +17,8 @@ use crate::txqueue::QueueTx; use ethereum::{Block, PartialHeader, ReceiptV3, TransactionV2}; use ethereum_types::{Bloom, H160, H64, U256}; +use crate::bytes::Bytes; +use crate::services::SERVICES; use crate::transaction::system::{DeployContractData, SystemTx}; use anyhow::anyhow; use hex::FromHex; @@ -24,6 +26,7 @@ use log::debug; use primitive_types::H256; use std::error::Error; use std::path::PathBuf; +use std::str::FromStr; use std::sync::Arc; pub struct EVMServices { @@ -59,32 +62,34 @@ impl EVMServices { /// /// Returns an instance of the struct, either restored from storage or created from a JSON file. pub fn new() -> Result { - if let Some(path) = ain_cpp_imports::get_state_input_json() { + let services = if let Some(path) = ain_cpp_imports::get_state_input_json() { if ain_cpp_imports::get_network() != "regtest" { return Err(anyhow!( "Loading a genesis from JSON file is restricted to regtest network" )); } let storage = Arc::new(Storage::new()); - Ok(Self { + Self { core: EVMCoreService::new_from_json(Arc::clone(&storage), PathBuf::from(path)), block: BlockService::new(Arc::clone(&storage)), receipt: ReceiptService::new(Arc::clone(&storage)), logs: LogService::new(Arc::clone(&storage)), filters: FilterService::new(), storage, - }) + } } else { let storage = Arc::new(Storage::restore()); - Ok(Self { + Self { core: EVMCoreService::restore(Arc::clone(&storage)), block: BlockService::new(Arc::clone(&storage)), receipt: ReceiptService::new(Arc::clone(&storage)), logs: LogService::new(Arc::clone(&storage)), filters: FilterService::new(), storage, - }) - } + } + }; + + Ok(services) } pub fn finalize_block( @@ -144,6 +149,16 @@ impl EVMServices { let mut executor = AinExecutor::new(&mut backend); + if current_block_number == U256::zero() { + let (address, bytecode, storage) = EVMServices::counter_contract().unwrap(); + executor + .deploy_contract(address, bytecode, storage) + .unwrap(); + } else { + let (address, _, storage) = EVMServices::counter_contract().unwrap(); + executor.update_storage(address, storage).unwrap(); + } + for (queue_tx, hash) in self.core.tx_queues.get_cloned_vec(context) { match queue_tx { QueueTx::SignedTx(signed_tx) => { @@ -340,4 +355,60 @@ impl EVMServices { Ok(()) } + + pub fn counter_contract() -> Result<(H160, Bytes, Vec<(H256, H256)>), Box> { + let address = H160::from_str("0x0000000000000000000000000000000000000301").unwrap(); + let bytecode = get_bytecode(include_str!( + "../../ain-rs-exports/counter_contract/output/bytecode.json" + ))?; + let (_, latest_block_number) = SERVICES + .evm + .block + .get_latest_block_hash_and_number() + .unwrap_or_default(); + let count = U256::from( + SERVICES + .evm + .core + .get_storage_at(address, U256::one(), latest_block_number)? + .unwrap_or_default() + .as_slice(), + ); + + debug!("Count: {:#x}", count + U256::one()); + + Ok(( + address, + bytecode, + vec![(H256::from_low_u64_be(1), u256_to_h256(count + U256::one()))], + )) + } +} + +fn u256_to_h256(input: U256) -> H256 { + let mut bytes = [0_u8; 32]; + input.to_big_endian(&mut bytes); + + H256::from(bytes) +} + +fn get_abi_encoded_string(input: &str) -> H256 { + let length = input.len(); + + let mut storage_value = H256::default(); + storage_value.0[31] = (length * 2) as u8; + storage_value.0[..length].copy_from_slice(input.as_bytes()); + + storage_value +} + +fn get_bytecode(input: &str) -> Result> { + let bytecode_json: serde_json::Value = serde_json::from_str(input)?; + let bytecode_raw = bytecode_json["object"] + .as_str() + .ok_or_else(|| anyhow!("Bytecode object not available".to_string()))?; + + Ok(Bytes::from( + hex::decode(&bytecode_raw[2..]).map_err(|e| anyhow!(e.to_string()))?, + )) } diff --git a/lib/ain-evm/src/executor.rs b/lib/ain-evm/src/executor.rs index d1af4ee64ed..1f9d659a69e 100644 --- a/lib/ain-evm/src/executor.rs +++ b/lib/ain-evm/src/executor.rs @@ -44,6 +44,14 @@ impl<'backend> AinExecutor<'backend> { self.backend.deploy_contract(&address, bytecode.0, storage) } + pub fn update_storage( + &mut self, + address: H160, + storage: Vec<(H256, H256)>, + ) -> Result<(), EVMBackendError> { + self.backend.update_storage(&address, storage) + } + pub fn commit(&mut self) -> H256 { self.backend.commit() } diff --git a/src/masternodes/validation.cpp b/src/masternodes/validation.cpp index a21ff9bde92..a0e415815f9 100644 --- a/src/masternodes/validation.cpp +++ b/src/masternodes/validation.cpp @@ -2465,14 +2465,6 @@ static void ProcessChangiIntermediate4(const CBlockIndex* pindex, CCustomCSView& attributes->SetValue(dvm_evm, true); cache.SetVariable(*attributes); - - if (pindex->nHeight == chainparams.GetConsensus().ChangiIntermediateHeight4) { - // deploy counter contract - CrossBoundaryResult result; - evm_deploy_counter_contract(result, evmContext); - - assert(result.ok); - } } void ProcessDeFiEvent(const CBlock &block, const CBlockIndex* pindex, CCustomCSView& mnview, const CCoinsViewCache& view, const CChainParams& chainparams, const CreationTxs &creationTxs, const uint64_t evmContext, std::array& beneficiary) { diff --git a/test/functional/feature_evm.py b/test/functional/feature_evm.py index 82170a9ee8f..87fe2707bc7 100755 --- a/test/functional/feature_evm.py +++ b/test/functional/feature_evm.py @@ -92,14 +92,6 @@ def run_test(self): self.nodes[0].setgov({"ATTRIBUTES": {'v0/params/feature/evm': 'true'}}) self.nodes[0].generate(1) - # check counter contract - from web3 import Web3 - w3 = Web3(Web3.HTTPProvider(self.nodes[0].get_evm_rpc())) - abi = open("./lib/ain-rs-exports/counter_contract/output/abi.json", encoding="utf-8").read() - counter = w3.eth.contract(address="0x0000000000000000000000000000000000000301", abi=abi) - - print(counter.functions.number().call()) - # Check error before transferdomain enabled assert_raises_rpc_error(-32600, "Cannot create tx, transfer domain is not enabled", self.nodes[0].transferdomain, [{"src": {"address":address, "amount":"100@DFI", "domain": 2}, "dst":{"address":eth_address, "amount":"100@DFI", "domain": 3}}]) diff --git a/test/functional/feature_evm_state_root_change.py b/test/functional/feature_evm_state_root_change.py new file mode 100644 index 00000000000..9f702a22e68 --- /dev/null +++ b/test/functional/feature_evm_state_root_change.py @@ -0,0 +1,38 @@ +from test_framework.test_framework import DefiTestFramework +from test_framework.util import ( + assert_equal +) + +class StateRootChangeTest(DefiTestFramework): + def set_test_params(self): + self.num_nodes = 1 + self.setup_clean_chain = True + self.extra_args = [ + ['-txordering=2', '-dummypos=0', '-txnotokens=0', '-amkheight=50', '-bayfrontheight=51', '-eunosheight=80', '-fortcanningheight=82', '-fortcanninghillheight=84', '-fortcanningroadheight=86', '-fortcanningcrunchheight=88', '-fortcanningspringheight=90', '-fortcanninggreatworldheight=94', '-fortcanningepilogueheight=96', '-grandcentralheight=101', '-nextnetworkupgradeheight=105', '-changiintermediateheight=105', '-changiintermediate2height=105', '-changiintermediate3height=105', '-changiintermediate4height=110', '-subsidytest=1', '-txindex=1'], + ] + + def run_test(self): + node = self.nodes[0] + node.generate(105) + + # Activate EVM + self.nodes[0].setgov({"ATTRIBUTES": {'v0/params/feature/evm': 'true'}}) + self.nodes[0].generate(1) + + # check counter contract + from web3 import Web3 + w3 = Web3(Web3.HTTPProvider(self.nodes[0].get_evm_rpc())) + + NUM_BLOCKS = 5 + state_roots = set() + for i in range(NUM_BLOCKS): + node.generate(1) + block = w3.eth.get_block('latest') + state_roots.add(Web3.to_hex(block["stateRoot"])) + + assert_equal(len(state_roots), NUM_BLOCKS) + + + +if __name__ == '__main__': + StateRootChangeTest().main() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 5436b1e2c48..356b4d081a0 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -301,6 +301,7 @@ 'feature_evm_smart_contract.py', 'feature_evm_transferdomain.py', 'feature_evm.py', + 'feature_evm_state_root_change.py', 'feature_loan_low_interest.py', 'feature_loan_estimatecollateral.py', 'feature_vault_pct_check_factor.py', From 8574bd804f36bb7de9151d85f01f839ca534f10d Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Mon, 24 Jul 2023 13:44:24 +0800 Subject: [PATCH 03/32] Remove FFI code, move contract and utils to new crate --- .gitignore | 4 +- lib/Cargo.lock | 16 +++- lib/Cargo.toml | 1 + lib/ain-evm/Cargo.toml | 1 + lib/ain-evm/src/evm.rs | 56 ++------------ lib/ain-evm/src/lib.rs | 2 +- lib/ain-evm/src/transaction/mod.rs | 1 - lib/ain-evm/src/transaction/system.rs | 14 ---- lib/ain-evm/src/txqueue.rs | 3 - lib/ain-rs-exports/Cargo.toml | 4 - lib/ain-rs-exports/build.rs | 43 +---------- lib/ain-rs-exports/src/counter_contract.rs | 75 ------------------- lib/ain-rs-exports/src/lib.rs | 3 - lib/contracts/build.rs | 47 ++++++++++++ .../counter_contract/Counter.sol | 0 15 files changed, 74 insertions(+), 196 deletions(-) delete mode 100644 lib/ain-evm/src/transaction/system.rs delete mode 100644 lib/ain-rs-exports/src/counter_contract.rs create mode 100644 lib/contracts/build.rs rename lib/{ain-rs-exports => contracts}/counter_contract/Counter.sol (100%) diff --git a/.gitignore b/.gitignore index 76f895846d4..ad0face2a83 100644 --- a/.gitignore +++ b/.gitignore @@ -148,5 +148,5 @@ contrib/devtools/split-debug.sh /lib/target *.bin -/lib/ain-rs-exports/**/cache -/lib/ain-rs-exports/**/output \ No newline at end of file +/lib/contracts/**/cache +/lib/contracts/**/output \ No newline at end of file diff --git a/lib/Cargo.lock b/lib/Cargo.lock index c7b927d67ef..c0de741ede6 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -104,6 +104,7 @@ dependencies = [ "ain-cpp-imports", "anyhow", "bincode", + "contracts", "ethbloom", "ethereum", "ethereum-types", @@ -188,8 +189,6 @@ dependencies = [ "cxx", "cxx-gen", "ethereum", - "ethers", - "ethers-solc", "hex", "log", "primitive-types", @@ -847,6 +846,19 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" +[[package]] +name = "contracts" +version = "0.1.0" +dependencies = [ + "anyhow", + "ethereum", + "ethers", + "ethers-solc", + "hex", + "primitive-types", + "serde_json", +] + [[package]] name = "core-foundation" version = "0.9.3" diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 7c2b12d6d29..84900bc68b2 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -3,6 +3,7 @@ members = [ "ain-*", "cli", "labs-grpc2", + "contracts", ] default-members = [ diff --git a/lib/ain-evm/Cargo.toml b/lib/ain-evm/Cargo.toml index beffd3173f0..e9f936ec21d 100644 --- a/lib/ain-evm/Cargo.toml +++ b/lib/ain-evm/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] ain-cpp-imports = { path = "../ain-cpp-imports" } +contracts = { path = "../contracts" } evm = { version = "0.39", default-features = false, features = ["with-serde"] } primitive-types = { version = "0.12", default-features = false, features = ["serde"] } diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 75df2396549..764eb43c574 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -1,4 +1,4 @@ -use crate::backend::{EVMBackend, EVMBackendError, Vicinity}; +use crate::backend::{EVMBackend, Vicinity}; use crate::block::BlockService; use crate::core::{EVMCoreService, EVMError, NativeTxHash, MAX_GAS_PER_BLOCK}; use crate::executor::{AinExecutor, TxResponse}; @@ -19,7 +19,6 @@ use ethereum_types::{Bloom, H160, H64, U256}; use crate::bytes::Bytes; use crate::services::SERVICES; -use crate::transaction::system::{DeployContractData, SystemTx}; use anyhow::anyhow; use hex::FromHex; use log::debug; @@ -218,20 +217,6 @@ impl EVMServices { failed_transactions.push(hex::encode(hash)); } } - QueueTx::SystemTx(SystemTx::DeployContract(DeployContractData { - address, - storage, - bytecode, - })) => { - debug!( - "[finalize_block] DeployContract for address {}, storage {:#?}, bytecode {:#?}", - address, storage, bytecode - ); - - if let Err(e) = executor.deploy_contract(address, bytecode, storage) { - debug!("[finalize_block] DeployContract failed with {e}"); - } - } } executor.commit(); @@ -359,9 +344,7 @@ impl EVMServices { pub fn counter_contract() -> Result<(H160, Bytes, Vec<(H256, H256)>), Box> { let address = H160::from_str("0x0000000000000000000000000000000000000301").unwrap(); - let bytecode = get_bytecode(include_str!( - "../../ain-rs-exports/counter_contract/output/bytecode.json" - ))?; + let bytecode = contracts::get_counter_bytecode()?; let (_, latest_block_number) = SERVICES .evm .block @@ -380,36 +363,11 @@ impl EVMServices { Ok(( address, - bytecode, - vec![(H256::from_low_u64_be(1), u256_to_h256(count + U256::one()))], + Bytes::from(bytecode), + vec![( + H256::from_low_u64_be(1), + contracts::u256_to_h256(count + U256::one()), + )], )) } } - -fn u256_to_h256(input: U256) -> H256 { - let mut bytes = [0_u8; 32]; - input.to_big_endian(&mut bytes); - - H256::from(bytes) -} - -fn get_abi_encoded_string(input: &str) -> H256 { - let length = input.len(); - - let mut storage_value = H256::default(); - storage_value.0[31] = (length * 2) as u8; - storage_value.0[..length].copy_from_slice(input.as_bytes()); - - storage_value -} - -fn get_bytecode(input: &str) -> Result> { - let bytecode_json: serde_json::Value = serde_json::from_str(input)?; - let bytecode_raw = bytecode_json["object"] - .as_str() - .ok_or_else(|| anyhow!("Bytecode object not available".to_string()))?; - - Ok(Bytes::from( - hex::decode(&bytecode_raw[2..]).map_err(|e| anyhow!(e.to_string()))?, - )) -} diff --git a/lib/ain-evm/src/lib.rs b/lib/ain-evm/src/lib.rs index 597a88c8de5..fbf7bc15bb8 100644 --- a/lib/ain-evm/src/lib.rs +++ b/lib/ain-evm/src/lib.rs @@ -16,5 +16,5 @@ pub mod storage; pub mod traits; pub mod transaction; mod trie; -pub mod txqueue; +mod txqueue; pub mod weiamount; diff --git a/lib/ain-evm/src/transaction/mod.rs b/lib/ain-evm/src/transaction/mod.rs index 7dd833522c2..9a99d1b7521 100644 --- a/lib/ain-evm/src/transaction/mod.rs +++ b/lib/ain-evm/src/transaction/mod.rs @@ -1,5 +1,4 @@ pub mod bridge; -pub mod system; use crate::ecrecover::{public_key_to_address, recover_public_key}; use ethereum::{ diff --git a/lib/ain-evm/src/transaction/system.rs b/lib/ain-evm/src/transaction/system.rs deleted file mode 100644 index cbb52b41ad3..00000000000 --- a/lib/ain-evm/src/transaction/system.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::bytes::Bytes; -use primitive_types::{H160, H256}; - -#[derive(Debug, Clone)] -pub struct DeployContractData { - pub bytecode: Bytes, - pub storage: Vec<(H256, H256)>, - pub address: H160, -} - -#[derive(Debug, Clone)] -pub enum SystemTx { - DeployContract(DeployContractData), -} diff --git a/lib/ain-evm/src/txqueue.rs b/lib/ain-evm/src/txqueue.rs index 0987a42f4b8..74de48f17d9 100644 --- a/lib/ain-evm/src/txqueue.rs +++ b/lib/ain-evm/src/txqueue.rs @@ -5,7 +5,6 @@ use std::{ sync::{Mutex, RwLock}, }; -use crate::transaction::system::SystemTx; use crate::{ core::NativeTxHash, transaction::{bridge::BridgeTx, SignedTx}, @@ -162,7 +161,6 @@ impl TransactionQueueMap { pub enum QueueTx { SignedTx(Box), BridgeTx(BridgeTx), - SystemTx(SystemTx), } type QueueTxWithNativeHash = (QueueTx, NativeTxHash); @@ -232,7 +230,6 @@ impl TransactionQueue { let tx_sender = match tx { QueueTx::SignedTx(tx) => tx.sender, QueueTx::BridgeTx(tx) => tx.sender(), - QueueTx::SystemTx(_) => H160::zero(), }; tx_sender != sender }); diff --git a/lib/ain-rs-exports/Cargo.toml b/lib/ain-rs-exports/Cargo.toml index d1ae79ef332..041445b9f2f 100644 --- a/lib/ain-rs-exports/Cargo.toml +++ b/lib/ain-rs-exports/Cargo.toml @@ -27,7 +27,3 @@ cxx = "1.0" [build-dependencies] cxx-gen = "0.7" proc-macro2 = "1.0" -ethers = "2.0.7" -ethers-solc = "2.0.7" -serde_json = "1.0" -anyhow = "1.0" diff --git a/lib/ain-rs-exports/build.rs b/lib/ain-rs-exports/build.rs index b9450cd54eb..1e360b94c0c 100644 --- a/lib/ain-rs-exports/build.rs +++ b/lib/ain-rs-exports/build.rs @@ -1,11 +1,9 @@ use proc_macro2::TokenStream; -use anyhow::anyhow; -use ethers_solc::{Project, ProjectPathsConfig}; +use std::env; use std::fs::File; use std::io::{Read, Write}; use std::path::PathBuf; -use std::{env, fs}; fn main() -> Result<(), Box> { let pkg_name = env::var("CARGO_PKG_NAME")?; @@ -57,44 +55,5 @@ fn main() -> Result<(), Box> { ); } - // compile solidity project - // configure `root` as our project root - let root = PathBuf::from("counter_contract"); - if !root.exists() { - return Err("Project root {root:?} does not exists!".into()); - } - - let paths = ProjectPathsConfig::builder() - .root(&root) - .sources(&root) - .build()?; - - let project = Project::builder() - .paths(paths) - .set_auto_detect(true) - .no_artifacts() - .build()?; - let output = project.compile().unwrap(); - let artifacts = output.into_artifacts(); - - for (id, artifact) in artifacts { - if id.name == "Counter" { - let abi = artifact.abi.ok_or_else(|| anyhow!("ABI not found"))?; - let bytecode = artifact.deployed_bytecode.expect("No bytecode found"); - - fs::create_dir_all("counter_contract/output/")?; - fs::write( - PathBuf::from("counter_contract/output/bytecode.json"), - serde_json::to_string(&bytecode).unwrap().as_bytes(), - )?; - fs::write( - PathBuf::from("counter_contract/output/abi.json"), - serde_json::to_string(&abi).unwrap().as_bytes(), - )?; - } - } - - project.rerun_if_sources_changed(); - Ok(()) } diff --git a/lib/ain-rs-exports/src/counter_contract.rs b/lib/ain-rs-exports/src/counter_contract.rs deleted file mode 100644 index 8875da1207b..00000000000 --- a/lib/ain-rs-exports/src/counter_contract.rs +++ /dev/null @@ -1,75 +0,0 @@ -use crate::ffi::CrossBoundaryResult; -use crate::prelude::{cross_boundary_error_return, cross_boundary_success}; -use ain_evm::bytes::Bytes; -use ain_evm::services::SERVICES; -use ain_evm::transaction::system::{DeployContractData, SystemTx}; -use ain_evm::txqueue::QueueTx; -use anyhow::anyhow; -use primitive_types::{H160, H256, U256}; -use std::error::Error; -use std::str::FromStr; - -pub fn evm_deploy_counter_contract(result: &mut CrossBoundaryResult, context: u64) { - match deploy_counter_contract(context) { - Ok(_) => cross_boundary_success(result), - Err(e) => cross_boundary_error_return(result, e.to_string()), - } -} - -fn deploy_counter_contract(context: u64) -> Result<(), Box> { - let address = H160::from_str("0x0000000000000000000000000000000000000301").unwrap(); - let bytecode = get_bytecode(include_str!("../counter_contract/output/bytecode.json"))?; - let (_, latest_block_number) = SERVICES - .evm - .block - .get_latest_block_hash_and_number() - .unwrap_or_default(); - let count = U256::from( - SERVICES - .evm - .core - .get_storage_at(address, U256::one(), latest_block_number)? - .unwrap_or_default() - .as_slice(), - ); - - let system_tx = QueueTx::SystemTx(SystemTx::DeployContract(DeployContractData { - bytecode, - storage: vec![(H256::from_low_u64_be(1), u256_to_h256(count + U256::one()))], - address, - })); - - SERVICES - .evm - .queue_tx(context, system_tx, Default::default(), 0)?; - - Ok(()) -} - -fn u256_to_h256(input: U256) -> H256 { - let mut bytes = [0_u8; 32]; - input.to_big_endian(&mut bytes); - - H256::from(bytes) -} - -fn get_abi_encoded_string(input: &str) -> H256 { - let length = input.len(); - - let mut storage_value = H256::default(); - storage_value.0[31] = (length * 2) as u8; - storage_value.0[..length].copy_from_slice(input.as_bytes()); - - storage_value -} - -fn get_bytecode(input: &str) -> Result> { - let bytecode_json: serde_json::Value = serde_json::from_str(input)?; - let bytecode_raw = bytecode_json["object"] - .as_str() - .ok_or_else(|| anyhow!("Bytecode object not available".to_string()))?; - - Ok(Bytes::from( - hex::decode(&bytecode_raw[2..]).map_err(|e| anyhow!(e.to_string()))?, - )) -} diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index f928dd8aa09..cb5d9c7cb99 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -1,10 +1,8 @@ mod core; -mod counter_contract; mod evm; mod prelude; use crate::core::*; -use crate::counter_contract::*; use crate::evm::*; #[cxx::bridge] @@ -124,6 +122,5 @@ pub mod ffi { result: &mut CrossBoundaryResult, hash: [u8; 32], ) -> u64; - fn evm_deploy_counter_contract(result: &mut CrossBoundaryResult, context: u64); } } diff --git a/lib/contracts/build.rs b/lib/contracts/build.rs new file mode 100644 index 00000000000..7187023c427 --- /dev/null +++ b/lib/contracts/build.rs @@ -0,0 +1,47 @@ +use anyhow::anyhow; +use ethers_solc::{Project, ProjectPathsConfig}; +use std::fs; +use std::path::PathBuf; + +fn main() -> Result<(), Box> { + // compile solidity project + // configure `root` as our project root + let root = PathBuf::from("counter_contract"); + if !root.exists() { + return Err("Project root {root:?} does not exists!".into()); + } + + let paths = ProjectPathsConfig::builder() + .root(&root) + .sources(&root) + .build()?; + + let project = Project::builder() + .paths(paths) + .set_auto_detect(true) + .no_artifacts() + .build()?; + let output = project.compile().unwrap(); + let artifacts = output.into_artifacts(); + + for (id, artifact) in artifacts { + if id.name == "Counter" { + let abi = artifact.abi.ok_or_else(|| anyhow!("ABI not found"))?; + let bytecode = artifact.deployed_bytecode.expect("No bytecode found"); + + fs::create_dir_all("counter_contract/output/")?; + fs::write( + PathBuf::from("counter_contract/output/bytecode.json"), + serde_json::to_string(&bytecode).unwrap().as_bytes(), + )?; + fs::write( + PathBuf::from("counter_contract/output/abi.json"), + serde_json::to_string(&abi).unwrap().as_bytes(), + )?; + } + } + + project.rerun_if_sources_changed(); + + Ok(()) +} diff --git a/lib/ain-rs-exports/counter_contract/Counter.sol b/lib/contracts/counter_contract/Counter.sol similarity index 100% rename from lib/ain-rs-exports/counter_contract/Counter.sol rename to lib/contracts/counter_contract/Counter.sol From 474b21b9a382ed78e73430c7f88410144327de0d Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Mon, 24 Jul 2023 13:46:26 +0800 Subject: [PATCH 04/32] Undo more changes --- lib/ain-evm/src/lib.rs | 2 +- src/masternodes/validation.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ain-evm/src/lib.rs b/lib/ain-evm/src/lib.rs index fbf7bc15bb8..1142d371ff3 100644 --- a/lib/ain-evm/src/lib.rs +++ b/lib/ain-evm/src/lib.rs @@ -1,4 +1,4 @@ -pub mod backend; +mod backend; pub mod block; pub mod bytes; pub mod core; diff --git a/src/masternodes/validation.cpp b/src/masternodes/validation.cpp index a0e415815f9..7bf9f8fac2a 100644 --- a/src/masternodes/validation.cpp +++ b/src/masternodes/validation.cpp @@ -2450,7 +2450,7 @@ static void ProcessEVMQueue(const CBlock &block, const CBlockIndex *pindex, CCus } } -static void ProcessChangiIntermediate4(const CBlockIndex* pindex, CCustomCSView& cache, const CChainParams& chainparams, const uint64_t evmContext) { +static void ProcessChangiIntermediate4(const CBlockIndex* pindex, CCustomCSView& cache, const CChainParams& chainparams) { if (pindex->nHeight != chainparams.GetConsensus().ChangiIntermediateHeight4 || IsRegtestNetwork()) { return; } @@ -2525,7 +2525,7 @@ void ProcessDeFiEvent(const CBlock &block, const CBlockIndex* pindex, CCustomCSV ProcessEVMQueue(block, pindex, cache, chainparams, evmContext, beneficiary); // Execute ChangiIntermediate4 Events. Delete when removing Changi forks - ProcessChangiIntermediate4(pindex, cache, chainparams, evmContext); + ProcessChangiIntermediate4(pindex, cache, chainparams); // construct undo auto& flushable = cache.GetStorage(); From 3a8cafcde3099a4d4de617a95173aff1ca774bd0 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Mon, 24 Jul 2023 14:01:18 +0800 Subject: [PATCH 05/32] Declare addresses in contracts crate --- lib/Cargo.lock | 1 + lib/ain-evm/src/evm.rs | 7 ++++-- lib/contracts/Cargo.toml | 20 +++++++++++++++ lib/contracts/src/lib.rs | 54 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 lib/contracts/Cargo.toml create mode 100644 lib/contracts/src/lib.rs diff --git a/lib/Cargo.lock b/lib/Cargo.lock index c0de741ede6..a6b2cbeef1f 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -855,6 +855,7 @@ dependencies = [ "ethers", "ethers-solc", "hex", + "lazy_static", "primitive-types", "serde_json", ] diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 764eb43c574..d6af52f7832 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -20,12 +20,12 @@ use ethereum_types::{Bloom, H160, H64, U256}; use crate::bytes::Bytes; use crate::services::SERVICES; use anyhow::anyhow; +use contracts::{Contracts, CONTRACT_ADDRESSES}; use hex::FromHex; use log::debug; use primitive_types::H256; use std::error::Error; use std::path::PathBuf; -use std::str::FromStr; use std::sync::Arc; pub struct EVMServices { @@ -343,7 +343,10 @@ impl EVMServices { } pub fn counter_contract() -> Result<(H160, Bytes, Vec<(H256, H256)>), Box> { - let address = H160::from_str("0x0000000000000000000000000000000000000301").unwrap(); + let address = CONTRACT_ADDRESSES + .get(&Contracts::CounterContract) + .unwrap() + .clone(); let bytecode = contracts::get_counter_bytecode()?; let (_, latest_block_number) = SERVICES .evm diff --git a/lib/contracts/Cargo.toml b/lib/contracts/Cargo.toml new file mode 100644 index 00000000000..bafd2bf2317 --- /dev/null +++ b/lib/contracts/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "contracts" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +primitive-types = "0.12.1" +anyhow = "1.0" +ethereum = "0.14.0" +serde_json = "1.0.96" +hex = "0.4.3" +lazy_static = "1.4" + +[build-dependencies] +ethers = "2.0.7" +ethers-solc = "2.0.7" +serde_json = "1.0" +anyhow = "1.0" diff --git a/lib/contracts/src/lib.rs b/lib/contracts/src/lib.rs new file mode 100644 index 00000000000..5cd54d4fade --- /dev/null +++ b/lib/contracts/src/lib.rs @@ -0,0 +1,54 @@ +use anyhow::anyhow; +use lazy_static::lazy_static; +use primitive_types::{H160, H256, U256}; +use std::collections::HashMap; +use std::error::Error; +use std::str::FromStr; + +pub fn u256_to_h256(input: U256) -> H256 { + let mut bytes = [0_u8; 32]; + input.to_big_endian(&mut bytes); + + H256::from(bytes) +} + +pub fn get_abi_encoded_string(input: &str) -> H256 { + let length = input.len(); + + let mut storage_value = H256::default(); + storage_value.0[31] = (length * 2) as u8; + storage_value.0[..length].copy_from_slice(input.as_bytes()); + + storage_value +} + +pub fn get_bytecode(input: &str) -> Result, Box> { + let bytecode_json: serde_json::Value = serde_json::from_str(input)?; + let bytecode_raw = bytecode_json["object"] + .as_str() + .ok_or_else(|| anyhow!("Bytecode object not available".to_string()))?; + + Ok(hex::decode(&bytecode_raw[2..]).map_err(|e| anyhow!(e.to_string()))?) +} + +pub fn get_counter_bytecode() -> Result, Box> { + get_bytecode(include_str!("../counter_contract/output/bytecode.json")) +} + +#[derive(Debug, PartialEq, Eq, Hash)] +pub enum Contracts { + CounterContract, +} + +lazy_static! { + pub static ref CONTRACT_ADDRESSES: HashMap = { + let mut map = HashMap::new(); + + map.insert( + Contracts::CounterContract, + H160::from_str("0x0000000000000000000000000000000000000301").unwrap(), + ); + + map + }; +} From 608aaefc889e908eb02bb943cf140d7584b5e7fb Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Mon, 24 Jul 2023 14:08:48 +0800 Subject: [PATCH 06/32] Rename contracts to ain-contracts --- lib/Cargo.lock | 30 +++++++++---------- lib/Cargo.toml | 1 - lib/{contracts => ain-contracts}/Cargo.toml | 2 +- lib/{contracts => ain-contracts}/build.rs | 0 .../counter_contract/Counter.sol | 0 lib/{contracts => ain-contracts}/src/lib.rs | 14 +++------ lib/ain-evm/Cargo.toml | 2 +- lib/ain-evm/src/evm.rs | 6 ++-- 8 files changed, 24 insertions(+), 31 deletions(-) rename lib/{contracts => ain-contracts}/Cargo.toml (94%) rename lib/{contracts => ain-contracts}/build.rs (100%) rename lib/{contracts => ain-contracts}/counter_contract/Counter.sol (100%) rename lib/{contracts => ain-contracts}/src/lib.rs (85%) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index a6b2cbeef1f..d308069862e 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -88,6 +88,20 @@ dependencies = [ "memchr", ] +[[package]] +name = "ain-contracts" +version = "0.1.0" +dependencies = [ + "anyhow", + "ethereum", + "ethers", + "ethers-solc", + "hex", + "lazy_static", + "primitive-types", + "serde_json", +] + [[package]] name = "ain-cpp-imports" version = "0.1.0" @@ -101,10 +115,10 @@ dependencies = [ name = "ain-evm" version = "0.1.0" dependencies = [ + "ain-contracts", "ain-cpp-imports", "anyhow", "bincode", - "contracts", "ethbloom", "ethereum", "ethereum-types", @@ -846,20 +860,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" -[[package]] -name = "contracts" -version = "0.1.0" -dependencies = [ - "anyhow", - "ethereum", - "ethers", - "ethers-solc", - "hex", - "lazy_static", - "primitive-types", - "serde_json", -] - [[package]] name = "core-foundation" version = "0.9.3" diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 84900bc68b2..7c2b12d6d29 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -3,7 +3,6 @@ members = [ "ain-*", "cli", "labs-grpc2", - "contracts", ] default-members = [ diff --git a/lib/contracts/Cargo.toml b/lib/ain-contracts/Cargo.toml similarity index 94% rename from lib/contracts/Cargo.toml rename to lib/ain-contracts/Cargo.toml index bafd2bf2317..b5d790cd11b 100644 --- a/lib/contracts/Cargo.toml +++ b/lib/ain-contracts/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "contracts" +name = "ain-contracts" version = "0.1.0" edition = "2021" diff --git a/lib/contracts/build.rs b/lib/ain-contracts/build.rs similarity index 100% rename from lib/contracts/build.rs rename to lib/ain-contracts/build.rs diff --git a/lib/contracts/counter_contract/Counter.sol b/lib/ain-contracts/counter_contract/Counter.sol similarity index 100% rename from lib/contracts/counter_contract/Counter.sol rename to lib/ain-contracts/counter_contract/Counter.sol diff --git a/lib/contracts/src/lib.rs b/lib/ain-contracts/src/lib.rs similarity index 85% rename from lib/contracts/src/lib.rs rename to lib/ain-contracts/src/lib.rs index 5cd54d4fade..99446592e36 100644 --- a/lib/contracts/src/lib.rs +++ b/lib/ain-contracts/src/lib.rs @@ -41,14 +41,8 @@ pub enum Contracts { } lazy_static! { - pub static ref CONTRACT_ADDRESSES: HashMap = { - let mut map = HashMap::new(); - - map.insert( - Contracts::CounterContract, - H160::from_str("0x0000000000000000000000000000000000000301").unwrap(), - ); - - map - }; + pub static ref CONTRACT_ADDRESSES: HashMap = HashMap::from([( + Contracts::CounterContract, + H160::from_str("0x0000000000000000000000000000000000000301").unwrap() + ),]); } diff --git a/lib/ain-evm/Cargo.toml b/lib/ain-evm/Cargo.toml index e9f936ec21d..b85e1acb120 100644 --- a/lib/ain-evm/Cargo.toml +++ b/lib/ain-evm/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] ain-cpp-imports = { path = "../ain-cpp-imports" } -contracts = { path = "../contracts" } +ain-contracts = { path = "../ain-contracts" } evm = { version = "0.39", default-features = false, features = ["with-serde"] } primitive-types = { version = "0.12", default-features = false, features = ["serde"] } diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index d6af52f7832..69b61551056 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -19,8 +19,8 @@ use ethereum_types::{Bloom, H160, H64, U256}; use crate::bytes::Bytes; use crate::services::SERVICES; +use ain_contracts::{Contracts, CONTRACT_ADDRESSES}; use anyhow::anyhow; -use contracts::{Contracts, CONTRACT_ADDRESSES}; use hex::FromHex; use log::debug; use primitive_types::H256; @@ -347,7 +347,7 @@ impl EVMServices { .get(&Contracts::CounterContract) .unwrap() .clone(); - let bytecode = contracts::get_counter_bytecode()?; + let bytecode = ain_contracts::get_counter_bytecode()?; let (_, latest_block_number) = SERVICES .evm .block @@ -369,7 +369,7 @@ impl EVMServices { Bytes::from(bytecode), vec![( H256::from_low_u64_be(1), - contracts::u256_to_h256(count + U256::one()), + ain_contracts::u256_to_h256(count + U256::one()), )], )) } From 906b8c97f8266b93adcd041208b006bb509565b0 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Mon, 24 Jul 2023 14:14:02 +0800 Subject: [PATCH 07/32] Fix clippy errors --- lib/ain-evm/src/evm.rs | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 69b61551056..5d9bb1befbd 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -44,6 +44,12 @@ pub struct FinalizedBlockInfo { pub total_priority_fees: U256, } +pub struct CounterContractInfo { + pub address: H160, + pub storage: Vec<(H256, H256)>, + pub bytecode: Bytes, +} + impl EVMServices { /// Constructs a new Handlers instance. Depending on whether the defid -ethstartstate flag is set, /// it either revives the storage from a previously saved state or initializes new storage using input from a JSON file. @@ -149,12 +155,18 @@ impl EVMServices { let mut executor = AinExecutor::new(&mut backend); if current_block_number == U256::zero() { - let (address, bytecode, storage) = EVMServices::counter_contract().unwrap(); + let CounterContractInfo { + address, + storage, + bytecode, + } = EVMServices::counter_contract().unwrap(); executor .deploy_contract(address, bytecode, storage) .unwrap(); } else { - let (address, _, storage) = EVMServices::counter_contract().unwrap(); + let CounterContractInfo { + address, storage, .. + } = EVMServices::counter_contract().unwrap(); executor.update_storage(address, storage).unwrap(); } @@ -342,11 +354,8 @@ impl EVMServices { Ok(()) } - pub fn counter_contract() -> Result<(H160, Bytes, Vec<(H256, H256)>), Box> { - let address = CONTRACT_ADDRESSES - .get(&Contracts::CounterContract) - .unwrap() - .clone(); + pub fn counter_contract() -> Result> { + let address = *CONTRACT_ADDRESSES.get(&Contracts::CounterContract).unwrap(); let bytecode = ain_contracts::get_counter_bytecode()?; let (_, latest_block_number) = SERVICES .evm @@ -364,13 +373,13 @@ impl EVMServices { debug!("Count: {:#x}", count + U256::one()); - Ok(( + Ok(CounterContractInfo { address, - Bytes::from(bytecode), - vec![( + bytecode: Bytes::from(bytecode), + storage: vec![( H256::from_low_u64_be(1), ain_contracts::u256_to_h256(count + U256::one()), )], - )) + }) } } From e0508b008019ecd7151daaebb18e372e13606f71 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Mon, 24 Jul 2023 14:28:11 +0800 Subject: [PATCH 08/32] Remove extra new line, update gitignore --- .gitignore | 4 ++-- test/functional/feature_evm_state_root_change.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index ad0face2a83..a2ba6e1b7ed 100644 --- a/.gitignore +++ b/.gitignore @@ -148,5 +148,5 @@ contrib/devtools/split-debug.sh /lib/target *.bin -/lib/contracts/**/cache -/lib/contracts/**/output \ No newline at end of file +/lib/ain-contracts/**/cache +/lib/ain-contracts/**/output \ No newline at end of file diff --git a/test/functional/feature_evm_state_root_change.py b/test/functional/feature_evm_state_root_change.py index 9f702a22e68..3c5d0126221 100644 --- a/test/functional/feature_evm_state_root_change.py +++ b/test/functional/feature_evm_state_root_change.py @@ -33,6 +33,5 @@ def run_test(self): assert_equal(len(state_roots), NUM_BLOCKS) - if __name__ == '__main__': StateRootChangeTest().main() From 4ee9b8d5472c89fcf89e6bc8ccaa9e3caa43aaa5 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Mon, 24 Jul 2023 16:29:39 +0800 Subject: [PATCH 09/32] Undo old changes --- lib/ain-evm/src/evm.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 5d9bb1befbd..70083eacb57 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -67,34 +67,32 @@ impl EVMServices { /// /// Returns an instance of the struct, either restored from storage or created from a JSON file. pub fn new() -> Result { - let services = if let Some(path) = ain_cpp_imports::get_state_input_json() { + if let Some(path) = ain_cpp_imports::get_state_input_json() { if ain_cpp_imports::get_network() != "regtest" { return Err(anyhow!( "Loading a genesis from JSON file is restricted to regtest network" )); } let storage = Arc::new(Storage::new()); - Self { + Ok(Self { core: EVMCoreService::new_from_json(Arc::clone(&storage), PathBuf::from(path)), block: BlockService::new(Arc::clone(&storage)), receipt: ReceiptService::new(Arc::clone(&storage)), logs: LogService::new(Arc::clone(&storage)), filters: FilterService::new(), storage, - } + }) } else { let storage = Arc::new(Storage::restore()); - Self { + Ok(Self { core: EVMCoreService::restore(Arc::clone(&storage)), block: BlockService::new(Arc::clone(&storage)), receipt: ReceiptService::new(Arc::clone(&storage)), logs: LogService::new(Arc::clone(&storage)), filters: FilterService::new(), storage, - } - }; - - Ok(services) + }) + } } pub fn finalize_block( From 0ffc20ac4b9ce5854eff2d9ace92bdb6f53a38af Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Mon, 24 Jul 2023 16:42:10 +0800 Subject: [PATCH 10/32] Remove unwraps --- lib/ain-evm/src/evm.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 70083eacb57..97cb271e125 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -157,15 +157,14 @@ impl EVMServices { address, storage, bytecode, - } = EVMServices::counter_contract().unwrap(); + } = EVMServices::counter_contract()?; executor - .deploy_contract(address, bytecode, storage) - .unwrap(); + .deploy_contract(address, bytecode, storage)?; } else { let CounterContractInfo { address, storage, .. - } = EVMServices::counter_contract().unwrap(); - executor.update_storage(address, storage).unwrap(); + } = EVMServices::counter_contract()?; + executor.update_storage(address, storage)?; } for (queue_tx, hash) in self.core.tx_queues.get_cloned_vec(context) { From 034ff1696b2676ffec3eec04eabbaae524bd6f69 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Tue, 25 Jul 2023 11:34:29 +0800 Subject: [PATCH 11/32] Add test header --- .gitignore | 2 +- test/functional/feature_evm_state_root_change.py | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index a2ba6e1b7ed..e6f95254d0b 100644 --- a/.gitignore +++ b/.gitignore @@ -149,4 +149,4 @@ contrib/devtools/split-debug.sh *.bin /lib/ain-contracts/**/cache -/lib/ain-contracts/**/output \ No newline at end of file +/lib/ain-contracts/**/output diff --git a/test/functional/feature_evm_state_root_change.py b/test/functional/feature_evm_state_root_change.py index 3c5d0126221..71a0e32aa1e 100644 --- a/test/functional/feature_evm_state_root_change.py +++ b/test/functional/feature_evm_state_root_change.py @@ -1,3 +1,10 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2019 The Bitcoin Core developers +# Copyright (c) DeFi Blockchain Developers +# Distributed under the MIT software license, see the accompanying +# file LICENSE or http://www.opensource.org/licenses/mit-license.php. +"""Test that EVM state root changes on every block""" + from test_framework.test_framework import DefiTestFramework from test_framework.util import ( assert_equal From 49ec7c6bd99f38f299817819353c1a652bdc55a4 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Tue, 25 Jul 2023 11:56:43 +0800 Subject: [PATCH 12/32] Refactor to use `get_contract_storage` --- lib/ain-evm/src/backend.rs | 16 +++++++--------- lib/ain-evm/src/core.rs | 32 ++++++++++++++++++++++++++++++++ lib/ain-evm/src/evm.rs | 15 ++------------- 3 files changed, 41 insertions(+), 22 deletions(-) diff --git a/lib/ain-evm/src/backend.rs b/lib/ain-evm/src/backend.rs index 2ffa8e861e9..28bbe912d16 100644 --- a/lib/ain-evm/src/backend.rs +++ b/lib/ain-evm/src/backend.rs @@ -188,19 +188,17 @@ impl EVMBackend { .unwrap_or_default() } - pub fn get_account_storage(&self, contract: H160, storage_index: H256) -> Result { - let account = self.get_account(&contract).unwrap_or(Account { - nonce: U256::zero(), - balance: U256::zero(), - storage_root: H256::zero(), - code_hash: H256::zero(), - }); + pub fn get_contract_storage(&self, contract: H160, storage_index: &[u8]) -> Result { + let account = match self.get_account(&contract) { + Some(account) => account, + None => return Ok(U256::zero()), + }; let state = self .trie_store .trie_db .trie_restore( - contract.clone().as_bytes(), + contract.clone().as_ref(), None, account.storage_root.into(), ) @@ -208,7 +206,7 @@ impl EVMBackend { Ok(U256::from( state - .get(storage_index.clone().as_bytes()) + .get(storage_index.clone()) .unwrap_or_default() .unwrap_or_default() .as_slice(), diff --git a/lib/ain-evm/src/core.rs b/lib/ain-evm/src/core.rs index ac7eb810b73..f3dea2f8b74 100644 --- a/lib/ain-evm/src/core.rs +++ b/lib/ain-evm/src/core.rs @@ -13,6 +13,7 @@ use crate::{ traits::{Executor, ExecutorContext}, transaction::SignedTx, }; +use crate::services::SERVICES; use ethereum::{AccessList, Account, Block, Log, PartialHeader, TransactionV2}; use ethereum_types::{Bloom, BloomInput, H160, U256}; @@ -405,6 +406,37 @@ impl EVMCoreService { Ok(backend.get_account(&address)) } + pub fn get_latest_contract_storage( + &self, + contract: H160, + storage_index: U256 + ) -> Result { + let (_, block_number) = SERVICES + .evm + .block + .get_latest_block_hash_and_number() + .unwrap_or_default(); + let state_root = self + .storage + .get_block_by_number(&block_number) + .or_else(|| self.storage.get_latest_block()) + .map(|block| block.header.state_root) + .unwrap_or_default(); + + let backend = EVMBackend::from_root( + state_root, + Arc::clone(&self.trie_store), + Arc::clone(&self.storage), + Vicinity::default(), + )?; + + // convert U256 to H256 + let tmp: &mut [u8; 32] = &mut [0; 32]; + storage_index.to_big_endian(tmp); + + backend.get_contract_storage(contract, tmp.as_slice()).map_err(|e| EVMError::TrieError(e.to_string())) + } + pub fn get_code(&self, address: H160, block_number: U256) -> Result>, EVMError> { self.get_account(address, block_number).map(|opt_account| { opt_account.map_or_else( diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 97cb271e125..03bf1dcc888 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -351,22 +351,11 @@ impl EVMServices { Ok(()) } + /// Returns address, bytecode and storage with incremented count for the counter contract pub fn counter_contract() -> Result> { let address = *CONTRACT_ADDRESSES.get(&Contracts::CounterContract).unwrap(); let bytecode = ain_contracts::get_counter_bytecode()?; - let (_, latest_block_number) = SERVICES - .evm - .block - .get_latest_block_hash_and_number() - .unwrap_or_default(); - let count = U256::from( - SERVICES - .evm - .core - .get_storage_at(address, U256::one(), latest_block_number)? - .unwrap_or_default() - .as_slice(), - ); + let count = SERVICES.evm.core.get_latest_contract_storage(address, U256::one())?; debug!("Count: {:#x}", count + U256::one()); From ad1c1a020ee4d2102e82e7cf0164504064d863ec Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Tue, 25 Jul 2023 12:02:54 +0800 Subject: [PATCH 13/32] Make `basic` optional in `apply` --- lib/ain-evm/src/backend.rs | 40 ++++++++++++++++++++------------------ lib/ain-evm/src/trie.rs | 2 +- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/lib/ain-evm/src/backend.rs b/lib/ain-evm/src/backend.rs index 28bbe912d16..248d2f52dff 100644 --- a/lib/ain-evm/src/backend.rs +++ b/lib/ain-evm/src/backend.rs @@ -65,7 +65,7 @@ impl EVMBackend { pub fn apply>( &mut self, address: H160, - basic: Basic, + basic: Option, code: Option>, storage: I, reset_storage: bool, @@ -100,11 +100,19 @@ impl EVMBackend { code_hash }); - let new_account = Account { - nonce: basic.nonce, - balance: basic.balance, - code_hash, - storage_root: storage_trie.commit().into(), + let new_account = match basic { + Some(basic) => Account { + nonce: basic.nonce, + balance: basic.balance, + code_hash, + storage_root: storage_trie.commit().into(), + }, + None => Account { + nonce: account.nonce, + balance: account.balance, + code_hash, + storage_root: storage_trie.commit().into(), + } }; self.state @@ -145,7 +153,7 @@ impl EVMBackend { let balance = basic.balance.saturating_sub(prepay_gas); let new_basic = Basic { balance, ..basic }; - self.apply(sender, new_basic, None, Vec::new(), false) + self.apply(sender, Some(new_basic), None, Vec::new(), false) .expect("Error deducting account balance"); self.commit(); } @@ -168,7 +176,7 @@ impl EVMBackend { ..basic }; - self.apply(sender, new_basic, None, Vec::new(), false) + self.apply(sender, Some(new_basic), None, Vec::new(), false) .expect("Error refunding account balance"); self.commit(); } @@ -221,10 +229,7 @@ impl EVMBackend { ) -> Result<()> { self.apply( *address, - Basic { - balance: U256::zero(), - nonce: U256::zero(), - }, + None, Some(code), storage, true, @@ -236,10 +241,7 @@ impl EVMBackend { pub fn update_storage(&mut self, address: &H160, storage: Vec<(H256, H256)>) -> Result<()> { self.apply( *address, - Basic { - balance: U256::zero(), - nonce: U256::zero(), - }, + None, None, storage, false, @@ -364,7 +366,7 @@ impl ApplyBackend for EVMBackend { ); let new_account = self - .apply(address, basic, code, storage, reset_storage) + .apply(address, Some(basic), code, storage, reset_storage) .expect("Error applying state"); if is_empty_account(&new_account) && delete_empty { @@ -396,7 +398,7 @@ impl BridgeBackend for EVMBackend { ..basic }; - self.apply(address, new_basic, None, Vec::new(), false)?; + self.apply(address, Some(new_basic), None, Vec::new(), false)?; Ok(()) } @@ -417,7 +419,7 @@ impl BridgeBackend for EVMBackend { nonce: account.nonce, }; - self.apply(address, new_basic, None, Vec::new(), false)?; + self.apply(address, Some(new_basic), None, Vec::new(), false)?; Ok(()) } } diff --git a/lib/ain-evm/src/trie.rs b/lib/ain-evm/src/trie.rs index d15973ab0ad..0bd25f1feb0 100644 --- a/lib/ain-evm/src/trie.rs +++ b/lib/ain-evm/src/trie.rs @@ -83,7 +83,7 @@ impl TrieDBStore { backend .apply( address, - new_basic, + Some(new_basic), data.code, data.storage.unwrap_or_default(), false, From 45f8c29ce87c91e714ab0edb9f654a265531868b Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Tue, 25 Jul 2023 12:07:30 +0800 Subject: [PATCH 14/32] Rename to `pkg_install_solc` --- make.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make.sh b/make.sh index 3addb8cb9b7..13a9c4a9717 100755 --- a/make.sh +++ b/make.sh @@ -527,7 +527,7 @@ pkg_install_rust() { _fold_end } -pkg_install_solc_linux() { +pkg_install_solc() { _fold_start "pkg-install-solc" add-apt-repository ppa:ethereum/ethereum -y apt-get update From 6192b983934adbd2b98bcdff13b2997e5057fd59 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Tue, 25 Jul 2023 12:12:31 +0800 Subject: [PATCH 15/32] Fix make.sh, remove redundant clone --- lib/ain-evm/src/backend.rs | 26 +++++--------------------- lib/ain-evm/src/core.rs | 8 +++++--- lib/ain-evm/src/evm.rs | 8 +++++--- make.sh | 2 +- 4 files changed, 16 insertions(+), 28 deletions(-) diff --git a/lib/ain-evm/src/backend.rs b/lib/ain-evm/src/backend.rs index 248d2f52dff..c49573a6441 100644 --- a/lib/ain-evm/src/backend.rs +++ b/lib/ain-evm/src/backend.rs @@ -112,7 +112,7 @@ impl EVMBackend { balance: account.balance, code_hash, storage_root: storage_trie.commit().into(), - } + }, }; self.state @@ -205,16 +205,12 @@ impl EVMBackend { let state = self .trie_store .trie_db - .trie_restore( - contract.clone().as_ref(), - None, - account.storage_root.into(), - ) + .trie_restore(contract.clone().as_ref(), None, account.storage_root.into()) .map_err(|e| EVMBackendError::TrieRestoreFailed(e.to_string()))?; Ok(U256::from( state - .get(storage_index.clone()) + .get(storage_index) .unwrap_or_default() .unwrap_or_default() .as_slice(), @@ -227,25 +223,13 @@ impl EVMBackend { code: Vec, storage: Vec<(H256, H256)>, ) -> Result<()> { - self.apply( - *address, - None, - Some(code), - storage, - true, - )?; + self.apply(*address, None, Some(code), storage, true)?; Ok(()) } pub fn update_storage(&mut self, address: &H160, storage: Vec<(H256, H256)>) -> Result<()> { - self.apply( - *address, - None, - None, - storage, - false, - )?; + self.apply(*address, None, None, storage, false)?; Ok(()) } diff --git a/lib/ain-evm/src/core.rs b/lib/ain-evm/src/core.rs index f3dea2f8b74..4f16bab9191 100644 --- a/lib/ain-evm/src/core.rs +++ b/lib/ain-evm/src/core.rs @@ -3,6 +3,7 @@ use crate::block::INITIAL_BASE_FEE; use crate::executor::TxResponse; use crate::fee::calculate_prepay_gas; use crate::receipt::ReceiptService; +use crate::services::SERVICES; use crate::storage::traits::{BlockStorage, PersistentStateError}; use crate::storage::Storage; use crate::transaction::bridge::{BalanceUpdate, BridgeTx}; @@ -13,7 +14,6 @@ use crate::{ traits::{Executor, ExecutorContext}, transaction::SignedTx, }; -use crate::services::SERVICES; use ethereum::{AccessList, Account, Block, Log, PartialHeader, TransactionV2}; use ethereum_types::{Bloom, BloomInput, H160, U256}; @@ -409,7 +409,7 @@ impl EVMCoreService { pub fn get_latest_contract_storage( &self, contract: H160, - storage_index: U256 + storage_index: U256, ) -> Result { let (_, block_number) = SERVICES .evm @@ -434,7 +434,9 @@ impl EVMCoreService { let tmp: &mut [u8; 32] = &mut [0; 32]; storage_index.to_big_endian(tmp); - backend.get_contract_storage(contract, tmp.as_slice()).map_err(|e| EVMError::TrieError(e.to_string())) + backend + .get_contract_storage(contract, tmp.as_slice()) + .map_err(|e| EVMError::TrieError(e.to_string())) } pub fn get_code(&self, address: H160, block_number: U256) -> Result>, EVMError> { diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 03bf1dcc888..78cba6d7e12 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -158,8 +158,7 @@ impl EVMServices { storage, bytecode, } = EVMServices::counter_contract()?; - executor - .deploy_contract(address, bytecode, storage)?; + executor.deploy_contract(address, bytecode, storage)?; } else { let CounterContractInfo { address, storage, .. @@ -355,7 +354,10 @@ impl EVMServices { pub fn counter_contract() -> Result> { let address = *CONTRACT_ADDRESSES.get(&Contracts::CounterContract).unwrap(); let bytecode = ain_contracts::get_counter_bytecode()?; - let count = SERVICES.evm.core.get_latest_contract_storage(address, U256::one())?; + let count = SERVICES + .evm + .core + .get_latest_contract_storage(address, U256::one())?; debug!("Count: {:#x}", count + U256::one()); diff --git a/make.sh b/make.sh index 13a9c4a9717..184828ec00d 100755 --- a/make.sh +++ b/make.sh @@ -956,7 +956,7 @@ ci_setup_deps() { DEBIAN_FRONTEND=noninteractive pkg_setup_locale DEBIAN_FRONTEND=noninteractive pkg_install_llvm DEBIAN_FRONTEND=noninteractive pkg_install_rust - DEBIAN_FRONTEND=noninteractive pkg_install_solc_linux + DEBIAN_FRONTEND=noninteractive pkg_install_solc } _ci_setup_deps_target() { From 6fbd318b0abb2185f8bd650e993731f57fa68bfe Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Tue, 25 Jul 2023 12:27:53 +0800 Subject: [PATCH 16/32] Compile multiple contracts --- lib/ain-contracts/build.rs | 70 ++-- lib/ain-contracts/dst20/ERC20.sol | 515 ++++++++++++++++++++++++++++++ 2 files changed, 552 insertions(+), 33 deletions(-) create mode 100644 lib/ain-contracts/dst20/ERC20.sol diff --git a/lib/ain-contracts/build.rs b/lib/ain-contracts/build.rs index 7187023c427..ce6b23a09ca 100644 --- a/lib/ain-contracts/build.rs +++ b/lib/ain-contracts/build.rs @@ -6,42 +6,46 @@ use std::path::PathBuf; fn main() -> Result<(), Box> { // compile solidity project // configure `root` as our project root - let root = PathBuf::from("counter_contract"); - if !root.exists() { - return Err("Project root {root:?} does not exists!".into()); - } + let contracts = vec![("counter_contract", "Counter"), ("dst20", "DST20")]; - let paths = ProjectPathsConfig::builder() - .root(&root) - .sources(&root) - .build()?; - - let project = Project::builder() - .paths(paths) - .set_auto_detect(true) - .no_artifacts() - .build()?; - let output = project.compile().unwrap(); - let artifacts = output.into_artifacts(); - - for (id, artifact) in artifacts { - if id.name == "Counter" { - let abi = artifact.abi.ok_or_else(|| anyhow!("ABI not found"))?; - let bytecode = artifact.deployed_bytecode.expect("No bytecode found"); - - fs::create_dir_all("counter_contract/output/")?; - fs::write( - PathBuf::from("counter_contract/output/bytecode.json"), - serde_json::to_string(&bytecode).unwrap().as_bytes(), - )?; - fs::write( - PathBuf::from("counter_contract/output/abi.json"), - serde_json::to_string(&abi).unwrap().as_bytes(), - )?; + for (file_path, contract_name) in contracts { + let root = PathBuf::from(file_path); + if !root.exists() { + return Err("Project root {root:?} does not exists!".into()); } - } - project.rerun_if_sources_changed(); + let paths = ProjectPathsConfig::builder() + .root(&root) + .sources(&root) + .build()?; + + let project = Project::builder() + .paths(paths) + .set_auto_detect(true) + .no_artifacts() + .build()?; + let output = project.compile().unwrap(); + let artifacts = output.into_artifacts(); + + for (id, artifact) in artifacts { + if id.name == contract_name { + let abi = artifact.abi.ok_or_else(|| anyhow!("ABI not found"))?; + let bytecode = artifact.deployed_bytecode.expect("No bytecode found"); + + fs::create_dir_all(format!("{file_path}/output/"))?; + fs::write( + PathBuf::from(format!("{file_path}/output/bytecode.json")), + serde_json::to_string(&bytecode).unwrap().as_bytes(), + )?; + fs::write( + PathBuf::from(format!("{file_path}/output/abi.json")), + serde_json::to_string(&abi).unwrap().as_bytes(), + )?; + } + } + + project.rerun_if_sources_changed(); + } Ok(()) } diff --git a/lib/ain-contracts/dst20/ERC20.sol b/lib/ain-contracts/dst20/ERC20.sol new file mode 100644 index 00000000000..b494acce4b2 --- /dev/null +++ b/lib/ain-contracts/dst20/ERC20.sol @@ -0,0 +1,515 @@ + +// File: @openzeppelin/contracts@4.9.2/utils/Context.sol + + +// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + +// File: @openzeppelin/contracts@4.9.2/token/ERC20/IERC20.sol + + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `from` to `to` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 amount) external returns (bool); +} + +// File: @openzeppelin/contracts@4.9.2/token/ERC20/extensions/IERC20Metadata.sol + + +// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) + +pragma solidity ^0.8.0; + + +/** + * @dev Interface for the optional metadata functions from the ERC20 standard. + * + * _Available since v4.1._ + */ +interface IERC20Metadata is IERC20 { + /** + * @dev Returns the name of the token. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the symbol of the token. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the decimals places of the token. + */ + function decimals() external view returns (uint8); +} + +// File: @openzeppelin/contracts@4.9.2/token/ERC20/ERC20.sol + + +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) + +pragma solidity ^0.8.0; + + + + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * For a generic mechanism see {ERC20PresetMinterPauser}. + * + * TIP: For a detailed writeup see our guide + * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * The default value of {decimals} is 18. To change this, you should override + * this function so it returns a different value. + * + * We have followed general OpenZeppelin Contracts guidelines: functions revert + * instead returning `false` on failure. This behavior is nonetheless + * conventional and does not conflict with the expectations of ERC20 + * applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + * + * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} + * functions have been added to mitigate the well-known issues around setting + * allowances. See {IERC20-approve}. + */ +contract ERC20 is Context, IERC20, IERC20Metadata { + mapping(address => uint256) private _balances; + + mapping(address => mapping(address => uint256)) private _allowances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + + /** + * @dev Sets the values for {name} and {symbol}. + * + * All two of these values are immutable: they can only be set once during + * construction. + */ + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5.05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the default value returned by this function, unless + * it's overridden. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view virtual override returns (uint8) { + return 18; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view virtual override returns (uint256) { + return _totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) public view virtual override returns (uint256) { + return _balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - the caller must have a balance of at least `amount`. + */ + function transfer(address to, uint256 amount) public virtual override returns (bool) { + address owner = _msgSender(); + _transfer(owner, to, amount); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) public view virtual override returns (uint256) { + return _allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on + * `transferFrom`. This is semantically equivalent to an infinite approval. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, amount); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}. + * + * NOTE: Does not update the allowance if the current allowance + * is the maximum `uint256`. + * + * Requirements: + * + * - `from` and `to` cannot be the zero address. + * - `from` must have a balance of at least `amount`. + * - the caller must have allowance for ``from``'s tokens of at least + * `amount`. + */ + function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { + address spender = _msgSender(); + _spendAllowance(from, spender, amount); + _transfer(from, to, amount); + return true; + } + + /** + * @dev Atomically increases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, allowance(owner, spender) + addedValue); + return true; + } + + /** + * @dev Atomically decreases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `spender` must have allowance for the caller of at least + * `subtractedValue`. + */ + function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { + address owner = _msgSender(); + uint256 currentAllowance = allowance(owner, spender); + require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); + unchecked { + _approve(owner, spender, currentAllowance - subtractedValue); + } + + return true; + } + + /** + * @dev Moves `amount` of tokens from `from` to `to`. + * + * This internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `from` must have a balance of at least `amount`. + */ + function _transfer(address from, address to, uint256 amount) internal virtual { + require(from != address(0), "ERC20: transfer from the zero address"); + require(to != address(0), "ERC20: transfer to the zero address"); + + _beforeTokenTransfer(from, to, amount); + + uint256 fromBalance = _balances[from]; + require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); + unchecked { + _balances[from] = fromBalance - amount; + // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by + // decrementing then incrementing. + _balances[to] += amount; + } + + emit Transfer(from, to, amount); + + _afterTokenTransfer(from, to, amount); + } + + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + function _mint(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: mint to the zero address"); + + _beforeTokenTransfer(address(0), account, amount); + + _totalSupply += amount; + unchecked { + // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. + _balances[account] += amount; + } + emit Transfer(address(0), account, amount); + + _afterTokenTransfer(address(0), account, amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, reducing the + * total supply. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * Requirements: + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + */ + function _burn(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: burn from the zero address"); + + _beforeTokenTransfer(account, address(0), amount); + + uint256 accountBalance = _balances[account]; + require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); + unchecked { + _balances[account] = accountBalance - amount; + // Overflow not possible: amount <= accountBalance <= totalSupply. + _totalSupply -= amount; + } + + emit Transfer(account, address(0), amount); + + _afterTokenTransfer(account, address(0), amount); + } + + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. + * + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _approve(address owner, address spender, uint256 amount) internal virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /** + * @dev Updates `owner` s allowance for `spender` based on spent `amount`. + * + * Does not update the allowance amount in case of infinite allowance. + * Revert if not enough allowance is available. + * + * Might emit an {Approval} event. + */ + function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { + uint256 currentAllowance = allowance(owner, spender); + if (currentAllowance != type(uint256).max) { + require(currentAllowance >= amount, "ERC20: insufficient allowance"); + unchecked { + _approve(owner, spender, currentAllowance - amount); + } + } + } + + /** + * @dev Hook that is called before any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * will be transferred to `to`. + * - when `from` is zero, `amount` tokens will be minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} + + /** + * @dev Hook that is called after any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * has been transferred to `to`. + * - when `from` is zero, `amount` tokens have been minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens have been burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} +} + +// File: oz.sol + + +pragma solidity ^0.8.9; + + +contract DST20 is ERC20 { + constructor(string memory name, string memory symbol) ERC20(name, symbol) {} +} From 979b7318de0b54071346011b39d3a9e4bd369c1c Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Tue, 25 Jul 2023 12:56:13 +0800 Subject: [PATCH 17/32] Add DST20 support --- lib/Cargo.lock | 2 + lib/ain-contracts/Cargo.toml | 1 + lib/ain-contracts/src/lib.rs | 32 +++++ lib/ain-evm/src/core.rs | 9 +- lib/ain-evm/src/evm.rs | 103 +++++++++++++- lib/ain-evm/src/lib.rs | 2 +- lib/ain-evm/src/transaction/mod.rs | 1 + lib/ain-evm/src/transaction/system.rs | 22 +++ lib/ain-evm/src/txqueue.rs | 3 + lib/ain-rs-exports/Cargo.toml | 1 + lib/ain-rs-exports/src/evm.rs | 85 +++++++++++ lib/ain-rs-exports/src/lib.rs | 17 +++ src/masternodes/mn_checks.cpp | 62 ++++++-- test/functional/feature_dst20.py | 196 ++++++++++++++++++++++++++ 14 files changed, 512 insertions(+), 24 deletions(-) create mode 100644 lib/ain-evm/src/transaction/system.rs create mode 100644 test/functional/feature_dst20.py diff --git a/lib/Cargo.lock b/lib/Cargo.lock index d308069862e..278108ca769 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -100,6 +100,7 @@ dependencies = [ "lazy_static", "primitive-types", "serde_json", + "sha3", ] [[package]] @@ -197,6 +198,7 @@ dependencies = [ name = "ain-rs-exports" version = "0.1.0" dependencies = [ + "ain-contracts", "ain-evm", "ain-grpc", "anyhow", diff --git a/lib/ain-contracts/Cargo.toml b/lib/ain-contracts/Cargo.toml index b5d790cd11b..337e169cf70 100644 --- a/lib/ain-contracts/Cargo.toml +++ b/lib/ain-contracts/Cargo.toml @@ -12,6 +12,7 @@ ethereum = "0.14.0" serde_json = "1.0.96" hex = "0.4.3" lazy_static = "1.4" +sha3 = "0.10.6" [build-dependencies] ethers = "2.0.7" diff --git a/lib/ain-contracts/src/lib.rs b/lib/ain-contracts/src/lib.rs index 99446592e36..176860c65ad 100644 --- a/lib/ain-contracts/src/lib.rs +++ b/lib/ain-contracts/src/lib.rs @@ -4,6 +4,7 @@ use primitive_types::{H160, H256, U256}; use std::collections::HashMap; use std::error::Error; use std::str::FromStr; +use sha3::{Digest, Keccak256}; pub fn u256_to_h256(input: U256) -> H256 { let mut bytes = [0_u8; 32]; @@ -22,6 +23,25 @@ pub fn get_abi_encoded_string(input: &str) -> H256 { storage_value } +pub fn get_address_storage_index(address: H160) -> H256 { + // padded slot, slot for our contract is 0 + let slot = H256::zero(); + + // padded key + let key = H256::from(address); + + // keccak256(padded key + padded slot) + let mut hasher = Keccak256::new(); + hasher.update(key.as_fixed_bytes()); + hasher.update(slot.as_fixed_bytes()); + let hash_result = hasher.finalize(); + + let mut index_bytes = [0u8; 32]; + index_bytes.copy_from_slice(&hash_result); + + H256::from(index_bytes) +} + pub fn get_bytecode(input: &str) -> Result, Box> { let bytecode_json: serde_json::Value = serde_json::from_str(input)?; let bytecode_raw = bytecode_json["object"] @@ -35,6 +55,18 @@ pub fn get_counter_bytecode() -> Result, Box> { get_bytecode(include_str!("../counter_contract/output/bytecode.json")) } +pub fn get_dst20_bytecode() -> Result, Box> { + get_bytecode(include_str!("../dst20/output/bytecode.json")) +} + +pub fn dst20_address_from_token_id(token_id: &str) -> Result> { + let number_str = format!("{:x}", token_id.parse::()?); + let padded_number_str = format!("{:0>38}", number_str); + let final_str = format!("ff{}", padded_number_str); + + Ok(H160::from_str(&final_str)?) +} + #[derive(Debug, PartialEq, Eq, Hash)] pub enum Contracts { CounterContract, diff --git a/lib/ain-evm/src/core.rs b/lib/ain-evm/src/core.rs index 411b920c149..7eae7b71a87 100644 --- a/lib/ain-evm/src/core.rs +++ b/lib/ain-evm/src/core.rs @@ -412,7 +412,7 @@ impl EVMCoreService { pub fn get_latest_contract_storage( &self, contract: H160, - storage_index: U256, + storage_index: H256, ) -> Result { let (_, block_number) = SERVICES .evm @@ -433,12 +433,8 @@ impl EVMCoreService { Vicinity::default(), )?; - // convert U256 to H256 - let tmp: &mut [u8; 32] = &mut [0; 32]; - storage_index.to_big_endian(tmp); - backend - .get_contract_storage(contract, tmp.as_slice()) + .get_contract_storage(contract, storage_index.as_bytes()) .map_err(|e| EVMError::TrieError(e.to_string())) } @@ -512,6 +508,7 @@ impl EVMCoreService { } use std::fmt; +use primitive_types::H256; #[derive(Debug)] pub enum EVMError { diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 6621ffb42a3..9c38b2a139a 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -19,6 +19,7 @@ use ethereum_types::{Bloom, H160, H64, U256}; use crate::bytes::Bytes; use crate::services::SERVICES; +use crate::transaction::system::{DST20Data, DeployContractData, SystemTx}; use ain_contracts::{Contracts, CONTRACT_ADDRESSES}; use anyhow::anyhow; use hex::FromHex; @@ -46,12 +47,17 @@ pub struct FinalizedBlockInfo { pub total_priority_fees: U256, } -pub struct CounterContractInfo { +pub struct DeployContractInfo { pub address: H160, pub storage: Vec<(H256, H256)>, pub bytecode: Bytes, } +pub struct DST20BridgeInfo { + pub address: H160, + pub storage: Vec<(H256, H256)>, +} + impl EVMServices { /// Constructs a new Handlers instance. Depending on whether the defid -ethstartstate flag is set, /// it either revives the storage from a previously saved state or initializes new storage using input from a JSON file. @@ -155,14 +161,14 @@ impl EVMServices { let mut executor = AinExecutor::new(&mut backend); if current_block_number == U256::zero() { - let CounterContractInfo { + let DeployContractInfo { address, storage, bytecode, } = EVMServices::counter_contract()?; executor.deploy_contract(address, bytecode, storage)?; } else { - let CounterContractInfo { + let DeployContractInfo { address, storage, .. } = EVMServices::counter_contract()?; executor.update_storage(address, storage)?; @@ -227,6 +233,44 @@ impl EVMServices { failed_transactions.push(hex::encode(hash)); } } + QueueTx::SystemTx(SystemTx::DeployContract(DeployContractData { + name, + symbol, + address, + })) => { + debug!( + "[finalize_block] DeployContract for address {}, name {}, symbol {}", + address, name, symbol + ); + + let DeployContractInfo { + address, + bytecode, + storage, + } = EVMServices::dst20_contract(address, name, symbol)?; + + if let Err(e) = executor.deploy_contract(address, bytecode, storage) { + debug!("[finalize_block] EvmOut failed with {e}"); + } + } + QueueTx::SystemTx(SystemTx::DST20Bridge(DST20Data { + to, + contract, + amount, + out, + })) => { + debug!( + "[finalize_block] DST20Bridge for to {}, contract {}, amount {}, out {}", + to, contract, amount, out + ); + + let DST20BridgeInfo { address, storage } = + EVMServices::bridge_dst20(contract, to, amount, out)?; + + if let Err(e) = executor.update_storage(address, storage) { + debug!("[finalize_block] EvmOut failed with {e}"); + } + } } executor.commit(); @@ -380,17 +424,17 @@ impl EVMServices { } /// Returns address, bytecode and storage with incremented count for the counter contract - pub fn counter_contract() -> Result> { + pub fn counter_contract() -> Result> { let address = *CONTRACT_ADDRESSES.get(&Contracts::CounterContract).unwrap(); let bytecode = ain_contracts::get_counter_bytecode()?; let count = SERVICES .evm .core - .get_latest_contract_storage(address, U256::one())?; + .get_latest_contract_storage(address, ain_contracts::u256_to_h256(U256::one()))?; debug!("Count: {:#x}", count + U256::one()); - Ok(CounterContractInfo { + Ok(DeployContractInfo { address, bytecode: Bytes::from(bytecode), storage: vec![( @@ -399,4 +443,51 @@ impl EVMServices { )], }) } + + pub fn dst20_contract( + address: H160, + name: String, + symbol: String, + ) -> Result> { + let bytecode = ain_contracts::get_dst20_bytecode()?; + let storage = vec![ + ( + H256::from_low_u64_be(3), + ain_contracts::get_abi_encoded_string(name.as_str()), + ), + ( + H256::from_low_u64_be(4), + ain_contracts::get_abi_encoded_string(symbol.as_str()), + ), + ]; + + Ok(DeployContractInfo { + address, + bytecode: Bytes::from(bytecode), + storage, + }) + } + + pub fn bridge_dst20( + contract: H160, + to: H160, + amount: U256, + out: bool, + ) -> Result> { + let storage_index = ain_contracts::get_address_storage_index(to); + let mut balance = SERVICES + .evm + .core + .get_latest_contract_storage(contract, storage_index)?; + + match out { + true => balance -= amount, + false => balance += amount, + } + + Ok(DST20BridgeInfo { + address: contract, + storage: vec![(storage_index, ain_contracts::u256_to_h256(balance))], + }) + } } diff --git a/lib/ain-evm/src/lib.rs b/lib/ain-evm/src/lib.rs index 4a49b436fbb..048553e7102 100644 --- a/lib/ain-evm/src/lib.rs +++ b/lib/ain-evm/src/lib.rs @@ -17,5 +17,5 @@ pub mod storage; pub mod traits; pub mod transaction; mod trie; -mod txqueue; +pub mod txqueue; pub mod weiamount; diff --git a/lib/ain-evm/src/transaction/mod.rs b/lib/ain-evm/src/transaction/mod.rs index 412621b58c6..0a9d178fe41 100644 --- a/lib/ain-evm/src/transaction/mod.rs +++ b/lib/ain-evm/src/transaction/mod.rs @@ -1,4 +1,5 @@ pub mod bridge; +pub mod system; use crate::ecrecover::{public_key_to_address, recover_public_key}; use ethereum::{ diff --git a/lib/ain-evm/src/transaction/system.rs b/lib/ain-evm/src/transaction/system.rs new file mode 100644 index 00000000000..8aa498a602c --- /dev/null +++ b/lib/ain-evm/src/transaction/system.rs @@ -0,0 +1,22 @@ +use primitive_types::{H160, U256}; + +#[derive(Debug, Clone)] +pub struct DeployContractData { + pub name: String, + pub symbol: String, + pub address: H160, +} + +#[derive(Debug, Clone)] +pub struct DST20Data { + pub to: H160, + pub contract: H160, + pub amount: U256, + pub out: bool, +} + +#[derive(Debug, Clone)] +pub enum SystemTx { + DeployContract(DeployContractData), + DST20Bridge(DST20Data), +} diff --git a/lib/ain-evm/src/txqueue.rs b/lib/ain-evm/src/txqueue.rs index 34b9e6c475a..4e4b6dbabc8 100644 --- a/lib/ain-evm/src/txqueue.rs +++ b/lib/ain-evm/src/txqueue.rs @@ -10,6 +10,7 @@ use crate::{ fee::calculate_gas_fee, transaction::{bridge::BridgeTx, SignedTx}, }; +use crate::transaction::system::SystemTx; #[derive(Debug)] pub struct TransactionQueueMap { @@ -171,6 +172,7 @@ impl TransactionQueueMap { pub enum QueueTx { SignedTx(Box), BridgeTx(BridgeTx), + SystemTx(SystemTx), } type QueueTxWithNativeHash = (QueueTx, NativeTxHash); @@ -263,6 +265,7 @@ impl TransactionQueue { let tx_sender = match tx { QueueTx::SignedTx(tx) => tx.sender, QueueTx::BridgeTx(tx) => tx.sender(), + QueueTx::SystemTx(_) => H160::zero(), // this is safe to do since we do not remove this transaction during mining }; tx_sender != sender }); diff --git a/lib/ain-rs-exports/Cargo.toml b/lib/ain-rs-exports/Cargo.toml index 041445b9f2f..4fcada7d874 100644 --- a/lib/ain-rs-exports/Cargo.toml +++ b/lib/ain-rs-exports/Cargo.toml @@ -12,6 +12,7 @@ crate-type = ["staticlib"] [dependencies] ain-evm = { path = "../ain-evm" } ain-grpc = { path = "../ain-grpc" } +ain-contracts = { path = "../ain-contracts" } ethereum = "0.14.0" rlp = "0.5.2" diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index 67c5096f3c5..d3a7668ee8c 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -1,3 +1,4 @@ +use std::error::Error; use ain_evm::{ core::ValidateTxInfo, evm::FinalizedBlockInfo, @@ -8,9 +9,11 @@ use ain_evm::{ }; use ain_evm::storage::traits::BlockStorage; +use ain_evm::transaction::system::{DeployContractData, DST20Data, SystemTx}; use ethereum::{EnvelopedEncodable, TransactionAction, TransactionSignature}; use log::debug; use primitive_types::{H160, H256, U256}; +use ain_evm::txqueue::QueueTx; use transaction::{LegacyUnsignedTransaction, TransactionError, LOWER_H256}; use crate::ffi; @@ -432,3 +435,85 @@ pub fn evm_try_get_block_number_by_hash( None => cross_boundary_error_return(result, "Invalid block hash"), } } + +pub fn evm_create_dst20( + result: &mut ffi::CrossBoundaryResult, + context: u64, + native_hash: [u8; 32], + name: &str, + symbol: &str, + token_id: &str, +) { + match create_dst20(context, native_hash, name, symbol, token_id) { + Ok(_) => cross_boundary_success(result), + Err(e) => { + cross_boundary_error_return(result, e.to_string()) + } + } +} + + +pub fn evm_bridge_dst20( + result: &mut ffi::CrossBoundaryResult, + context: u64, + address: &str, + amount: [u8; 32], + native_tx_hash: [u8; 32], + token_id: &str, + out: bool, +) { + match bridge_to_dst20( + context, + address, + amount, + native_tx_hash, + token_id, + out, + ) { + Ok(_) => cross_boundary_success(result), + Err(e) => cross_boundary_error_return(result, e.to_string()) + } +} + +fn create_dst20( + context: u64, + native_hash: [u8; 32], + name: &str, + symbol: &str, + token_id: &str, +) -> Result<(), Box> { + let address = ain_contracts::dst20_address_from_token_id(token_id)?; + debug!("Deploying to address {:#?}", address); + + let system_tx = QueueTx::SystemTx(SystemTx::DeployContract(DeployContractData { + name: String::from(name), + symbol: String::from(symbol), + address, + })); + SERVICES.evm.queue_tx(context, system_tx, native_hash, 0)?; + + Ok(()) +} + + +fn bridge_to_dst20( + context: u64, + address: &str, + amount: [u8; 32], + native_hash: [u8; 32], + token_id: &str, + out: bool, +) -> Result<(), Box> { + let address = address.parse()?; + let contract = ain_contracts::dst20_address_from_token_id(token_id)?; + + let system_tx = QueueTx::SystemTx(SystemTx::DST20Bridge(DST20Data { + to: address, + contract, + amount: amount.into(), + out, + })); + SERVICES.evm.queue_tx(context, system_tx, native_hash, 0)?; + + Ok(()) +} diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index e65ef567809..faea0896f07 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -122,5 +122,22 @@ pub mod ffi { result: &mut CrossBoundaryResult, hash: [u8; 32], ) -> u64; + fn evm_create_dst20( + result: &mut CrossBoundaryResult, + context: u64, + native_hash: [u8; 32], + name: &str, + symbol: &str, + token_id: &str, + ); + fn evm_bridge_dst20( + result: &mut CrossBoundaryResult, + context: u64, + address: &str, + amount: [u8; 32], + native_tx_hash: [u8; 32], + token_id: &str, + out: bool, + ); } } diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 418cc6936e4..ab8e21995f4 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -1047,8 +1047,11 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { CTokenImplementation token; static_cast(token) = obj; - token.symbol = trim_ws(token.symbol).substr(0, CToken::MAX_TOKEN_SYMBOL_LENGTH); - token.name = trim_ws(token.name).substr(0, CToken::MAX_TOKEN_NAME_LENGTH); + auto tokenSymbol = trim_ws(token.symbol).substr(0, CToken::MAX_TOKEN_SYMBOL_LENGTH); + auto tokenName = trim_ws(token.name).substr(0, CToken::MAX_TOKEN_NAME_LENGTH); + + token.symbol = tokenSymbol; + token.name = tokenName; token.creationTx = tx.GetHash(); token.creationHeight = height; @@ -1060,11 +1063,25 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { if (static_cast(height) >= consensus.BayfrontHeight) { // formal compatibility if someone cheat and create // LPS token on the pre-bayfront node if (token.IsPoolShare()) { - return Res::Err("Cant't manually create 'Liquidity Pool Share' token; use poolpair creation"); + return Res::Err("Can't manually create 'Liquidity Pool Share' token; use poolpair creation"); } } - return mnview.CreateToken(token, static_cast(height) < consensus.BayfrontHeight); + auto tokenId = mnview.CreateToken(token, static_cast(height) < consensus.BayfrontHeight); + + if (tokenId && IsEVMEnabled(height, mnview, consensus)) { + CrossBoundaryResult result; + evm_create_dst20(result, evmContext, tx.GetHash().GetByteArray(), + rust::string(tokenName.c_str()), + rust::string(tokenSymbol.c_str()), + tokenId->ToString()); + + if (!result.ok) { + return Res::Err("Error creating DST20 token: %s", result.reason); + } + } + + return tokenId; } Res operator()(const CUpdateTokenPreAMKMessage &obj) const { @@ -3886,9 +3903,23 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { ExtractDestination(src.address, dest); const auto fromAddress = std::get(dest); arith_uint256 balanceIn = src.amount.nValue; + auto tokenId = dst.amount.nTokenId; balanceIn *= CAMOUNT_TO_GWEI * WEI_IN_GWEI; - if (!evm_sub_balance(evmContext, HexStr(fromAddress.begin(), fromAddress.end()), ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray())) { - return DeFiErrors::TransferDomainNotEnoughBalance(EncodeDestination(dest)); + + if (tokenId == DCT_ID{0}) { + if (!evm_sub_balance(evmContext, HexStr(fromAddress.begin(), fromAddress.end()), + ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray())) { + return DeFiErrors::TransferDomainNotEnoughBalance(EncodeDestination(dest)); + } + } + else { + CrossBoundaryResult result; + evm_bridge_dst20(result, evmContext, HexStr(fromAddress.begin(), fromAddress.end()), + ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray(), tokenId.ToString(), true); + + if (!result.ok) { + return Res::Err("Error bridging DST20: %s", result.reason); + } } } if (dst.domain == static_cast(VMDomain::DVM)) { @@ -3904,8 +3935,21 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { ExtractDestination(dst.address, dest); const auto toAddress = std::get(dest); arith_uint256 balanceIn = dst.amount.nValue; + auto tokenId = dst.amount.nTokenId; balanceIn *= CAMOUNT_TO_GWEI * WEI_IN_GWEI; - evm_add_balance(evmContext, HexStr(toAddress.begin(), toAddress.end()), ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray()); + if (tokenId == DCT_ID{0}) { + evm_add_balance(evmContext, HexStr(toAddress.begin(), toAddress.end()), + ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray()); + } + else { + CrossBoundaryResult result; + evm_bridge_dst20(result, evmContext, HexStr(toAddress.begin(), toAddress.end()), + ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray(), tokenId.ToString(), false); + + if (!result.ok) { + return Res::Err("Error bridging DST20: %s", result.reason); + } + } } // If you are here to change ChangiIntermediateHeight to NextNetworkUpgradeHeight @@ -4058,10 +4102,6 @@ Res ValidateTransferDomainEdge(const CTransaction &tx, if (src.amount.nValue != dst.amount.nValue) return DeFiErrors::TransferDomainUnequalAmount(); - // Restrict only for use with DFI token for now. Will be enabled later. - if (src.amount.nTokenId != DCT_ID{0} || dst.amount.nTokenId != DCT_ID{0}) - return DeFiErrors::TransferDomainIncorrectToken(); - if (src.domain == static_cast(VMDomain::DVM) && dst.domain == static_cast(VMDomain::EVM)) { if (height >= static_cast(consensus.ChangiIntermediateHeight4)) { if (!transferdomainConfig.dvmToEvm) { diff --git a/test/functional/feature_dst20.py b/test/functional/feature_dst20.py new file mode 100644 index 00000000000..f95458d12e4 --- /dev/null +++ b/test/functional/feature_dst20.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2019 The Bitcoin Core developers +# Copyright (c) DeFi Blockchain Developers +# Distributed under the MIT software license, see the accompanying +# file LICENSE or http://www.opensource.org/licenses/mit-license.php. +"""Test EVM behaviour""" + +import math +from decimal import Decimal + +from test_framework.evm_key_pair import KeyPair +from test_framework.test_framework import DefiTestFramework +from test_framework.util import assert_equal + + + +class DST20(DefiTestFramework): + def set_test_params(self): + self.num_nodes = 1 + self.setup_clean_chain = True + self.extra_args = [ + [ + "-txordering=2", + "-dummypos=0", + "-txnotokens=0", + "-amkheight=50", + "-bayfrontheight=51", + "-eunosheight=80", + "-fortcanningheight=82", + "-fortcanninghillheight=84", + "-fortcanningroadheight=86", + "-fortcanningcrunchheight=88", + "-fortcanningspringheight=90", + "-fortcanninggreatworldheight=94", + "-fortcanningepilogueheight=96", + "-grandcentralheight=101", + "-nextnetworkupgradeheight=105", + "-changiintermediateheight=105", + "-changiintermediate3height=105", + "-subsidytest=1", + "-txindex=1", + ] + ] + + def run_test(self): + node = self.nodes[0] + address = node.get_genesis_keys().ownerAuthAddress + + # Generate chain + node.generate(105) + self.nodes[0].utxostoaccount({address: "100@DFI"}) + self.nodes[0].setgov({"ATTRIBUTES": {"v0/params/feature/evm": "true"}}) + self.nodes[0].generate(1) + node.transferdomain( + [ + { + "src": {"address": address, "amount": "50@DFI", "domain": 2}, + "dst": { + "address": "0xeB4B222C3dE281d40F5EBe8B273106bFcC1C1b94", + "amount": "50@DFI", + "domain": 3, + }, + } + ] + ) + self.nodes[0].generate(1) + + from web3 import Web3 + + web3 = Web3(Web3.HTTPProvider(node.get_evm_rpc())) + + node.createtoken( + { + "symbol": "BTC", + "name": "BTC token", + "isDAT": True, + "collateralAddress": address, + } + ) + self.nodes[0].generate(1) + self.sync_blocks() + + node.createtoken( + { + "symbol": "ETH", + "name": "ETH token", + "isDAT": True, + "collateralAddress": address, + } + ) + node.createtoken( + { + "symbol": "DUSD", + "name": "DUSD token", + "isDAT": True, + "collateralAddress": address, + } + ) + self.nodes[0].generate(1) + self.sync_blocks() + + contract_address_btc = "0xff00000000000000000000000000000000000001" + contract_address_eth = "0xff00000000000000000000000000000000000002" + contract_address_dusd = Web3.to_checksum_address( + "0xff00000000000000000000000000000000000003" + ) + + abi = open("./lib/ain-contracts/dst20/output/abi.json", encoding="utf-8").read() + + btc = web3.eth.contract(address=contract_address_btc, abi=abi) + assert_equal(btc.functions.name().call(), "BTC token") + assert_equal(btc.functions.symbol().call(), "BTC") + + eth = web3.eth.contract(address=contract_address_eth, abi=abi) + assert_equal(eth.functions.name().call(), "ETH token") + assert_equal(eth.functions.symbol().call(), "ETH") + + dusd = web3.eth.contract(address=contract_address_dusd, abi=abi) + assert_equal(dusd.functions.name().call(), "DUSD token") + assert_equal(dusd.functions.symbol().call(), "DUSD") + + key_pair = KeyPair.from_node(node) + + node.minttokens("10@BTC") + node.generate(1) + + self.nodes[0].transferdomain( + [ + { + "src": {"address": address, "amount": "1@BTC", "domain": 2}, + "dst": { + "address": key_pair.address, + "amount": "1@BTC", + "domain": 3, + }, + } + ] + ) + node.generate(1) + + assert_equal( + btc.functions.balanceOf(key_pair.address).call() + / math.pow(10, btc.functions.decimals().call()), + Decimal(1), + ) + + [amountBTC] = [x for x in node.getaccount(address) if "BTC" in x] + assert_equal(amountBTC, "9.00000000@BTC") + + self.nodes[0].transferdomain( + [ + { + "src": {"address": address, "amount": "1@BTC", "domain": 2}, + "dst": { + "address": key_pair.address, + "amount": "1@BTC", + "domain": 3, + }, + } + ] + ) + node.generate(1) + + assert_equal( + btc.functions.balanceOf(key_pair.address).call() + / math.pow(10, btc.functions.decimals().call()), + Decimal(2), + ) + [amountBTC] = [x for x in node.getaccount(address) if "BTC" in x] + assert_equal(amountBTC, "8.00000000@BTC") + + self.nodes[0].transferdomain( + [ + { + "dst": {"address": address, "amount": "1.5@BTC", "domain": 2}, + "src": { + "address": key_pair.address, + "amount": "1.5@BTC", + "domain": 3, + }, + } + ] + ) + node.generate(1) + + assert_equal( + btc.functions.balanceOf(key_pair.address).call() + / math.pow(10, btc.functions.decimals().call()), + Decimal(0.5), + ) + [amountBTC] = [x for x in node.getaccount(address) if "BTC" in x] + assert_equal(amountBTC, "9.50000000@BTC") + + +if __name__ == "__main__": + DST20().main() \ No newline at end of file From 3264493e227eb6fdc7b7558f9243b8b2a7510f31 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Tue, 25 Jul 2023 13:26:05 +0800 Subject: [PATCH 18/32] Only deploy DST20 of DATs --- src/masternodes/mn_checks.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index ab8e21995f4..b92dac58ffc 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -1069,7 +1069,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { auto tokenId = mnview.CreateToken(token, static_cast(height) < consensus.BayfrontHeight); - if (tokenId && IsEVMEnabled(height, mnview, consensus)) { + if (tokenId && token.IsDAT() && IsEVMEnabled(height, mnview, consensus)) { CrossBoundaryResult result; evm_create_dst20(result, evmContext, tx.GetHash().GetByteArray(), rust::string(tokenName.c_str()), From 2ce34929339b8c83aed7ebb26b1a5b2fda778f55 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Tue, 25 Jul 2023 14:33:54 +0800 Subject: [PATCH 19/32] Use executor state for bridge, add more tests --- lib/ain-evm/src/evm.rs | 18 ++--- lib/ain-evm/src/executor.rs | 2 +- test/functional/feature_dst20.py | 74 ++++++++++++++++++- test/functional/feature_evm_transferdomain.py | 4 - 4 files changed, 80 insertions(+), 18 deletions(-) diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 9c38b2a139a..7fd822daeef 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -265,7 +265,7 @@ impl EVMServices { ); let DST20BridgeInfo { address, storage } = - EVMServices::bridge_dst20(contract, to, amount, out)?; + EVMServices::bridge_dst20(&mut executor, contract, to, amount, out)?; if let Err(e) = executor.update_storage(address, storage) { debug!("[finalize_block] EvmOut failed with {e}"); @@ -469,25 +469,23 @@ impl EVMServices { } pub fn bridge_dst20( + executor: &mut AinExecutor, contract: H160, to: H160, amount: U256, out: bool, ) -> Result> { let storage_index = ain_contracts::get_address_storage_index(to); - let mut balance = SERVICES - .evm - .core - .get_latest_contract_storage(contract, storage_index)?; + let balance = executor.backend.get_contract_storage(contract, storage_index.as_bytes())?; - match out { - true => balance -= amount, - false => balance += amount, - } + let new_balance = match out { + true => balance - amount, + false => balance + amount, + }; Ok(DST20BridgeInfo { address: contract, - storage: vec![(storage_index, ain_contracts::u256_to_h256(balance))], + storage: vec![(storage_index, ain_contracts::u256_to_h256(new_balance))], }) } } diff --git a/lib/ain-evm/src/executor.rs b/lib/ain-evm/src/executor.rs index c1410e52e2c..51d7317bf6e 100644 --- a/lib/ain-evm/src/executor.rs +++ b/lib/ain-evm/src/executor.rs @@ -18,7 +18,7 @@ use log::trace; use primitive_types::{H160, H256}; pub struct AinExecutor<'backend> { - backend: &'backend mut EVMBackend, + pub backend: &'backend mut EVMBackend, } impl<'backend> AinExecutor<'backend> { diff --git a/test/functional/feature_dst20.py b/test/functional/feature_dst20.py index f95458d12e4..872f620faf8 100644 --- a/test/functional/feature_dst20.py +++ b/test/functional/feature_dst20.py @@ -10,7 +10,7 @@ from test_framework.evm_key_pair import KeyPair from test_framework.test_framework import DefiTestFramework -from test_framework.util import assert_equal +from test_framework.util import (assert_equal, assert_raises_rpc_error) @@ -78,7 +78,6 @@ def run_test(self): } ) self.nodes[0].generate(1) - self.sync_blocks() node.createtoken( { @@ -97,7 +96,6 @@ def run_test(self): } ) self.nodes[0].generate(1) - self.sync_blocks() contract_address_btc = "0xff00000000000000000000000000000000000001" contract_address_eth = "0xff00000000000000000000000000000000000002" @@ -191,6 +189,76 @@ def run_test(self): [amountBTC] = [x for x in node.getaccount(address) if "BTC" in x] assert_equal(amountBTC, "9.50000000@BTC") + # test multiple transferdomains in the same block + self.nodes[0].transferdomain( + [ + { + "src": {"address": address, "amount": "1@BTC", "domain": 2}, + "dst": { + "address": key_pair.address, + "amount": "1@BTC", + "domain": 3, + }, + } + ] + ) + self.nodes[0].transferdomain( + [ + { + "src": {"address": address, "amount": "2@BTC", "domain": 2}, + "dst": { + "address": key_pair.address, + "amount": "2@BTC", + "domain": 3, + }, + } + ] + ) + node.generate(1) + + assert_equal( + btc.functions.balanceOf(key_pair.address).call() + / math.pow(10, btc.functions.decimals().call()), + Decimal(3.5), + ) + [amountBTC] = [x for x in node.getaccount(address) if "BTC" in x] + assert_equal(amountBTC, "6.50000000@BTC") + + # test transferdomain for contract that does not exist + assert_raises_rpc_error(0, "Invalid Defi token: XYZ", self.nodes[0].transferdomain, + [ + { + "src": {"address": address, "amount": "1@XYZ", "domain": 2}, + "dst": { + "address": key_pair.address, + "amount": "1@XYZ", + "domain": 3, + }, + } + ] + ) + + # transferdomain to DST20 token address + self.nodes[0].transferdomain( + [ + { + "src": {"address": address, "amount": "2@BTC", "domain": 2}, + "dst": { + "address": contract_address_btc, + "amount": "2@BTC", + "domain": 3, + }, + } + ] + ) + node.generate(1) + + assert_equal( + btc.functions.balanceOf(contract_address_btc).call() + / math.pow(10, btc.functions.decimals().call()), + Decimal(2), + ) + if __name__ == "__main__": DST20().main() \ No newline at end of file diff --git a/test/functional/feature_evm_transferdomain.py b/test/functional/feature_evm_transferdomain.py index a183ad744ee..076dc185b3a 100755 --- a/test/functional/feature_evm_transferdomain.py +++ b/test/functional/feature_evm_transferdomain.py @@ -116,8 +116,6 @@ def invalid_values_dvm_evm(self): assert_raises_rpc_error(-32600, "Dst address must be an ERC55 address in case of \"EVM\" domain", self.nodes[0].transferdomain, [{"src": {"address":self.address, "amount":"100@DFI", "domain": 2}, "dst":{"address":self.address, "amount":"100@DFI", "domain": 3}}]) assert_raises_rpc_error(-32600, "Cannot transfer inside same domain", self.nodes[0].transferdomain, [{"src": {"address":self.address, "amount":"100@DFI", "domain": 2}, "dst":{"address":self.eth_address, "amount":"100@DFI", "domain": 2}}]) assert_raises_rpc_error(-32600, "Source amount must be equal to destination amount", self.nodes[0].transferdomain, [{"src": {"address":self.address, "amount":"100@DFI", "domain": 2}, "dst":{"address":self.eth_address, "amount":"101@DFI", "domain": 3}}]) - assert_raises_rpc_error(-32600, "For transferdomain, only DFI token is currently supported", self.nodes[0].transferdomain, [{"src": {"address":self.address, "amount":"100@BTC", "domain": 2}, "dst":{"address":self.eth_address, "amount":"100@DFI", "domain": 3}}]) - assert_raises_rpc_error(-32600, "For transferdomain, only DFI token is currently supported", self.nodes[0].transferdomain, [{"src": {"address":self.address, "amount":"100@DFI", "domain": 2}, "dst":{"address":self.eth_address, "amount":"100@BTC", "domain": 3}}]) assert_raises_rpc_error(-32600, "Excess data set, maximum allow is 0", self.nodes[0].transferdomain, [{"src": {"address":self.address, "amount":"100@DFI", "domain": 2, "data": "1"}, "dst":{"address":self.eth_address, "amount":"100@DFI", "domain": 3}}]) assert_raises_rpc_error(-32600, "Excess data set, maximum allow is 0", self.nodes[0].transferdomain, [{"src": {"address":self.address, "amount":"100@DFI", "domain": 2}, "dst":{"address":self.eth_address, "amount":"100@DFI", "domain": 3, "data": "1"}}]) @@ -152,8 +150,6 @@ def invalid_values_evm_dvm(self): assert_raises_rpc_error(-32600, "Dst address must be a legacy or Bech32 address in case of \"DVM\" domain", self.nodes[0].transferdomain, [{"src": {"address":self.eth_address, "amount":"100@DFI", "domain": 3}, "dst":{"address":self.eth_address, "amount":"100@DFI", "domain": 2}}]) assert_raises_rpc_error(-32600, "Cannot transfer inside same domain", self.nodes[0].transferdomain, [{"src": {"address":self.eth_address, "amount":"100@DFI", "domain": 3}, "dst":{"address":self.address, "amount":"100@DFI", "domain": 3}}]) assert_raises_rpc_error(-32600, "Source amount must be equal to destination amount", self.nodes[0].transferdomain, [{"src": {"address":self.eth_address, "amount":"100@DFI", "domain": 3}, "dst":{"address":self.address, "amount":"101@DFI", "domain": 2}}]) - assert_raises_rpc_error(-32600, "For transferdomain, only DFI token is currently supported", self.nodes[0].transferdomain, [{"src": {"address":self.eth_address, "amount":"100@BTC", "domain": 3}, "dst":{"address":self.address, "amount":"100@DFI", "domain": 2}}]) - assert_raises_rpc_error(-32600, "For transferdomain, only DFI token is currently supported", self.nodes[0].transferdomain, [{"src": {"address":self.eth_address, "amount":"100@DFI", "domain": 3}, "dst":{"address":self.address, "amount":"100@BTC", "domain": 2}}]) assert_raises_rpc_error(-32600, "TransferDomain currently only supports a single transfer per transaction", self.nodes[0].transferdomain, [{"src": {"address":self.eth_address1, "amount":"10@DFI", "domain": 3}, "dst":{"address":self.address, "amount":"10@DFI", "domain": 2}}, {"src": {"address":self.eth_address1, "amount":"10@DFI", "domain": 3}, "dst":{"address":self.address_2nd, "amount":"10@DFI", "domain": 2}}]) From a32949f4f33a1455cc172a2ff9caed134c14896a Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Wed, 26 Jul 2023 14:22:25 +0800 Subject: [PATCH 20/32] Add tests, fix empty balance bridge issue Bridge issue pending PR #2221 --- lib/ain-evm/src/evm.rs | 27 ++-- test/functional/feature_dst20.py | 269 ++++++++++++++++++++----------- 2 files changed, 190 insertions(+), 106 deletions(-) diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 7fd822daeef..20ee8320f5b 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -264,11 +264,17 @@ impl EVMServices { to, contract, amount, out ); - let DST20BridgeInfo { address, storage } = - EVMServices::bridge_dst20(&mut executor, contract, to, amount, out)?; - - if let Err(e) = executor.update_storage(address, storage) { - debug!("[finalize_block] EvmOut failed with {e}"); + match EVMServices::bridge_dst20(&mut executor, contract, to, amount, out) { + Ok(DST20BridgeInfo { address, storage }) => { + if let Err(e) = executor.update_storage(address, storage) { + debug!("[finalize_block] EvmOut failed with {e}"); + failed_transactions.push(hex::encode(hash)); + } + } + Err(e) => { + debug!("[finalize_block] EvmOut failed with {e}"); + failed_transactions.push(hex::encode(hash)); + } } } } @@ -476,12 +482,15 @@ impl EVMServices { out: bool, ) -> Result> { let storage_index = ain_contracts::get_address_storage_index(to); - let balance = executor.backend.get_contract_storage(contract, storage_index.as_bytes())?; + let balance = executor + .backend + .get_contract_storage(contract, storage_index.as_bytes())?; let new_balance = match out { - true => balance - amount, - false => balance + amount, - }; + true => balance.checked_sub(amount), + false => balance.checked_add(amount), + } + .ok_or_else(|| anyhow!("Balance overflow/underflow"))?; Ok(DST20BridgeInfo { address: contract, diff --git a/test/functional/feature_dst20.py b/test/functional/feature_dst20.py index 872f620faf8..fd12c5ea0d1 100644 --- a/test/functional/feature_dst20.py +++ b/test/functional/feature_dst20.py @@ -7,6 +7,7 @@ import math from decimal import Decimal +from web3 import Web3 from test_framework.evm_key_pair import KeyPair from test_framework.test_framework import DefiTestFramework @@ -42,195 +43,269 @@ def set_test_params(self): ] ] - def run_test(self): - node = self.nodes[0] - address = node.get_genesis_keys().ownerAuthAddress + def test_deploy_token(self): + # should have no code on contract address + assert_equal(Web3.to_hex(self.web3.eth.get_code(self.contract_address_btc)), "0x") - # Generate chain - node.generate(105) - self.nodes[0].utxostoaccount({address: "100@DFI"}) - self.nodes[0].setgov({"ATTRIBUTES": {"v0/params/feature/evm": "true"}}) - self.nodes[0].generate(1) - node.transferdomain( - [ - { - "src": {"address": address, "amount": "50@DFI", "domain": 2}, - "dst": { - "address": "0xeB4B222C3dE281d40F5EBe8B273106bFcC1C1b94", - "amount": "50@DFI", - "domain": 3, - }, - } - ] - ) - self.nodes[0].generate(1) - - from web3 import Web3 - - web3 = Web3(Web3.HTTPProvider(node.get_evm_rpc())) - - node.createtoken( + self.node.createtoken( { "symbol": "BTC", "name": "BTC token", "isDAT": True, - "collateralAddress": address, + "collateralAddress": self.address, } ) self.nodes[0].generate(1) - node.createtoken( + # should have code on contract address + assert(Web3.to_hex(self.web3.eth.get_code(self.contract_address_btc)) != "0x") + + # check contract variables + self.btc = self.web3.eth.contract(address=self.contract_address_btc, abi=self.abi) + assert_equal(self.btc.functions.name().call(), "BTC token") + assert_equal(self.btc.functions.symbol().call(), "BTC") + + def test_deploy_multiple_tokens(self): + # should have no code on contract addresses + assert_equal(Web3.to_hex(self.web3.eth.get_code(self.contract_address_eth)), "0x") + assert_equal(Web3.to_hex(self.web3.eth.get_code(self.contract_address_dusd)), "0x") + + self.node.createtoken( { "symbol": "ETH", "name": "ETH token", "isDAT": True, - "collateralAddress": address, + "collateralAddress": self.address, } ) - node.createtoken( + self.node.createtoken( { "symbol": "DUSD", "name": "DUSD token", "isDAT": True, - "collateralAddress": address, + "collateralAddress": self.address, } ) - self.nodes[0].generate(1) + self.node.generate(1) - contract_address_btc = "0xff00000000000000000000000000000000000001" - contract_address_eth = "0xff00000000000000000000000000000000000002" - contract_address_dusd = Web3.to_checksum_address( - "0xff00000000000000000000000000000000000003" - ) - - abi = open("./lib/ain-contracts/dst20/output/abi.json", encoding="utf-8").read() - - btc = web3.eth.contract(address=contract_address_btc, abi=abi) - assert_equal(btc.functions.name().call(), "BTC token") - assert_equal(btc.functions.symbol().call(), "BTC") - - eth = web3.eth.contract(address=contract_address_eth, abi=abi) - assert_equal(eth.functions.name().call(), "ETH token") - assert_equal(eth.functions.symbol().call(), "ETH") - - dusd = web3.eth.contract(address=contract_address_dusd, abi=abi) - assert_equal(dusd.functions.name().call(), "DUSD token") - assert_equal(dusd.functions.symbol().call(), "DUSD") + # should have code on contract address + assert(Web3.to_hex(self.web3.eth.get_code(self.contract_address_eth)) != "0x") + assert(Web3.to_hex(self.web3.eth.get_code(self.contract_address_dusd)) != "0x") - key_pair = KeyPair.from_node(node) + # check contract variables + self.eth = self.web3.eth.contract(address=self.contract_address_eth, abi=self.abi) + assert_equal(self.eth.functions.name().call(), "ETH token") + assert_equal(self.eth.functions.symbol().call(), "ETH") - node.minttokens("10@BTC") - node.generate(1) + self.dusd = self.web3.eth.contract(address=self.contract_address_dusd, abi=self.abi) + assert_equal(self.dusd.functions.name().call(), "DUSD token") + assert_equal(self.dusd.functions.symbol().call(), "DUSD") - self.nodes[0].transferdomain( + def test_dst20_dvm_to_evm_bridge(self): + self.node.transferdomain( [ { - "src": {"address": address, "amount": "1@BTC", "domain": 2}, + "src": {"address": self.address, "amount": "1@BTC", "domain": 2}, "dst": { - "address": key_pair.address, + "address": self.key_pair.address, "amount": "1@BTC", "domain": 3, }, } ] ) - node.generate(1) + self.node.generate(1) assert_equal( - btc.functions.balanceOf(key_pair.address).call() - / math.pow(10, btc.functions.decimals().call()), + self.btc.functions.balanceOf(self.key_pair.address).call() + / math.pow(10, self.btc.functions.decimals().call()), Decimal(1), ) - [amountBTC] = [x for x in node.getaccount(address) if "BTC" in x] + [amountBTC] = [x for x in self.node.getaccount(self.address) if "BTC" in x] assert_equal(amountBTC, "9.00000000@BTC") + # transfer again to check if state is updated instead of being overwritten by new value self.nodes[0].transferdomain( [ { - "src": {"address": address, "amount": "1@BTC", "domain": 2}, + "src": {"address": self.address, "amount": "1@BTC", "domain": 2}, "dst": { - "address": key_pair.address, + "address": self.key_pair.address, "amount": "1@BTC", "domain": 3, }, } ] ) - node.generate(1) + self.node.generate(1) assert_equal( - btc.functions.balanceOf(key_pair.address).call() - / math.pow(10, btc.functions.decimals().call()), + self.btc.functions.balanceOf(self.key_pair.address).call() + / math.pow(10, self.btc.functions.decimals().call()), Decimal(2), ) - [amountBTC] = [x for x in node.getaccount(address) if "BTC" in x] + [amountBTC] = [x for x in self.node.getaccount(self.address) if "BTC" in x] assert_equal(amountBTC, "8.00000000@BTC") - self.nodes[0].transferdomain( + def test_dst20_evm_to_dvm_bridge(self): + self.node.transferdomain( [ { - "dst": {"address": address, "amount": "1.5@BTC", "domain": 2}, + "dst": {"address": self.address, "amount": "1.5@BTC", "domain": 2}, "src": { - "address": key_pair.address, + "address": self.key_pair.address, "amount": "1.5@BTC", "domain": 3, }, } ] ) - node.generate(1) + self.node.generate(1) assert_equal( - btc.functions.balanceOf(key_pair.address).call() - / math.pow(10, btc.functions.decimals().call()), + self.btc.functions.balanceOf(self.key_pair.address).call() + / math.pow(10, self.btc.functions.decimals().call()), Decimal(0.5), ) - [amountBTC] = [x for x in node.getaccount(address) if "BTC" in x] + [amountBTC] = [x for x in self.node.getaccount(self.address) if "BTC" in x] assert_equal(amountBTC, "9.50000000@BTC") - # test multiple transferdomains in the same block + def test_multiple_dvm_evm_bridge(self): + self.nodes[0].transferdomain( + [ + { + "src": {"address": self.address, "amount": "1@BTC", "domain": 2}, + "dst": { + "address": self.key_pair.address, + "amount": "1@BTC", + "domain": 3, + }, + } + ] + ) self.nodes[0].transferdomain( [ { - "src": {"address": address, "amount": "1@BTC", "domain": 2}, + "src": {"address": self.address, "amount": "2@BTC", "domain": 2}, "dst": { - "address": key_pair.address, - "amount": "1@BTC", + "address": self.key_pair.address, + "amount": "2@BTC", "domain": 3, }, } ] ) + self.node.generate(1) + + assert_equal( + self.btc.functions.balanceOf(self.key_pair.address).call() + / math.pow(10, self.btc.functions.decimals().call()), + Decimal(3.5), + ) + [amountBTC] = [x for x in self.node.getaccount(self.address) if "BTC" in x] + assert_equal(amountBTC, "6.50000000@BTC") + + def test_conflicting_bridge(self): + [beforeAmount] = [x for x in self.node.getaccount(self.address) if "BTC" in x] + + # should be processed in order so balance is bridged to and back in the same block self.nodes[0].transferdomain( [ { - "src": {"address": address, "amount": "2@BTC", "domain": 2}, + "src": {"address": self.address, "amount": "1@BTC", "domain": 2}, "dst": { - "address": key_pair.address, - "amount": "2@BTC", + "address": self.key_pair2.address, + "amount": "1@BTC", "domain": 3, }, } ] ) - node.generate(1) + self.nodes[0].transferdomain( + [ + { + "src": { + "address": self.key_pair2.address, + "amount": "1@BTC", + "domain": 3, + }, + "dst": {"address": self.address, "amount": "1@BTC", "domain": 2} + } + ] + ) + self.node.generate(1) - assert_equal( - btc.functions.balanceOf(key_pair.address).call() - / math.pow(10, btc.functions.decimals().call()), - Decimal(3.5), - ) - [amountBTC] = [x for x in node.getaccount(address) if "BTC" in x] - assert_equal(amountBTC, "6.50000000@BTC") + [afterAmount] = [x for x in self.node.getaccount(self.address) if "BTC" in x] + assert_equal(self.btc.functions.balanceOf(self.key_pair2.address).call(), Decimal(0)) + assert_equal(beforeAmount, afterAmount) + + + def test_bridge_when_no_balance(self): + assert_equal(self.btc.functions.balanceOf(self.key_pair2.address).call(), Decimal(0)) + [beforeAmount] = [x for x in self.node.getaccount(self.address) if "BTC" in x] + + self.nodes[0].transferdomain( + [ + { + "src": { + "address": self.key_pair2.address, + "amount": "1@BTC", + "domain": 3, + }, + "dst": {"address": self.address, "amount": "1@BTC", "domain": 2} + } + ] + ) + self.node.generate(1) + + assert_equal(self.btc.functions.balanceOf(self.key_pair2.address).call(), Decimal(0)) + [afterAmount] = [x for x in self.node.getaccount(self.address) if "BTC" in x] + assert_equal(beforeAmount, afterAmount) + + + def run_test(self): + self.node = self.nodes[0] + self.address = self.node.get_genesis_keys().ownerAuthAddress + self.web3 = Web3(Web3.HTTPProvider(self.node.get_evm_rpc())) + + # Contract addresses + self.contract_address_btc = "0xff00000000000000000000000000000000000001" + self.contract_address_eth = "0xff00000000000000000000000000000000000002" + self.contract_address_dusd = Web3.to_checksum_address( + "0xff00000000000000000000000000000000000003" + ) + + # Contract ABI + self.abi = open("./lib/ain-contracts/dst20/output/abi.json", encoding="utf-8").read() + + # Generate chain + self.node.generate(105) + self.nodes[0].utxostoaccount({self.address: "100@DFI"}) + self.nodes[0].setgov({"ATTRIBUTES": {"v0/params/feature/evm": "true"}}) + self.nodes[0].generate(1) + + self.test_deploy_token() + self.test_deploy_multiple_tokens() + + self.key_pair = KeyPair.from_node(self.node) + self.key_pair2 = KeyPair.from_node(self.node) + self.node.minttokens("10@BTC") + self.node.generate(1) + + self.test_dst20_dvm_to_evm_bridge() + self.test_dst20_evm_to_dvm_bridge() + self.test_multiple_dvm_evm_bridge() + self.test_conflicting_bridge() + self.test_bridge_when_no_balance() # test transferdomain for contract that does not exist assert_raises_rpc_error(0, "Invalid Defi token: XYZ", self.nodes[0].transferdomain, [ { - "src": {"address": address, "amount": "1@XYZ", "domain": 2}, + "src": {"address": self.address, "amount": "1@XYZ", "domain": 2}, "dst": { - "address": key_pair.address, + "address": self.key_pair.address, "amount": "1@XYZ", "domain": 3, }, @@ -242,20 +317,20 @@ def run_test(self): self.nodes[0].transferdomain( [ { - "src": {"address": address, "amount": "2@BTC", "domain": 2}, + "src": {"address": self.address, "amount": "2@BTC", "domain": 2}, "dst": { - "address": contract_address_btc, + "address": self.contract_address_btc, "amount": "2@BTC", "domain": 3, }, } ] ) - node.generate(1) + self.node.generate(1) assert_equal( - btc.functions.balanceOf(contract_address_btc).call() - / math.pow(10, btc.functions.decimals().call()), + self.btc.functions.balanceOf(self.contract_address_btc).call() + / math.pow(10, self.btc.functions.decimals().call()), Decimal(2), ) From e72341ff077e2f039b270df010b4df858d6642ab Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Wed, 26 Jul 2023 14:41:09 +0800 Subject: [PATCH 21/32] Refactor rest of DST20 tests --- test/functional/feature_dst20.py | 182 +++++++++++++++++++------------ 1 file changed, 112 insertions(+), 70 deletions(-) diff --git a/test/functional/feature_dst20.py b/test/functional/feature_dst20.py index fd12c5ea0d1..1646c9f835e 100644 --- a/test/functional/feature_dst20.py +++ b/test/functional/feature_dst20.py @@ -11,8 +11,7 @@ from test_framework.evm_key_pair import KeyPair from test_framework.test_framework import DefiTestFramework -from test_framework.util import (assert_equal, assert_raises_rpc_error) - +from test_framework.util import assert_equal, assert_raises_rpc_error class DST20(DefiTestFramework): @@ -45,7 +44,9 @@ def set_test_params(self): def test_deploy_token(self): # should have no code on contract address - assert_equal(Web3.to_hex(self.web3.eth.get_code(self.contract_address_btc)), "0x") + assert_equal( + Web3.to_hex(self.web3.eth.get_code(self.contract_address_btc)), "0x" + ) self.node.createtoken( { @@ -58,17 +59,23 @@ def test_deploy_token(self): self.nodes[0].generate(1) # should have code on contract address - assert(Web3.to_hex(self.web3.eth.get_code(self.contract_address_btc)) != "0x") + assert Web3.to_hex(self.web3.eth.get_code(self.contract_address_btc)) != "0x" # check contract variables - self.btc = self.web3.eth.contract(address=self.contract_address_btc, abi=self.abi) + self.btc = self.web3.eth.contract( + address=self.contract_address_btc, abi=self.abi + ) assert_equal(self.btc.functions.name().call(), "BTC token") assert_equal(self.btc.functions.symbol().call(), "BTC") def test_deploy_multiple_tokens(self): # should have no code on contract addresses - assert_equal(Web3.to_hex(self.web3.eth.get_code(self.contract_address_eth)), "0x") - assert_equal(Web3.to_hex(self.web3.eth.get_code(self.contract_address_dusd)), "0x") + assert_equal( + Web3.to_hex(self.web3.eth.get_code(self.contract_address_eth)), "0x" + ) + assert_equal( + Web3.to_hex(self.web3.eth.get_code(self.contract_address_dusd)), "0x" + ) self.node.createtoken( { @@ -89,15 +96,19 @@ def test_deploy_multiple_tokens(self): self.node.generate(1) # should have code on contract address - assert(Web3.to_hex(self.web3.eth.get_code(self.contract_address_eth)) != "0x") - assert(Web3.to_hex(self.web3.eth.get_code(self.contract_address_dusd)) != "0x") + assert Web3.to_hex(self.web3.eth.get_code(self.contract_address_eth)) != "0x" + assert Web3.to_hex(self.web3.eth.get_code(self.contract_address_dusd)) != "0x" # check contract variables - self.eth = self.web3.eth.contract(address=self.contract_address_eth, abi=self.abi) + self.eth = self.web3.eth.contract( + address=self.contract_address_eth, abi=self.abi + ) assert_equal(self.eth.functions.name().call(), "ETH token") assert_equal(self.eth.functions.symbol().call(), "ETH") - self.dusd = self.web3.eth.contract(address=self.contract_address_dusd, abi=self.abi) + self.dusd = self.web3.eth.contract( + address=self.contract_address_dusd, abi=self.abi + ) assert_equal(self.dusd.functions.name().call(), "DUSD token") assert_equal(self.dusd.functions.symbol().call(), "DUSD") @@ -120,7 +131,7 @@ def test_dst20_dvm_to_evm_bridge(self): self.btc.functions.balanceOf(self.key_pair.address).call() / math.pow(10, self.btc.functions.decimals().call()), Decimal(1), - ) + ) [amountBTC] = [x for x in self.node.getaccount(self.address) if "BTC" in x] assert_equal(amountBTC, "9.00000000@BTC") @@ -144,7 +155,7 @@ def test_dst20_dvm_to_evm_bridge(self): self.btc.functions.balanceOf(self.key_pair.address).call() / math.pow(10, self.btc.functions.decimals().call()), Decimal(2), - ) + ) [amountBTC] = [x for x in self.node.getaccount(self.address) if "BTC" in x] assert_equal(amountBTC, "8.00000000@BTC") @@ -167,23 +178,23 @@ def test_dst20_evm_to_dvm_bridge(self): self.btc.functions.balanceOf(self.key_pair.address).call() / math.pow(10, self.btc.functions.decimals().call()), Decimal(0.5), - ) + ) [amountBTC] = [x for x in self.node.getaccount(self.address) if "BTC" in x] assert_equal(amountBTC, "9.50000000@BTC") def test_multiple_dvm_evm_bridge(self): self.nodes[0].transferdomain( - [ - { - "src": {"address": self.address, "amount": "1@BTC", "domain": 2}, - "dst": { - "address": self.key_pair.address, - "amount": "1@BTC", - "domain": 3, - }, - } - ] - ) + [ + { + "src": {"address": self.address, "amount": "1@BTC", "domain": 2}, + "dst": { + "address": self.key_pair.address, + "amount": "1@BTC", + "domain": 3, + }, + } + ] + ) self.nodes[0].transferdomain( [ { @@ -202,7 +213,7 @@ def test_multiple_dvm_evm_bridge(self): self.btc.functions.balanceOf(self.key_pair.address).call() / math.pow(10, self.btc.functions.decimals().call()), Decimal(3.5), - ) + ) [amountBTC] = [x for x in self.node.getaccount(self.address) if "BTC" in x] assert_equal(amountBTC, "6.50000000@BTC") @@ -230,19 +241,22 @@ def test_conflicting_bridge(self): "amount": "1@BTC", "domain": 3, }, - "dst": {"address": self.address, "amount": "1@BTC", "domain": 2} + "dst": {"address": self.address, "amount": "1@BTC", "domain": 2}, } ] ) self.node.generate(1) [afterAmount] = [x for x in self.node.getaccount(self.address) if "BTC" in x] - assert_equal(self.btc.functions.balanceOf(self.key_pair2.address).call(), Decimal(0)) + assert_equal( + self.btc.functions.balanceOf(self.key_pair2.address).call(), Decimal(0) + ) assert_equal(beforeAmount, afterAmount) - def test_bridge_when_no_balance(self): - assert_equal(self.btc.functions.balanceOf(self.key_pair2.address).call(), Decimal(0)) + assert_equal( + self.btc.functions.balanceOf(self.key_pair2.address).call(), Decimal(0) + ) [beforeAmount] = [x for x in self.node.getaccount(self.address) if "BTC" in x] self.nodes[0].transferdomain( @@ -253,16 +267,74 @@ def test_bridge_when_no_balance(self): "amount": "1@BTC", "domain": 3, }, - "dst": {"address": self.address, "amount": "1@BTC", "domain": 2} + "dst": {"address": self.address, "amount": "1@BTC", "domain": 2}, } ] ) self.node.generate(1) - assert_equal(self.btc.functions.balanceOf(self.key_pair2.address).call(), Decimal(0)) + assert_equal( + self.btc.functions.balanceOf(self.key_pair2.address).call(), Decimal(0) + ) [afterAmount] = [x for x in self.node.getaccount(self.address) if "BTC" in x] assert_equal(beforeAmount, afterAmount) + def test_invalid_token(self): + # DVM to EVM + assert_raises_rpc_error( + 0, + "Invalid Defi token: XYZ", + self.nodes[0].transferdomain, + [ + { + "src": {"address": self.address, "amount": "1@XYZ", "domain": 2}, + "dst": { + "address": self.key_pair.address, + "amount": "1@XYZ", + "domain": 3, + }, + } + ], + ) + + # EVM to DVM + assert_raises_rpc_error( + 0, + "Invalid Defi token: XYZ", + self.nodes[0].transferdomain, + [ + { + "src": { + "address": self.key_pair.address, + "amount": "1@XYZ", + "domain": 3, + }, + "dst": {"address": self.address, "amount": "1@XYZ", "domain": 2}, + } + ], + ) + + def test_transfer_to_token_address(self): + self.nodes[0].transferdomain( + [ + { + "src": {"address": self.address, "amount": "2@BTC", "domain": 2}, + "dst": { + "address": self.contract_address_btc, + "amount": "2@BTC", + "domain": 3, + }, + } + ] + ) + self.node.generate(1) + + assert_equal( + self.btc.functions.balanceOf(self.contract_address_btc).call() + / math.pow(10, self.btc.functions.decimals().call()), + Decimal(2), + ) + def run_test(self): self.node = self.nodes[0] @@ -277,7 +349,9 @@ def run_test(self): ) # Contract ABI - self.abi = open("./lib/ain-contracts/dst20/output/abi.json", encoding="utf-8").read() + self.abi = open( + "./lib/ain-contracts/dst20/output/abi.json", encoding="utf-8" + ).read() # Generate chain self.node.generate(105) @@ -297,43 +371,11 @@ def run_test(self): self.test_dst20_evm_to_dvm_bridge() self.test_multiple_dvm_evm_bridge() self.test_conflicting_bridge() - self.test_bridge_when_no_balance() - - # test transferdomain for contract that does not exist - assert_raises_rpc_error(0, "Invalid Defi token: XYZ", self.nodes[0].transferdomain, - [ - { - "src": {"address": self.address, "amount": "1@XYZ", "domain": 2}, - "dst": { - "address": self.key_pair.address, - "amount": "1@XYZ", - "domain": 3, - }, - } - ] - ) - - # transferdomain to DST20 token address - self.nodes[0].transferdomain( - [ - { - "src": {"address": self.address, "amount": "2@BTC", "domain": 2}, - "dst": { - "address": self.contract_address_btc, - "amount": "2@BTC", - "domain": 3, - }, - } - ] - ) - self.node.generate(1) - - assert_equal( - self.btc.functions.balanceOf(self.contract_address_btc).call() - / math.pow(10, self.btc.functions.decimals().call()), - Decimal(2), - ) + self.test_invalid_token() + self.test_transfer_to_token_address() + # node crashes due to miner issue, crash is fixed by https://github.com/DeFiCh/ain/pull/2221/. + # self.test_bridge_when_no_balance() if __name__ == "__main__": - DST20().main() \ No newline at end of file + DST20().main() From 96476ae59df982bd7a2002d006ffb44cf148f5f9 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Thu, 27 Jul 2023 11:49:35 +0800 Subject: [PATCH 22/32] Add 0 balance test --- test/functional/feature_dst20.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/functional/feature_dst20.py b/test/functional/feature_dst20.py index 1646c9f835e..ba221ffdeb5 100644 --- a/test/functional/feature_dst20.py +++ b/test/functional/feature_dst20.py @@ -373,9 +373,7 @@ def run_test(self): self.test_conflicting_bridge() self.test_invalid_token() self.test_transfer_to_token_address() - - # node crashes due to miner issue, crash is fixed by https://github.com/DeFiCh/ain/pull/2221/. - # self.test_bridge_when_no_balance() + self.test_bridge_when_no_balance() if __name__ == "__main__": DST20().main() From 24075138c5404a763a7863c0caab99438c5c9800 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Thu, 27 Jul 2023 12:09:04 +0800 Subject: [PATCH 23/32] Fix lints --- lib/ain-contracts/src/lib.rs | 2 +- lib/ain-evm/src/core.rs | 2 +- lib/ain-evm/src/txqueue.rs | 2 +- lib/ain-rs-exports/src/evm.rs | 23 ++++++----------------- test/functional/feature_dst20.py | 4 +--- 5 files changed, 10 insertions(+), 23 deletions(-) diff --git a/lib/ain-contracts/src/lib.rs b/lib/ain-contracts/src/lib.rs index 176860c65ad..a51c47aa550 100644 --- a/lib/ain-contracts/src/lib.rs +++ b/lib/ain-contracts/src/lib.rs @@ -1,10 +1,10 @@ use anyhow::anyhow; use lazy_static::lazy_static; use primitive_types::{H160, H256, U256}; +use sha3::{Digest, Keccak256}; use std::collections::HashMap; use std::error::Error; use std::str::FromStr; -use sha3::{Digest, Keccak256}; pub fn u256_to_h256(input: U256) -> H256 { let mut bytes = [0_u8; 32]; diff --git a/lib/ain-evm/src/core.rs b/lib/ain-evm/src/core.rs index 0d3f8597b40..a7ed155c2ab 100644 --- a/lib/ain-evm/src/core.rs +++ b/lib/ain-evm/src/core.rs @@ -505,8 +505,8 @@ impl EVMCoreService { } } -use std::fmt; use primitive_types::H256; +use std::fmt; #[derive(Debug)] pub enum EVMError { diff --git a/lib/ain-evm/src/txqueue.rs b/lib/ain-evm/src/txqueue.rs index 9df52bd62b1..167d3a751af 100644 --- a/lib/ain-evm/src/txqueue.rs +++ b/lib/ain-evm/src/txqueue.rs @@ -5,12 +5,12 @@ use std::{ sync::{Mutex, RwLock}, }; +use crate::transaction::system::SystemTx; use crate::{ core::NativeTxHash, fee::calculate_gas_fee, transaction::{bridge::BridgeTx, SignedTx}, }; -use crate::transaction::system::SystemTx; #[derive(Debug)] pub struct TransactionQueueMap { diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index 5429d143e8c..473bdae1286 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -1,4 +1,3 @@ -use std::error::Error; use ain_evm::{ core::ValidateTxInfo, evm::FinalizedBlockInfo, @@ -7,13 +6,14 @@ use ain_evm::{ transaction::{self, SignedTx}, weiamount::WeiAmount, }; +use std::error::Error; use ain_evm::storage::traits::BlockStorage; -use ain_evm::transaction::system::{DeployContractData, DST20Data, SystemTx}; +use ain_evm::transaction::system::{DST20Data, DeployContractData, SystemTx}; +use ain_evm::txqueue::QueueTx; use ethereum::{EnvelopedEncodable, TransactionAction, TransactionSignature}; use log::debug; use primitive_types::{H160, H256, U256}; -use ain_evm::txqueue::QueueTx; use transaction::{LegacyUnsignedTransaction, TransactionError, LOWER_H256}; use crate::ffi; @@ -446,13 +446,10 @@ pub fn evm_create_dst20( ) { match create_dst20(context, native_hash, name, symbol, token_id) { Ok(_) => cross_boundary_success(result), - Err(e) => { - cross_boundary_error_return(result, e.to_string()) - } + Err(e) => cross_boundary_error_return(result, e.to_string()), } } - pub fn evm_bridge_dst20( result: &mut ffi::CrossBoundaryResult, context: u64, @@ -462,16 +459,9 @@ pub fn evm_bridge_dst20( token_id: &str, out: bool, ) { - match bridge_to_dst20( - context, - address, - amount, - native_tx_hash, - token_id, - out, - ) { + match bridge_to_dst20(context, address, amount, native_tx_hash, token_id, out) { Ok(_) => cross_boundary_success(result), - Err(e) => cross_boundary_error_return(result, e.to_string()) + Err(e) => cross_boundary_error_return(result, e.to_string()), } } @@ -495,7 +485,6 @@ fn create_dst20( Ok(()) } - fn bridge_to_dst20( context: u64, address: &str, diff --git a/test/functional/feature_dst20.py b/test/functional/feature_dst20.py index ba221ffdeb5..7489e7afb5f 100644 --- a/test/functional/feature_dst20.py +++ b/test/functional/feature_dst20.py @@ -349,9 +349,7 @@ def run_test(self): ) # Contract ABI - self.abi = open( - "./lib/ain-contracts/dst20/output/abi.json", encoding="utf-8" - ).read() + self.abi = open("./lib/ain-contracts/dst20/output/abi.json", "r", encoding="utf8").read() # Generate chain self.node.generate(105) From 43e6fed01058bcd35e0ee05b42a94989e05c9e3c Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Fri, 28 Jul 2023 11:10:52 +0800 Subject: [PATCH 24/32] Use SOLC_PATH, fix build, add more tests --- lib/ain-contracts/build.rs | 5 ++++- lib/ain-rs-exports/src/evm.rs | 4 ++-- test/functional/feature_dst20.py | 15 +++++++++++++++ test/functional/test_runner.py | 1 + 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/lib/ain-contracts/build.rs b/lib/ain-contracts/build.rs index ce6b23a09ca..dfb2b7843a2 100644 --- a/lib/ain-contracts/build.rs +++ b/lib/ain-contracts/build.rs @@ -1,6 +1,7 @@ use anyhow::anyhow; -use ethers_solc::{Project, ProjectPathsConfig}; +use ethers_solc::{Project, ProjectPathsConfig, Solc}; use std::fs; +use std::env; use std::path::PathBuf; fn main() -> Result<(), Box> { @@ -9,6 +10,7 @@ fn main() -> Result<(), Box> { let contracts = vec![("counter_contract", "Counter"), ("dst20", "DST20")]; for (file_path, contract_name) in contracts { + let solc = Solc::new(env::var("SOLC_PATH")?); let root = PathBuf::from(file_path); if !root.exists() { return Err("Project root {root:?} does not exists!".into()); @@ -20,6 +22,7 @@ fn main() -> Result<(), Box> { .build()?; let project = Project::builder() + .solc(solc) .paths(paths) .set_auto_detect(true) .no_artifacts() diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index 8e184c669c6..f41ae4291c0 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -480,7 +480,7 @@ fn create_dst20( symbol: String::from(symbol), address, })); - SERVICES.evm.queue_tx(context, system_tx, native_hash, 0)?; + SERVICES.evm.queue_tx(context, system_tx, native_hash, U256::zero())?; Ok(()) } @@ -502,7 +502,7 @@ fn bridge_to_dst20( amount: amount.into(), out, })); - SERVICES.evm.queue_tx(context, system_tx, native_hash, 0)?; + SERVICES.evm.queue_tx(context, system_tx, native_hash, U256::zero())?; Ok(()) } diff --git a/test/functional/feature_dst20.py b/test/functional/feature_dst20.py index 7489e7afb5f..b3ed0702f0a 100644 --- a/test/functional/feature_dst20.py +++ b/test/functional/feature_dst20.py @@ -335,6 +335,20 @@ def test_transfer_to_token_address(self): Decimal(2), ) + def test_negative_transfer(self): + assert_raises_rpc_error(-3, "Amount out of range", self.nodes[0].transferdomain, + [ + { + "src": {"address": self.address, "amount": "-1@BTC", "domain": 2}, + "dst": { + "address": self.contract_address_btc, + "amount": "-1@BTC", + "domain": 3, + }, + } + ] + ) + def run_test(self): self.node = self.nodes[0] @@ -372,6 +386,7 @@ def run_test(self): self.test_invalid_token() self.test_transfer_to_token_address() self.test_bridge_when_no_balance() + self.test_negative_transfer() if __name__ == "__main__": DST20().main() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 2dcf70c0518..6ec79b4ea2d 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -301,6 +301,7 @@ 'feature_evm_smart_contract.py', 'feature_evm_transferdomain.py', 'feature_evm.py', + 'feature_dst20.py', 'feature_evm_state_root_change.py', 'feature_loan_low_interest.py', 'feature_loan_estimatecollateral.py', From e182e0ea8746ebfe878d4bd36a4e55688b2f2cf5 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Fri, 28 Jul 2023 11:15:53 +0800 Subject: [PATCH 25/32] Add check for same token ID --- lib/ain-contracts/build.rs | 2 +- lib/ain-evm/src/txqueue.rs | 4 ++++ lib/ain-rs-exports/src/evm.rs | 8 ++++++-- src/masternodes/errors.h | 4 ++++ src/masternodes/mn_checks.cpp | 3 +++ test/functional/feature_dst20.py | 15 +++++++++++++++ 6 files changed, 33 insertions(+), 3 deletions(-) diff --git a/lib/ain-contracts/build.rs b/lib/ain-contracts/build.rs index dfb2b7843a2..d6cf7001a77 100644 --- a/lib/ain-contracts/build.rs +++ b/lib/ain-contracts/build.rs @@ -1,7 +1,7 @@ use anyhow::anyhow; use ethers_solc::{Project, ProjectPathsConfig, Solc}; -use std::fs; use std::env; +use std::fs; use std::path::PathBuf; fn main() -> Result<(), Box> { diff --git a/lib/ain-evm/src/txqueue.rs b/lib/ain-evm/src/txqueue.rs index 3b37bf864e5..66d1298580a 100644 --- a/lib/ain-evm/src/txqueue.rs +++ b/lib/ain-evm/src/txqueue.rs @@ -277,6 +277,10 @@ impl TransactionQueue { self.data.lock().unwrap().transactions.len() } + pub fn is_empty(&self) -> bool { + self.data.lock().unwrap().transactions.is_empty() + } + pub fn remove_txs_by_sender(&self, sender: H160) { let mut data = self.data.lock().unwrap(); let mut fees_to_remove = U256::zero(); diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index f41ae4291c0..bf57b20dab1 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -480,7 +480,9 @@ fn create_dst20( symbol: String::from(symbol), address, })); - SERVICES.evm.queue_tx(context, system_tx, native_hash, U256::zero())?; + SERVICES + .evm + .queue_tx(context, system_tx, native_hash, U256::zero())?; Ok(()) } @@ -502,7 +504,9 @@ fn bridge_to_dst20( amount: amount.into(), out, })); - SERVICES.evm.queue_tx(context, system_tx, native_hash, U256::zero())?; + SERVICES + .evm + .queue_tx(context, system_tx, native_hash, U256::zero())?; Ok(()) } diff --git a/src/masternodes/errors.h b/src/masternodes/errors.h index 38d53fdf6d6..7fce0edd650 100644 --- a/src/masternodes/errors.h +++ b/src/masternodes/errors.h @@ -434,6 +434,10 @@ class DeFiErrors { return Res::Err("Source amount must be equal to destination amount"); } + static Res TransferDomainDifferentTokens() { + return Res::Err("Source token and destination token must be the same"); + } + static Res TransferDomainIncorrectToken() { return Res::Err("For transferdomain, only DFI token is currently supported"); } diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 0fdc0715600..3d6519a7962 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -4104,6 +4104,9 @@ Res ValidateTransferDomainEdge(const CTransaction &tx, if (src.amount.nValue != dst.amount.nValue) return DeFiErrors::TransferDomainUnequalAmount(); + if (src.amount.nTokenId != dst.amount.nTokenId) + return DeFiErrors::TransferDomainDifferentTokens(); + if (src.domain == static_cast(VMDomain::DVM) && dst.domain == static_cast(VMDomain::EVM)) { if (height >= static_cast(consensus.ChangiIntermediateHeight4)) { if (!transferdomainConfig.dvmToEvm) { diff --git a/test/functional/feature_dst20.py b/test/functional/feature_dst20.py index b3ed0702f0a..5e01683d71d 100644 --- a/test/functional/feature_dst20.py +++ b/test/functional/feature_dst20.py @@ -349,6 +349,20 @@ def test_negative_transfer(self): ] ) + def test_different_tokens(self): + assert_raises_rpc_error(-32600, "Source token and destination token must be the same", self.nodes[0].transferdomain, + [ + { + "src": {"address": self.address, "amount": "1@BTC", "domain": 2}, + "dst": { + "address": self.contract_address_btc, + "amount": "1@ETH", + "domain": 3, + }, + } + ] + ) + def run_test(self): self.node = self.nodes[0] @@ -387,6 +401,7 @@ def run_test(self): self.test_transfer_to_token_address() self.test_bridge_when_no_balance() self.test_negative_transfer() + self.test_different_tokens() if __name__ == "__main__": DST20().main() From e199b26293e3b631252932a23a87495d0f237069 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Fri, 28 Jul 2023 12:38:13 +0800 Subject: [PATCH 26/32] Move BridgeTx into SystemTx --- lib/ain-evm/src/core.rs | 6 +++--- lib/ain-evm/src/evm.rs | 7 +++---- lib/ain-evm/src/transaction/bridge.rs | 22 ---------------------- lib/ain-evm/src/transaction/mod.rs | 1 - lib/ain-evm/src/transaction/system.rs | 18 ++++++++++++++++++ lib/ain-evm/src/txqueue.rs | 10 ++-------- 6 files changed, 26 insertions(+), 38 deletions(-) delete mode 100644 lib/ain-evm/src/transaction/bridge.rs diff --git a/lib/ain-evm/src/core.rs b/lib/ain-evm/src/core.rs index 0e4fbfa8f42..bd2ecc0fb6a 100644 --- a/lib/ain-evm/src/core.rs +++ b/lib/ain-evm/src/core.rs @@ -7,7 +7,7 @@ use crate::receipt::ReceiptService; use crate::services::SERVICES; use crate::storage::traits::{BlockStorage, PersistentStateError}; use crate::storage::Storage; -use crate::transaction::bridge::{BalanceUpdate, BridgeTx}; +use crate::transaction::system::{BalanceUpdate, SystemTx}; use crate::trie::TrieDBStore; use crate::txqueue::{QueueError, QueueTx, TransactionQueueMap}; use crate::{ @@ -297,7 +297,7 @@ impl EVMCoreService { amount: U256, hash: NativeTxHash, ) -> Result<(), EVMError> { - let queue_tx = QueueTx::BridgeTx(BridgeTx::EvmIn(BalanceUpdate { address, amount })); + let queue_tx = QueueTx::SystemTx(SystemTx::EvmIn(BalanceUpdate { address, amount })); self.tx_queues .queue_tx(queue_id, queue_tx, hash, U256::zero(), U256::zero())?; Ok(()) @@ -323,7 +323,7 @@ impl EVMCoreService { }) .into()) } else { - let queue_tx = QueueTx::BridgeTx(BridgeTx::EvmOut(BalanceUpdate { address, amount })); + let queue_tx = QueueTx::SystemTx(SystemTx::EvmOut(BalanceUpdate { address, amount })); self.tx_queues .queue_tx(queue_id, queue_tx, hash, U256::zero(), U256::zero())?; Ok(()) diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index a957b50702c..9aaf5f13b76 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -9,7 +9,6 @@ use crate::receipt::ReceiptService; use crate::storage::traits::BlockStorage; use crate::storage::Storage; use crate::traits::Executor; -use crate::transaction::bridge::{BalanceUpdate, BridgeTx}; use crate::transaction::SignedTx; use crate::trie::GENESIS_STATE_ROOT; use crate::txqueue::QueueTx; @@ -19,7 +18,7 @@ use ethereum_types::{Bloom, H160, H64, U256}; use crate::bytes::Bytes; use crate::services::SERVICES; -use crate::transaction::system::{DST20Data, DeployContractData, SystemTx}; +use crate::transaction::system::{BalanceUpdate, DST20Data, DeployContractData, SystemTx}; use ain_contracts::{Contracts, CONTRACT_ADDRESSES}; use anyhow::anyhow; use hex::FromHex; @@ -212,7 +211,7 @@ impl EVMServices { EVMCoreService::logs_bloom(logs, &mut logs_bloom); receipts_v3.push(receipt); } - QueueTx::BridgeTx(BridgeTx::EvmIn(BalanceUpdate { address, amount })) => { + QueueTx::SystemTx(SystemTx::EvmIn(BalanceUpdate { address, amount })) => { debug!( "[finalize_block] EvmIn for address {:x?}, amount: {}, queue_id {}", address, amount, queue_id @@ -222,7 +221,7 @@ impl EVMServices { failed_transactions.push(hex::encode(queue_item.tx_hash)); } } - QueueTx::BridgeTx(BridgeTx::EvmOut(BalanceUpdate { address, amount })) => { + QueueTx::SystemTx(SystemTx::EvmOut(BalanceUpdate { address, amount })) => { debug!( "[finalize_block] EvmOut for address {}, amount: {}", address, amount diff --git a/lib/ain-evm/src/transaction/bridge.rs b/lib/ain-evm/src/transaction/bridge.rs deleted file mode 100644 index 6ff4fb7d13f..00000000000 --- a/lib/ain-evm/src/transaction/bridge.rs +++ /dev/null @@ -1,22 +0,0 @@ -use primitive_types::{H160, U256}; - -#[derive(Debug, Clone)] -pub struct BalanceUpdate { - pub address: H160, - pub amount: U256, -} - -#[derive(Debug, Clone)] -pub enum BridgeTx { - EvmIn(BalanceUpdate), - EvmOut(BalanceUpdate), -} - -impl BridgeTx { - pub fn sender(&self) -> H160 { - match self { - BridgeTx::EvmIn(tx) => tx.address, - BridgeTx::EvmOut(tx) => tx.address, - } - } -} diff --git a/lib/ain-evm/src/transaction/mod.rs b/lib/ain-evm/src/transaction/mod.rs index 45b85205809..14146215a7d 100644 --- a/lib/ain-evm/src/transaction/mod.rs +++ b/lib/ain-evm/src/transaction/mod.rs @@ -1,4 +1,3 @@ -pub mod bridge; pub mod system; use crate::ecrecover::{public_key_to_address, recover_public_key}; diff --git a/lib/ain-evm/src/transaction/system.rs b/lib/ain-evm/src/transaction/system.rs index 8aa498a602c..a5d0540181f 100644 --- a/lib/ain-evm/src/transaction/system.rs +++ b/lib/ain-evm/src/transaction/system.rs @@ -15,8 +15,26 @@ pub struct DST20Data { pub out: bool, } +#[derive(Debug, Clone)] +pub struct BalanceUpdate { + pub address: H160, + pub amount: U256, +} + #[derive(Debug, Clone)] pub enum SystemTx { DeployContract(DeployContractData), DST20Bridge(DST20Data), + EvmIn(BalanceUpdate), + EvmOut(BalanceUpdate), +} + +impl SystemTx { + pub fn sender(&self) -> Option { + match self { + SystemTx::EvmIn(tx) => Some(tx.address), + SystemTx::EvmOut(tx) => Some(tx.address), + _ => None, + } + } } diff --git a/lib/ain-evm/src/txqueue.rs b/lib/ain-evm/src/txqueue.rs index 66d1298580a..2efa1a77581 100644 --- a/lib/ain-evm/src/txqueue.rs +++ b/lib/ain-evm/src/txqueue.rs @@ -6,11 +6,7 @@ use std::{ }; use crate::transaction::system::SystemTx; -use crate::{ - core::NativeTxHash, - fee::calculate_gas_fee, - transaction::{bridge::BridgeTx, SignedTx}, -}; +use crate::{core::NativeTxHash, fee::calculate_gas_fee, transaction::SignedTx}; #[derive(Debug)] pub struct TransactionQueueMap { @@ -171,7 +167,6 @@ impl TransactionQueueMap { #[derive(Debug, Clone)] pub enum QueueTx { SignedTx(Box), - BridgeTx(BridgeTx), SystemTx(SystemTx), } @@ -288,8 +283,7 @@ impl TransactionQueue { data.transactions.retain(|item| { let tx_sender = match &item.queue_tx { QueueTx::SignedTx(tx) => tx.sender, - QueueTx::BridgeTx(tx) => tx.sender(), - QueueTx::SystemTx(_) => H160::zero(), // this is safe to do since we do not remove this transaction during mining + QueueTx::SystemTx(tx) => tx.sender().unwrap_or_default(), }; if tx_sender == sender { fees_to_remove += item.tx_fee; From b1f647db178415b682583881b6fc2a2b24ac3025 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Fri, 28 Jul 2023 15:53:20 +0800 Subject: [PATCH 27/32] Validate DST20 code during transferdomain --- lib/Cargo.lock | 1 + lib/ain-contracts/Cargo.toml | 1 + lib/ain-contracts/counter_contract/Counter.sol | 2 +- lib/ain-contracts/src/lib.rs | 6 ++++++ lib/ain-evm/src/evm.rs | 10 ++++++++++ 5 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index d733f0db6e8..49fe2882fc8 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -101,6 +101,7 @@ dependencies = [ "primitive-types", "serde_json", "sha3", + "sp-core 20.0.0", ] [[package]] diff --git a/lib/ain-contracts/Cargo.toml b/lib/ain-contracts/Cargo.toml index 337e169cf70..28ee5e1a44d 100644 --- a/lib/ain-contracts/Cargo.toml +++ b/lib/ain-contracts/Cargo.toml @@ -13,6 +13,7 @@ serde_json = "1.0.96" hex = "0.4.3" lazy_static = "1.4" sha3 = "0.10.6" +sp-core = "20.0.0" [build-dependencies] ethers = "2.0.7" diff --git a/lib/ain-contracts/counter_contract/Counter.sol b/lib/ain-contracts/counter_contract/Counter.sol index 9400207c376..4234d75bc5e 100644 --- a/lib/ain-contracts/counter_contract/Counter.sol +++ b/lib/ain-contracts/counter_contract/Counter.sol @@ -7,4 +7,4 @@ pragma solidity >=0.8.2 <0.9.0; */ contract Counter { uint256 public number; -} \ No newline at end of file +} diff --git a/lib/ain-contracts/src/lib.rs b/lib/ain-contracts/src/lib.rs index a51c47aa550..407b3df0ff8 100644 --- a/lib/ain-contracts/src/lib.rs +++ b/lib/ain-contracts/src/lib.rs @@ -2,6 +2,7 @@ use anyhow::anyhow; use lazy_static::lazy_static; use primitive_types::{H160, H256, U256}; use sha3::{Digest, Keccak256}; +use sp_core::{Blake2Hasher, Hasher}; use std::collections::HashMap; use std::error::Error; use std::str::FromStr; @@ -59,6 +60,11 @@ pub fn get_dst20_bytecode() -> Result, Box> { get_bytecode(include_str!("../dst20/output/bytecode.json")) } +pub fn get_dst20_codehash() -> Result> { + let bytecode = get_bytecode(include_str!("../dst20/output/bytecode.json"))?; + Ok(Blake2Hasher::hash(&bytecode)) +} + pub fn dst20_address_from_token_id(token_id: &str) -> Result> { let number_str = format!("{:x}", token_id.parse::()?); let padded_number_str = format!("{:0>38}", number_str); diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 9aaf5f13b76..00512e4262d 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -483,6 +483,16 @@ impl EVMServices { amount: U256, out: bool, ) -> Result> { + // check if code of address matches DST20 bytecode + let account = executor + .backend + .get_account(&contract) + .ok_or_else(|| anyhow!("DST20 token address is not a contract"))?; + + if account.code_hash != ain_contracts::get_dst20_codehash()? { + return Err(anyhow!("DST20 token code is not valid").into()); + } + let storage_index = ain_contracts::get_address_storage_index(to); let balance = executor .backend From 08ebc280363e88dcaf81ea12a1b10fee280b978d Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Fri, 28 Jul 2023 15:58:23 +0800 Subject: [PATCH 28/32] Check for address usage before deployment --- lib/ain-evm/src/evm.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 00512e4262d..596d235d571 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -246,7 +246,7 @@ impl EVMServices { address, bytecode, storage, - } = EVMServices::dst20_contract(address, name, symbol)?; + } = EVMServices::dst20_contract(&mut executor, address, name, symbol)?; if let Err(e) = executor.deploy_contract(address, bytecode, storage) { debug!("[finalize_block] EvmOut failed with {e}"); @@ -453,10 +453,15 @@ impl EVMServices { } pub fn dst20_contract( + executor: &mut AinExecutor, address: H160, name: String, symbol: String, ) -> Result> { + if executor.backend.get_account(&address).is_some() { + return Err(anyhow!("Token address is already in use").into()); + } + let bytecode = ain_contracts::get_dst20_bytecode()?; let storage = vec![ ( From 005979263f3bc0a2f36e79faf2fd1f37facdc0e1 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Fri, 28 Jul 2023 18:12:55 +0800 Subject: [PATCH 29/32] Add feature flag for transferdomain --- src/masternodes/errors.h | 8 ++++++++ src/masternodes/govvariables/attributes.cpp | 9 ++++++++- src/masternodes/govvariables/attributes.h | 2 ++ src/masternodes/mn_checks.cpp | 12 ++++++++++-- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/masternodes/errors.h b/src/masternodes/errors.h index 7fce0edd650..c41d9b5072e 100644 --- a/src/masternodes/errors.h +++ b/src/masternodes/errors.h @@ -438,6 +438,14 @@ class DeFiErrors { return Res::Err("Source token and destination token must be the same"); } + static Res TransferDomainNativeNotEnabled() { + return Res::Err("transferdomain for DFI is not enabled"); + } + + static Res TransferDomainDST20NotEnabled() { + return Res::Err("transferdomain for DST20 is not enabled"); + } + static Res TransferDomainIncorrectToken() { return Res::Err("For transferdomain, only DFI token is currently supported"); } diff --git a/src/masternodes/govvariables/attributes.cpp b/src/masternodes/govvariables/attributes.cpp index fbefa70e399..ef487196dce 100644 --- a/src/masternodes/govvariables/attributes.cpp +++ b/src/masternodes/govvariables/attributes.cpp @@ -245,6 +245,8 @@ const std::map> &ATTRIBUTES::allowedKeys {"emission-unused-fund", DFIPKeys::EmissionUnusedFund}, {"mint-tokens-to-address", DFIPKeys::MintTokens}, {"transferdomain", DFIPKeys::TransferDomain}, + {"dst20", DFIPKeys::DST20}, + {"transferdomain-dfi", DFIPKeys::TransferDomainDFI} }}, {AttributeTypes::EVMType, { @@ -336,6 +338,8 @@ const std::map> &ATTRIBUTES::displayKeys {DFIPKeys::EmissionUnusedFund, "emission-unused-fund"}, {DFIPKeys::MintTokens, "mint-tokens-to-address"}, {DFIPKeys::TransferDomain, "transferdomain"}, + {DFIPKeys::DST20, "dst20"}, + {DFIPKeys::TransferDomainDFI, "transferdomain-dfi"}, }}, {AttributeTypes::EVMType, { @@ -678,6 +682,8 @@ const std::map( {DFIPKeys::EmissionUnusedFund, VerifyBool}, {DFIPKeys::MintTokens, VerifyBool}, {DFIPKeys::TransferDomain, VerifyBool}, + {DFIPKeys::DST20, VerifyBool}, + {DFIPKeys::TransferDomainDFI, VerifyBool}, }}, {AttributeTypes::Locks, { @@ -921,7 +927,8 @@ Res ATTRIBUTES::ProcessVariable(const std::string &key, typeKey != DFIPKeys::ConsortiumEnabled && typeKey != DFIPKeys::CFPPayout && typeKey != DFIPKeys::EmissionUnusedFund && typeKey != DFIPKeys::MintTokens && typeKey != DFIPKeys::EVMEnabled && typeKey != DFIPKeys::ICXEnabled && - typeKey != DFIPKeys::TransferDomain) { + typeKey != DFIPKeys::TransferDomain && typeKey != DFIPKeys::DST20 && + typeKey != DFIPKeys::TransferDomainDFI) { return DeFiErrors::GovVarVariableUnsupportedFeatureType(typeKey); } } else if (typeId == ParamIDs::Foundation) { diff --git a/src/masternodes/govvariables/attributes.h b/src/masternodes/govvariables/attributes.h index c15be839026..ad079fa1959 100644 --- a/src/masternodes/govvariables/attributes.h +++ b/src/masternodes/govvariables/attributes.h @@ -108,6 +108,8 @@ enum DFIPKeys : uint8_t { EVMEnabled = 'u', ICXEnabled = 'v', TransferDomain = 'w', + DST20 = 'x', + TransferDomainDFI = 'y', }; enum GovernanceKeys : uint8_t { diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index ec6f1f64446..0a77e7dfa59 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -4110,6 +4110,12 @@ Res ValidateTransferDomainEdge(const CTransaction &tx, if (src.amount.nTokenId != dst.amount.nTokenId) return DeFiErrors::TransferDomainDifferentTokens(); + if (src.amount.nTokenId == DCT_ID{0} && !transferdomainConfig.nativeToken) + return DeFiErrors::TransferDomainNativeNotEnabled(); + + if (src.amount.nTokenId != DCT_ID{0} && !transferdomainConfig.datEnabled) + return DeFiErrors::TransferDomainDST20NotEnabled(); + if (src.domain == static_cast(VMDomain::DVM) && dst.domain == static_cast(VMDomain::EVM)) { if (height >= static_cast(consensus.ChangiIntermediateHeight4)) { if (!transferdomainConfig.dvmToEvm) { @@ -4168,13 +4174,15 @@ Res ValidateTransferDomain(const CTransaction &tx, CDataStructureV0 evm_dvm{AttributeTypes::Transfer, TransferIDs::Edges, TransferKeys::EVM_DVM}; CDataStructureV0 dvm_evm{AttributeTypes::Transfer, TransferIDs::Edges, TransferKeys::DVM_EVM}; + CDataStructureV0 dst20{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::DST20}; + CDataStructureV0 transferdomainNative{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::TransferDomainDFI}; const auto attributes = mnview.GetAttributes(); assert(attributes); TransferDomainLiveConfig transferdomainConfig{ attributes->GetValue(dvm_evm, false), attributes->GetValue(evm_dvm, false), - true, - true, + attributes->GetValue(transferdomainNative, false), + attributes->GetValue(dst20, false), {} }; From a0a6ad3c74f8e045af4767d2263151c620f4bce7 Mon Sep 17 00:00:00 2001 From: jouzo Date: Fri, 28 Jul 2023 16:12:06 +0200 Subject: [PATCH 30/32] Feature flag every edges --- src/masternodes/errors.h | 16 +++++-- src/masternodes/govvariables/attributes.cpp | 23 ++++++---- src/masternodes/govvariables/attributes.h | 50 +++++++++++---------- src/masternodes/mn_checks.cpp | 22 ++++++--- 4 files changed, 69 insertions(+), 42 deletions(-) diff --git a/src/masternodes/errors.h b/src/masternodes/errors.h index c41d9b5072e..77f75e60e93 100644 --- a/src/masternodes/errors.h +++ b/src/masternodes/errors.h @@ -438,12 +438,20 @@ class DeFiErrors { return Res::Err("Source token and destination token must be the same"); } - static Res TransferDomainNativeNotEnabled() { - return Res::Err("transferdomain for DFI is not enabled"); + static Res TransferDomainDVMNativeNotEnabled() { + return Res::Err("transferdomain for DFI from DVM is not enabled"); } - static Res TransferDomainDST20NotEnabled() { - return Res::Err("transferdomain for DST20 is not enabled"); + static Res TransferDomainEVMNativeNotEnabled() { + return Res::Err("transferdomain for DFI from EVM is not enabled"); + } + + static Res TransferDomainDST20DVMNotEnabled() { + return Res::Err("transferdomain for DST20 from DVM is not enabled"); + } + + static Res TransferDomainDST20EVMNotEnabled() { + return Res::Err("transferdomain for DST20 from EVM is not enabled"); } static Res TransferDomainIncorrectToken() { diff --git a/src/masternodes/govvariables/attributes.cpp b/src/masternodes/govvariables/attributes.cpp index ef487196dce..114c26afc8e 100644 --- a/src/masternodes/govvariables/attributes.cpp +++ b/src/masternodes/govvariables/attributes.cpp @@ -245,8 +245,10 @@ const std::map> &ATTRIBUTES::allowedKeys {"emission-unused-fund", DFIPKeys::EmissionUnusedFund}, {"mint-tokens-to-address", DFIPKeys::MintTokens}, {"transferdomain", DFIPKeys::TransferDomain}, - {"dst20", DFIPKeys::DST20}, - {"transferdomain-dfi", DFIPKeys::TransferDomainDFI} + {"dst20-dvm", DFIPKeys::DST20DVM}, + {"dst20-evm", DFIPKeys::DST20EVM}, + {"transferdomain-dvm", DFIPKeys::TransferDomainNativeDVM}, + {"transferdomain-evm", DFIPKeys::TransferDomainNativeEVM} }}, {AttributeTypes::EVMType, { @@ -338,8 +340,10 @@ const std::map> &ATTRIBUTES::displayKeys {DFIPKeys::EmissionUnusedFund, "emission-unused-fund"}, {DFIPKeys::MintTokens, "mint-tokens-to-address"}, {DFIPKeys::TransferDomain, "transferdomain"}, - {DFIPKeys::DST20, "dst20"}, - {DFIPKeys::TransferDomainDFI, "transferdomain-dfi"}, + {DFIPKeys::DST20DVM, "dst20-dvm"}, + {DFIPKeys::DST20EVM, "dst20-evm"}, + {DFIPKeys::TransferDomainNativeDVM, "transferdomain-dvm"}, + {DFIPKeys::TransferDomainNativeEVM, "transferdomain-evm"}, }}, {AttributeTypes::EVMType, { @@ -682,8 +686,10 @@ const std::map( {DFIPKeys::EmissionUnusedFund, VerifyBool}, {DFIPKeys::MintTokens, VerifyBool}, {DFIPKeys::TransferDomain, VerifyBool}, - {DFIPKeys::DST20, VerifyBool}, - {DFIPKeys::TransferDomainDFI, VerifyBool}, + {DFIPKeys::DST20DVM, VerifyBool}, + {DFIPKeys::DST20EVM, VerifyBool}, + {DFIPKeys::TransferDomainNativeDVM, VerifyBool}, + {DFIPKeys::TransferDomainNativeEVM, VerifyBool}, }}, {AttributeTypes::Locks, { @@ -927,8 +933,9 @@ Res ATTRIBUTES::ProcessVariable(const std::string &key, typeKey != DFIPKeys::ConsortiumEnabled && typeKey != DFIPKeys::CFPPayout && typeKey != DFIPKeys::EmissionUnusedFund && typeKey != DFIPKeys::MintTokens && typeKey != DFIPKeys::EVMEnabled && typeKey != DFIPKeys::ICXEnabled && - typeKey != DFIPKeys::TransferDomain && typeKey != DFIPKeys::DST20 && - typeKey != DFIPKeys::TransferDomainDFI) { + typeKey != DFIPKeys::TransferDomain && typeKey != DFIPKeys::DST20DVM && + typeKey != DFIPKeys::DST20EVM && typeKey != DFIPKeys::TransferDomainNativeDVM && + typeKey != DFIPKeys::TransferDomainNativeEVM) { return DeFiErrors::GovVarVariableUnsupportedFeatureType(typeKey); } } else if (typeId == ParamIDs::Foundation) { diff --git a/src/masternodes/govvariables/attributes.h b/src/masternodes/govvariables/attributes.h index ad079fa1959..cf4a31d1956 100644 --- a/src/masternodes/govvariables/attributes.h +++ b/src/masternodes/govvariables/attributes.h @@ -86,30 +86,32 @@ enum EconomyKeys : uint8_t { }; enum DFIPKeys : uint8_t { - Active = 'a', - Premium = 'b', - MinSwap = 'c', - RewardPct = 'd', - BlockPeriod = 'e', - DUSDInterestBurn = 'g', - DUSDLoanBurn = 'h', - StartBlock = 'i', - GovUnset = 'j', - GovFoundation = 'k', - MNSetRewardAddress = 'l', - MNSetOperatorAddress = 'm', - MNSetOwnerAddress = 'n', - ConsortiumEnabled = 'o', - Members = 'p', - GovernanceEnabled = 'q', - CFPPayout = 'r', - EmissionUnusedFund = 's', - MintTokens = 't', - EVMEnabled = 'u', - ICXEnabled = 'v', - TransferDomain = 'w', - DST20 = 'x', - TransferDomainDFI = 'y', + Active = 'a', + Premium = 'b', + MinSwap = 'c', + RewardPct = 'd', + BlockPeriod = 'e', + DUSDInterestBurn = 'g', + DUSDLoanBurn = 'h', + StartBlock = 'i', + GovUnset = 'j', + GovFoundation = 'k', + MNSetRewardAddress = 'l', + MNSetOperatorAddress = 'm', + MNSetOwnerAddress = 'n', + ConsortiumEnabled = 'o', + Members = 'p', + GovernanceEnabled = 'q', + CFPPayout = 'r', + EmissionUnusedFund = 's', + MintTokens = 't', + EVMEnabled = 'u', + ICXEnabled = 'v', + TransferDomain = 'w', + DST20DVM = 'x', + DST20EVM = 'y', + TransferDomainNativeDVM = 'z', + TransferDomainNativeEVM = '1', }; enum GovernanceKeys : uint8_t { diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 359bc7bdcee..5b7e51a1330 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -4116,10 +4116,16 @@ Res ValidateTransferDomainEdge(const CTransaction &tx, return DeFiErrors::TransferDomainDifferentTokens(); if (src.amount.nTokenId == DCT_ID{0} && !transferdomainConfig.dvmNativeToken) - return DeFiErrors::TransferDomainNativeNotEnabled(); + return DeFiErrors::TransferDomainDVMNativeNotEnabled(); + + if (dst.amount.nTokenId == DCT_ID{0} && !transferdomainConfig.evmNativeToken) + return DeFiErrors::TransferDomainEVMNativeNotEnabled(); if (src.amount.nTokenId != DCT_ID{0} && !transferdomainConfig.dvmDatEnabled) - return DeFiErrors::TransferDomainDST20NotEnabled(); + return DeFiErrors::TransferDomainDST20DVMNotEnabled(); + + if (dst.amount.nTokenId != DCT_ID{0} && !transferdomainConfig.evmDatEnabled) + return DeFiErrors::TransferDomainDST20EVMNotEnabled(); if (src.domain == static_cast(VMDomain::DVM) && dst.domain == static_cast(VMDomain::EVM)) { if (height >= static_cast(consensus.ChangiIntermediateHeight4)) { @@ -4179,15 +4185,19 @@ Res ValidateTransferDomain(const CTransaction &tx, CDataStructureV0 evm_dvm{AttributeTypes::Transfer, TransferIDs::Edges, TransferKeys::EVM_DVM}; CDataStructureV0 dvm_evm{AttributeTypes::Transfer, TransferIDs::Edges, TransferKeys::DVM_EVM}; - CDataStructureV0 dst20{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::DST20}; - CDataStructureV0 transferdomainNative{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::TransferDomainDFI}; + CDataStructureV0 dst20_dvm{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::DST20DVM}; + CDataStructureV0 dst20_evm{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::DST20EVM}; + CDataStructureV0 transferdomainNativeDVM{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::TransferDomainNativeDVM}; + CDataStructureV0 transferdomainNativeEVM{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::TransferDomainNativeEVM}; const auto attributes = mnview.GetAttributes(); assert(attributes); TransferDomainLiveConfig transferdomainConfig{ attributes->GetValue(dvm_evm, false), attributes->GetValue(evm_dvm, false), - attributes->GetValue(transferdomainNative, false), - attributes->GetValue(dst20, false), + attributes->GetValue(transferdomainNativeDVM, false), + attributes->GetValue(transferdomainNativeEVM, false), + attributes->GetValue(dst20_dvm, false), + attributes->GetValue(dst20_evm, false), {}, {} }; From e6e6159d49b55f7bf8896c92761e64312550ed02 Mon Sep 17 00:00:00 2001 From: jouzo Date: Fri, 28 Jul 2023 16:15:38 +0200 Subject: [PATCH 31/32] Trigger actions From 6062ead0c1240e3791fc84fc882a185d8f7a574a Mon Sep 17 00:00:00 2001 From: jouzo Date: Fri, 28 Jul 2023 22:06:30 +0200 Subject: [PATCH 32/32] Remove unused attributes --- src/masternodes/govvariables/attributes.cpp | 16 +--------------- src/masternodes/govvariables/attributes.h | 4 ---- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/src/masternodes/govvariables/attributes.cpp b/src/masternodes/govvariables/attributes.cpp index 63784306b20..6b58eecb534 100644 --- a/src/masternodes/govvariables/attributes.cpp +++ b/src/masternodes/govvariables/attributes.cpp @@ -247,10 +247,6 @@ const std::map> &ATTRIBUTES::allowedKeys {"emission-unused-fund", DFIPKeys::EmissionUnusedFund}, {"mint-tokens-to-address", DFIPKeys::MintTokens}, {"transferdomain", DFIPKeys::TransferDomain}, - {"dst20-dvm", DFIPKeys::DST20DVM}, - {"dst20-evm", DFIPKeys::DST20EVM}, - {"transferdomain-dvm", DFIPKeys::TransferDomainNativeDVM}, - {"transferdomain-evm", DFIPKeys::TransferDomainNativeEVM} }}, {AttributeTypes::EVMType, { @@ -347,10 +343,6 @@ const std::map> &ATTRIBUTES::displayKeys {DFIPKeys::EmissionUnusedFund, "emission-unused-fund"}, {DFIPKeys::MintTokens, "mint-tokens-to-address"}, {DFIPKeys::TransferDomain, "transferdomain"}, - {DFIPKeys::DST20DVM, "dst20-dvm"}, - {DFIPKeys::DST20EVM, "dst20-evm"}, - {DFIPKeys::TransferDomainNativeDVM, "transferdomain-dvm"}, - {DFIPKeys::TransferDomainNativeEVM, "transferdomain-evm"}, }}, {AttributeTypes::EVMType, { @@ -751,10 +743,6 @@ const std::map( {DFIPKeys::EmissionUnusedFund, VerifyBool}, {DFIPKeys::MintTokens, VerifyBool}, {DFIPKeys::TransferDomain, VerifyBool}, - {DFIPKeys::DST20DVM, VerifyBool}, - {DFIPKeys::DST20EVM, VerifyBool}, - {DFIPKeys::TransferDomainNativeDVM, VerifyBool}, - {DFIPKeys::TransferDomainNativeEVM, VerifyBool}, }}, {AttributeTypes::Locks, { @@ -999,9 +987,7 @@ Res ATTRIBUTES::ProcessVariable(const std::string &key, typeKey != DFIPKeys::ConsortiumEnabled && typeKey != DFIPKeys::CFPPayout && typeKey != DFIPKeys::EmissionUnusedFund && typeKey != DFIPKeys::MintTokens && typeKey != DFIPKeys::EVMEnabled && typeKey != DFIPKeys::ICXEnabled && - typeKey != DFIPKeys::TransferDomain && typeKey != DFIPKeys::DST20DVM && - typeKey != DFIPKeys::DST20EVM && typeKey != DFIPKeys::TransferDomainNativeDVM && - typeKey != DFIPKeys::TransferDomainNativeEVM) { + typeKey != DFIPKeys::TransferDomain) { return DeFiErrors::GovVarVariableUnsupportedFeatureType(typeKey); } } else if (typeId == ParamIDs::Foundation) { diff --git a/src/masternodes/govvariables/attributes.h b/src/masternodes/govvariables/attributes.h index 33c236705fa..0fb05b1511f 100644 --- a/src/masternodes/govvariables/attributes.h +++ b/src/masternodes/govvariables/attributes.h @@ -109,10 +109,6 @@ enum DFIPKeys : uint8_t { EVMEnabled = 'u', ICXEnabled = 'v', TransferDomain = 'w', - DST20DVM = 'x', - DST20EVM = 'y', - TransferDomainNativeDVM = 'z', - TransferDomainNativeEVM = '1', }; enum GovernanceKeys : uint8_t {