diff --git a/.circleci/config.yml b/.circleci/config.yml index 773dc8fc5..089e808ba 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -193,7 +193,7 @@ jobs: ./bin/aleo-develop start --server-address 0.0.0.0:5050 --peer http://localhost:3030 -d -k ciphertext1qvqgkey2cxklg4g5qjnkk4dy50zypte5ewp5kwdm9pt833eyext32pu07dgkxqzmn0wnpxx8kvh2phws6j5njsu6zrys20xpvqmqhw9gpngs50mpe9e0nkp6uyzctzdq3fs2n4p9d3kvaps6mg6xu0sef0xpzm028m7 1> /dev/null & sleep 15 cd rust - cargo test test_transfer -- --ignored --nocapture --test-threads=1 + cargo test test_transfer_roundtrip -- --ignored --nocapture --test-threads=1 cargo test test_deploy -- --ignored --nocapture --test-threads=1 cargo test test_execution -- --ignored --nocapture --test-threads=1 cd ../sdk && yarn install diff --git a/.github/workflows/test-release.yml b/.github/workflows/test-release.yml index 4a44a3386..8d3df8d93 100644 --- a/.github/workflows/test-release.yml +++ b/.github/workflows/test-release.yml @@ -86,7 +86,6 @@ jobs: uses: actions-rs/cargo@v1 with: command: test - args: --all - name: Print sccache stats run: sccache --show-stats @@ -150,7 +149,7 @@ jobs: run: | SDKROOT=$(xcrun -sdk macosx11.1 --show-sdk-path) \ MACOSX_DEPLOYMENT_TARGET=$(xcrun -sdk macosx11.1 --show-sdk-platform-version) \ - cargo test --all + cargo test - name: Print sccache stats run: sccache --show-stats @@ -174,4 +173,4 @@ jobs: - name: Test run: | - cargo test --all + cargo test diff --git a/Cargo.lock b/Cargo.lock index 397ac889c..ec2ace0f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,11 +30,11 @@ dependencies = [ [[package]] name = "aleo" -version = "0.4.3" +version = "0.4.4" dependencies = [ "aleo-rust", "anyhow", - "clap 3.2.25", + "clap", "colored", "num-format", "parking_lot", @@ -42,7 +42,7 @@ dependencies = [ "rand_chacha", "rpassword", "rusty-hook", - "self_update 0.37.0", + "self_update", "serde", "serde_json", "snarkvm", @@ -54,11 +54,11 @@ dependencies = [ [[package]] name = "aleo-development-server" -version = "0.4.3" +version = "0.4.4" dependencies = [ "aleo-rust", "anyhow", - "clap 3.2.25", + "clap", "colored", "env_logger", "http", @@ -77,10 +77,11 @@ dependencies = [ [[package]] name = "aleo-rust" -version = "0.4.3" +version = "0.4.4" dependencies = [ "anyhow", "bencher", + "clap", "indexmap", "once_cell", "rand", @@ -156,7 +157,7 @@ checksum = "7e4f181fc1a372e8ceff89612e5c9b13f72bff5b066da9f8d6827ae65af492c4" [[package]] name = "aleo-wasm" -version = "0.4.3" +version = "0.4.4" dependencies = [ "aleo-rust", "anyhow", @@ -181,6 +182,12 @@ dependencies = [ "wasm-bindgen-test", ] +[[package]] +name = "allocator-api2" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4f263788a35611fba42eb41ff811c5d0360c58b97402570312a350736e2542e" + [[package]] name = "anstream" version = "0.3.2" @@ -383,63 +390,33 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" -dependencies = [ - "atty", - "bitflags", - "clap_derive 3.2.25", - "clap_lex 0.2.4", - "indexmap", - "once_cell", - "strsim", - "termcolor", - "textwrap", -] - -[[package]] -name = "clap" -version = "4.3.0" +version = "4.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc" +checksum = "2686c4115cb0810d9a984776e197823d08ec94f176549a89a9efded477c456dc" dependencies = [ "clap_builder", - "clap_derive 4.3.0", + "clap_derive", "once_cell", ] [[package]] name = "clap_builder" -version = "4.3.0" +version = "4.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f423e341edefb78c9caba2d9c7f7687d0e72e89df3ce3394554754393ac3990" +checksum = "2e53afce1efce6ed1f633cf0e57612fe51db54a1ee4fd8f8503d078fe02d69ae" dependencies = [ "anstream", "anstyle", "bitflags", - "clap_lex 0.5.0", + "clap_lex", "strsim", ] [[package]] name = "clap_derive" -version = "3.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote 1.0.28", - "syn 1.0.109", -] - -[[package]] -name = "clap_derive" -version = "4.3.0" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "191d9573962933b4027f932c600cd252ce27a8ad5979418fe78e43c07996f27b" +checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" dependencies = [ "heck", "proc-macro2", @@ -447,15 +424,6 @@ dependencies = [ "syn 2.0.18", ] -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - [[package]] name = "clap_lex" version = "0.5.0" @@ -997,11 +965,12 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" dependencies = [ "ahash", + "allocator-api2", ] [[package]] @@ -1544,12 +1513,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "os_str_bytes" -version = "6.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" - [[package]] name = "overload" version = "0.1.1" @@ -1650,30 +1613,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote 1.0.28", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote 1.0.28", - "version_check", -] - [[package]] name = "proc-macro2" version = "1.0.59" @@ -2037,24 +1976,6 @@ dependencies = [ "libc", ] -[[package]] -name = "self_update" -version = "0.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca4e4e6f29fddb78b3e7a6e5a395e8274d4aca2d36b2278a297fa49673a5b7c7" -dependencies = [ - "hyper", - "indicatif", - "log", - "quick-xml", - "regex", - "reqwest", - "semver", - "serde_json", - "tempfile", - "urlencoding", -] - [[package]] name = "self_update" version = "0.37.0" @@ -2194,13 +2115,13 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "snarkvm" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7b0ba80caad1b2e0c2b032b972addd37d516157a00b8e9237466871158222d" +checksum = "3c226da8de4d4171b8346a5dc834a1dbabae8c3ffbf4d4b335113743a7e23e72" dependencies = [ "anstyle", "anyhow", - "clap 4.3.0", + "clap", "colored", "indexmap", "num-format", @@ -2208,7 +2129,7 @@ dependencies = [ "parking_lot", "rand", "rayon", - "self_update 0.36.0", + "self_update", "serde_json", "snarkvm-circuit", "snarkvm-console", @@ -2223,15 +2144,18 @@ dependencies = [ [[package]] name = "snarkvm-algorithms" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226312c04582b326758e89d8141edfb651160444bfca12e54af027a9dafedeaf" +checksum = "d7f96bc086f932e76b516db79b665861ab87f294bd8a5c4156fc224dd5897f31" dependencies = [ "aleo-std", "anyhow", "blake2", - "hashbrown 0.13.2", + "cfg-if", + "fxhash", + "hashbrown 0.14.0", "hex", + "indexmap", "itertools", "parking_lot", "rand", @@ -2244,7 +2168,6 @@ dependencies = [ "snarkvm-curves", "snarkvm-fields", "snarkvm-parameters", - "snarkvm-r1cs", "snarkvm-utilities", "thiserror", "wasm-bindgen-futures", @@ -2252,9 +2175,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e831f22711b39f4c4bed0ba20171723850433b0a4cd0580abc72313f0dbdd56" +checksum = "4c41077b078ca9c8e8429f84fc97863445ba74ca5138801d5d984485ee5f56be" dependencies = [ "snarkvm-circuit-account", "snarkvm-circuit-algorithms", @@ -2267,9 +2190,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-account" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d79ab89dc212affac862cbd9e32bfc9da3f26d95206e71228cf128e2f404327" +checksum = "4207440f26559da0c791eeb4b86ad8a5f2a5fe9e1ff0355a17868c6be6d1e0ca" dependencies = [ "snarkvm-circuit-algorithms", "snarkvm-circuit-network", @@ -2279,9 +2202,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-algorithms" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cac80f418ee76eacc409796413fcf6ad077878ab4c07a72138b8534fa152d21" +checksum = "1b1b4116a5a9873caeda71b0af8cb201cf2571ad285f17d3c8caa65cadf48b0c" dependencies = [ "snarkvm-circuit-types", "snarkvm-console-algorithms", @@ -2290,9 +2213,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-collections" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "098928c33c0b79fdd1bcd09cdc9eaf67a1fd877391cde2e38260f749ab99a5dd" +checksum = "b1173c1bf6368f3ddb37e30879dd25027547d6fde2d6c9fb284c137d91c4c25b" dependencies = [ "snarkvm-circuit-algorithms", "snarkvm-circuit-types", @@ -2301,34 +2224,34 @@ dependencies = [ [[package]] name = "snarkvm-circuit-environment" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8ed5fb5e1c66245e3274384981b3327162d91dcfc29d55575efe9bad6370403" +checksum = "8bbeaff27abd87bde33bdf6e1ae213121631068e6daf67eac5b78264731a42df" dependencies = [ "indexmap", "itertools", "nom", "num-traits", "once_cell", + "snarkvm-algorithms", "snarkvm-circuit-environment-witness", "snarkvm-console-network", "snarkvm-curves", "snarkvm-fields", - "snarkvm-r1cs", "snarkvm-utilities", ] [[package]] name = "snarkvm-circuit-environment-witness" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "541892d4bb40b46d9056047f0dd7adc52886536888d87c06e634038cbe5808b3" +checksum = "7bab331f6aa5e0cdb6dfe3f3eedda540eb13526365148bb786bc0d9b0fd073d6" [[package]] name = "snarkvm-circuit-network" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567f245bf03577b85dc4074d48492dcf17968dd9b47edd4c49702f8db9574b0c" +checksum = "64a80c239200086dc026af70a2884426a7408bcbadf0dcb2236dfcb33803905a" dependencies = [ "snarkvm-circuit-algorithms", "snarkvm-circuit-collections", @@ -2338,9 +2261,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-program" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25a028646191330d6cdd7e8e15cba772618ed865653e7e69f0bb3f1eea0153d" +checksum = "ef738ab352e0065d795859c29ce536d7ce8edcb42e16a354986cd4a20170b095" dependencies = [ "snarkvm-circuit-account", "snarkvm-circuit-collections", @@ -2352,9 +2275,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65a518fdf4dffcb2cf956510f2b9a9e55b48b86ada68997f42f2826d70cdebd1" +checksum = "d40bc1ad34286c1f2d1b25cece291ce5ebeca92e144973e4dcab60b58e9aaf5f" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-address", @@ -2368,9 +2291,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-address" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030e0aed861311c15a3007251edb086c82533c1444706c274cc9ce2931cd9e42" +checksum = "2f0981cee35e34a9472305566d74a94095ff398c441795e62c5ac8e13e0c5653" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -2382,9 +2305,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-boolean" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20144cdf483d91debdb5c8a4a1dccf1c6519cddf77c8c7ce7988b0f86af257a3" +checksum = "7718bc963b0cc179fd56429822aa62ccab2a48c936e65e448beae3fd70897237" dependencies = [ "snarkvm-circuit-environment", "snarkvm-console-types-boolean", @@ -2392,9 +2315,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-field" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8b546c8014a9bc28ac546b98b25ba73c983f34d55812547b725a122e137b69c" +checksum = "2bb13447b15e958baaa2a44b4e70998d4b737888e87ab61139467c3ce60f8b06" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -2403,9 +2326,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-group" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e45e00b16802fe79c55837cf9943c13b26fa6f19d3b247dbe861851237016c86" +checksum = "213b3cad07517e020fd2d67b80d3d3f2326fd1790f1174031aa24acd39dcf181" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -2416,9 +2339,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-integers" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "619ac503d50dc96c3da728cbef2cfd9ccd74fb00d19c34df7fff92f3fb35b414" +checksum = "5d3355e1720d3a7492ed526f715ad1502e8f2c68680e7744856b7776e3ed642f" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -2428,9 +2351,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-scalar" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc8c186bcdb3e6ffc27d9a75c86ea60aafb707d0c4c5b47788652fdb8f7ae93e" +checksum = "39d7ea4a7d3bd078b1a81d36ed3a026d732ac884ec5c979e006420bff56cb61a" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -2440,9 +2363,9 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-string" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5015df3735eef5c4469fbe28b6276daf8ebff77ad392dcfb18222750e53264c" +checksum = "d8c2ba2ef12a05518181a3680fd5e05bb7d3086f7a5c595141d54c19e5105ecb" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -2453,9 +2376,9 @@ dependencies = [ [[package]] name = "snarkvm-console" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f88afad3f4cdc580c0a9d6f5978bc5a26a0887fd393bc22519dd1b81efb2b8f0" +checksum = "5eff0cb7897c79af354d2fad6af0177c151a81052fb4186fc4924ed67fe3cc50" dependencies = [ "snarkvm-console-account", "snarkvm-console-algorithms", @@ -2467,9 +2390,9 @@ dependencies = [ [[package]] name = "snarkvm-console-account" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f42c0b1d177d181e0c30fe4d5327f5ac956b248e64cee36d59bbb9932db0f0a" +checksum = "17c2978db5bd0254458ee9bb2838085e7f6c81ea84febb64ebe3c24765d65fae" dependencies = [ "bs58", "snarkvm-console-network", @@ -2478,9 +2401,9 @@ dependencies = [ [[package]] name = "snarkvm-console-algorithms" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f077a0d18100890d32a8f246e941d048790c834e3fc795d5bf630561c935b337" +checksum = "8bc3a1bc1be988081c20d54d3fb52a5e47ad5f450ef261de702cf39738c51eb3" dependencies = [ "blake2s_simd", "smallvec", @@ -2491,9 +2414,9 @@ dependencies = [ [[package]] name = "snarkvm-console-collections" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f6975444eaac49b75429843224a280ee98ddcf4f8d284e9bab3dba2d9e1c12" +checksum = "41e1b0a5bb09257fc53fa4b62fcdf161eac8c76892f35e5ce52a0832ef46c5b4" dependencies = [ "aleo-std", "rayon", @@ -2503,9 +2426,9 @@ dependencies = [ [[package]] name = "snarkvm-console-network" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0f3cefbd0c57f0242d57facc92790a257612d0f65b8fbf8f4e0651f891d4b61" +checksum = "26fe2ba3e7adb26e003e5d283557890c9c7f2d54897bce4921bca7f6ac4cd145" dependencies = [ "anyhow", "indexmap", @@ -2527,9 +2450,9 @@ dependencies = [ [[package]] name = "snarkvm-console-network-environment" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "557799a68846de0a82b653bcc89d88b7ba71b672bcb95dd0ee410ebf2b40f1aa" +checksum = "bdea0c85f9198ce65ce95e4e7c31c1aee311c8fab1fdb176af964a34020031af" dependencies = [ "anyhow", "bech32", @@ -2545,9 +2468,9 @@ dependencies = [ [[package]] name = "snarkvm-console-program" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a88053052eb8fb17c813a8336ed302118c84edaeff85b608466cc3ebd7a96e5" +checksum = "433488f61bac6799b0c43733af4e92950a4674890693f67d7790675388ab3dd6" dependencies = [ "enum_index", "enum_index_derive", @@ -2565,9 +2488,9 @@ dependencies = [ [[package]] name = "snarkvm-console-types" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdc60ca6e04a65cc0f043dae6b20619b942ba482a92cac3bbe560b37dc2a107" +checksum = "db4417f6468d6d030456a0e354ad566ef24e859d54ae6d1ddc576bd1aa144526" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-address", @@ -2581,9 +2504,9 @@ dependencies = [ [[package]] name = "snarkvm-console-types-address" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e20ec7e7a69caa5f22a0d7f46ff78afcab0520fa55f3e8022ac3e56b51c3c3f" +checksum = "c929a6574cc92c22b9011f90abdd392e9af8d9262fcb118ccf8b13a6e3f1fc6a" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -2593,18 +2516,18 @@ dependencies = [ [[package]] name = "snarkvm-console-types-boolean" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b13634772c21db8cbfcf56d5f609552385962b72deb5d44fb34eb19808b00b45" +checksum = "65587cc1fbaa5550db5206de8620c0ba206ab3a117ebd8695b693b4bf9632986" dependencies = [ "snarkvm-console-network-environment", ] [[package]] name = "snarkvm-console-types-field" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae2824780d20f3d4b3efb1a97d0b5e1b37fc94847d8601d58d7173572061c71" +checksum = "3da560561f667ebfb343ddd4b28e00563da8641c6ad05b40e13f51d41ce176b9" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -2612,9 +2535,9 @@ dependencies = [ [[package]] name = "snarkvm-console-types-group" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7956ec4f14d9809a01e62ed96d4c4145ae43a4f7bdf8beeba5546f1fba94998b" +checksum = "f66b0ef37640aa0a5e5245c0ae7a47286519879d66d89dd349918adb65ebebd4" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -2624,9 +2547,9 @@ dependencies = [ [[package]] name = "snarkvm-console-types-integers" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "886168e09977830b6dd4552048474300b3bfdee2205b318e5008d27510f64660" +checksum = "1ccbc90319a6464d013e1c86227e0cef6bda5b67fddfa0ead97acb2ec014e8dd" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -2635,9 +2558,9 @@ dependencies = [ [[package]] name = "snarkvm-console-types-scalar" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1dc427120fc022ff2c6ed0b80be433ac5b83b142f9453f56813de79d6d2a4c" +checksum = "f61064fd70f486729e9d5b363dacbd4a139f0ddaca9454c6f64ca875c589cfd5" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -2646,9 +2569,9 @@ dependencies = [ [[package]] name = "snarkvm-console-types-string" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bfb509961d697e73f04a47eb983a559dc4442c7b97c1e7ef7eae46a8d5b5a7d" +checksum = "2ef7a9e309aa3a11c440dbf8ec7d7e96687e8e593720eb037676b25a30f369c0" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -2658,9 +2581,9 @@ dependencies = [ [[package]] name = "snarkvm-curves" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94379573b131e9effa23e8fe1332c0f7819d8b12237b96deb21045645c62c041" +checksum = "38b9512e840ba777df944718d27718b9530814723d6a48b9ee2a63e5b35f8980" dependencies = [ "rand", "rayon", @@ -2673,9 +2596,9 @@ dependencies = [ [[package]] name = "snarkvm-fields" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989512fa6377ec201648149b9e50e7431cbc3111af5de37f953da3d5e8533d6a" +checksum = "6d3c9efcfeded661a49ff4820d981d00192cf41ffd4db2da01998bf39ba5f0da" dependencies = [ "aleo-std", "anyhow", @@ -2691,9 +2614,9 @@ dependencies = [ [[package]] name = "snarkvm-ledger" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69be86792a4ec20361cfb0c88acb3f7bab992f8651639b4181631a928f45a488" +checksum = "cc8a58902c62a2ddf991a9940b33dc7ef6db14bc4f136d02e88016f2fe97e208" dependencies = [ "aleo-std", "anyhow", @@ -2704,14 +2627,15 @@ dependencies = [ "rayon", "snarkvm-console", "snarkvm-synthesizer", + "time", "tracing", ] [[package]] name = "snarkvm-parameters" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad39618d36fcb20907bb91b3387d8f09235b3182861b8f846369d87cec95630d" +checksum = "7bc0f36f4716eedd88fa5bb0da7c411c91d42cbc8f506294871bb2901f0cca82" dependencies = [ "aleo-std", "anyhow", @@ -2735,28 +2659,11 @@ dependencies = [ "web-sys", ] -[[package]] -name = "snarkvm-r1cs" -version = "0.11.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd3081c148c33400bed8d2378326e6c853f10d33bb429a634761d66606da660b" -dependencies = [ - "anyhow", - "cfg-if", - "fxhash", - "indexmap", - "itertools", - "snarkvm-curves", - "snarkvm-fields", - "snarkvm-utilities", - "thiserror", -] - [[package]] name = "snarkvm-synthesizer" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cee200e5fea7ad508febf097a3d2e2b2bafc4b474b6c71d7d9a8bad0835c89a" +checksum = "f9467d0d4cd482b9b85b994a52a99d6cad18341cfa856a92fe3f341091adfc68" dependencies = [ "aleo-std", "anyhow", @@ -2769,6 +2676,7 @@ dependencies = [ "parking_lot", "paste", "rand", + "rand_chacha", "rayon", "reqwest", "serde", @@ -2787,9 +2695,9 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer-coinbase" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7a9750e2926ecea94837ccf3d78174abb4d24bcd2a12cd949fc6eb1591eb57d" +checksum = "1c68d532cc2f430c8f568b81da87a81c090b6a580d4db7cd2f61aaf776a9c5a3" dependencies = [ "anyhow", "bincode", @@ -2807,9 +2715,9 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer-snark" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0dab87ea835182a65b9a319ce5786d5d81bf610a5d9e8cbf9c2c3f0f0564d1e" +checksum = "1eea7ca8f482a5c98d03167a074326e445f575eb0db4f32e21dfce64efc4cd1b" dependencies = [ "bincode", "once_cell", @@ -2821,9 +2729,9 @@ dependencies = [ [[package]] name = "snarkvm-utilities" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e352ed0950615016fa99ca54257f035e796a7da655fe1bd619d8ab1972610af" +checksum = "58899b49fecb502348e02e6627cbb8384e99b2a79047488c271ccebc2c474082" dependencies = [ "aleo-std", "anyhow", @@ -2841,9 +2749,9 @@ dependencies = [ [[package]] name = "snarkvm-utilities-derives" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd6a720478ae39b5ac866c7ec93aa93d344a4497c95130d1be09d5b97b6d9df" +checksum = "3154b00fa475bbe1a579148656722bdb8e4dbec74aa281acb7f0382bff744cb2" dependencies = [ "proc-macro2", "quote 1.0.28", @@ -2852,9 +2760,9 @@ dependencies = [ [[package]] name = "snarkvm-wasm" -version = "0.11.7" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297059b8659a135d446717c5e52515ba2418c6c7d8fd7cede900cb8b3acb34d2" +checksum = "d5af03e853b02442f3a9507059987f00c3e965bf20e8c8fdc7cc0283eec6f680" dependencies = [ "getrandom", "rand", @@ -2982,12 +2890,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" - [[package]] name = "thiserror" version = "1.0.40" @@ -3522,9 +3424,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 179dfa6ba..18e028acd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aleo" -version = "0.4.3" +version = "0.4.4" authors = [ "The Aleo Team " ] description = "Aleo" homepage = "https://aleo.org" @@ -21,27 +21,27 @@ edition = "2021" members = [ "rust", "wasm", "rust/develop"] [workspace.dependencies.aleo-rust] -version = "0.4.3" +version = "0.4.4" path = "rust" default-features = false [workspace.dependencies.snarkvm] -version = "=0.11.7" +version = "=0.12.3" [workspace.dependencies.snarkvm-circuit-network] -version = "=0.11.7" +version = "=0.12.3" [workspace.dependencies.snarkvm-console] -version = "=0.11.7" +version = "=0.12.3" [workspace.dependencies.snarkvm-console-network] -version = "=0.11.7" +version = "=0.12.3" [workspace.dependencies.snarkvm-synthesizer] -version = "=0.11.7" +version = "=0.12.3" [workspace.dependencies.snarkvm-wasm] -version = "=0.11.7" +version = "=0.12.3" [lib] path = "cli/lib.rs" @@ -61,8 +61,8 @@ workspace = true version = "1.0" [workspace.dependencies.clap] -version = "3.2" -features = [ "derive" ] +version = "4.3.5" +features = [ "derive", "string" ] [dependencies.clap] workspace = true diff --git a/cli/commands/deploy.rs b/cli/commands/deploy.rs index 3f03812ac..6b219212b 100644 --- a/cli/commands/deploy.rs +++ b/cli/commands/deploy.rs @@ -26,7 +26,6 @@ use colored::Colorize; #[derive(Debug, Parser)] pub struct Deploy { /// The program identifier - #[clap(parse(try_from_str))] program_id: ProgramID, /// Directory containing the program files #[clap(short, long)] @@ -44,10 +43,10 @@ pub struct Deploy { #[clap(short='k', long, conflicts_with_all = &["ciphertext", "password"])] private_key: Option>, /// Private key ciphertext used to generate the deployment (requires password to decrypt) - #[clap(short, long, conflicts_with = "private-key", requires = "password")] + #[clap(short, long, conflicts_with = "private_key", requires = "password")] ciphertext: Option>, /// Password to decrypt the private key - #[clap(short, long, conflicts_with = "private-key", requires = "ciphertext")] + #[clap(short, long, conflicts_with = "private_key", requires = "ciphertext")] password: Option, } @@ -166,7 +165,7 @@ mod tests { "password", ]); - assert_eq!(deploy_conflicting_inputs.unwrap_err().kind(), clap::ErrorKind::ArgumentConflict); + assert_eq!(deploy_conflicting_inputs.unwrap_err().kind(), clap::error::ErrorKind::ArgumentConflict); // Assert deploy fails if a ciphertext is provided without a password let ciphertext = Some(Encryptor::encrypt_private_key_with_secret(&recipient_private_key, "password").unwrap()); @@ -179,13 +178,13 @@ mod tests { &ciphertext.as_ref().unwrap().to_string(), ]); - assert_eq!(deploy_no_password.unwrap_err().kind(), clap::ErrorKind::MissingRequiredArgument); + assert_eq!(deploy_no_password.unwrap_err().kind(), clap::error::ErrorKind::MissingRequiredArgument); // Assert deploy fails if only a password is provided let deploy_password_only = Deploy::try_parse_from(["aleo", "hello.aleo", "-f", "0.5", "--password", "password"]); - assert_eq!(deploy_password_only.unwrap_err().kind(), clap::ErrorKind::MissingRequiredArgument); + assert_eq!(deploy_password_only.unwrap_err().kind(), clap::error::ErrorKind::MissingRequiredArgument); // Assert deploy fails if invalid peer is specified let deploy_bad_peer = Deploy::try_parse_from([ diff --git a/cli/commands/execute.rs b/cli/commands/execute.rs index 2c75be61f..c6a9a4333 100644 --- a/cli/commands/execute.rs +++ b/cli/commands/execute.rs @@ -26,13 +26,10 @@ use colored::Colorize; #[derive(Debug, Parser)] pub struct Execute { /// The program identifier - #[clap(parse(try_from_str))] program_id: ProgramID, /// The function name - #[clap(parse(try_from_str))] function: Identifier, /// The function inputs - #[clap(parse(try_from_str))] inputs: Vec>, /// Aleo Network peer to broadcast the transaction to #[clap(short, long)] @@ -47,10 +44,10 @@ pub struct Execute { #[clap(short='k', long, conflicts_with_all = &["ciphertext", "password"])] private_key: Option>, /// Private key ciphertext used to generate the execution (requires password to decrypt) - #[clap(short, long, conflicts_with = "private-key", requires = "password")] + #[clap(short, long, conflicts_with = "private_key", requires = "password")] ciphertext: Option>, /// Password to decrypt the private key - #[clap(short, long, conflicts_with = "private-key", requires = "ciphertext")] + #[clap(short, long, conflicts_with = "private_key", requires = "ciphertext")] password: Option, } @@ -181,7 +178,7 @@ mod tests { "password", ]); - assert_eq!(execute_conflicting_inputs.unwrap_err().kind(), clap::ErrorKind::ArgumentConflict); + assert_eq!(execute_conflicting_inputs.unwrap_err().kind(), clap::error::ErrorKind::ArgumentConflict); // Assert execute fails if a ciphertext is provided without a password let ciphertext = Some(Encryptor::encrypt_private_key_with_secret(&recipient_private_key, "password").unwrap()); @@ -197,13 +194,13 @@ mod tests { &ciphertext.as_ref().unwrap().to_string(), ]); - assert_eq!(execute_no_password.unwrap_err().kind(), clap::ErrorKind::MissingRequiredArgument); + assert_eq!(execute_no_password.unwrap_err().kind(), clap::error::ErrorKind::MissingRequiredArgument); // Assert execute fails if only a password is provided let execute_password_only = Execute::try_parse_from(["aleo", "hello.aleo", "hello", "1337u32", "42u32", "--password", "password"]); - assert_eq!(execute_password_only.unwrap_err().kind(), clap::ErrorKind::MissingRequiredArgument); + assert_eq!(execute_password_only.unwrap_err().kind(), clap::error::ErrorKind::MissingRequiredArgument); // Assert execute fails if invalid peer is specified let execute_bad_peer = Execute::try_parse_from([ diff --git a/cli/commands/mod.rs b/cli/commands/mod.rs index a0d0aaaaf..5f7b11aa4 100644 --- a/cli/commands/mod.rs +++ b/cli/commands/mod.rs @@ -48,7 +48,7 @@ use anyhow::Result; use clap::Parser; #[derive(Debug, Parser)] -#[clap(name = "aleo", author = "The Aleo Team ", setting = clap::AppSettings::ColoredHelp)] +#[clap(name = "aleo", author = "The Aleo Team ")] pub struct CLI { /// Specify the verbosity [options: 0, 1, 2, 3] #[clap(default_value = "2", short, long)] @@ -72,8 +72,6 @@ pub enum Command { Execute(Execute), #[clap(name = "new")] New(New), - // #[clap(subcommand)] - // Node(Node), #[clap(name = "run")] Run(Run), #[clap(name = "transfer")] diff --git a/cli/commands/run.rs b/cli/commands/run.rs index f8d4d4311..300c1f1c1 100644 --- a/cli/commands/run.rs +++ b/cli/commands/run.rs @@ -32,10 +32,8 @@ pub const LOCALE: &num_format::Locale = &num_format::Locale::en; #[derive(Debug, Parser)] pub struct Run { /// The function name. - #[clap(parse(try_from_str))] function: Identifier, /// The function inputs. - #[clap(parse(try_from_str))] inputs: Vec>, /// Uses the specified endpoint. #[clap(long)] @@ -59,7 +57,7 @@ impl Run { let rng = &mut rand::thread_rng(); // Execute the request. - let (response, _transition, _inclusion, metrics) = package.run::( + let (response, trace) = package.run::( self.endpoint, package.manifest_file().development_private_key(), self.function, @@ -69,7 +67,7 @@ impl Run { // Count the number of times a function is called. let mut program_frequency = HashMap::::new(); - for metric in metrics.iter() { + for metric in trace.call_metrics().iter() { // Prepare the function name string. let function_name_string = format!("'{}/{}'", metric.program_id, metric.function_name).bold(); diff --git a/cli/commands/transfer.rs b/cli/commands/transfer.rs index fe48eaac6..3f3cf6e31 100644 --- a/cli/commands/transfer.rs +++ b/cli/commands/transfer.rs @@ -14,9 +14,20 @@ // You should have received a copy of the GNU General Public License // along with the Aleo SDK library. If not, see . -use crate::CurrentNetwork; -use aleo_rust::{AleoAPIClient, Encryptor, ProgramManager, RecordFinder}; -use snarkvm::prelude::{Address, Ciphertext, Plaintext, PrivateKey, Record}; +use crate::{helpers::TransferTypeArg, CurrentNetwork}; +use aleo_rust::{ + Address, + AleoAPIClient, + Ciphertext, + Credits, + Encryptor, + Plaintext, + PrivateKey, + ProgramManager, + Record, + RecordFinder, + TransferType, +}; use anyhow::{anyhow, ensure, Result}; use clap::Parser; @@ -28,29 +39,32 @@ pub struct Transfer { /// Recipient address #[clap(short, long)] recipient: Address, - /// Record used to fund the transfer - #[clap(short, long)] - input_record: Option>>, - /// Record to spend the fee from - #[clap(long)] - fee_record: Option>>, + /// Transfer type + #[clap(short, long, value_enum, default_value_t=TransferTypeArg::Private)] + transfer_type: TransferTypeArg, /// Number of credits to transfer #[clap(short, long)] amount: f64, - /// Aleo Network peer to broadcast the transaction to - #[clap(short, long)] - endpoint: Option, /// Transaction fee in credits #[clap(short, long)] fee: f64, /// Private key used to generate the transfer #[clap(short='k', long, conflicts_with_all = &["ciphertext", "password"])] private_key: Option>, + /// Record used to fund the transfer + #[clap(long)] + amount_record: Option>>, + /// Record to spend the fee from + #[clap(long)] + fee_record: Option>>, + /// Aleo Network peer to broadcast the transaction to + #[clap(short, long)] + endpoint: Option, /// Private key ciphertext used to generate the transfer (requires password to decrypt) - #[clap(short, long, conflicts_with = "private-key", requires = "password")] + #[clap(short, long, conflicts_with = "private_key", requires = "password")] ciphertext: Option>, /// Password to decrypt the private key - #[clap(short = 'p', long, conflicts_with = "private-key", requires = "ciphertext")] + #[clap(short = 'p', long, conflicts_with = "private_key", requires = "ciphertext")] password: Option, } @@ -60,6 +74,8 @@ impl Transfer { ensure!(self.amount > 0f64, "Transfer amount must be greater than 0 credits"); ensure!(self.fee > 0f64, "fee must be greater than zero to make a transfer"); + let transfer_type = TransferType::from(self.transfer_type); + ensure!( !(self.private_key.is_none() && self.ciphertext.is_none()), "Private key or private key ciphertext required" @@ -108,23 +124,65 @@ impl Transfer { }; let record_finder = RecordFinder::new(api_client); - let (input_record, fee_record) = if self.input_record.is_none() { - println!("Finding records to make the requested transfer... (this may take a few minutes)"); - if self.fee_record.is_none() { - // An amount and fee were provided without records, so find records for both - let (input_record, fee_record) = - record_finder.find_amount_and_fee_records(amount_microcredits, fee_microcredits, &private_key)?; - (input_record, fee_record) - } else { - // Either the fee is none or the fee record is already provided, so just find the input record - (record_finder.find_one_record(&private_key, amount_microcredits)?, self.fee_record.unwrap()) + let (amount_record, fee_record) = if self.fee_record.is_none() { + match transfer_type { + TransferType::Public => { + // The transfer is drawing from a public account balance, so only a fee record is needed + (None, record_finder.find_one_record(&private_key, fee_microcredits)?) + } + TransferType::PublicToPrivate => { + // The transfer is drawing from a public account balance, so only a fee record is needed + (None, record_finder.find_one_record(&private_key, fee_microcredits)?) + } + _ => { + // The transfer is drawing being funded by a record, so an input record and fee record are both needed + if self.amount_record.is_none() { + let (amount_record, fee_record) = record_finder.find_amount_and_fee_records( + amount_microcredits, + fee_microcredits, + &private_key, + )?; + (Some(amount_record), fee_record) + } else { + let amount_record = self.amount_record.unwrap(); + ensure!( + amount_record.microcredits()? > amount_microcredits, + "Amount record must have more microcredits than the transfer amount specified" + ); + (Some(amount_record), record_finder.find_one_record(&private_key, fee_microcredits)?) + } + } } - } else if self.fee_record.is_none() { - // Either the amount is none or the input record is already provided, so just find the fee record - (self.input_record.unwrap(), record_finder.find_one_record(&private_key, fee_microcredits)?) } else { - // Both the amount and fee are already provided, so just use them - (self.input_record.unwrap(), self.fee_record.unwrap()) + let fee_record = self.fee_record.unwrap(); + // Check the specified record has enough credits + ensure!( + fee_record.microcredits()? > fee_microcredits, + "Fee record must have more microcredits than the fee" + ); + match transfer_type { + TransferType::Public => { + // The transfer is drawing from a public account balance, so only a fee record is needed + (None, fee_record) + } + TransferType::PublicToPrivate => { + // The transfer is drawing from a public account balance, so only a fee record is needed + (None, fee_record) + } + _ => { + // The transfer is drawing being funded by a record, so an input record and fee record are both needed + if self.amount_record.is_none() { + (Some(record_finder.find_one_record(&private_key, amount_microcredits)?), fee_record) + } else { + let amount_record = self.amount_record.unwrap(); + ensure!( + amount_record.microcredits()? > amount_microcredits, + "Amount record must have more microcredits than the transfer amount specified" + ); + (Some(amount_record), fee_record) + } + } + } }; // Execute the transfer @@ -132,8 +190,9 @@ impl Transfer { amount_microcredits, fee_microcredits, self.recipient, + transfer_type, self.password.as_deref(), - input_record, + amount_record, fee_record, ); @@ -182,7 +241,7 @@ mod tests { "password", ]); - assert_eq!(transfer_conflicting_inputs.unwrap_err().kind(), clap::ErrorKind::ArgumentConflict); + assert_eq!(transfer_conflicting_inputs.unwrap_err().kind(), clap::error::ErrorKind::ArgumentConflict); // Assert that the transfer fails if a ciphertext is provided without a password let ciphertext = Some(Encryptor::encrypt_private_key_with_secret(&recipient_private_key, "password").unwrap()); @@ -198,7 +257,7 @@ mod tests { &ciphertext.as_ref().unwrap().to_string(), ]); - assert_eq!(transfer_no_password.unwrap_err().kind(), clap::ErrorKind::MissingRequiredArgument); + assert_eq!(transfer_no_password.unwrap_err().kind(), clap::error::ErrorKind::MissingRequiredArgument); // Assert transfer fails if only a password is provided let transfer_password_only = Transfer::try_parse_from([ @@ -213,7 +272,7 @@ mod tests { "password", ]); - assert_eq!(transfer_password_only.unwrap_err().kind(), clap::ErrorKind::MissingRequiredArgument); + assert_eq!(transfer_password_only.unwrap_err().kind(), clap::error::ErrorKind::MissingRequiredArgument); // Assert transfer fails if invalid peer is specified let transfer_bad_peer = Transfer::try_parse_from([ diff --git a/cli/helpers/ledger.rs b/cli/helpers/ledger.rs deleted file mode 100644 index 10dfcbb4e..000000000 --- a/cli/helpers/ledger.rs +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (C) 2019-2023 Aleo Systems Inc. -// This file is part of the Aleo SDK library. - -// The Aleo SDK library is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The Aleo SDK library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with the Aleo SDK library. If not, see . - -use snarkvm::prelude::{ - Address, - Block, - BlockMemory, - Identifier, - Network, - PrivateKey, - Program, - ProgramID, - ProgramMemory, - ProgramStore, - RecordsFilter, - Transaction, - Value, - ViewKey, - Zero, - VM, -}; - -use anyhow::{bail, ensure, Result}; -use core::str::FromStr; -use parking_lot::RwLock; -use std::{convert::TryFrom, sync::Arc}; -use warp::{reply, Filter, Rejection}; - -pub(crate) type InternalStorage = ProgramMemory; -pub(crate) type InternalLedger = snarkvm::prelude::Ledger, InternalStorage>; -pub(crate) type InternalServer = snarkvm::prelude::Server, InternalStorage>; - -#[allow(dead_code)] -pub struct Ledger { - /// The internal ledger. - pub ledger: Arc>>, - /// The runtime. - runtime: tokio::runtime::Runtime, - /// The server. - server: InternalServer, - /// The account private key. - private_key: PrivateKey, - /// The account view key. - view_key: ViewKey, - /// The account address. - address: Address, -} - -impl Ledger { - /// Initializes a new instance of the ledger. - pub fn load(private_key: &PrivateKey) -> Result> { - // Derive the view key and address. - let view_key = ViewKey::try_from(private_key)?; - let address = Address::try_from(&view_key)?; - - // Initialize an RNG. - let rng = &mut ::rand::thread_rng(); - // Initialize the store. - let store = ProgramStore::<_, InternalStorage<_>>::open(None)?; - // Create a genesis block. - let genesis = Block::genesis(&VM::new(store)?, private_key, rng)?; - - // Initialize the ledger. - let ledger = Arc::new(RwLock::new(InternalLedger::new_with_genesis(&genesis, address, None)?)); - - // Initialize the additional routes. - let additional_routes = { - // GET /testnet3/development/privateKey - let get_development_private_key = warp::get() - .and(warp::path!("testnet3" / "development" / "privateKey")) - .and(snarkvm::rest::with(*private_key)) - .and_then(|private_key: PrivateKey| async move { - Ok::<_, Rejection>(reply::json(&private_key.to_string())) - }); - - // GET /testnet3/development/viewKey - let get_development_view_key = warp::get() - .and(warp::path!("testnet3" / "development" / "viewKey")) - .and(snarkvm::rest::with(view_key)) - .and_then(|view_key: ViewKey| async move { Ok::<_, Rejection>(reply::json(&view_key.to_string())) }); - - // GET /testnet3/development/address - let get_development_address = warp::get() - .and(warp::path!("testnet3" / "development" / "address")) - .and(snarkvm::rest::with(address)) - .and_then(|address: Address| async move { Ok::<_, Rejection>(reply::json(&address.to_string())) }); - - get_development_private_key.or(get_development_view_key).or(get_development_address) - }; - - // Initialize a runtime. - let runtime = - tokio::runtime::Builder::new_multi_thread().enable_all().thread_stack_size(8 * 1024 * 1024).build()?; - - // Initialize the server. - let ledger_clone = ledger.clone(); - let server = runtime.block_on(async move { - // Start the server. - InternalServer::::start(ledger_clone, Some(additional_routes), Some(4180)) - })?; - - // Return the ledger. - Ok(Arc::new(Self { ledger, runtime, server, private_key: *private_key, view_key, address })) - } - - /// Returns the account address. - pub const fn address(&self) -> &Address { - &self.address - } -} - -impl Ledger { - /// Adds the given transaction to the memory pool. - pub fn add_to_memory_pool(&self, transaction: Transaction) -> Result<()> { - self.ledger.write().add_to_memory_pool(transaction) - } - - /// Advances the ledger to the next block. - pub fn advance_to_next_block(&self) -> Result> { - // Initialize an RNG. - let rng = &mut ::rand::thread_rng(); - // Propose the next block. - let next_block = self.ledger.read().propose_next_block(&self.private_key, rng)?; - // Add the next block to the ledger. - if let Err(error) = self.ledger.write().add_next_block(&next_block) { - // Log the error. - eprintln!("{error}"); - } - // Return the next block. - Ok(next_block) - } - - /// Creates a deploy transaction. - pub fn create_deploy(&self, program: &Program, additional_fee: u64) -> Result> { - // Fetch the unspent record with the most gates. - let record = self - .ledger - .read() - .find_records(&self.view_key, RecordsFilter::Unspent)? - .max_by(|(_, a), (_, b)| (**a.gates()).cmp(&**b.gates())); - - // Prepare the additional fee. - let credits = match record { - Some((_, record)) => record, - None => bail!("The Aleo account has no records to spend."), - }; - ensure!(***credits.gates() >= additional_fee, "The additional fee exceeds the record balance."); - - // Deploy. - let transaction = Transaction::deploy( - self.ledger.read().vm(), - &self.private_key, - program, - (credits, additional_fee), - &mut rand::thread_rng(), - )?; - // Verify. - assert!(self.ledger.read().vm().verify(&transaction)); - // Return the transaction. - Ok(transaction) - } - - /// Creates a transfer transaction. - pub fn create_transfer(&self, to: &Address, amount: u64) -> Result> { - // Fetch the unspent record with the least gates. - let record = self - .ledger - .read() - .find_records(&self.view_key, RecordsFilter::Unspent)? - .filter(|(_, record)| !record.gates().is_zero()) - .min_by(|(_, a), (_, b)| (**a.gates()).cmp(&**b.gates())); - - // Prepare the record. - let record = match record { - Some((_, record)) => record, - None => bail!("The Aleo account has no records to spend."), - }; - - // Create a new transaction. - Transaction::execute( - self.ledger.read().vm(), - &self.private_key, - &ProgramID::from_str("credits.aleo")?, - Identifier::from_str("transfer")?, - &[Value::Record(record), Value::from_str(&format!("{to}"))?, Value::from_str(&format!("{amount}u64"))?], - None, - &mut rand::thread_rng(), - ) - } -} diff --git a/cli/helpers/serialize.rs b/cli/helpers/serialize.rs index 1cf79194b..6c3cef0fd 100644 --- a/cli/helpers/serialize.rs +++ b/cli/helpers/serialize.rs @@ -20,6 +20,7 @@ use snarkvm::{ prelude::{Address, PrivateKey, ViewKey}, }; +use aleo_rust::TransferType; use serde::{Deserialize, Serialize}; /// Serialization model for writing Aleo key material to disk @@ -34,3 +35,27 @@ pub struct AccountModel { #[serde(skip_serializing_if = "Option::is_none")] pub address: Option>, } + +/// Transfer Type to Perform +#[derive(Debug, Clone, PartialEq, Eq, clap::ValueEnum)] +pub enum TransferTypeArg { + /// Private credit transfer done via records associated with the account + Private, + /// Transfer credits from a record to the public account mapping for an Aleo account + PrivateToPublic, + /// Public credit transfer done via the account mapping + Public, + /// Transfer credits from the public account mapping to a record for an Aleo account + PublicToPrivate, +} + +impl From for TransferType { + fn from(arg: TransferTypeArg) -> Self { + match arg { + TransferTypeArg::Public => TransferType::Public, + TransferTypeArg::Private => TransferType::Private, + TransferTypeArg::PublicToPrivate => TransferType::PublicToPrivate, + TransferTypeArg::PrivateToPublic => TransferType::PrivateToPublic, + } + } +} diff --git a/rust/Cargo.toml b/rust/Cargo.toml index d5a5fc6eb..971a7c758 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aleo-rust" -version = "0.4.3" +version = "0.4.4" authors = [ "The Aleo Team " ] description = "Rust SDK for managing Aleo programs and communicating with the Aleo network" homepage = "https://aleo.org" @@ -31,6 +31,9 @@ harness = false [dependencies.anyhow] version = "1" +[dependencies.clap] +workspace = true + [dependencies.indexmap] version = "1.9.3" diff --git a/rust/develop/Cargo.toml b/rust/develop/Cargo.toml index cf463a912..26cc24f8c 100644 --- a/rust/develop/Cargo.toml +++ b/rust/develop/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aleo-development-server" -version = "0.4.3" +version = "0.4.4" authors = [ "The Aleo Team " ] description = "A REST API server for local or remote Aleo development" homepage = "https://aleo.org" diff --git a/rust/develop/src/lib.rs b/rust/develop/src/lib.rs index 3befa2098..14c3b092b 100644 --- a/rust/develop/src/lib.rs +++ b/rust/develop/src/lib.rs @@ -149,7 +149,7 @@ use requests::*; mod routes; pub use routes::*; -use aleo_rust::{AleoAPIClient, Encryptor, ProgramManager, RecordFinder}; +use aleo_rust::{AleoAPIClient, Encryptor, ProgramManager, RecordFinder, TransferType}; use snarkvm::{ console::{ account::{Address, PrivateKey}, @@ -160,7 +160,7 @@ use snarkvm::{ }; use tracing_subscriber::fmt; -use anyhow::Result; +use anyhow::{anyhow, Result}; use colored::*; use serde::{Deserialize, Serialize}; use std::net::SocketAddr; diff --git a/rust/develop/src/requests.rs b/rust/develop/src/requests.rs index 54f392de9..5778d9378 100644 --- a/rust/develop/src/requests.rs +++ b/rust/develop/src/requests.rs @@ -49,6 +49,7 @@ pub(crate) struct TransferRequest { pub amount: u64, pub fee: u64, pub recipient: Address, + pub transfer_type: String, pub private_key: Option>, pub password: Option, pub fee_record: Option>>, diff --git a/rust/develop/src/routes.rs b/rust/develop/src/routes.rs index 524c9c9c5..152ebf639 100644 --- a/rust/develop/src/routes.rs +++ b/rust/develop/src/routes.rs @@ -175,25 +175,62 @@ impl Rest { let private_key = Self::get_private_key(private_key_ciphertext, request.private_key, request.password.clone())?; let program_manager = ProgramManager::new(Some(private_key), None, Some(api_client), None).or_reject()?; - let (amount_record, fee_record) = match (request.amount_record, request.fee_record) { - (Some(amount_record), Some(fee_record)) => (amount_record, fee_record), - (Some(amount_record), None) => { - // Find a fee record if a fee is specified and a fee record is not provided - (amount_record, spawn_blocking!(record_finder.find_one_record(&private_key, request.fee))?) - } - (None, Some(fee_record)) => { - (spawn_blocking!(record_finder.find_one_record(&private_key, request.amount))?, fee_record) - } - (None, None) => { - spawn_blocking!(record_finder.find_amount_and_fee_records(request.amount, request.fee, &private_key))? - } + let specified_transfer_type = request.transfer_type.as_str(); + info!("Transfer type specified: {specified_transfer_type}"); + let transfer_type = match specified_transfer_type { + "private" => { TransferType::Private }, + "public" => { TransferType::Public }, + "private_to_public" => { TransferType::PrivateToPublic }, + "public_to_private" => { TransferType::PublicToPrivate }, + _ => Err(anyhow!("Invalid transfer type specified, type must be one of the following: private, public, private-to-public, public-to-private")).or_reject()?, }; + let (amount_record, fee_record) = + match transfer_type { + TransferType::Public => { + if let Some(fee_record) = request.fee_record { + (None, fee_record) + } else { + (None, spawn_blocking!(record_finder.find_one_record(&private_key, request.fee))?) + } + } + TransferType::PublicToPrivate => { + if let Some(fee_record) = request.fee_record { + (None, fee_record) + } else { + (None, spawn_blocking!(record_finder.find_one_record(&private_key, request.fee))?) + } + } + _ => { + match (request.amount_record, request.fee_record) { + (Some(amount_record), Some(fee_record)) => (Some(amount_record), fee_record), + (Some(amount_record), None) => { + // Find a fee record if a fee is specified and a fee record is not provided + ( + Some(amount_record), + spawn_blocking!(record_finder.find_one_record(&private_key, request.fee))?, + ) + } + (None, Some(fee_record)) => ( + Some(spawn_blocking!(record_finder.find_one_record(&private_key, request.amount))?), + fee_record, + ), + (None, None) => { + let (amount_record, fee_record) = spawn_blocking!( + record_finder.find_amount_and_fee_records(request.amount, request.fee, &private_key) + )?; + (Some(amount_record), fee_record) + } + } + } + }; + // Run the transfer program within credits.aleo and return the resulting transaction id let transaction_id = spawn_blocking!(program_manager.transfer( request.amount, request.fee, request.recipient, + transfer_type, None, amount_record, fee_record diff --git a/rust/src/lib.rs b/rust/src/lib.rs index bd75390e0..aecaf179e 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -81,7 +81,8 @@ //! ```no_run //! use aleo_rust::{ //! AleoAPIClient, Encryptor, ProgramManager, RecordFinder, -//! snarkvm_types::{Address, PrivateKey, Testnet3, Program} +//! snarkvm_types::{Address, PrivateKey, Testnet3, Program}, +//! TransferType //! }; //! use rand::thread_rng; //! use std::str::FromStr; @@ -157,7 +158,7 @@ //! // Find records to fund the transfer //! let (amount_record, fee_record) = record_finder.find_amount_and_fee_records(amount, fee, &private_key).unwrap(); //! // Create a transfer -//! program_manager.transfer(amount, fee, recipient_address, Some("password"), amount_record, fee_record).unwrap(); +//! program_manager.transfer(amount, fee, recipient_address, TransferType::Private, Some("password"), Some(amount_record), fee_record).unwrap(); //! //! ``` //! This API is currently under active development and is expected to change in the future in order @@ -178,7 +179,7 @@ pub use api::AleoAPIClient; pub mod program; #[cfg(feature = "full")] #[doc(inline)] -pub use program::{OnChainProgramState, ProgramManager, RecordFinder}; +pub use program::{OnChainProgramState, ProgramManager, RecordFinder, TransferType}; #[cfg(test)] #[cfg(feature = "full")] diff --git a/rust/src/program/deploy.rs b/rust/src/program/deploy.rs index 9b99902ae..66b432492 100644 --- a/rust/src/program/deploy.rs +++ b/rust/src/program/deploy.rs @@ -187,10 +187,11 @@ mod tests { #[ignore] fn test_deploy() { let recipient_private_key = PrivateKey::::from_str(RECIPIENT_PRIVATE_KEY).unwrap(); + let finalize_program = Program::::from_str(FINALIZE_TEST_PROGRAM).unwrap(); // Wait for the node to bootup thread::sleep(std::time::Duration::from_secs(5)); - transfer_to_test_account(2000000001, 8, recipient_private_key, "3030").unwrap(); + transfer_to_test_account(2000000001, 14, recipient_private_key, "3030").unwrap(); let api_client = AleoAPIClient::::local_testnet3("3030"); let record_finder = RecordFinder::::new(api_client.clone()); let temp_dir = setup_directory("aleo_test_deploy", CREDITS_IMPORT_TEST_PROGRAM, vec![]).unwrap(); @@ -202,7 +203,7 @@ mod tests { // Wait for the transactions to show up on chain thread::sleep(std::time::Duration::from_secs(30)); - let deployment_fee = 200000001; + let deployment_fee = 200_000_001; let fee_record = record_finder.find_one_record(&recipient_private_key, deployment_fee).unwrap(); program_manager.deploy_program("credits_import_test.aleo", deployment_fee, fee_record, None).unwrap(); @@ -218,6 +219,25 @@ mod tests { println!("Program has not yet appeared on chain, waiting another 15 seconds"); thread::sleep(std::time::Duration::from_secs(15)); } + + // Deploy a program with a finalize scope + program_manager.add_program(&finalize_program).unwrap(); + + let fee_record = record_finder.find_one_record(&recipient_private_key, deployment_fee).unwrap(); + program_manager.deploy_program("finalize_test.aleo", deployment_fee, fee_record, None).unwrap(); + + // Wait for the program to show up on chain + thread::sleep(std::time::Duration::from_secs(45)); + for _ in 0..4 { + let deployed_program = program_manager.api_client().unwrap().get_program("finalize_test.aleo"); + + if deployed_program.is_ok() { + assert_eq!(deployed_program.unwrap(), Program::from_str(FINALIZE_TEST_PROGRAM).unwrap()); + break; + } + println!("Program has not yet appeared on chain, waiting another 15 seconds"); + thread::sleep(std::time::Duration::from_secs(15)); + } } #[test] diff --git a/rust/src/program/execute.rs b/rust/src/program/execute.rs index 519fea7b0..d67947069 100644 --- a/rust/src/program/execute.rs +++ b/rust/src/program/execute.rs @@ -130,14 +130,18 @@ mod tests { let mut program_manager = ProgramManager::::new(Some(private_key), None, Some(api_client.clone()), None).unwrap(); + let fee = 2_500_000; + let finalize_fee = 8_000_000; + + // Test execution of an on chain program is successful for i in 0..5 { - let fee_record = record_finder.find_one_record(&private_key, 500_000).unwrap(); + let fee_record = record_finder.find_one_record(&private_key, fee).unwrap(); // Test execution of a on chain program is successful let execution = program_manager.execute_program( "credits_import_test.aleo", "test", ["1312u32", "62131112u32"].into_iter(), - 500_000, + fee, fee_record, None, ); @@ -155,13 +159,32 @@ mod tests { ProgramManager::::new(None, Some(encrypted_private_key), Some(api_client), None).unwrap(); for i in 0..5 { - let fee_record = record_finder.find_one_record(&private_key, 500_000).unwrap(); + let fee_record = record_finder.find_one_record(&private_key, fee).unwrap(); // Test execution of an on chain program is successful using an encrypted private key let execution = program_manager.execute_program( "credits_import_test.aleo", "test", ["1337u32", "42u32"].into_iter(), - 500000, + fee, + fee_record, + Some("password"), + ); + if execution.is_ok() { + break; + } else if i == 4 { + panic!("{}", format!("Execution failed after 5 attempts with error: {:?}", execution)); + } + } + + // Test execution with a finalize scope can be done + for i in 0..5 { + let fee_record = record_finder.find_one_record(&private_key, finalize_fee).unwrap(); + // Test execution of an on chain program is successful using an encrypted private key + let execution = program_manager.execute_program( + "finalize_test.aleo", + "increase_counter", + ["0u32", "42u32"].into_iter(), + finalize_fee, fee_record, Some("password"), ); diff --git a/rust/src/program/helpers/mod.rs b/rust/src/program/helpers/mod.rs index 98064ab1b..d06c382a5 100644 --- a/rust/src/program/helpers/mod.rs +++ b/rust/src/program/helpers/mod.rs @@ -21,3 +21,16 @@ pub use state::*; pub mod records; pub use records::*; + +/// Transfer Type to Perform +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum TransferType { + /// Private credit transfer done via records associated with the account + Private, + /// Transfer credits from a record to the public account mapping for an Aleo account + PrivateToPublic, + /// Public credit transfer done via the account mapping + Public, + /// Transfer credits from the public account mapping to a record for an Aleo account + PublicToPrivate, +} diff --git a/rust/src/program/transfer.rs b/rust/src/program/transfer.rs index cee509f3f..f8cbdba0a 100644 --- a/rust/src/program/transfer.rs +++ b/rust/src/program/transfer.rs @@ -19,20 +19,24 @@ use super::*; impl ProgramManager { /// Executes a transfer to the specified recipient_address with the specified amount and fee. /// Specify 0 for no fee. + #[allow(clippy::too_many_arguments)] pub fn transfer( &self, amount: u64, fee: u64, recipient_address: Address, + transfer_type: TransferType, password: Option<&str>, - amount_record: Record>, + amount_record: Option>>, fee_record: Record>, ) -> Result { // Ensure records provided have enough credits to cover the transfer amount and fee - ensure!( - amount_record.microcredits()? >= amount, - "Credits in amount record must greater than transfer amount specified" - ); + if let Some(amount_record) = amount_record.as_ref() { + ensure!( + amount_record.microcredits()? >= amount, + "Credits in amount record must greater than transfer amount specified" + ); + } ensure!(fee_record.microcredits()? >= fee, "Fee must be greater than 0"); // Specify the network state query @@ -50,16 +54,51 @@ impl ProgramManager { let vm = VM::from(store)?; // Prepare the inputs for a transfer. - let inputs = vec![ - Value::Record(amount_record), - Value::from_str(&recipient_address.to_string())?, - Value::from_str(&format!("{}u64", amount))?, - ]; + let (transfer_function, inputs) = match transfer_type { + TransferType::Public => { + let inputs = vec![ + Value::from_str(&recipient_address.to_string())?, + Value::from_str(&format!("{}u64", amount))?, + ]; + ("transfer_public", inputs) + } + TransferType::Private => { + if amount_record.is_none() { + bail!("Amount record must be specified for private transfers"); + } else { + let inputs = vec![ + Value::Record(amount_record.unwrap()), + Value::from_str(&recipient_address.to_string())?, + Value::from_str(&format!("{}u64", amount))?, + ]; + ("transfer_private", inputs) + } + } + TransferType::PublicToPrivate => { + let inputs = vec![ + Value::from_str(&recipient_address.to_string())?, + Value::from_str(&format!("{}u64", amount))?, + ]; + ("transfer_public_to_private", inputs) + } + TransferType::PrivateToPublic => { + if amount_record.is_none() { + bail!("Amount record must be specified for private transfers"); + } else { + let inputs = vec![ + Value::Record(amount_record.unwrap()), + Value::from_str(&recipient_address.to_string())?, + Value::from_str(&format!("{}u64", amount))?, + ]; + ("transfer_private_to_public", inputs) + } + } + }; // Create a new transaction. vm.execute( &private_key, - ("credits.aleo", "transfer"), + ("credits.aleo", transfer_function), inputs.iter(), Some((fee_record, fee)), Some(query), @@ -79,53 +118,170 @@ mod tests { use std::{str::FromStr, thread}; - #[test] - #[ignore] - fn test_transfer() { + // Attempt to transfer the specified amount from the sender to the recipient. + fn try_transfer( + sender: &PrivateKey, + recipient: &Address, + amount: u64, + visibility: TransferType, + ) { + println!("Attempting to transfer of type: {visibility:?} of {amount} to {recipient:?}"); let api_client = AleoAPIClient::::local_testnet3("3030"); - let beacon_private_key = PrivateKey::::from_str(BEACON_PRIVATE_KEY).unwrap(); - let rng = &mut rand::thread_rng(); - let recipient_private_key = PrivateKey::::new(rng).unwrap(); - let recipient_view_key = ViewKey::try_from(&recipient_private_key).unwrap(); - let recipient_address = Address::try_from(&recipient_view_key).unwrap(); let program_manager = - ProgramManager::::new(Some(beacon_private_key), None, Some(api_client.clone()), None).unwrap(); + ProgramManager::::new(Some(*sender), None, Some(api_client.clone()), None).unwrap(); let record_finder = RecordFinder::new(api_client); - // Wait for the chain to to start - //thread::sleep(std::time::Duration::from_secs(60)); - - // Make several transactions from the genesis account since the genesis account keeps spending records, - // it may take a few tries to transfer successfully + let fee = 5_000_000; for i in 0..10 { - let records = record_finder.find_amount_and_fee_records(100, 500_000, &beacon_private_key); - if records.is_err() { - println!("Record not found: {} - retrying", records.unwrap_err()); - thread::sleep(std::time::Duration::from_secs(3)); - continue; - } + let (amount_record, fee_record) = match &visibility { + TransferType::Public => { + let fee_record = record_finder.find_one_record(sender, fee); + if fee_record.is_err() { + println!("Record not found: {} - retrying", fee_record.unwrap_err()); + thread::sleep(std::time::Duration::from_secs(3)); + if i == 9 { + panic!("Transfer failed after 10 attempts"); + } + continue; + } + (None, fee_record.unwrap()) + } + TransferType::PublicToPrivate => { + let fee_record = record_finder.find_one_record(sender, fee); + if fee_record.is_err() { + println!("Record not found: {} - retrying", fee_record.unwrap_err()); + thread::sleep(std::time::Duration::from_secs(3)); + if i == 9 { + panic!("Transfer failed after 10 attempts"); + } + continue; + } + (None, fee_record.unwrap()) + } + _ => { + let record = record_finder.find_amount_and_fee_records(amount, fee, sender); + if record.is_err() { + println!("Record not found: {} - retrying", record.unwrap_err()); + thread::sleep(std::time::Duration::from_secs(3)); + continue; + } + let (amount_record, fee_record) = record.unwrap(); + (Some(amount_record), fee_record) + } + }; - let (input_record, fee_record) = records.unwrap(); - let result = program_manager.transfer(100, 500000, recipient_address, None, input_record, fee_record); + let result = program_manager.transfer(amount, fee, *recipient, visibility, None, amount_record, fee_record); if result.is_err() { println!("Transfer error: {} - retrying", result.unwrap_err()); - } else if i > 8 { - panic!("Failed to transfer after 8 transfer errors"); + if i == 9 { + panic!("Transfer failed after 10 attempts"); + } + } else { + break; } + } + } - // Wait for the chain to update blocks - thread::sleep(std::time::Duration::from_secs(15)); - - // Check the balance of the recipient - let api_client = program_manager.api_client().unwrap(); + // Check that the specified amount has been transferred from the sender to the recipient. + fn verify_transfer( + amount: u64, + api_client: &AleoAPIClient, + recipient_private_key: &PrivateKey, + visibility: TransferType, + ) { + for i in 0..10 { + println!("Attempting to verify transfer of visibility: {visibility:?} for amount: {amount}"); let height = api_client.latest_height().unwrap(); - let records = api_client.get_unspent_records(&recipient_private_key, 0..height, None, None).unwrap(); + let records = api_client.get_unspent_records(recipient_private_key, 0..height, None, None).unwrap(); + let mut is_verified = false; if !records.is_empty() { - let (_, record) = &records[0]; - let amount = record.microcredits().unwrap(); - if amount == 100 { + for record in records.iter() { + let (_, record) = record; + let record_amount = record.microcredits().unwrap(); + println!("Found amount: {record_amount} - expected: {amount}"); + if amount == record_amount { + println!("✅ Transfer of {amount} verified for transfer type: {visibility:?}"); + is_verified = true; + break; + } + } + if is_verified { break; } } + thread::sleep(std::time::Duration::from_secs(3)); + if i > 8 { + let error = + format!("❌ Failed to verify transfer of visibility: {visibility:?} after 8 transfer errors"); + panic!("{error}"); + } } } + + #[test] + #[ignore] + fn test_transfer_roundtrip() { + // Initialize necessary key material + // Use the beacon private key to make the initial transfer + let beacon_private_key = PrivateKey::::from_str(BEACON_PRIVATE_KEY).unwrap(); + let rng = &mut rand::thread_rng(); + // Create a unique recipient for each transfer type so we can unique identify each transfer + let private_recipient_private_key = PrivateKey::::new(rng).unwrap(); + let private_recipient_view_key = ViewKey::try_from(&private_recipient_private_key).unwrap(); + let private_recipient_address = Address::try_from(&private_recipient_view_key).unwrap(); + let private_to_public_recipient_private_key = PrivateKey::::new(rng).unwrap(); + let private_to_public_recipient_view_key = ViewKey::try_from(&private_to_public_recipient_private_key).unwrap(); + let private_to_public_recipient_address = Address::try_from(&private_to_public_recipient_view_key).unwrap(); + let public_recipient_private_key = PrivateKey::::new(rng).unwrap(); + let public_recipient_view_key = ViewKey::try_from(&public_recipient_private_key).unwrap(); + let public_recipient_address = Address::try_from(&public_recipient_view_key).unwrap(); + let public_to_private_recipient_private_key = PrivateKey::::new(rng).unwrap(); + let public_to_private_recipient_view_key = ViewKey::try_from(&public_to_private_recipient_private_key).unwrap(); + let public_to_private_recipient_address = Address::try_from(&public_to_private_recipient_view_key).unwrap(); + let api_client = AleoAPIClient::::local_testnet3("3030"); + + println!("Private recipient address: {}", private_recipient_address); + println!("Private to public recipient address: {}", private_to_public_recipient_address); + println!("Public recipient address: {}", public_recipient_address); + println!("Public to private recipient address: {}", public_to_private_recipient_address); + + let amount = 16_666_666; + let fee = 6_666_666; + // Transfer funds to the private recipient and confirm that the transaction is on chain + try_transfer(&beacon_private_key, &private_recipient_address, amount, TransferType::Private); + + // Transfer funds to each of the other recipients to pay the fee with + try_transfer(&beacon_private_key, &private_recipient_address, fee, TransferType::Private); + try_transfer(&beacon_private_key, &private_to_public_recipient_address, fee, TransferType::Private); + try_transfer(&beacon_private_key, &public_recipient_address, fee, TransferType::Private); + try_transfer(&beacon_private_key, &public_to_private_recipient_address, fee, TransferType::Private); + thread::sleep(std::time::Duration::from_secs(20)); + + // Verify private transfer + verify_transfer(amount, &api_client, &private_recipient_private_key, TransferType::Private); + + // Transfer funds to the private_to_public recipient + try_transfer( + &private_recipient_private_key, + &private_to_public_recipient_address, + amount, + TransferType::PrivateToPublic, + ); + thread::sleep(std::time::Duration::from_secs(20)); + // TODO: when a snarkOS api is available for finalize, verify the transfer is on chain + + try_transfer(&private_to_public_recipient_private_key, &public_recipient_address, amount, TransferType::Public); + thread::sleep(std::time::Duration::from_secs(20)); + // TODO: when a snarkOS api is available for finalize, verify the transfer is on chain + + // Transfer funds to the public_to_private recipient and ensure the funds made the entire journey + try_transfer( + &public_recipient_private_key, + &public_to_private_recipient_address, + amount, + TransferType::PublicToPrivate, + ); + thread::sleep(std::time::Duration::from_secs(20)); + + verify_transfer(amount, &api_client, &public_to_private_recipient_private_key, TransferType::PublicToPrivate); + } } diff --git a/rust/src/test_utils/mod.rs b/rust/src/test_utils/mod.rs index 947258633..b59ddf8c9 100644 --- a/rust/src/test_utils/mod.rs +++ b/rust/src/test_utils/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Aleo SDK library. If not, see . -use crate::{AleoAPIClient, ProgramManager, RecordFinder}; +use crate::{AleoAPIClient, ProgramManager, RecordFinder, TransferType}; use snarkvm::file::Manifest; use snarkvm_console::{ account::{PrivateKey, ViewKey}, @@ -41,6 +41,34 @@ function test: output r2 as u32.private; "; +pub const FINALIZE_TEST_PROGRAM: &str = "program finalize_test.aleo; + +mapping monotonic_counter: + // Counter key + key id as u32.public; + // Counter value + value counter as u32.public; + +function increase_counter: + // Counter index + input r0 as u32.public; + // Value to increment by + input r1 as u32.public; + finalize r0 r1; + +finalize increase_counter: + // Counter index + input r0 as u32.public; + // Value to increment by + input r1 as u32.public; + // Get or initialize counter key + get.or_use monotonic_counter[r0] 0u32 into r2; + // Add r1 to into the existing counter value + add r1 r2 into r3; + // Set r3 into account[r0]; + set r3 into monotonic_counter[r0]; +"; + pub const CREDITS_IMPORT_TEST_PROGRAM: &str = "import credits.aleo; program credits_import_test.aleo; @@ -179,7 +207,15 @@ pub fn transfer_to_test_account( continue; } let (input_record, fee_record) = input_record.unwrap(); - let result = program_manager.transfer(amount, 500_000, recipient_address, None, input_record, fee_record); + let result = program_manager.transfer( + amount, + 500_000, + recipient_address, + TransferType::Private, + None, + Some(input_record), + fee_record, + ); if result.is_ok() { println!("Transfer succeeded"); transfer_successes += 1; @@ -192,7 +228,7 @@ pub fn transfer_to_test_account( break; } if retries > 15 { - println!("exceeded 10 retries, exiting with found records"); + println!("exceeded 15 retries, exiting with found records"); break; } sleep(std::time::Duration::from_secs(3)); diff --git a/sdk/package.json b/sdk/package.json index c1fcf5563..81eeb96a8 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@aleohq/sdk", - "version": "0.4.3", + "version": "0.4.4", "description": "A Software Development Kit (SDK) for Zero-Knowledge Transactions", "collaborators": [ "The Aleo Team " @@ -35,7 +35,7 @@ }, "homepage": "https://github.com/AleoHQ/sdk#readme", "dependencies": { - "@aleohq/wasm": "0.4.2", + "@aleohq/aleo-nodejs": "0.4.4", "axios": "^1.1.3", "jsdoc": "^3.6.11", "unfetch": "^5.0.0" diff --git a/sdk/src/account.ts b/sdk/src/account.ts index f486a01fe..737192ed1 100644 --- a/sdk/src/account.ts +++ b/sdk/src/account.ts @@ -5,7 +5,7 @@ import { ViewKey, PrivateKeyCiphertext, RecordCiphertext, -} from "@aleohq/wasm"; +} from "@aleohq/aleo-nodejs"; interface AccountParam { privateKey?: string; diff --git a/sdk/src/aleo_network_client.ts b/sdk/src/aleo_network_client.ts index a4d2946bb..e855dda7d 100644 --- a/sdk/src/aleo_network_client.ts +++ b/sdk/src/aleo_network_client.ts @@ -1,6 +1,6 @@ import axios from "axios"; import { Account, Block, Transaction, Transition } from "."; -import { RecordCiphertext, RecordPlaintext, PrivateKey } from "@aleohq/wasm"; +import { RecordCiphertext, RecordPlaintext, PrivateKey } from "@aleohq/aleo-nodejs"; /** * Connection management class that encapsulates REST calls to publicly exposed endpoints of Aleo nodes. diff --git a/sdk/src/development_client.ts b/sdk/src/development_client.ts index f5a7c890a..8d134dcd9 100644 --- a/sdk/src/development_client.ts +++ b/sdk/src/development_client.ts @@ -22,6 +22,7 @@ interface TransferRequest { amount: number; fee: number; recipient: string; + transfer_type: string; private_key?: string; password?: string; fee_record?: string; @@ -160,6 +161,7 @@ export class DevelopmentClient { * @param {string} amount The amount of credits to be sent (e.g. 1.5) * @param {number} fee Optional Fee to be paid for the transfer, specify 0 for no fee * @param {string} recipient The recipient of the transfer + * @param {string} transfer_type The type of the transfer (possible values are "private", "public", "private_to_public", "public_to_private") * @param {string | undefined} privateKey Optional private key of the user who is sending the transfer * @param {string | undefined} password If the development server is started with an encrypted private key, the password is required * @param {string | undefined} feeRecord Optional record in text format to be used for the fee. If not provided, the server will search the network for a suitable record to pay the fee. @@ -176,6 +178,7 @@ export class DevelopmentClient { amount: number, fee: number, recipient: string, + transfer_type: string, privateKey?: string, password?: string, feeRecord?: string, @@ -184,6 +187,7 @@ export class DevelopmentClient { const request: TransferRequest = { amount: amount*1000000, fee: fee*1000000, + transfer_type, recipient, private_key: privateKey, password, diff --git a/sdk/src/index.ts b/sdk/src/index.ts index 41e35b63d..bb22d2c35 100644 --- a/sdk/src/index.ts +++ b/sdk/src/index.ts @@ -8,6 +8,6 @@ import { Transaction } from "./models/transaction"; import { Transition } from "./models/transition"; import { DevelopmentClient } from "./development_client"; -import { Address, PrivateKey, Signature, ViewKey } from "@aleohq/wasm"; +import { Address, PrivateKey, Signature, ViewKey } from "@aleohq/aleo-nodejs"; export { Account, Address, AleoNetworkClient, Block, DevelopmentClient, Execution, Input, PrivateKey, Output, Signature, Transaction, Transition, ViewKey }; diff --git a/sdk/tests/account.test.ts b/sdk/tests/account.test.ts index 0a31ae5f2..5f2b85240 100644 --- a/sdk/tests/account.test.ts +++ b/sdk/tests/account.test.ts @@ -1,5 +1,5 @@ import { Account } from '../src' -import { PrivateKey, ViewKey, Address, RecordCiphertext } from '@aleohq/wasm'; +import { PrivateKey, ViewKey, Address, RecordCiphertext } from '@aleohq/aleo-nodejs'; import { seed, message, beaconPrivateKeyString, beaconViewKeyString, beaconAddressString, recordCiphertextString, foreignCiphertextString, recordPlaintextString } from './data/account-data'; diff --git a/sdk/tests/development.integration.ts b/sdk/tests/development.integration.ts index e21b17987..e2e9e3f0a 100644 --- a/sdk/tests/development.integration.ts +++ b/sdk/tests/development.integration.ts @@ -29,9 +29,11 @@ describe('DevelopmentServer', () => { for (let i = 0; i < 4; i++) { try { log("Attempting to make a value transfer"); - transaction_id = await devClient.transfer(1000, 1, fundedAddressString, fundedPrivateKeyString); + transaction_id = await devClient.transfer(1000, 1, fundedAddressString, "private", fundedPrivateKeyString); break; } catch (e) { + log("Transaction failed, retrying in 5 seconds"); + await wait(5000); } } diff --git a/sdk/tests/node.test.ts b/sdk/tests/node.test.ts index 3703885d7..5f4c4230c 100644 --- a/sdk/tests/node.test.ts +++ b/sdk/tests/node.test.ts @@ -20,7 +20,7 @@ describe('NodeConnection', () => { describe('getBlock', () => { it('should return a Block object', async () => { const block = await connection.getBlock(1); - expect((block as Block).block_hash).toEqual("ab1lpku7j04u0zgejhvf53j3f22zn8n3xu50tdtr3v0m64wydsxkgrsvahf3p"); + expect((block as Block).block_hash).toEqual("ab1tz33xvmcwm4q9fc7kplxn43mzdf7nr4232jtp77a6hrq4dhu6cpsuuhvc6"); }, 60000); it('should throw an error if the request fails', async () => { @@ -33,8 +33,8 @@ describe('NodeConnection', () => { const blockRange = await connection.getBlockRange(1, 3); expect(Array.isArray(blockRange)).toBe(true); expect((blockRange as Block[]).length).toBe(2); - expect(((blockRange as Block[])[0] as Block).block_hash).toBe("ab1lpku7j04u0zgejhvf53j3f22zn8n3xu50tdtr3v0m64wydsxkgrsvahf3p"); - expect(((blockRange as Block[])[1] as Block).block_hash).toBe("ab1ffk2v4jpdslg3m8mylsrdp0f8pxpjeqmd6h396mlpyrts3kuzqysjw57ve"); + expect(((blockRange as Block[])[0] as Block).block_hash).toBe("ab1tz33xvmcwm4q9fc7kplxn43mzdf7nr4232jtp77a6hrq4dhu6cpsuuhvc6"); + expect(((blockRange as Block[])[1] as Block).block_hash).toBe("ab174s4uw9ufs5f05cqznqqy0x42n5vv6jf6fslsh4v6e4xyf7zwugqansd40"); }, 60000); @@ -45,7 +45,7 @@ describe('NodeConnection', () => { describe('getProgram', () => { it('should return a string', async () => { - const program = await connection.getProgram('hello.aleo'); + const program = await connection.getProgram('credits.aleo'); expect(typeof program).toBe('string'); }, 60000); @@ -86,7 +86,7 @@ describe('NodeConnection', () => { describe('getTransaction', () => { it('should return a Transaction object', async () => { - const transaction = await connection.getTransaction('at1arcqcfz2k5xr5xvdsf8kchusagfh2wfcp9dt4ertmvasftmv9urqeskqmv'); + const transaction = await connection.getTransaction('at1nfpzfn57p59l8fz8p962y042n3xd7tks7wpphalle3ywzagqwufq0w98eq'); expect((transaction as Transaction).type).toBe("execute"); }, 60000); @@ -109,7 +109,7 @@ describe('NodeConnection', () => { describe('getTransitionId', () => { it('should return a transition id', async () => { - const transition = await connection.getTransitionId('5100410941838577086896407843889050454902473880580872189574699659938979554393field') + const transition = await connection.getTransitionId('215289562929251901873489364071437708748482144332199791410604867535220208424field') expect(typeof transition).toBe('string'); }, 60000); diff --git a/sdk/tests/wasm.test.ts b/sdk/tests/wasm.test.ts index 0a707bda7..2b9f66828 100644 --- a/sdk/tests/wasm.test.ts +++ b/sdk/tests/wasm.test.ts @@ -1,4 +1,4 @@ -import { Address, PrivateKey, ViewKey, Signature, RecordCiphertext, RecordPlaintext, PrivateKeyCiphertext } from "@aleohq/wasm"; +import { Address, PrivateKey, ViewKey, Signature, RecordCiphertext, RecordPlaintext, PrivateKeyCiphertext } from "@aleohq/aleo-nodejs"; import { seed, message, diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index b2cb76a7f..744e0d3ec 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aleo-wasm" -version = "0.4.3" +version = "0.4.4" authors = [ "The Aleo Team " ] description = "WebAssembly based toolkit for developing zero knowledge applications with Aleo" homepage = "https://aleo.org" diff --git a/wasm/src/programs/macros.rs b/wasm/src/programs/macros.rs index e686e957a..ef4c5de87 100644 --- a/wasm/src/programs/macros.rs +++ b/wasm/src/programs/macros.rs @@ -83,37 +83,16 @@ macro_rules! execute_program { log("Executing program"); let result = $process - .execute::(authorization, &mut StdRng::from_entropy()) + .execute::(authorization) .map_err(|err| err.to_string())?; result }}; } -#[macro_export] -macro_rules! inclusion_proof { - ($process:expr, $inclusion:expr, $execution:expr, $url:expr) => {{ - log("Preparing execution inclusion proof"); - let (assignments, global_state_root) = $inclusion - .prepare_execution_async::(&$execution, &$url) - .await - .map_err(|err| err.to_string())?; - - log("Proving execution inclusion proof"); - let execution = $inclusion - .prove_execution::($execution, &assignments, global_state_root, &mut StdRng::from_entropy()) - .map_err(|err| err.to_string())?; - - log("Verifying execution"); - $process.verify_execution::(&execution).map_err(|e| e.to_string())?; - - execution - }}; -} - #[macro_export] macro_rules! fee_inclusion_proof { - ($process:expr, $private_key:expr, $fee_record:expr, $fee_microcredits:expr, $submission_url:expr, $fee_proving_key:expr, $fee_verifying_key:expr) => {{ + ($process:expr, $private_key:expr, $fee_record:expr, $fee_microcredits:expr, $submission_url:expr, $fee_proving_key:expr, $fee_verifying_key:expr, $execution_id:expr) => {{ if (($fee_proving_key.is_some() && $fee_verifying_key.is_none()) || ($fee_proving_key.is_none() && $fee_verifying_key.is_some())) { @@ -138,33 +117,24 @@ macro_rules! fee_inclusion_proof { .map_err(|e| e.to_string())?; } } - }; log("Executing fee program"); let fee_record_native = RecordPlaintextNative::from_str(&$fee_record.to_string()).unwrap(); - let (_, fee_transition, inclusion, _) = $process + let (_, _, trace) = $process .execute_fee::( &$private_key, fee_record_native, $fee_microcredits, + $execution_id, &mut StdRng::from_entropy(), ) .map_err(|err| err.to_string())?; - log("Preparing fee inclusion proof"); - let assignment = inclusion - .prepare_fee_async::(&fee_transition, &$submission_url) - .await - .map_err(|err| err.to_string())?; - - log("Proving fee inclusion proof"); - let fee = inclusion - .prove_fee::(fee_transition, &assignment, &mut StdRng::from_entropy()) - .map_err(|err| err.to_string())?; + let fee = trace.prove_fee::(&mut StdRng::from_entropy()).map_err(|e|e.to_string())?; log("Verifying fee execution"); - $process.verify_fee(&fee).map_err(|e| e.to_string())?; + $process.verify_fee(&fee, $execution_id).map_err(|e| e.to_string())?; fee }}; diff --git a/wasm/src/programs/manager/deploy.rs b/wasm/src/programs/manager/deploy.rs index ed5d59e39..39a61289b 100644 --- a/wasm/src/programs/manager/deploy.rs +++ b/wasm/src/programs/manager/deploy.rs @@ -22,7 +22,6 @@ use crate::{ log, types::{ CurrentAleo, - CurrentBlockMemory, CurrentNetwork, ProcessNative, ProgramIDNative, @@ -69,7 +68,7 @@ impl ProgramManager { imports: Option, fee_credits: f64, fee_record: RecordPlaintext, - url: String, + _url: String, cache: bool, fee_proving_key: Option, fee_verifying_key: Option, @@ -125,16 +124,18 @@ impl ProgramManager { .verify_deployment::(&deployment, &mut StdRng::from_entropy()) .map_err(|err| err.to_string())?; + let deployment_id = deployment.to_deployment_id().map_err(|e| e.to_string())?; + let fee = fee_inclusion_proof!( process, private_key, fee_record, fee_microcredits, - url, + _url, fee_proving_key, - fee_verifying_key + fee_verifying_key, + deployment_id ); - process.verify_fee(&fee).map_err(|e| e.to_string())?; log("Create the deployment transaction"); TransactionNative::check_deployment_size(&deployment).map_err(|err| err.to_string())?; @@ -161,7 +162,7 @@ impl ProgramManager { &leaves.collect::>>().map_err(|err| err.to_string())?, ) .map_err(|err| err.to_string())?; - let owner = ProgramOwnerNative::new(&private_key, (*id.root()).into(), &mut StdRng::from_entropy()) + let owner = ProgramOwnerNative::new(&private_key, *id.root(), &mut StdRng::from_entropy()) .map_err(|err| err.to_string())?; log("Creating deployment transaction"); diff --git a/wasm/src/programs/manager/execute.rs b/wasm/src/programs/manager/execute.rs index ca71f1fe7..04b2e5eac 100644 --- a/wasm/src/programs/manager/execute.rs +++ b/wasm/src/programs/manager/execute.rs @@ -15,22 +15,13 @@ // along with the Aleo SDK library. If not, see . use super::*; +use std::ops::Add; use crate::{ execute_program, - fee_inclusion_proof, get_process, - inclusion_proof, log, - types::{ - CurrentAleo, - CurrentBlockMemory, - IdentifierNative, - ProcessNative, - ProgramNative, - RecordPlaintextNative, - TransactionNative, - }, + types::{CurrentAleo, CurrentBlockMemory, IdentifierNative, ProcessNative, ProgramNative, TransactionNative}, ExecutionResponse, PrivateKey, RecordPlaintext, @@ -78,12 +69,9 @@ impl ProgramManager { let mut new_process; let process: &mut ProcessNative = get_process!(self, cache, new_process); - let (response, execution, _, _) = + let (response, _) = execute_program!(process, inputs, program, function, private_key, proving_key, verifying_key); - log(&format!("Verifying execution for local function: {function}")); - process.verify_execution::(&execution).map_err(|e| e.to_string())?; - log("Creating execution response"); let outputs = js_sys::Array::new_with_length(response.outputs().len() as u32); for (i, output) in response.outputs().iter().enumerate() { @@ -128,23 +116,41 @@ impl ProgramManager { fee_verifying_key: Option, ) -> Result { log(&format!("Executing function: {function} on-chain")); - let fee_microcredits = Self::validate_amount(fee_credits, &fee_record, true)?; + Self::validate_amount(fee_credits, &fee_record, true)?; let mut new_process; let process = get_process!(self, cache, new_process); + let stack = process.get_stack("credits.aleo").map_err(|e| e.to_string())?; + let fee_identifier = IdentifierNative::from_str("fee").map_err(|e| e.to_string())?; + if !stack.contains_proving_key(&fee_identifier) && fee_proving_key.is_some() && fee_verifying_key.is_some() { + let fee_proving_key = fee_proving_key.unwrap(); + let fee_verifying_key = fee_verifying_key.unwrap(); + stack + .insert_proving_key(&fee_identifier, ProvingKeyNative::from(fee_proving_key)) + .map_err(|e| e.to_string())?; + stack + .insert_verifying_key(&fee_identifier, VerifyingKeyNative::from(fee_verifying_key)) + .map_err(|e| e.to_string())?; + } - let (_, execution, inclusion, _) = + let (_, mut trace) = execute_program!(process, inputs, program, function, private_key, proving_key, verifying_key); - let execution = inclusion_proof!(process, inclusion, execution, url); - let fee = fee_inclusion_proof!( - process, - private_key, - fee_record, - fee_microcredits, - url, - fee_proving_key, - fee_verifying_key - ); + + // Prepare the inclusion proofs for the fee & execution + trace.prepare_async::(&url).await.map_err(|err| err.to_string())?; + + // Prove the execution and fee + let program = ProgramNative::from_str(&program).map_err(|err| err.to_string())?; + let locator = program.id().to_string().add("/").add(&function); + let execution = trace + .prove_execution::(&locator, &mut StdRng::from_entropy()) + .map_err(|e| e.to_string())?; + let fee = trace.prove_fee::(&mut StdRng::from_entropy()).map_err(|e| e.to_string())?; + let execution_id = execution.to_execution_id().map_err(|e| e.to_string())?; + + // Verify the execution and fee + process.verify_execution(&execution).map_err(|err| err.to_string())?; + process.verify_fee(&fee, execution_id).map_err(|err| err.to_string())?; log("Creating execution transaction"); let transaction = TransactionNative::from_execution(execution, Some(fee)).map_err(|err| err.to_string())?; diff --git a/wasm/src/programs/manager/join.rs b/wasm/src/programs/manager/join.rs index 663f8e7e4..a28c4b5b7 100644 --- a/wasm/src/programs/manager/join.rs +++ b/wasm/src/programs/manager/join.rs @@ -18,19 +18,9 @@ use super::*; use crate::{ execute_program, - fee_inclusion_proof, get_process, - inclusion_proof, log, - types::{ - CurrentAleo, - CurrentBlockMemory, - IdentifierNative, - ProcessNative, - ProgramNative, - RecordPlaintextNative, - TransactionNative, - }, + types::{CurrentAleo, CurrentBlockMemory, IdentifierNative, ProcessNative, ProgramNative, TransactionNative}, PrivateKey, RecordPlaintext, Transaction, @@ -77,7 +67,7 @@ impl ProgramManager { fee_verifying_key: Option, ) -> Result { log("Executing join program"); - let fee_microcredits = Self::validate_amount(fee_credits, &fee_record, true)?; + Self::validate_amount(fee_credits, &fee_record, true)?; log("Setup program and inputs"); let program = ProgramNative::credits().unwrap().to_string(); @@ -87,19 +77,35 @@ impl ProgramManager { let mut new_process; let process = get_process!(self, cache, new_process); + let stack = process.get_stack("credits.aleo").map_err(|e| e.to_string())?; + let fee_identifier = IdentifierNative::from_str("fee").map_err(|e| e.to_string())?; + if !stack.contains_proving_key(&fee_identifier) && fee_proving_key.is_some() && fee_verifying_key.is_some() { + let fee_proving_key = fee_proving_key.unwrap(); + let fee_verifying_key = fee_verifying_key.unwrap(); + stack + .insert_proving_key(&fee_identifier, ProvingKeyNative::from(fee_proving_key)) + .map_err(|e| e.to_string())?; + stack + .insert_verifying_key(&fee_identifier, VerifyingKeyNative::from(fee_verifying_key)) + .map_err(|e| e.to_string())?; + } - let (_, execution, inclusion, _) = + let (_, mut trace) = execute_program!(process, inputs, program, "join", private_key, join_proving_key, join_verifying_key); - let execution = inclusion_proof!(process, inclusion, execution, url); - let fee = fee_inclusion_proof!( - process, - private_key, - fee_record, - fee_microcredits, - url, - fee_proving_key, - fee_verifying_key - ); + + // Prepare the inclusion proofs for the fee & execution + trace.prepare_async::(&url).await.map_err(|err| err.to_string())?; + + // Prove the execution and fee + let execution = trace + .prove_execution::("credits.aleo/join", &mut StdRng::from_entropy()) + .map_err(|e| e.to_string())?; + let fee = trace.prove_fee::(&mut StdRng::from_entropy()).map_err(|e| e.to_string())?; + let execution_id = execution.to_execution_id().map_err(|e| e.to_string())?; + + // Verify the execution and fee + process.verify_execution(&execution).map_err(|err| err.to_string())?; + process.verify_fee(&fee, execution_id).map_err(|err| err.to_string())?; log("Creating execution transaction for join"); let transaction = TransactionNative::from_execution(execution, Some(fee)).map_err(|err| err.to_string())?; diff --git a/wasm/src/programs/manager/split.rs b/wasm/src/programs/manager/split.rs index 6286b44c9..4d2aca66c 100644 --- a/wasm/src/programs/manager/split.rs +++ b/wasm/src/programs/manager/split.rs @@ -19,7 +19,6 @@ use super::*; use crate::{ execute_program, get_process, - inclusion_proof, log, types::{CurrentAleo, CurrentBlockMemory, IdentifierNative, ProcessNative, ProgramNative, TransactionNative}, PrivateKey, @@ -71,9 +70,19 @@ impl ProgramManager { let mut new_process; let process = get_process!(self, cache, new_process); - let (_, execution, inclusion, _) = + let (_, mut trace) = execute_program!(process, inputs, program, "split", private_key, split_proving_key, split_verifying_key); - let execution = inclusion_proof!(process, inclusion, execution, url); + + // Prepare the inclusion proofs for the fee & execution + trace.prepare_async::(&url).await.map_err(|err| err.to_string())?; + + // Prove the execution and fee + let execution = trace + .prove_execution::("credits.aleo/split", &mut StdRng::from_entropy()) + .map_err(|e| e.to_string())?; + + // Verify the execution and fee + process.verify_execution(&execution).map_err(|err| err.to_string())?; log("Creating execution transaction for split"); let transaction = TransactionNative::from_execution(execution, None).map_err(|err| err.to_string())?; diff --git a/wasm/src/programs/manager/transfer.rs b/wasm/src/programs/manager/transfer.rs index 6d5ebff62..4e4a76cb6 100644 --- a/wasm/src/programs/manager/transfer.rs +++ b/wasm/src/programs/manager/transfer.rs @@ -18,19 +18,9 @@ use super::*; use crate::{ execute_program, - fee_inclusion_proof, get_process, - inclusion_proof, log, - types::{ - CurrentAleo, - CurrentBlockMemory, - IdentifierNative, - ProcessNative, - ProgramNative, - RecordPlaintextNative, - TransactionNative, - }, + types::{CurrentAleo, CurrentBlockMemory, IdentifierNative, ProcessNative, ProgramNative, TransactionNative}, PrivateKey, RecordPlaintext, Transaction, @@ -47,6 +37,7 @@ impl ProgramManager { /// @param private_key The private key of the sender /// @param amount_credits The amount of credits to send /// @param recipient The recipient of the transaction + /// @param transfer_type The type of the transfer (options: "private", "public", "private_to_public", "public_to_private") /// @param amount_record The record to fund the amount from /// @param fee_credits The amount of credits to pay as a fee /// @param fee_record The record to spend the fee from @@ -69,7 +60,8 @@ impl ProgramManager { private_key: PrivateKey, amount_credits: f64, recipient: String, - amount_record: RecordPlaintext, + transfer_type: String, + amount_record: Option, fee_credits: f64, fee_record: RecordPlaintext, url: String, @@ -80,38 +72,95 @@ impl ProgramManager { fee_verifying_key: Option, ) -> Result { log("Executing transfer program"); - let fee_microcredits = Self::validate_amount(fee_credits, &fee_record, true)?; - let amount_microcredits = Self::validate_amount(amount_credits, &amount_record, true)?; + let amount_microcredits = if let Some(amount_record) = amount_record.as_ref() { + Self::validate_amount(amount_credits, amount_record, false)? + } else { + (amount_credits * 1_000_000.0) as u64 + }; + Self::validate_amount(fee_credits, &fee_record, true)?; log("Setup the program and inputs"); let program = ProgramNative::credits().unwrap().to_string(); let inputs = Array::new_with_length(3); - inputs.set(0u32, wasm_bindgen::JsValue::from_str(&amount_record.to_string())); - inputs.set(1u32, wasm_bindgen::JsValue::from_str(&recipient)); - inputs.set(2u32, wasm_bindgen::JsValue::from_str(&amount_microcredits.to_string().add("u64"))); + + let transfer_type = match transfer_type.as_str() { + "private" => "transfer_".to_string().add("private"), + "private_to_public" => "transfer_".to_string().add("private_to_public"), + "public" => "transfer_".to_string().add("public"), + "public_to_private" => "transfer_".to_string().add("public_to_private"), + _ => transfer_type, + }; + + let transfer_type = match transfer_type.as_str() { + "transfer_private" => { + if amount_record.is_none() { + return Err("Amount record must be provided for private transfers".to_string()); + } + inputs.set(0u32, wasm_bindgen::JsValue::from_str(&amount_record.unwrap().to_string())); + inputs.set(1u32, wasm_bindgen::JsValue::from_str(&recipient)); + inputs.set(2u32, wasm_bindgen::JsValue::from_str(&amount_microcredits.to_string().add("u64"))); + transfer_type + } + "transfer_private_to_public" => { + if amount_record.is_none() { + return Err("Amount record must be provided for private transfers".to_string()); + } + inputs.set(0u32, wasm_bindgen::JsValue::from_str(&amount_record.unwrap().to_string())); + inputs.set(1u32, wasm_bindgen::JsValue::from_str(&recipient)); + inputs.set(2u32, wasm_bindgen::JsValue::from_str(&amount_microcredits.to_string().add("u64"))); + transfer_type + } + "transfer_public" => { + inputs.set(0u32, wasm_bindgen::JsValue::from_str(&recipient)); + inputs.set(1u32, wasm_bindgen::JsValue::from_str(&amount_microcredits.to_string().add("u64"))); + transfer_type + } + "transfer_public_to_private" => { + inputs.set(1u32, wasm_bindgen::JsValue::from_str(&recipient)); + inputs.set(2u32, wasm_bindgen::JsValue::from_str(&amount_microcredits.to_string().add("u64"))); + transfer_type + } + _ => return Err("Invalid transfer type".to_string()), + }; let mut new_process; let process = get_process!(self, cache, new_process); + let fee_identifier = IdentifierNative::from_str("fee").map_err(|e| e.to_string())?; + let stack = process.get_stack("credits.aleo").map_err(|e| e.to_string())?; + if !stack.contains_proving_key(&fee_identifier) && fee_proving_key.is_some() && fee_verifying_key.is_some() { + let fee_proving_key = fee_proving_key.unwrap(); + let fee_verifying_key = fee_verifying_key.unwrap(); + stack + .insert_proving_key(&fee_identifier, ProvingKeyNative::from(fee_proving_key)) + .map_err(|e| e.to_string())?; + stack + .insert_verifying_key(&fee_identifier, VerifyingKeyNative::from(fee_verifying_key)) + .map_err(|e| e.to_string())?; + } - let (_, execution, inclusion, _) = execute_program!( + let (_, mut trace) = execute_program!( process, inputs, program, - "transfer", + &transfer_type, private_key, transfer_proving_key, transfer_verifying_key ); - let execution = inclusion_proof!(process, inclusion, execution, url); - let fee = fee_inclusion_proof!( - process, - private_key, - fee_record, - fee_microcredits, - url, - fee_proving_key, - fee_verifying_key - ); + + // Prepare the inclusion proofs for the fee & execution + trace.prepare_async::(&url).await.map_err(|err| err.to_string())?; + + // Prove the execution and fee + let execution = trace + .prove_execution::("credits.aleo/transfer", &mut StdRng::from_entropy()) + .map_err(|e| e.to_string())?; + let fee = trace.prove_fee::(&mut StdRng::from_entropy()).map_err(|e| e.to_string())?; + let execution_id = execution.to_execution_id().map_err(|e| e.to_string())?; + + // Verify the execution and fee + process.verify_execution(&execution).map_err(|err| err.to_string())?; + process.verify_fee(&fee, execution_id).map_err(|err| err.to_string())?; log("Creating execution transaction for transfer"); let transaction = TransactionNative::from_execution(execution, Some(fee)).map_err(|err| err.to_string())?; diff --git a/wasm/src/programs/program.rs b/wasm/src/programs/program.rs index 23ce07174..5f58e89fc 100644 --- a/wasm/src/programs/program.rs +++ b/wasm/src/programs/program.rs @@ -269,13 +269,31 @@ function bump_token_version: #[wasm_bindgen_test] fn test_get_functions() { let program = Program::from(ProgramNative::credits().unwrap()); - assert_eq!(program.get_functions().to_vec(), vec!["mint", "transfer", "join", "split", "fee"]); + let mint = JsValue::from_str("mint"); + let transfer_public = JsValue::from_str("transfer_public"); + let transfer_private = JsValue::from_str("transfer_private"); + let transfer_private_to_public = JsValue::from_str("transfer_private_to_public"); + let transfer_public_to_private = JsValue::from_str("transfer_public_to_private"); + let join = JsValue::from_str("join"); + let split = JsValue::from_str("split"); + let fee = JsValue::from_str("fee"); + + assert_eq!(program.get_functions().to_vec(), vec![ + mint, + transfer_public, + transfer_private, + transfer_private_to_public, + transfer_public_to_private, + join, + split, + fee + ]); } #[wasm_bindgen_test] fn test_get_inputs() { let credits = Program::from(ProgramNative::credits().unwrap()); - let inputs = credits.get_function_inputs("transfer".to_string()).unwrap(); + let inputs = credits.get_function_inputs("transfer_private".to_string()).unwrap(); let expected = r#"Array { obj: Object { obj: JsValue([Object({"type":"record","name":"credits","members":[{"name":"microcredits","type":"u64","visibility":"private"}]}), Object({"type":"address","visibility":"private"}), Object({"type":"u64","visibility":"private"})]) } }"#.to_string(); assert_eq!(format!("{:?}", inputs), expected); diff --git a/wasm/src/programs/proving_key.rs b/wasm/src/programs/proving_key.rs index 17e8350fa..4d2f5761b 100644 --- a/wasm/src/programs/proving_key.rs +++ b/wasm/src/programs/proving_key.rs @@ -69,7 +69,7 @@ mod tests { use super::*; use wasm_bindgen_test::*; - const FEE_PROVER_URL: &str = "https://testnet3.parameters.aleo.org/fee.prover.0bfc24f"; + const FEE_PROVER_URL: &str = "https://testnet3.parameters.aleo.org/fee.prover.36542ce"; #[wasm_bindgen_test] async fn test_proving_key_roundtrip() { diff --git a/wasm/src/programs/transaction.rs b/wasm/src/programs/transaction.rs index 767fd682f..7d238d8f0 100644 --- a/wasm/src/programs/transaction.rs +++ b/wasm/src/programs/transaction.rs @@ -88,8 +88,9 @@ impl FromStr for Transaction { mod tests { use super::*; use wasm_bindgen_test::*; - const TRANSACTION_STRING: &str = "{\"type\":\"execute\",\"id\":\"at1pkw4ms8yuw29k8lfqdqkcdaffd6hngnzkw3j8f8j0aht0egkz5fq4h652c\",\"execution\":{\"transitions\":[{\"id\":\"as1w46uteuwlm85yp85af0xsd52pt4qa04m2nm20ux6zh78u5d4ecys6v85ch\",\"program\":\"credits.aleo\",\"function\":\"mint\",\"inputs\":[{\"type\":\"public\",\"id\":\"5040908569006131213612149758844338587983081600819749361338731441075240131558field\",\"value\":\"aleo1q6qstg8q8shwqf5m6q5fcenuwsdqsvp4hhsgfnx5chzjm3secyzqt9mxm8\"},{\"type\":\"public\",\"id\":\"1276789444601847309812664117152425665973038141628909950908919191663021093021field\",\"value\":\"1u64\"}],\"outputs\":[{\"type\":\"record\",\"id\":\"95928634596052979246019218801908083236653595200887025551448057926055637040field\",\"checksum\":\"7583379478720147365928563614237196759288927925463919661327931764780242134350field\",\"value\":\"record1qyqsqw5vumkswscee2ht4yju9el5g02uwv7204sx8nf96ln4mjugmasyqyxx66trwfhkxun9v35hguerqqpqzqpken3n6ghr0mm509pn7sgersrrnxfvcp5zsctd9cr03ay2yncap2khg34cktpumr8mnv7sqa4zjxu9ww78u69nfqxh9mwxxqvv6ssqsepzx3u\"}],\"proof\":\"proof1qqqsqqqqqqqqqqqpqqqqqqqqqqqdxthfnfwmf8htv998y84helwczfhr525qx6fe4d3xfhz9tnz5htjpspzk9l38u4uyxge2hfteva5qc50ht0dklnvqvmukzjvc0q47a3y79e0zaz8mmtl3kzq5rtpeegny8cduhd8v02hg7tfranq7cl7cqlzeth8eak93d2p63nmt5datq6n6v6nv0uxxl0nj9r6lydef228xm34getesxvxchxtt9kj3c4vzqyqcqrnlmzf8mphcwns8wt9js8n67tvrnx8x9dnq66tjl46j2paj75pe0yh057hf9fw9989zacc5y0qq64ekr4cpkyl0jxx6l0l64nt8lgtltlwvfzmad55vh8lz5xsmhhau530n8ttw4h9de7uju2s9wqscrfp8tgfpn5sfyx5k27ue2t5dumfe0w63uq9tf2gjh9j2uegxfn3aqn42j3esmervqa57zms9055lqp09nyv3v7exa3hkqsy9vvu37tve6wrv9xwxf3euk6yf4kecdvf3v6llvjg9ehgtv6a8xqek0vzn7qz6n5sshwnhxn4mel85nqnlz5rp3e0p0tfj0k2cvr4ssw62qgyynr52ckykw84g2an72f6ark9vfzqama0jgalrtrufhet48lew523386xv87p9k57vnvwturq4qclk3yfy8nsfveghjnhuy9znvmu78h5qrzyzhlsnz5fgatex2nqgu8vyvtvrzghxc7dzwspsux93jsn2y64uhecf45r2myk7d7c4cfcfjcmgpp8gp2482ljfhtv3lrjkqhdlu73x7pzzft70xslqk2mypg7ufns2yckh8353ss7frsq4h7etrhdswyytjn0t5gp6m9pzwt4qenznp5p3pq8lhuaj42yhhllzp8huvstmxlcrmjyn09s6vts782rqnu8j6qzpy4p59ujnh9ykunxcyrtm7422jkmus9r7p4ck0fm64fm9ry0rppvhs6p5rh6s05kmpsnrjdx3p8rpqgk8l4m4nhjsxjwr6l7c4mrsxqgqqqqqqqqqqzkfxa64vdye8v2zsjxm8ny3ytmnzd63jpnzdrqys66d3nlay75q30mjd3p7ua2y8fv4rg8xrurzexgh0jptxxt5dxza36qdxxrafys0zx2ckw7662xygr4gynaj2yzzesjlzvs8aw6yr5hn04vdl7ey5q9qyqqqqqqqqqqqqn4ekpaxek52nzpaptxky4cuar5exs9w8spskwn4xu87203y2s8k3l2h0w80zj4m3m39akgytmxcqqtytm0a68pmtwxy8c0rfl09z3mfgxvnprqwmwtq7aa0wmpvg0j0zgc9f35uczk7z2pf54xn2kwp23mrwd6fc4x3cl3lw5khhcl36z0rwsqve9v86newep09epdq7pe8eqqqqq035d6j\",\"tpk\":\"6632149043115422828236144456828746891849538829103670866843594215187740194210group\",\"tcm\":\"4818412099071103605161859576211275541485358629762154526095011715785635126388field\"}],\"global_state_root\":\"ar1jexd2yp8k5lal4rn7khtf0ejgzqcq7rada0chywes7q3hvmcxqgq0u4930\"}}"; - const TRANSACTION_ID: &str = "at1pkw4ms8yuw29k8lfqdqkcdaffd6hngnzkw3j8f8j0aht0egkz5fq4h652c"; + const TRANSACTION_STRING: &str = "{\"type\":\"execute\",\"id\":\"at1xrxemapaf385s43ed5nwsteg8cq54e39lk2d2lw4rujvja4cwq9sg5pseq\",\"execution\":{\"transitions\":[{\"id\":\"as1t7quw0wv44zkrem48s25mdwzyjr0qn6eq6ac3neh7s9fv5ww8qzswv37gq\",\"program\":\"credits.aleo\",\"function\":\"mint\",\"inputs\":[{\"type\":\"public\",\"id\":\"4571474674041498190570175739605649554896377072704024916067816371486863204251field\",\"value\":\"aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px\"},{\"type\":\"public\",\"id\":\"8061372082825942177836550247297053850302997632012579379895213511313014824528field\",\"value\":\"1u64\"}],\"outputs\":[{\"type\":\"record\",\"id\":\"1815634065770981623360291510624106631041220031671340894298102432902040793411field\",\"checksum\":\"1015167472992783511311101598574240443268988130054487982421923374591159165351field\",\"value\":\"record1qyqsp79mapsrlhq9nagchuptc0j28de50fgynyqqx9tktvc54uquqggdqyxx66trwfhkxun9v35hguerqqpqzqzscf2u4qdzkwtf3nqflkmu3suwsssx94nm5mzvgq3lwjkp2s6pqa5upd4uv47akp03x4dekwt3j8ete9gdqm3qcl0am4dul5ysgeeq7kcnax7\"}],\"tpk\":\"7389326660456621081896114306777120980284671073551156387156944531787954948120group\",\"tcm\":\"4153485374762916289562399739094103978130001873040055685900383330717020526427field\"}],\"global_state_root\":\"ar1s2rpkf7derk239umx5wqlsz4tnqrkywdp7ls5f5rlawl06z4kggscft4pu\",\"proof\":\"proof1qqqsqqqqqqqqqqqpqqqqqqqqqqqz6uuh99ckx3rzxg7fxfjstdtdwk9ag4yq30qrse8gtkrzj949m3z66ap2vpz6sr0m8eyde5323rgpdf2q33ukew5pxt7g40v73um3r225a5n2qe99ztulm43lt49nkaqqn4ktk5lzdqfjes3etatkkgncrke2q9p3zsc07ru3tuhvpnv7frlt0qtrl2f06wkpyafl75yzdd4z0rztvy9c22gpxxmv5g52jxpfqqqupjt7a3l7nwalslfq4rqxyqcrz4qnrav3k829979czuq9cyjkztmgzc7nath3ran79edyq338m95q0mnet3jtkyr0a9utjnr5t5pgvf8s6v4mn9wjzqcufwkpmw943tgnjr2338ysyay3st2fewgl4klcpkuc42tch723sgps5kwnq8s5wt43jjj8vwyz89kjhqh4e6894n0ppjm7qds508sxcphxdv5gzfuqsz8h0lajd8lru740aqut9uyr7nlmcydqvuk0lhuyd7v5ne86qv6yvfrtq55mf2lnk4remyprkdajxqpr2en8s3jy0w9rt6kafzq625qz775gl4wt7h9zyevamjjx45c290fk6tr637vtchc5q670svg0wuq0te0dspd4ttzy7ty2njdzj74yngrqajuudvsycsj9kevpvw8fs929wwtsfvvpgqg2l6f54uj5c3cp9u0uv70yk33a0cvnn0lszc72ymqlu0y779nchphl2r90d6fhc87gtx0qgcn8epx32xel97qdasgqztsh6wecct4paz4was8fxyq8rd0jutsl9l772z9prj8s7jjjvsgyxalygw6yj5yu7qgkk7uprf7sa6ew0kl6lew796pzr2x0j2esagzljsr7usamwja0wuwcw0v028u43msyqeeulr7lkkmhhhcc7dpyxzj8y6uxcyw72dd0lr0vzkwumswjzuvtytf8823ur3zacqc2g8v7p6ld4q26nht5a22d3t23qhre3ak20vcatf8hrpcskw8fjx6kdppqsqgqqqqqqqqqqzwf2wl74jh0zs2fgp60xe0z8legf3xwdwf7ujaswf7h38q0datq0vtccxpwgazyemk3mjcg5603uwq33t9sate0kalnhsjzfrw7q4cxfhf8q6ztmrunze77jl2sv4xvtet8rweuraxp7can9r4g69kguursyqqqqqqqqqqqqf8nmctdkcss4ju4femxj93uuzdsw6vwyr3twtyuzdk86zfs40hhp4pjspq7tfwsjw3auha3xvagzq0qg2jfpmsazykcyuqslr3ga4zqa8m5hepqg9a0amm90kvj2k45zps0lp3304q929kl4pw0qtr4wggrzau056qgsa2krsmyg0r37x6fqqfe9jhhd5hxp08m4me4arlaxqqqqqf43srp\"}}"; + + const TRANSACTION_ID: &str = "at1xrxemapaf385s43ed5nwsteg8cq54e39lk2d2lw4rujvja4cwq9sg5pseq"; #[wasm_bindgen_test] fn test_transaction_string_constructor_and_accessor_methods() { diff --git a/wasm/src/programs/verifying_key.rs b/wasm/src/programs/verifying_key.rs index 7cf03cddb..ec13be0ac 100644 --- a/wasm/src/programs/verifying_key.rs +++ b/wasm/src/programs/verifying_key.rs @@ -70,10 +70,10 @@ mod tests { use super::*; use wasm_bindgen_test::*; - const FEE_VERIFIER_URL: &str = "https://testnet3.parameters.aleo.org/fee.verifier.44783e8"; + const FEE_VERIFIER_URL: &str = "https://testnet3.parameters.aleo.org/fee.verifier.2de311b"; #[wasm_bindgen_test] - async fn test_proving_key_roundtrip() { + async fn test_verifying_key_roundtrip() { let fee_verifying_key_bytes = reqwest::get(FEE_VERIFIER_URL).await.unwrap().bytes().await.unwrap().to_vec(); let fee_verifying_key = VerifyingKey::from_bytes(&fee_verifying_key_bytes).unwrap(); let bytes = fee_verifying_key.to_bytes().unwrap(); diff --git a/wasm/tests/offchain.rs b/wasm/tests/offchain.rs index 10dde96c5..1644b4e5d 100644 --- a/wasm/tests/offchain.rs +++ b/wasm/tests/offchain.rs @@ -36,42 +36,42 @@ function hello: output r2 as u32.private; "#; -const FEE_PROVER_URL: &str = "https://testnet3.parameters.aleo.org/fee.prover.0bfc24f"; -const FEE_VERIFIER_URL: &str = "https://testnet3.parameters.aleo.org/fee.verifier.44783e8"; +const SPLIT_PROVER_URL: &str = "https://testnet3.parameters.aleo.org/split.prover.8c585f2"; +const SPLIT_VERIFIER_URL: &str = "https://testnet3.parameters.aleo.org/split.verifier.8281688"; const RECORD: &str = "{ owner: aleo184vuwr5u7u0ha5f5k44067dd2uaqewxx6pe5ltha5pv99wvhfqxqv339h4.private, microcredits: 2000000u64.private, _nonce: 4106205762862305308495708971985748592380064201230396559307556388725936304984group.public}"; #[wasm_bindgen_test] async fn test_cache_functionality() { - // Get the fee proving and verifying keys from the official Aleo parameters server - let fee_proving_key_bytes = reqwest::get(FEE_PROVER_URL).await.unwrap().bytes().await.unwrap().to_vec(); - let fee_verifying_key_bytes = reqwest::get(FEE_VERIFIER_URL).await.unwrap().bytes().await.unwrap().to_vec(); - let fee_proving_key = ProvingKey::from_bytes(&fee_proving_key_bytes).unwrap(); - let fee_proving_key_clone = fee_proving_key.clone(); - let fee_verifying_key = VerifyingKey::from_bytes(&fee_verifying_key_bytes).unwrap(); - let fee_verifying_key_clone = fee_verifying_key.clone(); + // Get the split proving and verifying keys from the official Aleo parameters server + let split_proving_key_bytes = reqwest::get(SPLIT_PROVER_URL).await.unwrap().bytes().await.unwrap().to_vec(); + let split_verifying_key_bytes = reqwest::get(SPLIT_VERIFIER_URL).await.unwrap().bytes().await.unwrap().to_vec(); + let split_proving_key = ProvingKey::from_bytes(&split_proving_key_bytes).unwrap(); + let split_proving_key_clone = split_proving_key.clone(); + let split_verifying_key = VerifyingKey::from_bytes(&split_verifying_key_bytes).unwrap(); + let split_verifying_key_clone = split_verifying_key.clone(); let mut program_manager = ProgramManager::new(); // Ensure the keypair is not in wasm memory if it has not been cached - assert!(program_manager.get_cached_keypair("credits.aleo", "fee").is_err()); - assert!(!program_manager.key_exists("credits.aleo", "fee").unwrap()); + assert!(program_manager.get_cached_keypair("credits.aleo", "split").is_err()); + assert!(!program_manager.key_exists("credits.aleo", "split").unwrap()); // Cache the keypair in wasm memory program_manager .cache_keypair_in_wasm_memory( &Program::get_credits_program().to_string(), - "fee", - fee_proving_key, - fee_verifying_key, + "split", + split_proving_key, + split_verifying_key, ) .unwrap(); // Ensure the keypair is in wasm memory and can be retrieved - let mut key_pair = program_manager.get_cached_keypair("credits.aleo", "fee").unwrap(); + let mut key_pair = program_manager.get_cached_keypair("credits.aleo", "split").unwrap(); let retrieved_proving_key = key_pair.proving_key().unwrap(); let retreived_verifying_key = key_pair.verifying_key().unwrap(); - assert_eq!(fee_proving_key_clone, retrieved_proving_key); - assert_eq!(fee_verifying_key_clone, retreived_verifying_key); + assert_eq!(split_proving_key_clone, retrieved_proving_key); + assert_eq!(split_verifying_key_clone, retreived_verifying_key); let inputs = Array::new(); inputs.set(0u32, JsValue::from_str("{ owner: aleo184vuwr5u7u0ha5f5k44067dd2uaqewxx6pe5ltha5pv99wvhfqxqv339h4.private, microcredits: 2000000u64.private, _nonce: 4106205762862305308495708971985748592380064201230396559307556388725936304984group.public}")); @@ -82,7 +82,7 @@ async fn test_cache_functionality() { .execute_local( PrivateKey::from_string("APrivateKey1zkp3dQx4WASWYQVWKkq14v3RoQDfY2kbLssUj7iifi1VUQ6").unwrap(), Program::get_credits_program().to_string(), - "fee".to_string(), + "split".to_string(), inputs, true, None, @@ -94,33 +94,33 @@ async fn test_cache_functionality() { assert_eq!(record.microcredits(), 1000000u64); // Ensure the 'key_exists' function can find the keys - assert!(program_manager.key_exists("credits.aleo", "fee").unwrap()); + assert!(program_manager.key_exists("credits.aleo", "split").unwrap()); // Ensure the keypair can't be overwritten assert!( program_manager - .cache_keypair_in_wasm_memory("credits.aleo", "fee", fee_proving_key_clone, fee_verifying_key_clone) + .cache_keypair_in_wasm_memory("credits.aleo", "split", split_proving_key_clone, split_verifying_key_clone) .is_err() ); // Ensure the cache clears correctly program_manager.clear_key_cache(); - assert!(program_manager.get_cached_keypair("credits.aleo", "fee").is_err()); - assert!(!program_manager.key_exists("credits.aleo", "fee").unwrap()); + assert!(program_manager.get_cached_keypair("credits.aleo", "split").is_err()); + assert!(!program_manager.key_exists("credits.aleo", "split").unwrap()); } #[wasm_bindgen_test] async fn test_key_synthesis() { - // Synthesize a keypair for the fee program + // Synthesize a keypair for the split program let mut program_manager = ProgramManager::new(); let credits = Program::get_credits_program(); - let mut key_pair = program_manager.synthesize_keypair(&credits.to_string(), "fee").unwrap(); + let mut key_pair = program_manager.synthesize_keypair(&credits.to_string(), "split").unwrap(); let retrieved_proving_key = key_pair.proving_key().unwrap(); let retreived_verifying_key = key_pair.verifying_key().unwrap(); - // Cache the keypair for the fee program in wasm memory + // Cache the keypair for the split program in wasm memory program_manager - .cache_keypair_in_wasm_memory(&credits.to_string(), "fee", retrieved_proving_key, retreived_verifying_key) + .cache_keypair_in_wasm_memory(&credits.to_string(), "split", retrieved_proving_key, retreived_verifying_key) .unwrap(); // Ensure program can be executed with the synthesized keypair stored in wasm memory @@ -132,7 +132,7 @@ async fn test_key_synthesis() { .execute_local( PrivateKey::from_string("APrivateKey1zkp3dQx4WASWYQVWKkq14v3RoQDfY2kbLssUj7iifi1VUQ6").unwrap(), credits.to_string(), - "fee".to_string(), + "split".to_string(), inputs, true, None, @@ -160,7 +160,7 @@ async fn test_fee_validation() { .execute( private_key.clone(), Program::get_credits_program().to_string(), - "fee".to_string(), + "split".to_string(), inputs, 100.0, fee_record.clone(), @@ -196,7 +196,8 @@ async fn test_fee_validation() { private_key.clone(), 100.00, "aleo184vuwr5u7u0ha5f5k44067dd2uaqewxx6pe5ltha5pv99wvhfqxqv339h4".to_string(), - fee_record.clone(), + "private".to_string(), + Some(fee_record.clone()), 0.9, fee_record.clone(), "https://vm.aleo.org/api".to_string(), @@ -214,7 +215,8 @@ async fn test_fee_validation() { private_key.clone(), 0.5, "aleo184vuwr5u7u0ha5f5k44067dd2uaqewxx6pe5ltha5pv99wvhfqxqv339h4".to_string(), - fee_record.clone(), + "private".to_string(), + Some(fee_record.clone()), 100.00, fee_record.clone(), "https://vm.aleo.org/api".to_string(), diff --git a/website/package.json b/website/package.json index 161cb1797..461bec604 100644 --- a/website/package.json +++ b/website/package.json @@ -35,7 +35,7 @@ "build": "webpack --config webpack.config.js", "predeploy": "yarn build", "deploy": "gh-pages -d build", - "clean": "rm -rf node_modules" + "clean": "rm -rf nodeg_modules" }, "eslintConfig": { "extends": [ diff --git a/website/src/tabs/develop/Transfer.js b/website/src/tabs/develop/Transfer.js index f93a2df35..d0935a7ab 100644 --- a/website/src/tabs/develop/Transfer.js +++ b/website/src/tabs/develop/Transfer.js @@ -82,6 +82,7 @@ export const Transfer = () => { type: 'ALEO_TRANSFER', privateKey: privateKeyString(), amountCredits: amount, + transfer_type: "transfer_private", recipient: recipientString(), amountRecord: amountRecordString(), fee: feeAmount, diff --git a/website/src/workers/keys.js b/website/src/workers/keys.js index 35679f117..e2e1126f6 100644 --- a/website/src/workers/keys.js +++ b/website/src/workers/keys.js @@ -4,7 +4,15 @@ const JOIN_PROVER_URL = "https://testnet3.parameters.aleo.org/join.prover.6856be const JOIN_VERIFIER_URL = "https://testnet3.parameters.aleo.org/join.verifier.9c946a3"; const SPLIT_PROVER_URL = "https://testnet3.parameters.aleo.org/split.prover.8469bca"; const SPLIT_VERIFIER_URL = "https://testnet3.parameters.aleo.org/split.verifier.ba3bdd9"; -const TRANSFER_PROVER_URL = "https://testnet3.parameters.aleo.org/transfer.prover.c3bcd1a"; -const TRANSFER_VERIFIER_URL = "https://testnet3.parameters.aleo.org/transfer.verifier.2192afd"; +const TRANSFER_PRIVATE_PROVER_URL = "https://testnet3.parameters.aleo.org/transfer.prover.2a9a6f2"; +const TRANSFER_PRIVATE_VERIFIER_URL = "https://testnet3.parameters.aleo.org/transfer.verifier.3a59762"; +const TRANSFER_PRIVATE_TO_PUBLIC_PROVER_URL = "https://testnet3.parameters.aleo.org/transfer_private_to_public.prover.cf3b952"; +const TRANSFER_PRIVATE_TO_PUBLIC_VERIFIER_URL = "https://testnet3.parameters.aleo.org/transfer_private_to_public.verifier.5bd459b"; +const TRANSFER_PUBLIC_PROVER_URL = "https://testnet3.parameters.aleo.org/transfer_public.prover.1117f0a"; +const TRANSFER_PUBLIC_VERIFIER_URL = "https://testnet3.parameters.aleo.org/transfer_public.verifier.d63af11"; +const TRANSFER_PUBLIC_TO_PRIVATE_PROVER_URL = "https://testnet3.parameters.aleo.org/transfer_public_to_private.prover.7b763af"; +const TRANSFER_PUBLIC_TO_PRIVATE_VERIFIER_URL = "https://testnet3.parameters.aleo.org/transfer_public_to_private.verifier.25f6542"; -export {FEE_PROVER_URL, FEE_VERIFIER_URL, JOIN_PROVER_URL, JOIN_VERIFIER_URL, SPLIT_PROVER_URL, SPLIT_VERIFIER_URL, TRANSFER_PROVER_URL, TRANSFER_VERIFIER_URL}; \ No newline at end of file +export {FEE_PROVER_URL, FEE_VERIFIER_URL, JOIN_PROVER_URL, JOIN_VERIFIER_URL, SPLIT_PROVER_URL, SPLIT_VERIFIER_URL, + TRANSFER_PRIVATE_PROVER_URL, TRANSFER_PRIVATE_VERIFIER_URL, TRANSFER_PUBLIC_PROVER_URL, TRANSFER_PUBLIC_VERIFIER_URL, + TRANSFER_PRIVATE_TO_PUBLIC_PROVER_URL, TRANSFER_PRIVATE_TO_PUBLIC_VERIFIER_URL, TRANSFER_PUBLIC_TO_PRIVATE_PROVER_URL, TRANSFER_PUBLIC_TO_PRIVATE_VERIFIER_URL}; \ No newline at end of file diff --git a/website/src/workers/worker.js b/website/src/workers/worker.js index 3f161ec09..d3be2621e 100644 --- a/website/src/workers/worker.js +++ b/website/src/workers/worker.js @@ -1,5 +1,8 @@ import init, * as aleo from '@aleohq/wasm'; -import { FEE_PROVER_URL, FEE_VERIFIER_URL, JOIN_PROVER_URL, JOIN_VERIFIER_URL, SPLIT_PROVER_URL, SPLIT_VERIFIER_URL, TRANSFER_PROVER_URL, TRANSFER_VERIFIER_URL } from './keys'; +import { FEE_PROVER_URL, FEE_VERIFIER_URL, JOIN_PROVER_URL, JOIN_VERIFIER_URL, SPLIT_PROVER_URL, SPLIT_VERIFIER_URL, + TRANSFER_PRIVATE_PROVER_URL, TRANSFER_PRIVATE_VERIFIER_URL, TRANSFER_PRIVATE_TO_PUBLIC_PROVER_URL, +TRANSFER_PRIVATE_TO_PUBLIC_VERIFIER_URL, TRANSFER_PUBLIC_PROVER_URL, TRANSFER_PUBLIC_VERIFIER_URL, + TRANSFER_PUBLIC_TO_PRIVATE_PROVER_URL, TRANSFER_PUBLIC_TO_PRIVATE_VERIFIER_URL} from './keys'; let feeProvingKey = null; let feeVerifyingKey = null; @@ -7,8 +10,14 @@ let joinProvingKey = null; let joinVerifyingKey = null; let splitProvingKey = null; let splitVerifyingKey = null; -let transferProvingKey = null; -let transferVerifyingKey = null; +let transferPrivateProvingKey = null; +let transferPrivateVerifyingKey = null; +let transferPrivateToPublicProvingKey = null; +let transferPrivateToPublicVerifyingKey = null; +let transferPublicProvingKey = null; +let transferPublicVerifyingKey = null; +let transferPublicToPrivateProvingKey = null; +let transferPublicToPrivateVerifyingKey = null; await init(); await aleo.initThreadPool(10); @@ -151,6 +160,7 @@ self.addEventListener("message", ev => { privateKey, amountCredits, recipient, + transfer_type, amountRecord, fee, feeRecord, @@ -162,11 +172,27 @@ self.addEventListener("message", ev => { (async function() { try { - if (transferProvingKey === null || transferVerifyingKey === null) { - [transferProvingKey, transferVerifyingKey] = await getFunctionKeys(TRANSFER_PROVER_URL, TRANSFER_VERIFIER_URL); + if (transfer_type === "public") { + if (transferPublicProvingKey === null || transferPublicVerifyingKey === null) { + [transferPublicProvingKey, transferPublicVerifyingKey] = await getFunctionKeys(TRANSFER_PUBLIC_PROVER_URL, TRANSFER_PUBLIC_VERIFIER_URL); + } + } else if (transfer_type === "private") { + if (transferPrivateProvingKey === null || transferPrivateVerifyingKey === null) { + [transferPrivateProvingKey, transferPrivateVerifyingKey] = await getFunctionKeys(TRANSFER_PRIVATE_PROVER_URL, TRANSFER_PRIVATE_VERIFIER_URL); + } + } else if (transfer_type === "publicToPrivate") { + if (transferPublicToPrivateProvingKey === null || transferPublicToPrivateVerifyingKey === null) { + [transferPublicToPrivateProvingKey, transferPublicToPrivateVerifyingKey] = await getFunctionKeys(TRANSFER_PUBLIC_TO_PRIVATE_PROVER_URL, TRANSFER_PUBLIC_TO_PRIVATE_VERIFIER_URL); + } + } else if (transfer_type === "privateToPublic") { + if (transferPrivateToPublicProvingKey === null || transferPrivateToPublicVerifyingKey === null) { + [transferPrivateToPublicProvingKey, transferPrivateToPublicVerifyingKey] = await getFunctionKeys(TRANSFER_PRIVATE_TO_PUBLIC_PROVER_URL, TRANSFER_PRIVATE_TO_PUBLIC_VERIFIER_URL); + } + } else { + throw (`Invalid transfer type`); } if (!aleoProgramManager.keyExists("credits.aleo", "transfer")) { - aleoProgramManager.cacheKeypairInWasmMemory(aleo.Program.getCreditsProgram().toString(), "transfer", transferProvingKey, transferVerifyingKey); + aleoProgramManager.cacheKeypairInWasmMemory(aleo.Program.getCreditsProgram().toString(), "transfer", transferPrivateProvingKey, transferPrivateVerifyingKey); } if (feeProvingKey === null || feeVerifyingKey === null) { [feeProvingKey, feeVerifyingKey] = await getFunctionKeys(FEE_PROVER_URL, FEE_VERIFIER_URL); @@ -179,6 +205,7 @@ self.addEventListener("message", ev => { aleo.PrivateKey.from_string(privateKey), amountCredits, recipient, + "transfer_private", aleo.RecordPlaintext.fromString(amountRecord), fee, aleo.RecordPlaintext.fromString(feeRecord),