From e24556a14f0a4b2475ab2c2aa5f14b0ac6565520 Mon Sep 17 00:00:00 2001 From: Oleksandr Anyshchenko Date: Tue, 18 Jul 2023 22:04:07 +0100 Subject: [PATCH] feat: relayer function call keys (#792) ## Description The PR adds new types of transactions for adding and removing functional keys used by our relayer. High-level requirements: - The keys could be added/removed by a specific account with access granted by the owner. - The list of allowing functions to invoke: `submit`, `submit_with_args`, `call`. - The added key can call the contract via which the key has been added ( receiver_id == io.current_id() on step 1 ). - The key has allowance equals attached NEAR on the adding stage. - The key should be verified at the removal stage to correspond to the 2 and 3 requirements. ## Performance / NEAR gas cost considerations There are no changes in performance. ## Testing Added integration tests. ## Additional information !!! **The base branch should be changed to `develop` after merging #777** !!! Also, these changes along with changes from #779 require updating borealis-engine. cc @mandreyel. --- Cargo.lock | 233 +++++++------- Cargo.toml | 1 + engine-sdk/src/near_runtime.rs | 69 ++--- .../src/relayer_db/mod.rs | 1 + engine-standalone-storage/src/sync/mod.rs | 18 ++ engine-standalone-storage/src/sync/types.rs | 20 ++ engine-tests/src/tests/mod.rs | 1 + engine-tests/src/tests/relayer_keys.rs | 286 ++++++++++++++++++ engine-tests/src/tests/sanity.rs | 12 +- engine-tests/src/tests/standalone/sanity.rs | 1 + engine-tests/src/utils/mod.rs | 2 + engine-tests/src/utils/standalone/mod.rs | 20 ++ engine-types/Cargo.toml | 1 + engine-types/src/lib.rs | 1 + engine-types/src/parameters/engine.rs | 39 +++ engine-types/src/parameters/promise.rs | 17 +- engine-types/src/public_key.rs | 210 +++++++++++++ engine-types/src/storage.rs | 3 + engine-workspace/src/account.rs | 6 + engine-workspace/src/contract.rs | 39 ++- engine-workspace/src/lib.rs | 1 + engine-workspace/src/node.rs | 4 + engine-workspace/src/operation.rs | 9 + engine/src/engine.rs | 40 +++ engine/src/errors.rs | 5 +- engine/src/lib.rs | 98 +++++- engine/src/state.rs | 23 ++ etc/xcc-router/Cargo.lock | 168 +++++----- 28 files changed, 1092 insertions(+), 236 deletions(-) create mode 100644 engine-tests/src/tests/relayer_keys.rs create mode 100644 engine-types/src/public_key.rs diff --git a/Cargo.lock b/Cargo.lock index 67b859a8c..c191c75f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,7 +29,7 @@ dependencies = [ "pin-project-lite", "smallvec", "tokio", - "tokio-util 0.7.3", + "tokio-util 0.7.8", ] [[package]] @@ -180,9 +180,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" [[package]] name = "arbitrary" @@ -238,7 +238,7 @@ dependencies = [ "polling", "rustix 0.37.23", "slab", - "socket2", + "socket2 0.4.9", "waker-fn", ] @@ -288,7 +288,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] @@ -305,7 +305,7 @@ checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] @@ -461,6 +461,7 @@ dependencies = [ "base64 0.21.2", "borsh 0.10.3", "borsh 0.9.3", + "bs58 0.5.0", "hex 0.4.3", "primitive-types 0.12.1", "rand 0.8.5", @@ -769,6 +770,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +[[package]] +name = "bs58" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +dependencies = [ + "sha2 0.10.7", + "tinyvec", +] + [[package]] name = "bstr" version = "1.6.0" @@ -776,7 +787,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" dependencies = [ "memchr", - "regex-automata 0.3.2", + "regex-automata 0.3.3", "serde", ] @@ -967,9 +978,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.11" +version = "4.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1640e5cc7fb47dbb8338fd471b105e7ed6c3cb2aeb00c2e067127ffd3764a05d" +checksum = "3eab9e8ceb9afdade1ab3f0fd8dbce5b1b2f468ad653baf10e771781b2b67b73" dependencies = [ "clap_builder", "clap_derive", @@ -978,9 +989,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.11" +version = "4.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c59138d527eeaf9b53f35a77fcc1fad9d883116070c63d5de1c7dc7b00c72b" +checksum = "9f2763db829349bf00cfc06251268865ed4363b93a943174f638daf3ecdba2cd" dependencies = [ "anstream", "anstyle", @@ -990,14 +1001,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.3.2" +version = "4.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" +checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] @@ -1305,7 +1316,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "socket2", + "socket2 0.4.9", "winapi", ] @@ -1339,9 +1350,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ "darling_core", "darling_macro", @@ -1349,27 +1360,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] name = "darling_macro" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] @@ -1380,7 +1391,7 @@ checksum = "53e0efad4403bfc52dc201159c4b842a246a14b98c64b55dfd0f2d89729dfeb8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] @@ -1449,15 +1460,15 @@ dependencies = [ [[package]] name = "dissimilar" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "210ec60ae7d710bed8683e333e9d2855a8a56a3e9892b38bad3bb0d4d29b0d5e" +checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" [[package]] name = "dyn-clone" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" +checksum = "304e6508efa593091e97a9abbc10f90aa7ca635b6d2784feff3c89d41dd12272" [[package]] name = "dynasm" @@ -1577,7 +1588,7 @@ checksum = "8560b409800a72d2d7860f8e5f4e0b0bd22bea6a352ea2a9ce30ccdef7f16d2f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] @@ -1598,7 +1609,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] @@ -1987,7 +1998,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] @@ -2114,7 +2125,7 @@ dependencies = [ "indexmap 1.9.3", "slab", "tokio", - "tokio-util 0.7.3", + "tokio-util 0.7.8", "tracing", ] @@ -2307,7 +2318,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -2520,9 +2531,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jobserver" @@ -2988,7 +2999,7 @@ dependencies = [ "arrayref", "blake2", "borsh 0.9.3", - "bs58", + "bs58 0.4.0", "c2-chacha", "curve25519-dalek", "derive_more", @@ -3014,7 +3025,7 @@ dependencies = [ "arrayref", "blake2", "borsh 0.9.3", - "bs58", + "bs58 0.4.0", "c2-chacha", "curve25519-dalek", "derive_more", @@ -3038,7 +3049,7 @@ checksum = "ff6b382b626e7e0cd372d027c6672ac97b4b6ee6114288c9e58d8180b935d315" dependencies = [ "blake2", "borsh 0.10.3", - "bs58", + "bs58 0.4.0", "c2-chacha", "curve25519-dalek", "derive_more", @@ -3231,7 +3242,7 @@ checksum = "91d508f0fc340f6461e4e256417685720d3c4c00bb5a939b105160e49137caba" dependencies = [ "base64 0.11.0", "borsh 0.9.3", - "bs58", + "bs58 0.4.0", "derive_more", "near-account-id 0.14.0", "num-rational 0.3.2", @@ -3248,7 +3259,7 @@ checksum = "7929e19d862221949734c4a0063a8f55e7069de3a2ebc2d4f4c13497a5e953cb" dependencies = [ "base64 0.13.1", "borsh 0.9.3", - "bs58", + "bs58 0.4.0", "derive_more", "near-account-id 0.15.0", "num-rational 0.3.2", @@ -3267,7 +3278,7 @@ dependencies = [ "arbitrary", "base64 0.21.2", "borsh 0.10.3", - "bs58", + "bs58 0.4.0", "derive_more", "enum-map", "near-account-id 0.17.0", @@ -3310,7 +3321,7 @@ checksum = "84c1eda300e2e78f4f945ae58117d49e806899f4a51ee2faa09eda5ebc2e6571" dependencies = [ "quote", "serde", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] @@ -3344,7 +3355,7 @@ dependencies = [ "fs2", "near-rpc-error-core 0.17.0", "serde", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] @@ -3370,7 +3381,7 @@ checksum = "15eb3de2defe3626260cc209a6cdb985c6b27b0bd4619fad97dcfae002c3c5bd" dependencies = [ "base64 0.13.1", "borsh 0.9.3", - "bs58", + "bs58 0.4.0", "near-abi", "near-crypto 0.14.0", "near-primitives 0.14.0", @@ -3494,7 +3505,7 @@ checksum = "81b534828419bacbf1f7b11ef7b00420f248c548c485d3f0cfda8bb6931152f2" dependencies = [ "base64 0.13.1", "borsh 0.9.3", - "bs58", + "bs58 0.4.0", "byteorder", "near-account-id 0.14.0", "near-crypto 0.14.0", @@ -3586,9 +3597,9 @@ dependencies = [ [[package]] name = "num" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" dependencies = [ "num-bigint 0.4.3", "num-complex", @@ -3766,7 +3777,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] @@ -3948,9 +3959,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "peeking_take_while" @@ -4009,7 +4020,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] @@ -4085,9 +4096,9 @@ dependencies = [ [[package]] name = "postgres" -version = "0.19.4" +version = "0.19.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960c214283ef8f0027974c03e9014517ced5db12f021a9abb66185a5751fab0a" +checksum = "0bed5017bc2ff49649c0075d0d7a9d676933c1292480c1d137776fb205b5cd18" dependencies = [ "bytes", "fallible-iterator", @@ -4208,9 +4219,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.64" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] @@ -4331,9 +4342,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.29" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" dependencies = [ "proc-macro2", ] @@ -4518,7 +4529,7 @@ checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.2", + "regex-automata 0.3.3", "regex-syntax 0.7.4", ] @@ -4533,9 +4544,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" dependencies = [ "aho-corasick", "memchr", @@ -4763,15 +4774,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc31bd9b61a32c31f9650d18add92aa83a49ba979c143eefd27fe7177b05bd5f" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "same-file" @@ -4915,9 +4926,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "serde" @@ -4936,7 +4947,7 @@ checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] @@ -4952,9 +4963,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.100" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c" +checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" dependencies = [ "itoa", "ryu", @@ -4969,7 +4980,7 @@ checksum = "1d89a8107374290037607734c0b73a85db7ed80cae314b3c5791f192a496e731" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] @@ -5009,14 +5020,14 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] name = "serde_yaml" -version = "0.9.22" +version = "0.9.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "452e67b9c20c37fa79df53201dc03839651086ed9bbe92b3ca585ca9fdaa7d85" +checksum = "da6075b41c7e3b079e5f246eb6094a44850d3a4c25a67c581c80796c80134012" dependencies = [ "indexmap 2.0.0", "itoa", @@ -5076,9 +5087,9 @@ checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" [[package]] name = "signal-hook" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" +checksum = "b824b6e687aff278cdbf3b36f07aa52d4bd4099699324d5da86a2ebce3aa00b3" dependencies = [ "libc", "signal-hook-registry", @@ -5159,6 +5170,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "spin" version = "0.5.2" @@ -5179,9 +5200,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stringprep" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" +checksum = "db3737bde7edce97102e0e2b15365bf7a20bfdb5f60f4f9e8d7004258a51a8da" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -5234,9 +5255,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.25" +version = "2.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" +checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" dependencies = [ "proc-macro2", "quote", @@ -5263,9 +5284,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tar" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" +checksum = "ec96d2ffad078296368d46ff1cb309be1c23c513b4ab0e22a45de0185275ac96" dependencies = [ "filetime", "libc", @@ -5344,7 +5365,7 @@ checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] @@ -5443,7 +5464,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.4.9", "tokio-macros", "windows-sys 0.48.0", ] @@ -5466,7 +5487,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] @@ -5481,9 +5502,9 @@ dependencies = [ [[package]] name = "tokio-postgres" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29a12c1b3e0704ae7dfc25562629798b29c72e6b1d0a681b6f29ab4ae5e7f7bf" +checksum = "6e89f6234aa8fd43779746012fcf53603cdb91fdd8399aa0de868c2d56b6dde1" dependencies = [ "async-trait", "byteorder", @@ -5498,9 +5519,9 @@ dependencies = [ "pin-project-lite", "postgres-protocol", "postgres-types", - "socket2", + "socket2 0.5.3", "tokio", - "tokio-util 0.7.3", + "tokio-util 0.7.8", ] [[package]] @@ -5541,9 +5562,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.3" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes", "futures-core", @@ -5570,9 +5591,9 @@ checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" -version = "0.19.12" +version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ "indexmap 2.0.0", "toml_datetime", @@ -5636,7 +5657,7 @@ dependencies = [ "rand 0.8.5", "slab", "tokio", - "tokio-util 0.7.3", + "tokio-util 0.7.8", "tower-layer", "tower-service", "tracing", @@ -5686,7 +5707,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] @@ -5794,9 +5815,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-normalization" @@ -5821,9 +5842,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "unsafe-libyaml" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1865806a559042e51ab5414598446a5871b561d21b6764f2eabb0dd481d880a6" +checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" [[package]] name = "url" @@ -5845,9 +5866,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" dependencies = [ "getrandom 0.2.10", ] @@ -5962,7 +5983,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.26", "wasm-bindgen-shared", ] @@ -5996,7 +6017,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.26", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6547,9 +6568,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.9" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a2094c43cc94775293eaa0e499fbc30048a6d824ac82c0351a8c0bf9112529" +checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7" dependencies = [ "memchr", ] @@ -6573,7 +6594,7 @@ dependencies = [ "async-trait", "base64 0.13.1", "borsh 0.9.3", - "bs58", + "bs58 0.4.0", "chrono", "dirs 3.0.2", "hex 0.4.3", @@ -6637,7 +6658,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.26", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ba7c261cc..fea7dc915 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ bitflags = { version = "1", default-features = false } bn = { version = "0.5", package = "zeropool-bn", default-features = false } borsh = { version = "0.10", default-features = false } borsh-compat = { version = "0.9", package = "borsh", default-features = false } +bs58 = { version = "0.5", default-features = false, features = ["alloc", "sha2"] } bstr = "1" byte-slice-cast = { version = "1", default-features = false } criterion = "0.5" diff --git a/engine-sdk/src/near_runtime.rs b/engine-sdk/src/near_runtime.rs index 4ab76e780..3600a55b9 100644 --- a/engine-sdk/src/near_runtime.rs +++ b/engine-sdk/src/near_runtime.rs @@ -2,9 +2,8 @@ use crate::io::StorageIntermediate; use crate::prelude::NearGas; use crate::promise::PromiseId; use aurora_engine_types::account_id::AccountId; -use aurora_engine_types::parameters::{ - NearPublicKey, PromiseAction, PromiseBatchAction, PromiseCreateArgs, -}; +use aurora_engine_types::parameters::{PromiseAction, PromiseBatchAction, PromiseCreateArgs}; +use aurora_engine_types::public_key::PublicKey; use aurora_engine_types::types::PromiseResult; use aurora_engine_types::H256; @@ -418,36 +417,32 @@ impl crate::promise::PromiseHandler for Runtime { receiver_id, function_names, } => { - feature_gated!("all-promise-actions", { - let pk: RawPublicKey = public_key.into(); - let pk_bytes = pk.as_bytes(); - let allowance = allowance.as_u128(); - let allowance_addr = core::ptr::addr_of!(allowance); - let receiver_id = receiver_id.as_bytes(); - let function_names = function_names.as_bytes(); - exports::promise_batch_action_add_key_with_function_call( - id, - pk_bytes.len() as _, - pk_bytes.as_ptr() as _, - *nonce, - allowance_addr as _, - receiver_id.len() as _, - receiver_id.as_ptr() as _, - function_names.len() as _, - function_names.as_ptr() as _, - ); - }); + let pk: RawPublicKey = public_key.into(); + let pk_bytes = pk.as_bytes(); + let allowance = allowance.as_u128(); + let allowance_addr = core::ptr::addr_of!(allowance); + let receiver_id = receiver_id.as_bytes(); + let function_names = function_names.as_bytes(); + exports::promise_batch_action_add_key_with_function_call( + id, + pk_bytes.len() as _, + pk_bytes.as_ptr() as _, + *nonce, + allowance_addr as _, + receiver_id.len() as _, + receiver_id.as_ptr() as _, + function_names.len() as _, + function_names.as_ptr() as _, + ); } PromiseAction::DeleteKey { public_key } => { - feature_gated!("all-promise-actions", { - let pk: RawPublicKey = public_key.into(); - let pk_bytes = pk.as_bytes(); - exports::promise_batch_action_delete_key( - id, - pk_bytes.len() as _, - pk_bytes.as_ptr() as _, - ); - }); + let pk: RawPublicKey = public_key.into(); + let pk_bytes = pk.as_bytes(); + exports::promise_batch_action_delete_key( + id, + pk_bytes.len() as _, + pk_bytes.as_ptr() as _, + ); } PromiseAction::DeleteAccount { beneficiary_id } => { feature_gated!("all-promise-actions", { @@ -508,18 +503,18 @@ impl RawPublicKey { } } -impl<'a> From<&'a NearPublicKey> for RawPublicKey { - fn from(key: &'a NearPublicKey) -> Self { +impl<'a> From<&'a PublicKey> for RawPublicKey { + fn from(key: &'a PublicKey) -> Self { match key { - NearPublicKey::Ed25519(bytes) => { + PublicKey::Ed25519(_) => { let mut buf = [0u8; 33]; - buf[1..33].copy_from_slice(bytes); + buf[1..33].copy_from_slice(key.key_data()); Self::Ed25519(buf) } - NearPublicKey::Secp256k1(bytes) => { + PublicKey::Secp256k1(_) => { let mut buf = [0u8; 65]; buf[0] = 0x01; - buf[1..65].copy_from_slice(bytes); + buf[1..65].copy_from_slice(key.key_data()); Self::Secp256k1(buf) } } diff --git a/engine-standalone-storage/src/relayer_db/mod.rs b/engine-standalone-storage/src/relayer_db/mod.rs index fc0bb02df..5e29a0488 100644 --- a/engine-standalone-storage/src/relayer_db/mod.rs +++ b/engine-standalone-storage/src/relayer_db/mod.rs @@ -220,6 +220,7 @@ mod test { owner_id: "aurora".parse().unwrap(), upgrade_delay_blocks: 0, is_paused: false, + key_manager: None, }; // Initialize engine and connector states in storage. diff --git a/engine-standalone-storage/src/sync/mod.rs b/engine-standalone-storage/src/sync/mod.rs index 1670e970b..0f32b33ba 100644 --- a/engine-standalone-storage/src/sync/mod.rs +++ b/engine-standalone-storage/src/sync/mod.rs @@ -469,6 +469,24 @@ fn non_submit_execute<'db, M: ModExpAlgorithm + 'static>( prev.is_paused = false; state::set_state(&mut io, &prev)?; + None + } + TransactionKind::SetKeyManager(args) => { + let mut prev = state::get_state(&io)?; + + prev.key_manager = args.key_manager.clone(); + state::set_state(&mut io, &prev)?; + + None + } + TransactionKind::AddRelayerKey(args) => { + engine::add_function_call_key(&mut io, &args.public_key); + + None + } + TransactionKind::RemoveRelayerKey(args) => { + engine::remove_function_call_key(&mut io, &args.public_key)?; + None } }; diff --git a/engine-standalone-storage/src/sync/types.rs b/engine-standalone-storage/src/sync/types.rs index d401f4df0..1c702aa8b 100644 --- a/engine-standalone-storage/src/sync/types.rs +++ b/engine-standalone-storage/src/sync/types.rs @@ -135,6 +135,12 @@ pub enum TransactionKind { PauseContract, /// Resume the contract ResumeContract, + /// Set the relayer key manager + SetKeyManager(parameters::RelayerKeyManagerArgs), + /// Add a new relayer public function call access key + AddRelayerKey(parameters::RelayerKeyArgs), + /// Remove the relayer public function call access key + RemoveRelayerKey(parameters::RelayerKeyArgs), /// Sentinel kind for cases where a NEAR receipt caused a /// change in Aurora state, but we failed to parse the Action. Unknown, @@ -360,6 +366,9 @@ impl TransactionKind { Self::FundXccSubAccound(_) => Self::no_evm_execution("fund_xcc_sub_account"), Self::PauseContract => Self::no_evm_execution("pause_contract"), Self::ResumeContract => Self::no_evm_execution("resume_contract"), + Self::SetKeyManager(_) => Self::no_evm_execution("set_key_manager"), + Self::AddRelayerKey(_) => Self::no_evm_execution("add_relayer_key"), + Self::RemoveRelayerKey(_) => Self::no_evm_execution("remove_relayer_key"), } } @@ -531,6 +540,9 @@ enum BorshableTransactionKind<'a> { SetUpgradeDelayBlocks(Cow<'a, parameters::SetUpgradeDelayBlocksArgs>), PauseContract, ResumeContract, + SetKeyManager(Cow<'a, parameters::RelayerKeyManagerArgs>), + AddRelayerKey(Cow<'a, parameters::RelayerKeyArgs>), + RemoveRelayerKey(Cow<'a, parameters::RelayerKeyArgs>), } impl<'a> From<&'a TransactionKind> for BorshableTransactionKind<'a> { @@ -579,6 +591,9 @@ impl<'a> From<&'a TransactionKind> for BorshableTransactionKind<'a> { } TransactionKind::PauseContract => Self::PauseContract, TransactionKind::ResumeContract => Self::ResumeContract, + TransactionKind::SetKeyManager(x) => Self::SetKeyManager(Cow::Borrowed(x)), + TransactionKind::AddRelayerKey(x) => Self::AddRelayerKey(Cow::Borrowed(x)), + TransactionKind::RemoveRelayerKey(x) => Self::RemoveRelayerKey(Cow::Borrowed(x)), } } } @@ -646,6 +661,11 @@ impl<'a> TryFrom> for TransactionKind { } BorshableTransactionKind::PauseContract => Ok(Self::PauseContract), BorshableTransactionKind::ResumeContract => Ok(Self::ResumeContract), + BorshableTransactionKind::SetKeyManager(x) => Ok(Self::SetKeyManager(x.into_owned())), + BorshableTransactionKind::AddRelayerKey(x) => Ok(Self::AddRelayerKey(x.into_owned())), + BorshableTransactionKind::RemoveRelayerKey(x) => { + Ok(Self::RemoveRelayerKey(x.into_owned())) + } } } } diff --git a/engine-tests/src/tests/mod.rs b/engine-tests/src/tests/mod.rs index 4f1c3c61d..7adb5cb1c 100644 --- a/engine-tests/src/tests/mod.rs +++ b/engine-tests/src/tests/mod.rs @@ -15,6 +15,7 @@ mod pause_contract; mod prepaid_gas_precompile; mod promise_results_precompile; mod random; +mod relayer_keys; mod repro; pub mod sanity; mod self_destruct_state; diff --git a/engine-tests/src/tests/relayer_keys.rs b/engine-tests/src/tests/relayer_keys.rs new file mode 100644 index 000000000..300b3807b --- /dev/null +++ b/engine-tests/src/tests/relayer_keys.rs @@ -0,0 +1,286 @@ +use crate::utils::workspace::deploy_engine; +use aurora_engine_types::parameters::engine::{RelayerKeyArgs, RelayerKeyManagerArgs}; +use aurora_engine_types::public_key::PublicKey; +use aurora_engine_types::types::Address; +use aurora_engine_workspace::parse_near; +use aurora_engine_workspace::types::{KeyType, SecretKey}; +use std::fmt::Debug; +use std::str::FromStr; + +#[tokio::test] +async fn test_add_key_manager() { + let aurora = deploy_engine().await; + let pk = PublicKey::from_str("ed25519:DcA2MzgpJbrUATQLLceocVckhhAqrkingax4oJ9kZ847").unwrap(); + let relayer_key_args = RelayerKeyArgs { public_key: pk }; + let manager = aurora + .root() + .create_subaccount("key_manager", parse_near!("10 N")) + .await + .unwrap(); + + let result = manager + .call(&aurora.id(), "add_relayer_key") + .args_json(relayer_key_args.clone()) + .deposit(parse_near!("0.5 N")) + .max_gas() + .transact() + .await + .unwrap(); + assert!(result.is_failure()); + let err = result.into_result().err().unwrap(); + assert_error_message(&err, "Smart contract panicked: ERR_KEY_MANAGER_IS_NOT_SET"); + + let result = aurora + .set_key_manager(RelayerKeyManagerArgs { + key_manager: Some(manager.id().clone()), + }) + .max_gas() + .transact() + .await + .unwrap(); + assert!(result.is_success()); + + let result = manager + .call(&aurora.id(), "add_relayer_key") + .args_json(relayer_key_args.clone()) + .max_gas() + .deposit(parse_near!("0.5 N")) + .transact() + .await + .unwrap(); + assert!(result.is_success()); + + let result = aurora + .set_key_manager(RelayerKeyManagerArgs { key_manager: None }) + .max_gas() + .transact() + .await + .unwrap(); + assert!(result.is_success()); + + let result = manager + .call(&aurora.id(), "add_relayer_key") + .args_json(relayer_key_args) + .max_gas() + .deposit(parse_near!("0.5 N")) + .transact() + .await + .unwrap(); + assert!(result.is_failure()); + let err = result.into_result().err().unwrap(); + assert_error_message(&err, "Smart contract panicked: ERR_KEY_MANAGER_IS_NOT_SET"); +} + +#[tokio::test] +async fn test_submit_by_relayer() { + let aurora = deploy_engine().await; + let secret_key = SecretKey::from_random(KeyType::ED25519); + let public_key = public_key(&secret_key); + let relayer = aurora.create_account(&aurora.id(), secret_key); + + let manager = aurora + .root() + .create_subaccount("key_manager", parse_near!("10 N")) + .await + .unwrap(); + let result = aurora + .set_key_manager(RelayerKeyManagerArgs { + key_manager: Some(manager.id().clone()), + }) + .max_gas() + .transact() + .await + .unwrap(); + assert!(result.is_success()); + + let err = relayer + .call(&aurora.id(), "submit") + .max_gas() + .transact() + .await + .err() + .unwrap(); + assert_error_message(&err, "Failed to query access key"); + + let result = manager + .call(&aurora.id(), "add_relayer_key") + .args_json(RelayerKeyArgs { public_key }) + .max_gas() + .deposit(parse_near!("0.5 N")) + .transact() + .await + .unwrap(); + assert!(result.is_success()); + + let result = relayer + .call(&aurora.id(), "submit") + .max_gas() + .transact() + .await; + assert!(result.is_ok()); +} + +#[tokio::test] +async fn test_delete_relayer_key() { + let aurora = deploy_engine().await; + let secret_key = SecretKey::from_random(KeyType::ED25519); + let public_key = public_key(&secret_key); + let relayer = aurora.create_account(&aurora.id(), secret_key); + + let manager = aurora + .root() + .create_subaccount("key_manager", parse_near!("10 N")) + .await + .unwrap(); + let result = aurora + .set_key_manager(RelayerKeyManagerArgs { + key_manager: Some(manager.id().clone()), + }) + .max_gas() + .transact() + .await + .unwrap(); + assert!(result.is_success()); + + let result = manager + .call(&aurora.id(), "add_relayer_key") + .args_json(RelayerKeyArgs { public_key }) + .max_gas() + .deposit(parse_near!("0.5 N")) + .transact() + .await + .unwrap(); + assert!(result.is_success()); + + let result = relayer + .call(&aurora.id(), "submit") + .max_gas() + .transact() + .await; + assert!(result.is_ok()); + + let result = manager + .call(&aurora.id(), "remove_relayer_key") + .args_json(RelayerKeyArgs { public_key }) + .max_gas() + .transact() + .await + .unwrap(); + assert!(result.is_success()); + + // Second attempt should be finished with fail. + let result = manager + .call(&aurora.id(), "remove_relayer_key") + .args_json(RelayerKeyArgs { public_key }) + .max_gas() + .transact() + .await + .unwrap(); + assert!(result.is_failure()); + + let err = relayer + .call(&aurora.id(), "submit") + .max_gas() + .transact() + .await + .err() + .unwrap(); + assert_error_message(&err, "unable to broadcast the transaction to the network"); +} + +#[tokio::test] +async fn test_call_not_allowed_method() { + let aurora = deploy_engine().await; + let secret_key = SecretKey::from_random(KeyType::ED25519); + let public_key = public_key(&secret_key); + let relayer = aurora.create_account(&aurora.id(), secret_key); + + let manager = aurora + .root() + .create_subaccount("key_manager", parse_near!("10 N")) + .await + .unwrap(); + let result = aurora + .set_key_manager(RelayerKeyManagerArgs { + key_manager: Some(manager.id().clone()), + }) + .max_gas() + .transact() + .await + .unwrap(); + assert!(result.is_success()); + + let result = manager + .call(&aurora.id(), "add_relayer_key") + .args_json(RelayerKeyArgs { public_key }) + .max_gas() + .deposit(parse_near!("0.5 N")) + .transact() + .await + .unwrap(); + assert!(result.is_success()); + + let err = relayer + .call(&aurora.id(), "register_relayer") + .args_borsh(Address::zero()) + .max_gas() + .transact() + .await + .err() + .unwrap(); + + assert_error_message(&err, "unable to broadcast the transaction to the network"); +} + +#[tokio::test] +async fn test_call_not_allowed_contract() { + let aurora = deploy_engine().await; + let secret_key = SecretKey::from_random(KeyType::ED25519); + let public_key = public_key(&secret_key); + let relayer = aurora.create_account(&aurora.id(), secret_key); + + let manager = aurora + .root() + .create_subaccount("key_manager", parse_near!("10 N")) + .await + .unwrap(); + let result = aurora + .set_key_manager(RelayerKeyManagerArgs { + key_manager: Some(manager.id().clone()), + }) + .max_gas() + .transact() + .await + .unwrap(); + assert!(result.is_success()); + + let result = manager + .call(&aurora.id(), "add_relayer_key") + .args_json(RelayerKeyArgs { public_key }) + .max_gas() + .deposit(parse_near!("0.5 N")) + .transact() + .await + .unwrap(); + assert!(result.is_success()); + + let err = relayer + .call(&"some-contract.near".parse().unwrap(), "submit") + .args_borsh(Address::zero()) + .max_gas() + .transact() + .await + .err() + .unwrap(); + assert_error_message(&err, "unable to broadcast the transaction to the network"); +} + +fn public_key(sk: &SecretKey) -> PublicKey { + let pk_str = serde_json::to_string(&sk.public_key()).unwrap(); + PublicKey::from_str(pk_str.trim_matches('"')).unwrap() +} + +fn assert_error_message(err: &T, expected: &str) { + let err_msg = format!("{err:?}"); + assert!(err_msg.contains(expected)); +} diff --git a/engine-tests/src/tests/sanity.rs b/engine-tests/src/tests/sanity.rs index c729cfac4..3b7d65cbd 100644 --- a/engine-tests/src/tests/sanity.rs +++ b/engine-tests/src/tests/sanity.rs @@ -131,16 +131,20 @@ fn test_state_format() { // change the binary format of the `EngineState` then we will know // about it. This is important because changing the state format will // break the contract unless we do a state migration. - let args = aurora_engine::parameters::NewCallArgsV2 { + let args = aurora_engine::parameters::NewCallArgsV3 { chain_id: aurora_engine_types::types::u256_to_arr(&666.into()), owner_id: "boss".parse().unwrap(), upgrade_delay_blocks: 3, + key_manager: "key_manager".parse().unwrap(), }; let state: aurora_engine::state::EngineState = args.into(); let expected_hex: String = [ - "02000000000000000000000000000000000000000000000000000000000000029a", - "04000000626f7373", - "030000000000000000", + "02", // state version + "000000000000000000000000000000000000000000000000000000000000029a", // chain id + "04000000626f7373", // owner id + "0300000000000000", // upgrade delay blocks + "00", // contract mode + "010b0000006b65795f6d616e61676572", // key manager ] .concat(); assert_eq!(hex::encode(state.borsh_serialize().unwrap()), expected_hex); diff --git a/engine-tests/src/tests/standalone/sanity.rs b/engine-tests/src/tests/standalone/sanity.rs index 1ec721c2e..cc303ba9e 100644 --- a/engine-tests/src/tests/standalone/sanity.rs +++ b/engine-tests/src/tests/standalone/sanity.rs @@ -20,6 +20,7 @@ fn test_deploy_code() { owner_id: owner_id.clone(), upgrade_delay_blocks: 0, is_paused: false, + key_manager: None, }; let origin = Address::new(H160([0u8; 20])); let storage = RefCell::new(Storage::default()); diff --git a/engine-tests/src/utils/mod.rs b/engine-tests/src/utils/mod.rs index 357987e4c..2a0087f60 100644 --- a/engine-tests/src/utils/mod.rs +++ b/engine-tests/src/utils/mod.rs @@ -44,6 +44,7 @@ pub const SET_OWNER: &str = "set_owner"; pub const SET_UPGRADE_DELAY_BLOCKS: &str = "set_upgrade_delay_blocks"; pub const PAUSE_CONTRACT: &str = "pause_contract"; pub const RESUME_CONTRACT: &str = "resume_contract"; +pub const SET_KEY_MANAGER: &str = "set_key_manager"; const CALLER_ACCOUNT_ID: &str = "some-account.near"; @@ -243,6 +244,7 @@ impl AuroraRunner { || method_name == SET_UPGRADE_DELAY_BLOCKS || method_name == PAUSE_CONTRACT || method_name == RESUME_CONTRACT + || method_name == SET_KEY_MANAGER { standalone_runner.submit_raw(method_name, &self.context, &self.promise_results)?; self.validate_standalone(); diff --git a/engine-tests/src/utils/standalone/mod.rs b/engine-tests/src/utils/standalone/mod.rs index 19d0b35e8..8a41ed5f7 100644 --- a/engine-tests/src/utils/standalone/mod.rs +++ b/engine-tests/src/utils/standalone/mod.rs @@ -7,6 +7,7 @@ use aurora_engine_modexp::AuroraModExp; use aurora_engine_sdk::env::{self, Env}; use aurora_engine_transactions::legacy::{LegacyEthSignedTransaction, TransactionLegacy}; use aurora_engine_types::borsh::BorshDeserialize; +use aurora_engine_types::parameters::engine::RelayerKeyManagerArgs; use aurora_engine_types::types::{Address, NearGas, PromiseResult, Wei}; use aurora_engine_types::{H256, U256}; use engine_standalone_storage::{ @@ -364,6 +365,25 @@ impl StandaloneRunner { self.cumulative_diff.append(outcome.diff.clone()); storage::commit(storage, &outcome); + Ok(SubmitResult::new( + TransactionStatus::Succeed(Vec::new()), + 0, + Vec::new(), + )) + } else if method_name == utils::SET_KEY_MANAGER { + let transaction_hash = aurora_engine_sdk::keccak(&ctx.input); + let call_args: RelayerKeyManagerArgs = serde_json::from_slice(&ctx.input) + .expect("Unable to parse input as RelayerKeyManagerArgs"); + + let mut tx_msg = + Self::template_tx_msg(storage, &env, 0, transaction_hash, promise_results); + tx_msg.transaction = TransactionKind::SetKeyManager(call_args); + + let outcome = + sync::execute_transaction_message::(storage, tx_msg).unwrap(); + self.cumulative_diff.append(outcome.diff.clone()); + storage::commit(storage, &outcome); + Ok(SubmitResult::new( TransactionStatus::Succeed(Vec::new()), 0, diff --git a/engine-types/Cargo.toml b/engine-types/Cargo.toml index f58f43604..611f81582 100644 --- a/engine-types/Cargo.toml +++ b/engine-types/Cargo.toml @@ -14,6 +14,7 @@ publish.workspace = true base64.workspace = true borsh-compat = { workspace = true, optional = true } borsh.workspace = true +bs58.workspace = true hex.workspace = true primitive-types.workspace = true rlp.workspace = true diff --git a/engine-types/src/lib.rs b/engine-types/src/lib.rs index 74ec29b41..bd9ab7406 100644 --- a/engine-types/src/lib.rs +++ b/engine-types/src/lib.rs @@ -8,6 +8,7 @@ pub mod account_id; pub mod parameters; +pub mod public_key; pub mod storage; pub mod types; diff --git a/engine-types/src/parameters/engine.rs b/engine-types/src/parameters/engine.rs index 70018fbb6..7b4820199 100644 --- a/engine-types/src/parameters/engine.rs +++ b/engine-types/src/parameters/engine.rs @@ -1,5 +1,6 @@ use crate::{ account_id::AccountId, + public_key::PublicKey, types::{Address, RawH256, RawU256, WeiU256, Yocto}, Vec, }; @@ -7,12 +8,14 @@ use crate::{ use borsh::{BorshDeserialize, BorshSerialize}; #[cfg(feature = "borsh-compat")] use borsh_compat::{self as borsh, BorshDeserialize, BorshSerialize}; +use serde::{Deserialize, Serialize}; /// Parameters for the `new` function. #[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub enum NewCallArgs { V1(LegacyNewCallArgs), V2(NewCallArgsV2), + V3(NewCallArgsV3), } impl NewCallArgs { @@ -50,6 +53,19 @@ pub struct NewCallArgsV2 { pub upgrade_delay_blocks: u64, } +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] +pub struct NewCallArgsV3 { + /// Chain id, according to the EIP-115 / ethereum-lists spec. + pub chain_id: RawU256, + /// Account which can upgrade this contract. + /// Use empty to disable updatability. + pub owner_id: AccountId, + /// How many blocks after staging upgrade can deploy it. + pub upgrade_delay_blocks: u64, + /// Relayer keys manager. + pub key_manager: AccountId, +} + /// Borsh-encoded parameters for the `set_owner` function. #[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] #[cfg_attr(feature = "impl-serde", derive(serde::Serialize, serde::Deserialize))] @@ -286,6 +302,18 @@ pub struct GetStorageAtArgs { pub key: RawH256, } +/// Parameters for setting relayer keys manager. +#[derive(Debug, Clone, Eq, PartialEq, BorshSerialize, BorshDeserialize, Serialize, Deserialize)] +pub struct RelayerKeyManagerArgs { + pub key_manager: Option, +} + +/// Parameters for adding or removing relayer function all keys. +#[derive(Debug, Clone, Eq, PartialEq, BorshSerialize, BorshDeserialize, Serialize, Deserialize)] +pub struct RelayerKeyArgs { + pub public_key: PublicKey, +} + pub mod errors { use crate::{account_id::ParseAccountError, String, ToString}; @@ -388,4 +416,15 @@ mod tests { let parsed_data = CallArgs::deserialize(&input_bytes); assert_eq!(parsed_data, None); } + + #[test] + fn test_deserialize_relayer_key_args() { + let json = r#"{"public_key": "ed25519:DcA2MzgpJbrUATQLLceocVckhhAqrkingax4oJ9kZ847"}"#; + let public_key: PublicKey = "ed25519:DcA2MzgpJbrUATQLLceocVckhhAqrkingax4oJ9kZ847" + .parse() + .unwrap(); + let args = serde_json::from_str::(json).unwrap(); + + assert_eq!(args.public_key, public_key); + } } diff --git a/engine-types/src/parameters/promise.rs b/engine-types/src/parameters/promise.rs index d13519483..8820bbaa3 100644 --- a/engine-types/src/parameters/promise.rs +++ b/engine-types/src/parameters/promise.rs @@ -1,4 +1,5 @@ use crate::account_id::AccountId; +use crate::public_key::PublicKey; use crate::types::{Address, NEP141Wei, NearGas, RawU256, Yocto}; use crate::{Box, String, Vec}; @@ -260,35 +261,27 @@ pub enum PromiseAction { }, Stake { amount: Yocto, - public_key: NearPublicKey, + public_key: PublicKey, }, AddFullAccessKey { - public_key: NearPublicKey, + public_key: PublicKey, nonce: u64, }, AddFunctionCallKey { - public_key: NearPublicKey, + public_key: PublicKey, nonce: u64, allowance: Yocto, receiver_id: AccountId, function_names: String, }, DeleteKey { - public_key: NearPublicKey, + public_key: PublicKey, }, DeleteAccount { beneficiary_id: AccountId, }, } -#[derive(Debug, BorshSerialize, BorshDeserialize, Clone, PartialEq, Eq)] -pub enum NearPublicKey { - /// ed25519 public keys are 32 bytes - Ed25519([u8; 32]), - /// secp256k1 keys are in the uncompressed 64 byte format - Secp256k1([u8; 64]), -} - #[must_use] #[derive(Debug, BorshSerialize, BorshDeserialize, Clone, PartialEq, Eq)] pub struct PromiseBatchAction { diff --git a/engine-types/src/public_key.rs b/engine-types/src/public_key.rs new file mode 100644 index 000000000..cf75a6002 --- /dev/null +++ b/engine-types/src/public_key.rs @@ -0,0 +1,210 @@ +use crate::{fmt, str::FromStr, String, ToString}; +#[cfg(not(feature = "borsh-compat"))] +use borsh::{maybestd::io, BorshDeserialize, BorshSerialize}; +#[cfg(feature = "borsh-compat")] +use borsh_compat::{maybestd::io, BorshDeserialize, BorshSerialize}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PublicKey { + /// ed25519 public keys are 32 bytes + Ed25519([u8; 32]), + /// secp256k1 keys are in the uncompressed 64 byte format + Secp256k1([u8; 64]), +} + +impl PublicKey { + #[must_use] + pub fn key_data(&self) -> &[u8] { + match self { + Self::Ed25519(data) => &data[..], + Self::Secp256k1(data) => &data[..], + } + } +} + +impl BorshSerialize for PublicKey { + fn serialize(&self, writer: &mut W) -> Result<(), io::Error> { + match self { + Self::Ed25519(public_key) => { + BorshSerialize::serialize(&0u8, writer)?; + writer.write_all(public_key)?; + } + Self::Secp256k1(public_key) => { + BorshSerialize::serialize(&1u8, writer)?; + writer.write_all(public_key)?; + } + } + Ok(()) + } +} + +#[cfg(not(feature = "borsh-compat"))] +impl BorshDeserialize for PublicKey { + fn deserialize_reader(rd: &mut R) -> io::Result { + let key_type = u8::deserialize_reader(rd).and_then(KeyType::try_from)?; + + match key_type { + KeyType::Ed25519 => Ok(Self::Ed25519(BorshDeserialize::deserialize_reader(rd)?)), + KeyType::Secp256k1 => Ok(Self::Secp256k1(BorshDeserialize::deserialize_reader(rd)?)), + } + } +} + +#[cfg(feature = "borsh-compat")] +impl BorshDeserialize for PublicKey { + fn deserialize(buf: &mut &[u8]) -> io::Result { + let key_type = ::deserialize(buf).and_then(KeyType::try_from)?; + + match key_type { + KeyType::Ed25519 => Ok(Self::Ed25519(BorshDeserialize::deserialize(buf)?)), + KeyType::Secp256k1 => Ok(Self::Secp256k1(BorshDeserialize::deserialize(buf)?)), + } + } +} + +impl serde::Serialize for PublicKey { + fn serialize( + &self, + serializer: S, + ) -> Result<::Ok, ::Error> + where + S: serde::Serializer, + { + serializer.collect_str(self) + } +} + +impl<'de> serde::Deserialize<'de> for PublicKey { + fn deserialize(deserializer: D) -> Result>::Error> + where + D: serde::Deserializer<'de>, + { + let s = ::deserialize(deserializer)?; + s.parse() + .map_err(|_| serde::de::Error::custom("PublicKey decode error")) + } +} + +impl FromStr for PublicKey { + type Err = DecodeBs58Error; + + fn from_str(value: &str) -> Result { + let (key_type, key_data) = split_key_type_data(value)?; + Ok(match key_type { + KeyType::Ed25519 => Self::Ed25519(decode_bs58(key_data)?), + KeyType::Secp256k1 => Self::Secp256k1(decode_bs58(key_data)?), + }) + } +} + +impl fmt::Display for PublicKey { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let (key_type, key_data) = match self { + Self::Ed25519(public_key) => (KeyType::Ed25519, &public_key[..]), + Self::Secp256k1(public_key) => (KeyType::Secp256k1, &public_key[..]), + }; + write!(fmt, "{}:{}", key_type, Bs58(key_data)) + } +} + +pub enum KeyType { + Ed25519, + Secp256k1, +} + +impl TryFrom for KeyType { + type Error = io::Error; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::Ed25519), + 1 => Ok(Self::Secp256k1), + _ => Err(io::Error::new( + io::ErrorKind::InvalidData, + "Wrong key prefix", + )), + } + } +} + +impl fmt::Display for KeyType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(match self { + Self::Ed25519 => "ed25519", + Self::Secp256k1 => "secp256k1", + }) + } +} + +impl FromStr for KeyType { + type Err = DecodeBs58Error; + + fn from_str(value: &str) -> Result { + let lowercase_key_type = value.to_ascii_lowercase(); + match lowercase_key_type.as_str() { + "ed25519" => Ok(Self::Ed25519), + "secp256k1" => Ok(Self::Secp256k1), + _ => Err(Self::Err::BadData(value.to_string())), + } + } +} + +fn split_key_type_data(value: &str) -> Result<(KeyType, &str), DecodeBs58Error> { + if let Some(idx) = value.find(':') { + let (prefix, key_data) = value.split_at(idx); + Ok((KeyType::from_str(prefix)?, &key_data[1..])) + } else { + // If there is no prefix then we Default to ED25519. + Ok((KeyType::Ed25519, value)) + } +} + +/// Helper struct which provides Display implementation for bytes slice +/// encoding them using base58. +// TODO(mina86): Get rid of it once bs58 has this feature. There’s currently PR +// for that: https://github.com/Nullus157/bs58-rs/pull/97 +struct Bs58<'a>(&'a [u8]); + +impl<'a> fmt::Display for Bs58<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + debug_assert!(self.0.len() <= 65); + // The largest buffer we’re ever encoding is 65-byte long. Base58 + // increases size of the value by less than 40%. 96-byte buffer is + // therefore enough to fit the largest value we’re ever encoding. + let mut buf = [0u8; 96]; + let len = bs58::encode(self.0).onto(&mut buf[..]).unwrap(); + let output = &buf[..len]; + // SAFETY: we know that alphabet can only include ASCII characters + // thus our result is an ASCII string. + fmt.write_str(unsafe { crate::str::from_utf8_unchecked(output) }) + } +} + +/// Helper which decodes fixed-length base58-encoded data. +/// +/// If the encoded string decodes into a buffer of different length than `N`, +/// returns error. Similarly returns error if decoding fails. +fn decode_bs58(encoded: &str) -> Result<[u8; N], DecodeBs58Error> { + let mut buffer = [0u8; N]; + decode_bs58_impl(&mut buffer[..], encoded)?; + Ok(buffer) +} + +fn decode_bs58_impl(dst: &mut [u8], encoded: &str) -> Result<(), DecodeBs58Error> { + let expected = dst.len(); + match bs58::decode(encoded).onto(dst) { + Ok(received) if received == expected => Ok(()), + Ok(received) => Err(DecodeBs58Error::BadLength { expected, received }), + Err(bs58::decode::Error::BufferTooSmall) => Err(DecodeBs58Error::BadLength { + expected, + received: expected.saturating_add(1), + }), + Err(err) => Err(DecodeBs58Error::BadData(err.to_string())), + } +} + +#[derive(Debug)] +pub enum DecodeBs58Error { + BadLength { expected: usize, received: usize }, + BadData(String), +} diff --git a/engine-types/src/storage.rs b/engine-types/src/storage.rs index e4c2a2606..4dfa80e2d 100644 --- a/engine-types/src/storage.rs +++ b/engine-types/src/storage.rs @@ -32,6 +32,7 @@ pub enum KeyPrefix { Nep141Erc20Map = 0x8, Erc20Nep141Map = 0x9, CrossContractCall = 0xa, + RelayerFunctionCallKey = 0xb, } impl From for u8 { @@ -48,6 +49,7 @@ impl From for u8 { KeyPrefix::Nep141Erc20Map => 0x8, KeyPrefix::Erc20Nep141Map => 0x9, KeyPrefix::CrossContractCall => 0xa, + KeyPrefix::RelayerFunctionCallKey => 0xb, } } } @@ -94,6 +96,7 @@ impl From for KeyPrefix { 0x8 => Self::Nep141Erc20Map, 0x9 => Self::Erc20Nep141Map, 0xa => Self::CrossContractCall, + 0xb => Self::RelayerFunctionCallKey, _ => unreachable!("Unknown key prefix"), } } diff --git a/engine-workspace/src/account.rs b/engine-workspace/src/account.rs index 8cdaba6a3..c8b4112a5 100644 --- a/engine-workspace/src/account.rs +++ b/engine-workspace/src/account.rs @@ -3,6 +3,7 @@ use aurora_engine_types::account_id::AccountId; use std::str::FromStr; use crate::contract::RawContract; +use aurora_engine_types::public_key::PublicKey; pub use near_units::parse_near; #[derive(Debug, Clone)] @@ -48,4 +49,9 @@ impl Account { .map(|inner| Account { inner }) .map_err(Into::into) } + + pub fn public_key(&self) -> anyhow::Result { + let pk = self.inner.secret_key().public_key(); + PublicKey::from_str(&serde_json::to_string(&pk)?).map_err(|e| anyhow::anyhow!("{e:?}")) + } } diff --git a/engine-workspace/src/contract.rs b/engine-workspace/src/contract.rs index 3c0366d35..000ba8531 100644 --- a/engine-workspace/src/contract.rs +++ b/engine-workspace/src/contract.rs @@ -1,14 +1,15 @@ use crate::account::Account; use crate::node::Node; use crate::operation::{ - CallCall, CallDeployCode, CallDeployErc20Token, CallDeployUpgrade, CallDeposit, - CallFactorySetWNearAddress, CallFactoryUpdate, CallFactoryUpdateAddressVersion, + CallAddRelayerKey, CallCall, CallDeployCode, CallDeployErc20Token, CallDeployUpgrade, + CallDeposit, CallFactorySetWNearAddress, CallFactoryUpdate, CallFactoryUpdateAddressVersion, CallFtOnTransfer, CallFtTransfer, CallFtTransferCall, CallFundXccSubAccount, CallMintAccount, CallNew, CallNewEthConnector, CallPausePrecompiles, CallRefundOnError, CallRegisterRelayer, - CallResumePrecompiles, CallSetEthConnectorContractData, CallSetPausedFlags, CallStageUpgrade, - CallStateMigration, CallStorageDeposit, CallStorageUnregister, CallStorageWithdraw, CallSubmit, - CallWithdraw, ViewAccountsCounter, ViewBalance, ViewBlockHash, ViewBridgeProver, ViewChainId, - ViewCode, ViewErc20FromNep141, ViewFtBalanceOf, ViewFtBalanceOfEth, ViewFtMetadata, + CallRemoveRelayerKey, CallResumePrecompiles, CallSetEthConnectorContractData, + CallSetKeyManager, CallSetPausedFlags, CallStageUpgrade, CallStateMigration, + CallStorageDeposit, CallStorageUnregister, CallStorageWithdraw, CallSubmit, CallWithdraw, + ViewAccountsCounter, ViewBalance, ViewBlockHash, ViewBridgeProver, ViewChainId, ViewCode, + ViewErc20FromNep141, ViewFtBalanceOf, ViewFtBalanceOfEth, ViewFtMetadata, ViewFtTotalEthSupplyOnAurora, ViewFtTotalEthSupplyOnNear, ViewFtTotalSupply, ViewIsUsedProof, ViewNep141FromErc20, ViewNonce, ViewOwner, ViewPausedFlags, ViewPausedPrecompiles, ViewStorageAt, ViewStorageBalanceOf, ViewUpgradeIndex, ViewVersion, ViewView, @@ -17,13 +18,15 @@ use crate::transaction::{CallTransaction, ViewTransaction}; use aurora_engine_types::account_id::AccountId; use aurora_engine_types::parameters::connector::{FungibleTokenMetadata, Proof}; use aurora_engine_types::parameters::engine::{ - CallArgs, FunctionCallArgsV2, NewCallArgs, NewCallArgsV2, PausedMask, + CallArgs, FunctionCallArgsV2, NewCallArgs, NewCallArgsV2, PausedMask, RelayerKeyArgs, + RelayerKeyManagerArgs, }; use aurora_engine_types::parameters::xcc::FundXccArgs; use aurora_engine_types::types::{Address, RawU256, WeiU256}; use aurora_engine_types::{H256, U256}; use near_sdk::json_types::U128; use serde_json::json; +use workspaces::types::SecretKey; #[derive(Debug, Clone)] pub struct EngineContract { @@ -43,6 +46,16 @@ impl EngineContract { pub fn root(&self) -> Account { self.node.root() } + + pub fn create_account(&self, account_id: &AccountId, secret_key: SecretKey) -> Account { + let inner = workspaces::Account::from_secret_key( + account_id.as_ref().parse().unwrap(), + secret_key, + self.node.worker(), + ); + + Account::from_inner(inner) + } } impl From<(RawContract, Node)> for EngineContract { @@ -257,6 +270,18 @@ impl EngineContract { pub fn set_paused_flags(&self, flags: PausedMask) -> CallSetPausedFlags { CallSetPausedFlags::call(&self.contract).args_borsh(flags) } + + pub fn set_key_manager(&self, args: RelayerKeyManagerArgs) -> CallSetKeyManager { + CallSetKeyManager::call(&self.contract).args_json(args) + } + + pub fn add_relayer_key(&self, key: RelayerKeyArgs) -> CallAddRelayerKey { + CallAddRelayerKey::call(&self.contract).args_json(key) + } + + pub fn remove_relayer_key(&self, key: RelayerKeyArgs) -> CallRemoveRelayerKey { + CallRemoveRelayerKey::call(&self.contract).args_json(key) + } } /// View functions diff --git a/engine-workspace/src/lib.rs b/engine-workspace/src/lib.rs index c1a7303bb..bea07ef9f 100644 --- a/engine-workspace/src/lib.rs +++ b/engine-workspace/src/lib.rs @@ -18,6 +18,7 @@ pub mod transaction; pub mod types { pub use workspaces::result::ExecutionOutcome; + pub use workspaces::types::{KeyType, SecretKey}; } const AURORA_LOCAL_CHAIN_ID: u64 = 1313161556; diff --git a/engine-workspace/src/node.rs b/engine-workspace/src/node.rs index 194bb603c..486bf3705 100644 --- a/engine-workspace/src/node.rs +++ b/engine-workspace/src/node.rs @@ -26,6 +26,10 @@ impl Node { Account::from_inner(self.root.clone()) } + pub fn worker(&self) -> &Worker { + &self.worker + } + pub async fn get_balance(&self, account_id: &AccountId) -> anyhow::Result { let account_id = workspaces::AccountId::from_str(account_id.as_ref())?; diff --git a/engine-workspace/src/operation.rs b/engine-workspace/src/operation.rs index 69374dc93..0a084694f 100644 --- a/engine-workspace/src/operation.rs +++ b/engine-workspace/src/operation.rs @@ -36,6 +36,9 @@ impl_call_return![ (CallStateMigration, Call::StateMigration), (CallMintAccount, Call::MintAccount), (CallSetPausedFlags, Call::SetPausedFlags), + (CallSetKeyManager, Call::SetKeyManager), + (CallAddRelayerKey, Call::AddRelayerKey), + (CallRemoveRelayerKey, Call::RemoveRelayerKey), ]; impl_call_return![ @@ -109,6 +112,9 @@ pub(crate) enum Call { RefundOnError, MintAccount, SetPausedFlags, + SetKeyManager, + AddRelayerKey, + RemoveRelayerKey, } impl AsRef for Call { @@ -142,6 +148,9 @@ impl AsRef for Call { Call::RefundOnError => "refund_on_error", Call::MintAccount => "mint_account", Call::SetPausedFlags => "set_paused_flags", + Call::SetKeyManager => "set_key_manager", + Call::AddRelayerKey => "add_relayer_key", + Call::RemoveRelayerKey => "remove_relayer_key", } } } diff --git a/engine/src/engine.rs b/engine/src/engine.rs index b0b7b1fa4..b4132996c 100644 --- a/engine/src/engine.rs +++ b/engine/src/engine.rs @@ -1,6 +1,7 @@ use crate::parameters::{ CallArgs, NEP141FtOnTransferArgs, ResultLog, SubmitArgs, SubmitResult, ViewCallArgs, }; +use aurora_engine_types::public_key::PublicKey; use aurora_engine_types::PhantomData; use core::mem; use evm::backend::{Apply, ApplyBackend, Backend, Basic, Log}; @@ -112,6 +113,7 @@ pub enum EngineErrorKind { MaxPriorityGasFeeTooLarge, GasPayment(GasPaymentError), GasOverflow, + NonExistedKey, } impl EngineErrorKind { @@ -142,6 +144,7 @@ impl EngineErrorKind { Self::MaxPriorityGasFeeTooLarge => errors::ERR_MAX_PRIORITY_FEE_GREATER, Self::GasPayment(e) => e.as_ref(), Self::GasOverflow => errors::ERR_GAS_OVERFLOW, + Self::NonExistedKey => errors::ERR_FUNCTION_CALL_KEY_NOT_FOUND, Self::EvmFatal(_) | Self::EvmError(_) => unreachable!(), // unused misc } } @@ -1329,6 +1332,21 @@ pub fn get_generation(io: &I, address: &Address) -> u32 { }) } +/// Adds a public function call key for a relayer. +pub fn add_function_call_key(io: &mut I, key: &PublicKey) { + let prefixed_key = bytes_to_key(KeyPrefix::RelayerFunctionCallKey, key.key_data()); + io.write_storage(&prefixed_key, &[1]); +} + +/// Removes a public function call key for a relayer. +pub fn remove_function_call_key(io: &mut I, key: &PublicKey) -> Result<(), EngineError> { + let prefixed_key = bytes_to_key(KeyPrefix::RelayerFunctionCallKey, key.key_data()); + io.remove_storage(&prefixed_key) + .ok_or_else(|| EngineError::from(EngineErrorKind::NonExistedKey))?; + + Ok(()) +} + /// Removes all storage for the given address. fn remove_all_storage(io: &mut I, address: &Address, generation: u32) { // FIXME: there is presently no way to prefix delete trie state. @@ -1759,6 +1777,7 @@ mod tests { use aurora_engine_sdk::promise::Noop; use aurora_engine_test_doubles::io::{Storage, StoragePointer}; use aurora_engine_test_doubles::promise::PromiseTracker; + use aurora_engine_types::parameters::engine::RelayerKeyArgs; use aurora_engine_types::types::{make_address, Balance, NearGas, RawU256}; use std::cell::RefCell; @@ -2272,4 +2291,25 @@ mod tests { assert_eq!(expected_logs, actual_logs); } + + #[test] + fn test_add_remove_function_call_key() { + let storage = RefCell::new(Storage::default()); + let mut io = StoragePointer(&storage); + let public_key = serde_json::from_str::( + r#"{"public_key":"ed25519:DcA2MzgpJbrUATQLLceocVckhhAqrkingax4oJ9kZ847"}"#, + ) + .map(|args| args.public_key) + .unwrap(); + + let result = remove_function_call_key(&mut io, &public_key); + assert!(result.is_err()); // should fail because the key doesn't exist yet. + + add_function_call_key(&mut io, &public_key); + + let result = remove_function_call_key(&mut io, &public_key); + assert!(result.is_ok()); + let result = remove_function_call_key(&mut io, &public_key); + assert!(result.is_err()); // should fail because the key doesn't exist anymore. + } } diff --git a/engine/src/errors.rs b/engine/src/errors.rs index 0d2c48ea1..c2bc58e42 100644 --- a/engine/src/errors.rs +++ b/engine/src/errors.rs @@ -31,6 +31,7 @@ pub const ERR_ARGS: &str = "ERR_ARGS"; pub const ERR_VALUE_CONVERSION: &str = "ERR_VALUE_CONVERSION"; pub const ERR_BORSH_DESERIALIZE: &str = "ERR_BORSH_DESERIALIZE"; +pub const ERR_JSON_DESERIALIZE: &str = "ERR_JSON_DESERIALIZE"; pub const ERR_META_TX_PARSE: &str = "ERR_META_TX_PARSE"; pub const ERR_STACK_UNDERFLOW: &[u8; 19] = b"ERR_STACK_UNDERFLOW"; @@ -86,5 +87,7 @@ pub const ERR_ATTACHED_DEPOSIT_NOT_ENOUGH: &[u8; 31] = b"ERR_ATTACHED_DEPOSIT_NO pub const ERR_FAILED_UNREGISTER_ACCOUNT_POSITIVE_BALANCE: &[u8; 46] = b"ERR_FAILED_UNREGISTER_ACCOUNT_POSITIVE_BALANCE"; pub const ERR_SAME_OWNER: &[u8; 14] = b"ERR_SAME_OWNER"; - +pub const ERR_SAME_KEY_MANAGER: &[u8] = b"ERR_SAME_KEY_MANAGER"; +pub const ERR_FUNCTION_CALL_KEY_NOT_FOUND: &[u8] = b"ERR_FUNCTION_CALL_KEY_NOT_FOUND"; +pub const ERR_KEY_MANAGER_IS_NOT_SET: &[u8] = b"ERR_KEY_MANAGER_IS_NOT_SET"; pub const ERR_ACCOUNTS_COUNTER_OVERFLOW: &str = "ERR_ACCOUNTS_COUNTER_OVERFLOW"; diff --git a/engine/src/lib.rs b/engine/src/lib.rs index 9fdf655d5..bcd786599 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -100,14 +100,19 @@ mod contract { near_account_to_evm_address, SdkExpect, SdkProcess, SdkUnwrap, }; use crate::prelude::storage::{bytes_to_key, KeyPrefix}; - use crate::prelude::{sdk, u256_to_arr, Address, PromiseResult, Yocto, ERR_FAILED_PARSE, H256}; + use crate::prelude::{ + sdk, u256_to_arr, vec, Address, PromiseResult, ToString, Yocto, ERR_FAILED_PARSE, H256, + }; use crate::{errors, pausables, state}; use aurora_engine_sdk::env::Env; use aurora_engine_sdk::io::{StorageIntermediate, IO}; use aurora_engine_sdk::near_runtime::{Runtime, ViewEnv}; use aurora_engine_sdk::promise::PromiseHandler; + use aurora_engine_sdk::types::ExpectUtf8; use aurora_engine_types::borsh::{BorshDeserialize, BorshSerialize}; use aurora_engine_types::parameters::engine::errors::ParseTypeFromJsonError; + use aurora_engine_types::parameters::engine::{RelayerKeyArgs, RelayerKeyManagerArgs}; + use aurora_engine_types::parameters::{PromiseAction, PromiseBatchAction}; #[cfg(feature = "integration-test")] use crate::prelude::NearGas; @@ -598,6 +603,87 @@ mod contract { } } + /// Sets relayer key manager. + #[no_mangle] + pub extern "C" fn set_key_manager() { + let mut io = Runtime; + let mut state = state::get_state(&io).sdk_unwrap(); + + require_owner_only(&state, &io.predecessor_account_id()); + + let key_manager = + serde_json::from_slice::(&io.read_input().to_vec()) + .map(|args| args.key_manager) + .sdk_expect(errors::ERR_JSON_DESERIALIZE); + + if state.key_manager == key_manager { + sdk::panic_utf8(errors::ERR_SAME_KEY_MANAGER) + } else { + state.key_manager = key_manager; + state::set_state(&mut io, &state).sdk_unwrap(); + } + } + + /// Adds a relayer function call key. + #[no_mangle] + pub extern "C" fn add_relayer_key() { + let mut io = Runtime; + let state = state::get_state(&io).sdk_unwrap(); + require_key_manager_only(&state, &io.predecessor_account_id()); + + let public_key = serde_json::from_slice::(&io.read_input().to_vec()) + .map(|args| args.public_key) + .sdk_expect(errors::ERR_JSON_DESERIALIZE); + let allowance = Yocto::new(io.attached_deposit()); + sdk::log!("attached key allowance: {allowance}"); + + if allowance.as_u128() < 100 { + // TODO: Clarify the minimum amount if check is needed then change error type + sdk::panic_utf8(errors::ERR_NOT_ALLOWED); + } + + engine::add_function_call_key(&mut io, &public_key); + + let action = PromiseAction::AddFunctionCallKey { + public_key, + allowance, + nonce: 0, // not actually used - depends on block height + receiver_id: io.current_account_id(), + function_names: "call,submit,submit_with_args".to_string(), + }; + let promise = PromiseBatchAction { + target_account_id: io.current_account_id(), + actions: vec![action], + }; + + let promise_id = unsafe { io.promise_create_batch(&promise) }; + io.promise_return(promise_id); + } + + /// Removes a relayer function call key. + #[no_mangle] + pub extern "C" fn remove_relayer_key() { + let mut io = Runtime; + let state = state::get_state(&io).sdk_unwrap(); + require_key_manager_only(&state, &io.predecessor_account_id()); + + let args: RelayerKeyArgs = serde_json::from_slice(&io.read_input().to_vec()) + .sdk_expect(errors::ERR_JSON_DESERIALIZE); + + engine::remove_function_call_key(&mut io, &args.public_key).sdk_unwrap(); + + let action = PromiseAction::DeleteKey { + public_key: args.public_key, + }; + let promise = PromiseBatchAction { + target_account_id: io.current_account_id(), + actions: vec![action], + }; + + let promise_id = unsafe { io.promise_create_batch(&promise) }; + io.promise_return(promise_id); + } + /// /// NONMUTATIVE METHODS /// @@ -1161,6 +1247,16 @@ mod contract { } } + fn require_key_manager_only(state: &state::EngineState, predecessor_account_id: &AccountId) { + let key_manager = state + .key_manager + .as_ref() + .expect_utf8(errors::ERR_KEY_MANAGER_IS_NOT_SET); + if key_manager != predecessor_account_id { + sdk::panic_utf8(errors::ERR_NOT_ALLOWED); + } + } + fn predecessor_address(predecessor_account_id: &AccountId) -> Address { near_account_to_evm_address(predecessor_account_id.as_bytes()) } diff --git a/engine/src/state.rs b/engine/src/state.rs index 9dabbec13..d066f6d0a 100644 --- a/engine/src/state.rs +++ b/engine/src/state.rs @@ -2,6 +2,7 @@ use crate::parameters::{LegacyNewCallArgs, NewCallArgs, NewCallArgsV2}; use aurora_engine_sdk::io::{StorageIntermediate, IO}; use aurora_engine_types::account_id::AccountId; use aurora_engine_types::borsh::{self, BorshDeserialize, BorshSerialize}; +use aurora_engine_types::parameters::engine::NewCallArgsV3; use aurora_engine_types::storage::{bytes_to_key, KeyPrefix}; use aurora_engine_types::{Cow, Vec}; @@ -23,6 +24,8 @@ pub struct EngineState { pub upgrade_delay_blocks: u64, /// Flag to pause and unpause the engine. pub is_paused: bool, + /// Relayer key manager. + pub key_manager: Option, } impl EngineState { @@ -77,6 +80,7 @@ pub struct BorshableEngineStateV3<'a> { pub owner_id: Cow<'a, AccountId>, pub upgrade_delay_blocks: u64, pub is_paused: bool, + pub key_manager: Option>, } impl<'a> From<&'a EngineState> for BorshableEngineState<'a> { @@ -86,6 +90,7 @@ impl<'a> From<&'a EngineState> for BorshableEngineState<'a> { owner_id: Cow::Borrowed(&state.owner_id), upgrade_delay_blocks: state.upgrade_delay_blocks, is_paused: state.is_paused, + key_manager: state.key_manager.as_ref().map(Cow::Borrowed), }) } } @@ -107,6 +112,7 @@ impl<'a> From> for EngineState { owner_id: state.owner_id.into_owned(), upgrade_delay_blocks: state.upgrade_delay_blocks, is_paused: false, + key_manager: None, } } } @@ -118,6 +124,7 @@ impl<'a> From> for EngineState { owner_id: state.owner_id.into_owned(), upgrade_delay_blocks: state.upgrade_delay_blocks, is_paused: false, + key_manager: None, } } } @@ -129,6 +136,7 @@ impl<'a> From> for EngineState { owner_id: state.owner_id.into_owned(), upgrade_delay_blocks: state.upgrade_delay_blocks, is_paused: state.is_paused, + key_manager: state.key_manager.map(Cow::into_owned), } } } @@ -140,6 +148,7 @@ impl From for EngineState { owner_id: args.owner_id, upgrade_delay_blocks: args.upgrade_delay_blocks, is_paused: false, + key_manager: None, } } } @@ -151,6 +160,19 @@ impl From for EngineState { owner_id: args.owner_id, upgrade_delay_blocks: args.upgrade_delay_blocks, is_paused: false, + key_manager: None, + } + } +} + +impl From for EngineState { + fn from(args: NewCallArgsV3) -> Self { + Self { + chain_id: args.chain_id, + owner_id: args.owner_id, + upgrade_delay_blocks: args.upgrade_delay_blocks, + is_paused: false, + key_manager: Some(args.key_manager), } } } @@ -160,6 +182,7 @@ impl From for EngineState { match args { NewCallArgs::V1(args) => args.into(), NewCallArgs::V2(args) => args.into(), + NewCallArgs::V3(args) => args.into(), } } } diff --git a/etc/xcc-router/Cargo.lock b/etc/xcc-router/Cargo.lock index e64886355..c9d30e2b7 100644 --- a/etc/xcc-router/Cargo.lock +++ b/etc/xcc-router/Cargo.lock @@ -59,9 +59,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "arrayvec" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8868f09ff8cea88b079da74ae569d9b8c62a23c68c746240b704ee6f7525c89c" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "aurora-engine-types" @@ -70,6 +70,7 @@ dependencies = [ "base64 0.21.2", "borsh 0.10.3", "borsh 0.9.3", + "bs58 0.5.0", "hex", "primitive-types 0.12.1", "rlp", @@ -238,6 +239,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +[[package]] +name = "bs58" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +dependencies = [ + "sha2 0.10.7", + "tinyvec", +] + [[package]] name = "bumpalo" version = "3.13.0" @@ -335,9 +346,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.7" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -415,9 +426,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" +checksum = "304e6508efa593091e97a9abbc10f90aa7ca635b6d2784feff3c89d41dd12272" [[package]] name = "easy-ext" @@ -448,6 +459,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "fixed-hash" version = "0.7.0" @@ -516,12 +533,6 @@ dependencies = [ "ahash 0.7.6", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.13.2" @@ -531,6 +542,12 @@ 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 = "heck" version = "0.4.1" @@ -606,19 +623,19 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.3" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ - "autocfg", - "hashbrown 0.12.3", + "equivalent", + "hashbrown 0.14.0", ] [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" @@ -649,9 +666,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.146" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "log" @@ -702,7 +719,7 @@ dependencies = [ "arrayref", "blake2", "borsh 0.9.3", - "bs58", + "bs58 0.4.0", "c2-chacha", "curve25519-dalek", "derive_more", @@ -756,12 +773,12 @@ checksum = "91d508f0fc340f6461e4e256417685720d3c4c00bb5a939b105160e49137caba" dependencies = [ "base64 0.11.0", "borsh 0.9.3", - "bs58", + "bs58 0.4.0", "derive_more", "near-account-id", "num-rational", "serde", - "sha2 0.10.6", + "sha2 0.10.7", "strum", ] @@ -795,7 +812,7 @@ checksum = "15eb3de2defe3626260cc209a6cdb985c6b27b0bd4619fad97dcfae002c3c5bd" dependencies = [ "base64 0.13.1", "borsh 0.9.3", - "bs58", + "bs58 0.4.0", "near-abi", "near-crypto", "near-primitives", @@ -848,7 +865,7 @@ checksum = "81b534828419bacbf1f7b11ef7b00420f248c548c485d3f0cfda8bb6931152f2" dependencies = [ "base64 0.13.1", "borsh 0.9.3", - "bs58", + "bs58 0.4.0", "byteorder", "near-account-id", "near-crypto", @@ -857,7 +874,7 @@ dependencies = [ "near-vm-errors", "ripemd", "serde", - "sha2 0.10.6", + "sha2 0.10.7", "sha3", "zeropool-bn", ] @@ -923,7 +940,7 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" dependencies = [ - "arrayvec 0.7.3", + "arrayvec 0.7.4", "bitvec", "byte-slice-cast", "impl-trait-for-tuples", @@ -1005,18 +1022,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.28" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" dependencies = [ "proc-macro2", ] @@ -1143,15 +1160,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "schemars" @@ -1179,28 +1196,28 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "serde" -version = "1.0.164" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -1216,9 +1233,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" dependencies = [ "itoa", "ryu", @@ -1240,9 +1257,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if 1.0.0", "cpufeatures", @@ -1267,9 +1284,9 @@ checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "smart-default" @@ -1335,9 +1352,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" dependencies = [ "proc-macro2", "quote", @@ -1352,22 +1369,22 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -1381,6 +1398,21 @@ dependencies = [ "winapi", ] +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "toml" version = "0.5.11" @@ -1392,15 +1424,15 @@ dependencies = [ [[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" [[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", "toml_datetime", @@ -1427,9 +1459,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "version_check" @@ -1476,7 +1508,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", "wasm-bindgen-shared", ] @@ -1498,7 +1530,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1554,9 +1586,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -1611,9 +1643,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.6" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" +checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7" dependencies = [ "memchr", ] @@ -1649,7 +1681,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]]