diff --git a/.cargo/config b/.cargo/config.toml similarity index 100% rename from .cargo/config rename to .cargo/config.toml diff --git a/Cargo.lock b/Cargo.lock index fe8c0f9d66..db45344699 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,17 +36,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - [[package]] name = "ahash" version = "0.8.11" @@ -207,15 +196,6 @@ version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" -[[package]] -name = "arbitrary" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" -dependencies = [ - "derive_arbitrary", -] - [[package]] name = "arrayref" version = "0.3.7" @@ -251,7 +231,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -262,9 +242,15 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.3.0" @@ -416,7 +402,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -498,16 +484,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - [[package]] name = "bzip2-sys" version = "0.1.11+1.0.8" @@ -533,9 +509,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" dependencies = [ "jobserver", "libc", @@ -593,21 +569,11 @@ dependencies = [ "half", ] -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - [[package]] name = "clang-sys" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", @@ -645,7 +611,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -730,21 +696,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crc" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - [[package]] name = "crc32fast" version = "1.4.2" @@ -911,7 +862,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -927,12 +878,6 @@ dependencies = [ "parking_lot_core", ] -[[package]] -name = "deflate64" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83ace6c86376be0b6cdcf3fb41882e81d94b31587573d1cfa9d01cd06bba210d" - [[package]] name = "der" version = "0.7.9" @@ -963,17 +908,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "derive_arbitrary" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" -dependencies = [ - "proc-macro2", - "quote 1.0.36", - "syn 2.0.63", -] - [[package]] name = "difflib" version = "0.4.0" @@ -1032,17 +966,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "displaydoc" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" -dependencies = [ - "proc-macro2", - "quote 1.0.36", - "syn 2.0.63", -] - [[package]] name = "doc-comment" version = "0.3.3" @@ -1082,9 +1005,9 @@ dependencies = [ [[package]] name = "either" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" [[package]] name = "encode_unicode" @@ -1277,7 +1200,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -1410,15 +1333,15 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816ec7294445779408f36fe57bc5b7fc1cf59664059096c65f905c1c61f58069" +checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" dependencies = [ + "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "futures-util", "http 1.1.0", "indexmap 2.2.6", "slab", @@ -1501,15 +1424,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - [[package]] name = "http" version = "0.2.12" @@ -1611,7 +1525,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.4", + "h2 0.4.5", "http 1.1.0", "http-body 1.0.0", "httparse", @@ -1654,9 +1568,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" dependencies = [ "bytes", "futures-channel", @@ -1724,20 +1638,11 @@ version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] @@ -1888,6 +1793,7 @@ dependencies = [ "leo-package", "leo-parser", "leo-passes", + "leo-retriever", "leo-span", "leo-test-framework", "rand", @@ -1967,7 +1873,6 @@ dependencies = [ "tracing-subscriber", "ureq", "walkdir", - "zip 2.1.3", ] [[package]] @@ -2075,9 +1980,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.154" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libloading" @@ -2116,9 +2021,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.16" +version = "1.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" +checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" dependencies = [ "cc", "libc", @@ -2134,9 +2039,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" @@ -2148,12 +2053,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "lockfree-object-pool" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" - [[package]] name = "log" version = "0.4.21" @@ -2179,16 +2078,6 @@ dependencies = [ "libc", ] -[[package]] -name = "lzma-rs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" -dependencies = [ - "byteorder", - "crc", -] - [[package]] name = "matchers" version = "0.1.0" @@ -2287,9 +2176,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" dependencies = [ "adler", ] @@ -2308,11 +2197,10 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" dependencies = [ - "lazy_static", "libc", "log", "openssl", @@ -2405,7 +2293,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -2499,7 +2387,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -2534,9 +2422,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -2561,16 +2449,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest", - "hmac", -] - [[package]] name = "peeking_take_while" version = "0.1.2" @@ -2610,7 +2488,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -2649,9 +2527,9 @@ checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" [[package]] name = "plotters" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" dependencies = [ "num-traits", "plotters-backend", @@ -2662,15 +2540,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" +checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" [[package]] name = "plotters-svg" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" dependencies = [ "plotters-backend", ] @@ -2727,14 +2605,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6" dependencies = [ "unicode-ident", ] @@ -2981,7 +2859,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.4.4", + "h2 0.4.5", "http 1.1.0", "http-body 1.0.0", "http-body-util", @@ -3134,9 +3012,9 @@ checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" [[package]] name = "rustls-webpki" -version = "0.102.3" +version = "0.102.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3bce581c0dd41bce533ce695a1437fa16a7ab5ac3ccfa99fe1a620a7885eabf" +checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" dependencies = [ "ring", "rustls-pki-types", @@ -3301,7 +3179,7 @@ dependencies = [ "serde_json", "tempfile", "urlencoding", - "zip 0.6.6", + "zip", "zipsign-api", ] @@ -3328,7 +3206,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -3408,7 +3286,7 @@ checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -3488,12 +3366,6 @@ dependencies = [ "rand_core", ] -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - [[package]] name = "simple_asn1" version = "0.6.2" @@ -4748,7 +4620,7 @@ source = "git+https://github.com/AleoNet/snarkVM.git?rev=140ff26#140ff26f87697c2 dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -4821,7 +4693,7 @@ dependencies = [ "proc-macro2", "quote 1.0.36", "rustversion", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -4854,9 +4726,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.63" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote 1.0.36", @@ -4968,7 +4840,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -5048,9 +4920,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", @@ -5067,13 +4939,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -5234,7 +5106,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -5457,7 +5329,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", "wasm-bindgen-shared", ] @@ -5491,7 +5363,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5693,9 +5565,9 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +checksum = "86c949fede1d13936a99f14fafd3e76fd642b556dd2ce96287fbe2e0151bfac6" dependencies = [ "memchr", ] @@ -5746,7 +5618,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -5766,7 +5638,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.63", + "syn 2.0.66", ] [[package]] @@ -5781,35 +5653,6 @@ dependencies = [ "time", ] -[[package]] -name = "zip" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775a2b471036342aa69bc5a602bc889cb0a06cda00477d0c69566757d5553d39" -dependencies = [ - "aes", - "arbitrary", - "bzip2", - "constant_time_eq", - "crc32fast", - "crossbeam-utils", - "deflate64", - "displaydoc", - "flate2", - "hmac", - "indexmap 2.2.6", - "lzma-rs", - "memchr", - "pbkdf2", - "rand", - "sha1", - "thiserror", - "time", - "zeroize", - "zopfli", - "zstd", -] - [[package]] name = "zipsign-api" version = "0.1.1" @@ -5819,45 +5662,3 @@ dependencies = [ "ed25519-dalek", "thiserror", ] - -[[package]] -name = "zopfli" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" -dependencies = [ - "bumpalo", - "crc32fast", - "lockfree-object-pool", - "log", - "once_cell", - "simd-adler32", -] - -[[package]] -name = "zstd" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "7.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a" -dependencies = [ - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.10+zstd.1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/Cargo.toml b/Cargo.toml index cf75008985..bd762adb04 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -176,9 +176,6 @@ version = "0.1" version = "0.3.18" features = [ "fmt" ] -[dependencies.zip] -version = "^2.1" - [dependencies.crossterm] version = "0.27.0" diff --git a/compiler/compiler/Cargo.toml b/compiler/compiler/Cargo.toml index 5ca8822ca4..fb5917550e 100644 --- a/compiler/compiler/Cargo.toml +++ b/compiler/compiler/Cargo.toml @@ -51,12 +51,15 @@ features = [ ] [dev-dependencies.leo-disassembler] path = "../../utils/disassembler" -[dev-dependencies.leo-test-framework] -path = "../../tests/test-framework" - [dev-dependencies.leo-package] path = "../../leo/package" +[dev-dependencies.leo-retriever] +path = "../../utils/retriever" + +[dev-dependencies.leo-test-framework] +path = "../../tests/test-framework" + [dev-dependencies.aleo-std-storage] version = "0.1.7" default-features = false diff --git a/compiler/parser/examples/parser.rs b/compiler/parser/examples/parser.rs index 8616f9674e..cf093f412d 100644 --- a/compiler/parser/examples/parser.rs +++ b/compiler/parser/examples/parser.rs @@ -26,8 +26,6 @@ use std::{ path::{Path, PathBuf}, }; -type CurrentNetwork = snarkvm::prelude::MainnetV0; - #[derive(Debug, Parser)] #[clap(name = "leo parser", about = "Parse Leo AST and store it as a JSON")] struct Opt { @@ -40,6 +38,10 @@ struct Opt { /// Whether to print result to STDOUT. #[clap(short, long)] print_stdout: bool, + + /// The network to use. Defaults to mainnet. + #[clap(long, default_value = "mainnet")] + pub(crate) network: String, } fn main() -> Result<(), String> { @@ -50,7 +52,15 @@ fn main() -> Result<(), String> { Handler::with(|h| { let node_builder = NodeBuilder::default(); - let ast = leo_parser::parse_ast::(h, &node_builder, &code.src, code.start_pos)?; + let ast = match opt.network.as_str() { + "mainnet" => { + leo_parser::parse_ast::(h, &node_builder, &code.src, code.start_pos) + } + "testnet" => { + leo_parser::parse_ast::(h, &node_builder, &code.src, code.start_pos) + } + _ => panic!("Invalid network"), + }?; let json = Ast::to_json_string(&ast)?; println!("{json}"); Ok(json) diff --git a/errors/src/errors/cli/cli_errors.rs b/errors/src/errors/cli/cli_errors.rs index 7e7519cca4..02c7ef23a9 100644 --- a/errors/src/errors/cli/cli_errors.rs +++ b/errors/src/errors/cli/cli_errors.rs @@ -93,7 +93,7 @@ create_messages!( @backtraced failed_to_load_instructions { args: (error: impl Display), - msg: format!("Failed to load compiled Aleo instructions into an Aleo file.\nSnarkVM Error: {error}"), + msg: format!("Failed to load compiled Aleo instructions into an Aleo file.\nError: {error}"), help: Some("Generated Aleo instructions have been left in `main.aleo`".to_string()), } @@ -107,84 +107,84 @@ create_messages!( @backtraced failed_to_execute_build { args: (error: impl Display), - msg: format!("Failed to execute the `build` command.\nSnarkVM Error: {error}"), + msg: format!("Failed to execute the `build` command.\nError: {error}"), help: None, } @backtraced failed_to_execute_new { args: (error: impl Display), - msg: format!("Failed to execute the `new` command.\nSnarkVM Error: {error}"), + msg: format!("Failed to execute the `new` command.\nError: {error}"), help: None, } @backtraced failed_to_execute_run { args: (error: impl Display), - msg: format!("Failed to execute the `run` command.\nSnarkVM Error: {error}"), + msg: format!("Failed to execute the `run` command.\nError: {error}"), help: None, } @backtraced failed_to_execute_node { args: (error: impl Display), - msg: format!("Failed to execute the `node` command.\nSnarkVM Error: {error}"), + msg: format!("Failed to execute the `node` command.\nError: {error}"), help: None, } @backtraced failed_to_execute_deploy { args: (error: impl Display), - msg: format!("Failed to execute the `deploy` command.\nSnarkVM Error: {error}"), + msg: format!("Failed to execute the `deploy` command.\nError: {error}"), help: None, } @backtraced failed_to_parse_new { args: (error: impl Display), - msg: format!("Failed to parse the `new` command.\nSnarkVM Error: {error}"), + msg: format!("Failed to parse the `new` command.\nError: {error}"), help: None, } @backtraced failed_to_parse_run { args: (error: impl Display), - msg: format!("Failed to parse the `run` command.\nSnarkVM Error: {error}"), + msg: format!("Failed to parse the `run` command.\nError: {error}"), help: None, } @backtraced failed_to_parse_node { args: (error: impl Display), - msg: format!("Failed to parse the `node` command.\nSnarkVM Error: {error}"), + msg: format!("Failed to parse the `node` command.\nError: {error}"), help: None, } @backtraced failed_to_parse_deploy { args: (error: impl Display), - msg: format!("Failed to parse the `deploy` command.\nSnarkVM Error: {error}"), + msg: format!("Failed to parse the `deploy` command.\nError: {error}"), help: None, } @backtraced failed_to_parse_execute { args: (error: impl Display), - msg: format!("Failed to parse the `execute` command.\nSnarkVM Error: {error}"), + msg: format!("Failed to parse the `execute` command.\nError: {error}"), help: None, } @backtraced failed_to_execute_execute { args: (error: impl Display), - msg: format!("Failed to execute the `execute` command.\nSnarkVM Error: {error}"), + msg: format!("Failed to execute the `execute` command.\nError: {error}"), help: None, } @backtraced failed_to_parse_seed { args: (error: impl Display), - msg: format!("Failed to parse the seed string for account.\nSnarkVM Error: {error}"), + msg: format!("Failed to parse the seed string for account.\nError: {error}"), help: None, } @@ -198,14 +198,14 @@ create_messages!( @backtraced failed_to_parse_private_key { args: (error: impl Display), - msg: format!("Failed to parse private key.\nSnarkVM Error: {error}"), + msg: format!("Failed to parse private key.\nError: {error}"), help: None, } @backtraced failed_to_execute_account { args: (error: impl Display), - msg: format!("Failed to execute the `account` command.\nSnarkVM Error: {error}"), + msg: format!("Failed to execute the `account` command.\nError: {error}"), help: None, } @@ -222,4 +222,25 @@ create_messages!( msg: "Cannot combine recursive deploy with private fee.".to_string(), help: None, } + + @backtraced + invalid_network_name { + args: (network: impl Display), + msg: format!("Invalid network name: {network}"), + help: Some("Valid network names are `testnet` and `mainnet`.".to_string()), + } + + @backtraced + invalid_example { + args: (example: impl Display), + msg: format!("Invalid Leo example: {example}"), + help: Some("Valid Leo examples are `lottery`, `tictactoe`, and `token`.".to_string()), + } + + @backtraced + build_error { + args: (error: impl Display), + msg: format!("Failed to build program: {error}"), + help: None, + } ); diff --git a/errors/src/errors/package/package_errors.rs b/errors/src/errors/package/package_errors.rs index f328648a9c..19546afbec 100644 --- a/errors/src/errors/package/package_errors.rs +++ b/errors/src/errors/package/package_errors.rs @@ -198,8 +198,8 @@ create_messages!( /// For when the package failed to initialize. @backtraced failed_to_initialize_package { - args: (package: impl Display, path: impl Debug), - msg: format!("failed to initialize package {package} {path:?}"), + args: (package: impl Display, path: impl Debug, error: impl Display), + msg: format!("Failed to initialize package {package} at {path:?}. Error: {error}"), help: None, } @@ -207,7 +207,7 @@ create_messages!( @backtraced invalid_package_name { args: (package: impl Display), - msg: format!("invalid project name {package}"), + msg: format!("Invalid project name {package}"), help: None, } @@ -397,4 +397,11 @@ create_messages!( msg: "The name of the program to execute on-chain is missing.".to_string(), help: Some("Either set `--local` to execute the local program on chain, or set `--program `.".to_string()), } + + @backtraced + failed_to_read_manifest_file { + args: (path: impl Display, error: impl ErrorArg), + msg: format!("Failed to read manifest file from the provided file path {path} - {error}"), + help: None, + } ); diff --git a/examples/battleship/.gitignore b/examples/battleship/.gitignore index 750b56f237..3aceddb0d8 100644 --- a/examples/battleship/.gitignore +++ b/examples/battleship/.gitignore @@ -1,4 +1,4 @@ outputs/ *.avm *.prover -*.verifier \ No newline at end of file +*.verifier diff --git a/examples/battleship/leo.lock b/examples/battleship/leo.lock deleted file mode 100644 index 1d3aa3990c..0000000000 --- a/examples/battleship/leo.lock +++ /dev/null @@ -1,20 +0,0 @@ -[[package]] -name = "board.aleo" -location = "local" -path = "board" -checksum = "da94274230d0c0c3deb96d80e07ad9db8bbf53264286c14cc3231b7a8b7ef380" -dependencies = [] - -[[package]] -name = "move.aleo" -location = "local" -path = "move" -checksum = "7d9fef5fe083eb24376e63935855e4ec709c17fb5ee46a0bb4594b0f9ef8eb08" -dependencies = [] - -[[package]] -name = "verify.aleo" -location = "local" -path = "verify" -checksum = "2c2035ebd70500b7e5a9a6198bed1a1163cd1ddfd09128db8f4c16cf23ad2c62" -dependencies = [] diff --git a/leo/cli/cli.rs b/leo/cli/cli.rs index 9f2b70b3bd..bc3b647821 100644 --- a/leo/cli/cli.rs +++ b/leo/cli/cli.rs @@ -54,7 +54,7 @@ enum Commands { }, #[clap(about = "Create a new Leo example package in a new directory")] Example { - #[clap(subcommand)] + #[clap(flatten)] command: Example, }, #[clap(about = "Run a program with input variables")] @@ -314,6 +314,8 @@ mod test_helpers { use leo_span::symbol::create_session_if_not_set_then; use std::path::Path; + const NETWORK: &str = "mainnet"; + pub(crate) fn sample_nested_package(temp_dir: &Path) { let name = "nested"; @@ -327,7 +329,7 @@ mod test_helpers { let new = CLI { debug: false, quiet: false, - command: Commands::New { command: New { name: name.to_string() } }, + command: Commands::New { command: New { name: name.to_string(), network: NETWORK.to_string() } }, path: Some(project_directory.clone()), home: None, }; @@ -395,7 +397,7 @@ function external_nested_function: command: Add { name: "nested_example_layer_0".to_string(), local: None, - network: "mainnet".to_string(), + network: NETWORK.to_string(), clear: false, }, }, @@ -428,7 +430,7 @@ function external_nested_function: let create_grandparent_project = CLI { debug: false, quiet: false, - command: Commands::New { command: New { name: "grandparent".to_string() } }, + command: Commands::New { command: New { name: "grandparent".to_string(), network: NETWORK.to_string() } }, path: Some(grandparent_directory.clone()), home: None, }; @@ -436,7 +438,7 @@ function external_nested_function: let create_parent_project = CLI { debug: false, quiet: false, - command: Commands::New { command: New { name: "parent".to_string() } }, + command: Commands::New { command: New { name: "parent".to_string(), network: NETWORK.to_string() } }, path: Some(parent_directory.clone()), home: None, }; @@ -444,7 +446,7 @@ function external_nested_function: let create_child_project = CLI { debug: false, quiet: false, - command: Commands::New { command: New { name: "child".to_string() } }, + command: Commands::New { command: New { name: "child".to_string(), network: NETWORK.to_string() } }, path: Some(child_directory.clone()), home: None, }; @@ -489,7 +491,7 @@ program child.aleo { command: Add { name: "parent".to_string(), local: Some(parent_directory.clone()), - network: "mainnet".to_string(), + network: NETWORK.to_string(), clear: false, }, }, @@ -504,7 +506,7 @@ program child.aleo { command: Add { name: "child".to_string(), local: Some(child_directory.clone()), - network: "mainnet".to_string(), + network: NETWORK.to_string(), clear: false, }, }, @@ -519,7 +521,7 @@ program child.aleo { command: Add { name: "child".to_string(), local: Some(child_directory.clone()), - network: "mainnet".to_string(), + network: NETWORK.to_string(), clear: false, }, }, @@ -559,7 +561,7 @@ program child.aleo { let create_outer_project = CLI { debug: false, quiet: false, - command: Commands::New { command: New { name: "outer".to_string() } }, + command: Commands::New { command: New { name: "outer".to_string(), network: NETWORK.to_string() } }, path: Some(outer_directory.clone()), home: None, }; @@ -567,7 +569,7 @@ program child.aleo { let create_inner_1_project = CLI { debug: false, quiet: false, - command: Commands::New { command: New { name: "inner_1".to_string() } }, + command: Commands::New { command: New { name: "inner_1".to_string(), network: NETWORK.to_string() } }, path: Some(inner_1_directory.clone()), home: None, }; @@ -575,7 +577,7 @@ program child.aleo { let create_inner_2_project = CLI { debug: false, quiet: false, - command: Commands::New { command: New { name: "inner_2".to_string() } }, + command: Commands::New { command: New { name: "inner_2".to_string(), network: NETWORK.to_string() } }, path: Some(inner_2_directory.clone()), home: None, }; @@ -643,7 +645,7 @@ program outer.aleo { command: Add { name: "inner_1".to_string(), local: Some(inner_1_directory.clone()), - network: "mainnet".to_string(), + network: NETWORK.to_string(), clear: false, }, }, @@ -658,7 +660,7 @@ program outer.aleo { command: Add { name: "inner_2".to_string(), local: Some(inner_2_directory.clone()), - network: "mainnet".to_string(), + network: NETWORK.to_string(), clear: false, }, }, @@ -697,7 +699,7 @@ program outer.aleo { let create_outer_project = CLI { debug: false, quiet: false, - command: Commands::New { command: New { name: "outer_2".to_string() } }, + command: Commands::New { command: New { name: "outer_2".to_string(), network: NETWORK.to_string() } }, path: Some(outer_directory.clone()), home: None, }; @@ -705,7 +707,7 @@ program outer.aleo { let create_inner_1_project = CLI { debug: false, quiet: false, - command: Commands::New { command: New { name: "inner_1".to_string() } }, + command: Commands::New { command: New { name: "inner_1".to_string(), network: NETWORK.to_string() } }, path: Some(inner_1_directory.clone()), home: None, }; @@ -713,7 +715,7 @@ program outer.aleo { let create_inner_2_project = CLI { debug: false, quiet: false, - command: Commands::New { command: New { name: "inner_2".to_string() } }, + command: Commands::New { command: New { name: "inner_2".to_string(), network: NETWORK.to_string() } }, path: Some(inner_2_directory.clone()), home: None, }; @@ -812,7 +814,7 @@ program outer_2.aleo { command: Add { name: "inner_1".to_string(), local: Some(inner_1_directory.clone()), - network: "mainnet".to_string(), + network: NETWORK.to_string(), clear: false, }, }, @@ -827,7 +829,7 @@ program outer_2.aleo { command: Add { name: "inner_2".to_string(), local: Some(inner_2_directory.clone()), - network: "mainnet".to_string(), + network: NETWORK.to_string(), clear: false, }, }, diff --git a/leo/cli/commands/account.rs b/leo/cli/commands/account.rs index 20d1752786..8951519c07 100644 --- a/leo/cli/commands/account.rs +++ b/leo/cli/commands/account.rs @@ -18,14 +18,15 @@ use super::*; use leo_errors::UtilError; use leo_package::root::Env; use snarkvm::{ - cli::dotenv_private_key, console::program::{Signature, ToFields, Value}, prelude::{Address, PrivateKey, ViewKey}, }; use crossterm::ExecutableCommand; +use leo_retriever::NetworkName; use rand::SeedableRng; use rand_chacha::ChaChaRng; +use snarkvm::prelude::{MainnetV0, Network, TestnetV0}; use std::{ io::{self, Read, Write}, path::PathBuf, @@ -46,23 +47,27 @@ pub enum Account { /// Print sensitive information (such as private key) discreetly to an alternate screen #[clap(long)] discreet: bool, + #[clap(short = 'n', long, help = "Name of the network to use", default_value = "mainnet")] + network: String, }, /// Derive an Aleo account from a private key. Import { /// Private key plaintext - private_key: Option>, + private_key: Option, /// Write the private key to the .env file. #[clap(short = 'w', long)] write: bool, /// Print sensitive information (such as private key) discreetly to an alternate screen #[clap(long)] discreet: bool, + #[clap(short = 'n', long, help = "Name of the network to use", default_value = "mainnet")] + network: String, }, /// Sign a message using your Aleo private key. Sign { /// Specify the account private key of the node #[clap(long = "private-key")] - private_key: Option>, + private_key: Option, /// Specify the path to a file containing the account private key of the node #[clap(long = "private-key-file")] private_key_file: Option, @@ -75,12 +80,14 @@ pub enum Account { /// When enabled, parses the message as bytes instead of Aleo literals #[clap(short = 'r', long)] raw: bool, + #[clap(short = 'n', long, help = "Name of the network to use", default_value = "mainnet")] + network: String, }, /// Verify a message from an Aleo address. Verify { /// Address to use for verification #[clap(short = 'a', long)] - address: Address, + address: String, /// Signature to verify #[clap(short = 's', long)] signature: String, @@ -90,6 +97,8 @@ pub enum Account { /// When enabled, parses the message as bytes instead of Aleo literals #[clap(short = 'r', long)] raw: bool, + #[clap(short = 'n', long, help = "Name of the network to use", default_value = "mainnet")] + network: String, }, } @@ -109,79 +118,43 @@ impl Command for Account { Self: Sized, { match self { - Account::New { seed, write, discreet } => { - // Sample a new Aleo account. - let private_key = match seed { - // Recover the field element deterministically. - Some(seed) => PrivateKey::new(&mut ChaChaRng::seed_from_u64(seed)), - // Sample a random field element. - None => PrivateKey::new(&mut ChaChaRng::from_entropy()), - } - .map_err(CliError::failed_to_parse_seed)?; - - // Derive the view key and address and print to stdout. - print_keys(private_key, discreet)?; - - // Save key data to .env file. - if write { - write_to_env_file(private_key, &ctx)?; - } + Account::New { seed, write, discreet, network } => { + // Parse the network. + let network = NetworkName::try_from(network.as_str())?; + match network { + NetworkName::MainnetV0 => generate_new_account::(seed, write, discreet, &ctx), + NetworkName::TestnetV0 => generate_new_account::(seed, write, discreet, &ctx), + }? } - Account::Import { private_key, write, discreet } => { - let priv_key = match discreet { - true => { - let private_key_input = rpassword::prompt_password("Please enter your private key: ").unwrap(); - snarkvm::prelude::FromStr::from_str(&private_key_input) - .map_err(CliError::failed_to_parse_private_key)? - } - false => match private_key { - Some(private_key) => private_key, - None => { - return Err(CliError::failed_to_execute_account( - "PRIVATE_KEY shouldn't be empty when --discreet is false", - ) - .into()); - } - }, - }; - // Derive the view key and address and print to stdout. - print_keys(priv_key, discreet)?; - - // Save key data to .env file. - if write { - write_to_env_file(priv_key, &ctx)?; - } + Account::Import { private_key, write, discreet, network } => { + // Parse the network. + let network = NetworkName::try_from(network.as_str())?; + match network { + NetworkName::MainnetV0 => import_account::(private_key, write, discreet, &ctx), + NetworkName::TestnetV0 => import_account::(private_key, write, discreet, &ctx), + }? } - Self::Sign { message, seed, raw, private_key, private_key_file } => { - let key = match (private_key, private_key_file) { - (Some(private_key), None) => private_key, - (None, Some(private_key_file)) => { - let path = private_key_file - .parse::() - .map_err(|e| CliError::cli_invalid_input(format!("invalid path - {e}")))?; - let key_str = std::fs::read_to_string(path).map_err(UtilError::failed_to_read_file)?; - PrivateKey::::from_str(key_str.trim()) - .map_err(|e| CliError::cli_invalid_input(format!("could not parse private key: {e}")))? + Self::Sign { message, seed, raw, private_key, private_key_file, network } => { + // Parse the network. + let network = NetworkName::try_from(network.as_str())?; + let result = match network { + NetworkName::MainnetV0 => { + sign_message::(message, seed, raw, private_key, private_key_file) } - (None, None) => { - // Attempt to pull private key from env, then .env file - match dotenvy::var("PRIVATE_KEY") - .map_or_else(|_| dotenv_private_key(), |key| PrivateKey::::from_str(&key)) - { - Ok(key) => key, - Err(_) => Err(CliError::cli_invalid_input( - "missing the '--private-key', '--private-key-file', PRIVATE_KEY env, or .env", - ))?, - } + NetworkName::TestnetV0 => { + sign_message::(message, seed, raw, private_key, private_key_file) } - (Some(_), Some(_)) => Err(CliError::cli_invalid_input( - "cannot specify both the '--private-key' and '--private-key-file' flags", - ))?, - }; - println!("{}", sign_message(key, message, seed, raw)?); + }?; + println!("{result}") } - Self::Verify { address, signature, message, raw } => { - println!("{}", verify_message(address, signature, message, raw)?) + Self::Verify { address, signature, message, raw, network } => { + // Parse the network. + let network = NetworkName::try_from(network.as_str())?; + let result = match network { + NetworkName::MainnetV0 => verify_message::(address, signature, message, raw), + NetworkName::TestnetV0 => verify_message::(address, signature, message, raw), + }?; + println!("{result}") } } Ok(()) @@ -190,10 +163,60 @@ impl Command for Account { // Helper functions +// Generate a new account. +fn generate_new_account(seed: Option, write: bool, discreet: bool, ctx: &Context) -> Result<()> { + // Sample a new Aleo account. + let private_key = match seed { + // Recover the field element deterministically. + Some(seed) => PrivateKey::::new(&mut ChaChaRng::seed_from_u64(seed)), + // Sample a random field element. + None => PrivateKey::new(&mut ChaChaRng::from_entropy()), + } + .map_err(CliError::failed_to_parse_seed)?; + + // Derive the view key and address and print to stdout. + print_keys(private_key, discreet)?; + + // Save key data to .env file. + if write { + write_to_env_file(private_key, ctx)?; + } + Ok(()) +} + +// Import an account. +fn import_account(private_key: Option, write: bool, discreet: bool, ctx: &Context) -> Result<()> { + let priv_key = match discreet { + true => { + let private_key_input = rpassword::prompt_password("Please enter your private key: ").unwrap(); + FromStr::from_str(&private_key_input).map_err(CliError::failed_to_parse_private_key)? + } + false => match private_key { + Some(private_key) => FromStr::from_str(&private_key).map_err(CliError::failed_to_parse_private_key)?, + None => { + return Err(CliError::failed_to_execute_account( + "PRIVATE_KEY shouldn't be empty when --discreet is false", + ) + .into()); + } + }, + }; + + // Derive the view key and address and print to stdout. + print_keys::(priv_key, discreet)?; + + // Save key data to .env file. + if write { + write_to_env_file::(priv_key, ctx)?; + } + + Ok(()) +} + // Print keys as a formatted string without log level. -fn print_keys(private_key: PrivateKey, discreet: bool) -> Result<()> { +fn print_keys(private_key: PrivateKey, discreet: bool) -> Result<()> { let view_key = ViewKey::try_from(&private_key)?; - let address = Address::::try_from(&view_key)?; + let address = Address::::try_from(&view_key)?; if !discreet { println!( @@ -209,14 +232,100 @@ fn print_keys(private_key: PrivateKey, discreet: bool) -> Result "### Do not share or lose this private key! Press any key to complete. ###", )?; println!("\n {:>12} {view_key}\n {:>12} {address}\n", "View Key".cyan().bold(), "Address".cyan().bold(),); + Ok(()) } +// Sign a message with an Aleo private key +pub(crate) fn sign_message( + message: String, + seed: Option, + raw: bool, + private_key: Option, + private_key_file: Option, +) -> Result { + let private_key = match (private_key, private_key_file) { + (Some(private_key), None) => PrivateKey::::from_str(private_key.trim()) + .map_err(|e| CliError::cli_invalid_input(format!("could not parse private key: {e}")))?, + (None, Some(private_key_file)) => { + let path = private_key_file + .parse::() + .map_err(|e| CliError::cli_invalid_input(format!("invalid path - {e}")))?; + let key_str = std::fs::read_to_string(path).map_err(UtilError::failed_to_read_file)?; + PrivateKey::::from_str(key_str.trim()) + .map_err(|e| CliError::cli_invalid_input(format!("could not parse private key: {e}")))? + } + (None, None) => { + // Attempt to pull private key from env, then .env file + match dotenvy::var("PRIVATE_KEY") { + Ok(key) => PrivateKey::::from_str(key.trim()) + .map_err(|e| CliError::cli_invalid_input(format!("could not parse private key: {e}")))?, + Err(_) => Err(CliError::cli_invalid_input( + "missing the '--private-key', '--private-key-file', PRIVATE_KEY env, or .env", + ))?, + } + } + (Some(_), Some(_)) => { + Err(CliError::cli_invalid_input("cannot specify both the '--private-key' and '--private-key-file' flags"))? + } + }; + // Recover the seed. + let mut rng = match seed { + // Recover the field element deterministically. + Some(seed) => ChaChaRng::seed_from_u64(seed), + // Sample a random field element. + None => ChaChaRng::from_entropy(), + }; + + // Sign the message + let signature = if raw { + private_key.sign_bytes(message.as_bytes(), &mut rng) + } else { + let fields = Value::::from_str(&message)? + .to_fields() + .map_err(|_| CliError::cli_invalid_input("Failed to parse a valid Aleo value"))?; + private_key.sign(&fields, &mut rng) + } + .map_err(|_| CliError::cli_runtime_error("Failed to sign the message"))? + .to_string(); + // Return the signature as a string + Ok(signature) +} + +// Verify a signature with an Aleo address +pub(crate) fn verify_message( + address: String, + signature: String, + message: String, + raw: bool, +) -> Result { + // Parse the address. + let address = Address::::from_str(&address)?; + + let signature = Signature::::from_str(&signature) + .map_err(|e| CliError::cli_invalid_input(format!("Failed to parse a valid signature: {e}")))?; + + // Verify the signature + let verified = if raw { + signature.verify_bytes(&address, message.as_bytes()) + } else { + let fields = Value::::from_str(&message)? + .to_fields() + .map_err(|_| CliError::cli_invalid_input("Failed to parse a valid Aleo value"))?; + signature.verify(&address, &fields) + }; + + // Return the verification result + match verified { + true => Ok("✅ The signature is valid".to_string()), + false => Err(CliError::cli_runtime_error("❌ The signature is invalid"))?, + } +} + // Write the network and private key to the .env file in project directory. -fn write_to_env_file(private_key: PrivateKey, ctx: &Context) -> Result<()> { - let data = format!("NETWORK=mainnet\nPRIVATE_KEY={private_key}\n"); +fn write_to_env_file(private_key: PrivateKey, ctx: &Context) -> Result<()> { let program_dir = ctx.dir()?; - Env::::from(data).write_to(&program_dir)?; + Env::::from(private_key).write_to(&program_dir)?; tracing::info!("✅ Private Key written to {}", program_dir.join(".env").display()); Ok(()) } @@ -242,155 +351,100 @@ fn wait_for_keypress() { std::io::stdin().read_exact(&mut single_key).unwrap(); } -// Sign a message with an Aleo private key -pub(crate) fn sign_message( - private_key: PrivateKey, - message: String, - seed: Option, - raw: bool, -) -> Result { - // Recover the seed. - let mut rng = match seed { - // Recover the field element deterministically. - Some(seed) => ChaChaRng::seed_from_u64(seed), - // Sample a random field element. - None => ChaChaRng::from_entropy(), - }; - - // Sign the message - let signature = if raw { - private_key.sign_bytes(message.as_bytes(), &mut rng) - } else { - let fields = Value::::from_str(&message)? - .to_fields() - .map_err(|_| CliError::cli_invalid_input("Failed to parse a valid Aleo value"))?; - private_key.sign(&fields, &mut rng) - } - .map_err(|_| CliError::cli_runtime_error("Failed to sign the message"))? - .to_string(); - // Return the signature as a string - Ok(signature) -} - -// Verify a signature with an Aleo address -pub(crate) fn verify_message( - address: Address, - signature: String, - message: String, - raw: bool, -) -> Result { - let signature = Signature::::from_str(&signature) - .map_err(|e| CliError::cli_invalid_input(format!("Failed to parse a valid signature: {e}")))?; - - // Verify the signature - let verified = if raw { - signature.verify_bytes(&address, message.as_bytes()) - } else { - let fields = Value::::from_str(&message)? - .to_fields() - .map_err(|_| CliError::cli_invalid_input("Failed to parse a valid Aleo value"))?; - signature.verify(&address, &fields) - }; - - // Return the verification result - match verified { - true => Ok("✅ The signature is valid".to_string()), - false => Err(CliError::cli_runtime_error("❌ The signature is invalid"))?, - } -} - #[cfg(test)] mod tests { use super::{sign_message, verify_message}; + type CurrentNetwork = snarkvm::prelude::MainnetV0; + #[test] fn test_signature_raw() { - let key = "APrivateKey1zkp61PAYmrYEKLtRWeWhUoDpFnGLNuHrCciSqN49T86dw3p".parse().unwrap(); + let key = "APrivateKey1zkp61PAYmrYEKLtRWeWhUoDpFnGLNuHrCciSqN49T86dw3p".to_string(); let message = "Hello, world!".to_string(); - assert!(sign_message(key, message, None, true).is_ok()); + assert!(sign_message::(message, None, true, Some(key), None).is_ok()); } #[test] fn test_signature() { - let key = "APrivateKey1zkp61PAYmrYEKLtRWeWhUoDpFnGLNuHrCciSqN49T86dw3p".parse().unwrap(); + let key = "APrivateKey1zkp61PAYmrYEKLtRWeWhUoDpFnGLNuHrCciSqN49T86dw3p".to_string(); let message = "5field".to_string(); - assert!(sign_message(key, message, None, false).is_ok()); + assert!(sign_message::(message, None, false, Some(key), None).is_ok()); } #[test] fn test_signature_fail() { - let key = "APrivateKey1zkp61PAYmrYEKLtRWeWhUoDpFnGLNuHrCciSqN49T86dw3p".parse().unwrap(); + let key = "APrivateKey1zkp61PAYmrYEKLtRWeWhUoDpFnGLNuHrCciSqN49T86dw3p".to_string(); let message = "not a literal value".to_string(); - assert!(sign_message(key, message, None, false).is_err()); + assert!(sign_message::(message, None, false, Some(key), None).is_err()); } #[test] fn test_seeded_signature_raw() { let seed = Some(38868010450269069); - let key = "APrivateKey1zkp61PAYmrYEKLtRWeWhUoDpFnGLNuHrCciSqN49T86dw3p".parse().unwrap(); + let key = "APrivateKey1zkp61PAYmrYEKLtRWeWhUoDpFnGLNuHrCciSqN49T86dw3p".to_string(); let message = "Hello, world!".to_string(); let expected = "sign175pmqldmkqw2nwp7wz7tfmpyqdnvzaq06mh8t2g22frsmrdtuvpf843p0wzazg27rwrjft8863vwn5a5cqgr97ldw69cyq53l0zlwqhesm5elrqqunzqzmac7kzutl6zk7mqht3c0m9kg4hklv7h2js0qmxavwnpuwyl4lzldl6prs4qeqy9wxyp8y44nnydg3h8sg6ue99qkevd26g"; - let actual = sign_message(key, message, seed, true).unwrap(); + let actual = sign_message::(message, seed, true, Some(key), None).unwrap(); assert_eq!(expected, actual); } #[test] fn test_seeded_signature() { let seed = Some(38868010450269069); - let key = "APrivateKey1zkp61PAYmrYEKLtRWeWhUoDpFnGLNuHrCciSqN49T86dw3p".parse().unwrap(); + let key = "APrivateKey1zkp61PAYmrYEKLtRWeWhUoDpFnGLNuHrCciSqN49T86dw3p".to_string(); let message = "5field".to_string(); let expected = "sign1ad29myqy8gv6xve2r6tuly39m63l2mpfpyvqkwdl2umxqek6q5qxmy63zmhjx75x90sqxq69u5ntzp25kp59e0hp4hj8l8085sg7vqlesm5elrqqunzqzmac7kzutl6zk7mqht3c0m9kg4hklv7h2js0qmxavwnpuwyl4lzldl6prs4qeqy9wxyp8y44nnydg3h8sg6ue99qk7v46re"; - let actual = sign_message(key, message, seed, false).unwrap(); + let actual = sign_message::(message, seed, false, Some(key), None).unwrap(); assert_eq!(expected, actual); } #[test] fn test_verify_raw() { // test signature of "Hello, world!" - let address = "aleo1zecnqchckrzw7dlsyf65g6z5le2rmys403ecwmcafrag0e030yxqrnlg8j".parse().unwrap(); + let address = "aleo1zecnqchckrzw7dlsyf65g6z5le2rmys403ecwmcafrag0e030yxqrnlg8j".to_string(); let signature = "sign1nnvrjlksrkxdpwsrw8kztjukzhmuhe5zf3srk38h7g32u4kqtqpxn3j5a6k8zrqcfx580a96956nsjvluzt64cqf54pdka9mgksfqp8esm5elrqqunzqzmac7kzutl6zk7mqht3c0m9kg4hklv7h2js0qmxavwnpuwyl4lzldl6prs4qeqy9wxyp8y44nnydg3h8sg6ue99qkwsnaqq".to_string(); let message = "Hello, world!".to_string(); - assert!(verify_message(address, signature, message, true).is_ok()); + assert!(verify_message::(address.clone(), signature, message, true).is_ok()); // test signature of "Hello, world!" against the message "Different Message" let signature = "sign1nnvrjlksrkxdpwsrw8kztjukzhmuhe5zf3srk38h7g32u4kqtqpxn3j5a6k8zrqcfx580a96956nsjvluzt64cqf54pdka9mgksfqp8esm5elrqqunzqzmac7kzutl6zk7mqht3c0m9kg4hklv7h2js0qmxavwnpuwyl4lzldl6prs4qeqy9wxyp8y44nnydg3h8sg6ue99qkwsnaqq".to_string(); let message = "Different Message".to_string(); - assert!(verify_message(address, signature, message, true).is_err()); + assert!(verify_message::(address.clone(), signature, message, true).is_err()); // test signature of "Hello, world!" against the wrong address let signature = "sign1nnvrjlksrkxdpwsrw8kztjukzhmuhe5zf3srk38h7g32u4kqtqpxn3j5a6k8zrqcfx580a96956nsjvluzt64cqf54pdka9mgksfqp8esm5elrqqunzqzmac7kzutl6zk7mqht3c0m9kg4hklv7h2js0qmxavwnpuwyl4lzldl6prs4qeqy9wxyp8y44nnydg3h8sg6ue99qkwsnaqq".to_string(); let message = "Hello, world!".to_string(); - let wrong_address = "aleo1uxl69laseuv3876ksh8k0nd7tvpgjt6ccrgccedpjk9qwyfensxst9ftg5".parse().unwrap(); - assert!(verify_message(wrong_address, signature, message, true).is_err()); + let wrong_address = "aleo1uxl69laseuv3876ksh8k0nd7tvpgjt6ccrgccedpjk9qwyfensxst9ftg5".to_string(); + assert!(verify_message::(wrong_address, signature, message, true).is_err()); // test a valid signature of "Different Message" let signature = "sign1424ztyt9hcm77nq450gvdszrvtg9kvhc4qadg4nzy9y0ah7wdqq7t36cxal42p9jj8e8pjpmc06lfev9nvffcpqv0cxwyr0a2j2tjqlesm5elrqqunzqzmac7kzutl6zk7mqht3c0m9kg4hklv7h2js0qmxavwnpuwyl4lzldl6prs4qeqy9wxyp8y44nnydg3h8sg6ue99qk3yrr50".to_string(); let message = "Different Message".to_string(); - assert!(verify_message(address, signature, message, true).is_ok()); + assert!(verify_message::(address, signature, message, true).is_ok()); } #[test] fn test_verify() { // test signature of 5u8 - let address = "aleo1zecnqchckrzw7dlsyf65g6z5le2rmys403ecwmcafrag0e030yxqrnlg8j".parse().unwrap(); + let address = "aleo1zecnqchckrzw7dlsyf65g6z5le2rmys403ecwmcafrag0e030yxqrnlg8j".to_string(); let signature = "sign1j7swjfnyujt2vme3ulu88wdyh2ddj85arh64qh6c6khvrx8wvsp8z9wtzde0sahqj2qwz8rgzt803c0ceega53l4hks2mf5sfsv36qhesm5elrqqunzqzmac7kzutl6zk7mqht3c0m9kg4hklv7h2js0qmxavwnpuwyl4lzldl6prs4qeqy9wxyp8y44nnydg3h8sg6ue99qkdetews".to_string(); let message = "5field".to_string(); - assert!(verify_message(address, signature, message, false).is_ok()); + assert!(verify_message::(address.clone(), signature, message, false).is_ok()); // test signature of 5u8 against the message 10u8 let signature = "sign1j7swjfnyujt2vme3ulu88wdyh2ddj85arh64qh6c6khvrx8wvsp8z9wtzde0sahqj2qwz8rgzt803c0ceega53l4hks2mf5sfsv36qhesm5elrqqunzqzmac7kzutl6zk7mqht3c0m9kg4hklv7h2js0qmxavwnpuwyl4lzldl6prs4qeqy9wxyp8y44nnydg3h8sg6ue99qkdetews".to_string(); let message = "10field".to_string(); - assert!(verify_message(address, signature, message, false).is_err()); + assert!(verify_message::(address.clone(), signature, message, false).is_err()); // test signature of 5u8 against the wrong address let signature = "sign1j7swjfnyujt2vme3ulu88wdyh2ddj85arh64qh6c6khvrx8wvsp8z9wtzde0sahqj2qwz8rgzt803c0ceega53l4hks2mf5sfsv36qhesm5elrqqunzqzmac7kzutl6zk7mqht3c0m9kg4hklv7h2js0qmxavwnpuwyl4lzldl6prs4qeqy9wxyp8y44nnydg3h8sg6ue99qkdetews".to_string(); let message = "5field".to_string(); - let wrong_address = "aleo1uxl69laseuv3876ksh8k0nd7tvpgjt6ccrgccedpjk9qwyfensxst9ftg5".parse().unwrap(); - assert!(verify_message(wrong_address, signature, message, false).is_err()); + let wrong_address = "aleo1uxl69laseuv3876ksh8k0nd7tvpgjt6ccrgccedpjk9qwyfensxst9ftg5".to_string(); + assert!(verify_message::(wrong_address, signature, message, false).is_err()); // test a valid signature of 10u8 let signature = "sign1t9v2t5tljk8pr5t6vkcqgkus0a3v69vryxmfrtwrwg0xtj7yv5qj2nz59e5zcyl50w23lhntxvt6vzeqfyu6dt56698zvfj2l6lz6q0esm5elrqqunzqzmac7kzutl6zk7mqht3c0m9kg4hklv7h2js0qmxavwnpuwyl4lzldl6prs4qeqy9wxyp8y44nnydg3h8sg6ue99qk8rh9kt".to_string(); let message = "10field".to_string(); - assert!(verify_message(address, signature, message, false).is_ok()); + assert!(verify_message::(address, signature, message, false).is_ok()); } } diff --git a/leo/cli/commands/add.rs b/leo/cli/commands/add.rs index 6ac1f27b59..54720807eb 100755 --- a/leo/cli/commands/add.rs +++ b/leo/cli/commands/add.rs @@ -59,12 +59,10 @@ impl Command for Add { // Make sure the program name is valid. // Allow both `credits.aleo` and `credits` syntax. let name: String = match &self.name { - name if name.ends_with(".aleo") - && Package::::is_aleo_name_valid(&name[0..self.name.len() - 5]) => - { + name if name.ends_with(".aleo") && Package::is_aleo_name_valid(&name[0..self.name.len() - 5]) => { name.clone() } - name if Package::::is_aleo_name_valid(name) => format!("{name}.aleo"), + name if Package::is_aleo_name_valid(name) => format!("{name}.aleo"), name => return Err(PackageError::invalid_file_name_dependency(name).into()), }; @@ -113,7 +111,7 @@ impl Command for Add { } None => { tracing::info!("✅ Added network dependency to program `{name}` from network `{}`.", self.network); - Dependency::new(name, Location::Network, Some(NetworkName::from(&self.network)), None) + Dependency::new(name, Location::Network, Some(NetworkName::try_from(self.network.as_str())?), None) } }); @@ -125,9 +123,7 @@ impl Command for Add { manifest.license(), Some(dependencies), ); - let new_manifest_data = serde_json::to_string_pretty(&new_manifest) - .map_err(|err| PackageError::failed_to_serialize_manifest_file(path.to_str().unwrap(), err))?; - std::fs::write(path.join("program.json"), new_manifest_data).map_err(PackageError::failed_to_write_manifest)?; + new_manifest.write_to_dir(&path)?; Ok(()) } diff --git a/leo/cli/commands/build.rs b/leo/cli/commands/build.rs index b4b1047727..1999df9f79 100644 --- a/leo/cli/commands/build.rs +++ b/leo/cli/commands/build.rs @@ -18,17 +18,21 @@ use super::*; use leo_ast::Stub; use leo_compiler::{Compiler, CompilerOptions, OutputOptions}; -use leo_errors::UtilError; +use leo_errors::{CliError, UtilError}; use leo_package::{build::BuildDirectory, outputs::OutputsDirectory, source::SourceDirectory}; -use leo_retriever::Retriever; +use leo_retriever::{Manifest, NetworkName, Retriever}; use leo_span::Symbol; -use snarkvm::{package::Package, prelude::ProgramID}; +use snarkvm::{ + package::Package, + prelude::{MainnetV0, Network, ProgramID, TestnetV0}, +}; use indexmap::IndexMap; use std::{ io::Write, path::{Path, PathBuf}, + str::FromStr, }; impl From for CompilerOptions { @@ -88,101 +92,96 @@ impl Command for Build { } fn apply(self, context: Context, _: Self::Input) -> Result { - // Get the package path. - let package_path = context.dir()?; - let home_path = context.home()?; + // Parse the network. + let network = NetworkName::try_from(self.options.network.as_str())?; + match network { + NetworkName::MainnetV0 => handle_build::(&self, context), + NetworkName::TestnetV0 => handle_build::(&self, context), + } + } +} - // Open the build directory. - let build_directory = BuildDirectory::create(&package_path)?; +// A helper function to handle the build command. +fn handle_build(command: &Build, context: Context) -> Result<::Output> { + // Get the package path. + let package_path = context.dir()?; + let home_path = context.home()?; - // Get the program id. - let manifest = context.open_manifest()?; - let program_id = manifest.program_id(); + // Get the program id. + let manifest = Manifest::read_from_dir(&package_path)?; + let program_id = ProgramID::::from_str(manifest.program())?; - // Initialize error handler - let handler = Handler::default(); + // Clear and recreate the build directory. + let build_directory = package_path.join("build"); + if build_directory.exists() { + std::fs::remove_dir_all(&build_directory).map_err(CliError::build_error)?; + } + Package::create(&build_directory, &program_id).map_err(CliError::build_error)?; - // Retrieve all local dependencies in post order - let main_sym = Symbol::intern(&program_id.name().to_string()); - let mut retriever = - Retriever::::new(main_sym, &package_path, &home_path, self.options.endpoint.clone()) - .map_err(|err| UtilError::failed_to_retrieve_dependencies(err, Default::default()))?; - let mut local_dependencies = - retriever.retrieve().map_err(|err| UtilError::failed_to_retrieve_dependencies(err, Default::default()))?; + // Initialize error handler + let handler = Handler::default(); - // Push the main program at the end of the list to be compiled after all of its dependencies have been processed - local_dependencies.push(main_sym); + // Retrieve all local dependencies in post order + let main_sym = Symbol::intern(&program_id.name().to_string()); + let mut retriever = Retriever::::new(main_sym, &package_path, &home_path, command.options.endpoint.clone()) + .map_err(|err| UtilError::failed_to_retrieve_dependencies(err, Default::default()))?; + let mut local_dependencies = + retriever.retrieve().map_err(|err| UtilError::failed_to_retrieve_dependencies(err, Default::default()))?; - // Recursive build will recursively compile all local dependencies. Can disable to save compile time. - let recursive_build = !self.options.non_recursive; + // Push the main program at the end of the list to be compiled after all of its dependencies have been processed + local_dependencies.push(main_sym); - // Loop through all local dependencies and compile them in order - for dependency in local_dependencies.into_iter() { - if recursive_build || dependency == main_sym { - // Get path to the local project - let (local_path, stubs) = retriever.prepare_local(dependency)?; + // Recursive build will recursively compile all local dependencies. Can disable to save compile time. + let recursive_build = !command.options.non_recursive; - // Create the outputs directory. - let local_outputs_directory = OutputsDirectory::create(&local_path)?; + // Loop through all local dependencies and compile them in order + for dependency in local_dependencies.into_iter() { + if recursive_build || dependency == main_sym { + // Get path to the local project + let (local_path, stubs) = retriever.prepare_local(dependency)?; - // Open the build directory. - let local_build_directory = BuildDirectory::create(&local_path)?; + // Create the outputs directory. + let local_outputs_directory = OutputsDirectory::create(&local_path)?; - // Fetch paths to all .leo files in the source directory. - let local_source_files = SourceDirectory::files(&local_path)?; + // Open the build directory. + let local_build_directory = BuildDirectory::create(&local_path)?; - // Check the source files. - SourceDirectory::check_files(&local_source_files)?; + // Fetch paths to all .leo files in the source directory. + let local_source_files = SourceDirectory::files(&local_path)?; - // Compile all .leo files into .aleo files. - for file_path in local_source_files { - compile_leo_file( - file_path, - &ProgramID::::try_from(format!("{}.aleo", dependency)) - .map_err(|_| UtilError::snarkvm_error_building_program_id(Default::default()))?, - &local_outputs_directory, - &local_build_directory, - &handler, - self.options.clone(), - stubs.clone(), - )?; - } + // Check the source files. + SourceDirectory::check_files(&local_source_files)?; + + // Compile all .leo files into .aleo files. + for file_path in local_source_files { + compile_leo_file( + file_path, + &ProgramID::::try_from(format!("{}.aleo", dependency)) + .map_err(|_| UtilError::snarkvm_error_building_program_id(Default::default()))?, + &local_outputs_directory, + &local_build_directory, + &handler, + command.options.clone(), + stubs.clone(), + )?; } - - // Writes `leo.lock` as well as caches objects (when target is an intermediate dependency) - retriever.process_local(dependency, recursive_build)?; } - // `Package::open` checks that the build directory and that `main.aleo` and all imported files are well-formed. - Package::::open(&build_directory).map_err(CliError::failed_to_execute_build)?; - - // // Unset the Leo panic hook. - // let _ = std::panic::take_hook(); - // - // // Change the cwd to the build directory to compile aleo files. - // std::env::set_current_dir(&build_directory) - // .map_err(|err| PackageError::failed_to_set_cwd(build_directory.display(), err))?; - // - // // Call the `build` command. - // let mut args = vec![SNARKVM_COMMAND]; - // if self.options.offline { - // args.push("--offline"); - // } - // let command = AleoBuild::try_parse_from(&args).map_err(CliError::failed_to_execute_aleo_build)?; - // let result = command.parse().map_err(CliError::failed_to_execute_aleo_build)?; - // - // // Log the result of the build - // tracing::info!("{}", result); - - Ok(()) + // Writes `leo.lock` as well as caches objects (when target is an intermediate dependency) + retriever.process_local(dependency, recursive_build)?; } + + // `Package::open` checks that the build directory and that `main.aleo` and all imported files are well-formed. + Package::::open(&build_directory).map_err(CliError::failed_to_execute_build)?; + + Ok(()) } /// Compiles a Leo file in the `src/` directory. #[allow(clippy::too_many_arguments)] -fn compile_leo_file( +fn compile_leo_file( file_path: PathBuf, - program_id: &ProgramID, + program_id: &ProgramID, outputs: &Path, build: &Path, handler: &Handler, @@ -197,7 +196,7 @@ fn compile_leo_file( aleo_file_path.push(format!("main.{}", program_id.network())); // Create a new instance of the Leo compiler. - let mut compiler = Compiler::::new( + let mut compiler = Compiler::::new( program_name.clone(), program_id.network().to_string(), handler, diff --git a/leo/cli/commands/deploy.rs b/leo/cli/commands/deploy.rs index 1a444d0782..64ed03fad1 100644 --- a/leo/cli/commands/deploy.rs +++ b/leo/cli/commands/deploy.rs @@ -15,8 +15,12 @@ // along with the Leo library. If not, see . use super::*; +use leo_retriever::NetworkName; use snarkos_cli::commands::{Deploy as SnarkOSDeploy, Developer}; -use snarkvm::cli::helpers::dotenv_private_key; +use snarkvm::{ + cli::helpers::dotenv_private_key, + prelude::{MainnetV0, TestnetV0}, +}; use std::path::PathBuf; /// Deploys an Aleo program. @@ -54,8 +58,13 @@ impl Command for Deploy { } fn apply(self, context: Context, _: Self::Input) -> Result { + // Parse the network. + let network = NetworkName::try_from(self.compiler_options.network.as_str())?; // Get the program name. - let project_name = context.open_manifest()?.program_id().to_string(); + let project_name = match network { + NetworkName::MainnetV0 => context.open_manifest::()?.program_id().to_string(), + NetworkName::TestnetV0 => context.open_manifest::()?.program_id().to_string(), + }; // Get the private key. let mut private_key = self.fee_options.private_key; @@ -88,10 +97,12 @@ impl Command for Deploy { self.compiler_options.endpoint.clone(), "--priority-fee".to_string(), self.fee_options.priority_fee.to_string(), + "--network".to_string(), + network.id().to_string(), "--path".to_string(), path.to_str().unwrap().parse().unwrap(), "--broadcast".to_string(), - format!("{}/{}/transaction/broadcast", self.compiler_options.endpoint, self.fee_options.network) + format!("{}/{}/transaction/broadcast", self.compiler_options.endpoint, self.compiler_options.network) .to_string(), name.clone(), ]; diff --git a/leo/cli/commands/example.rs b/leo/cli/commands/example.rs index 7952cfa85f..3c759fe077 100644 --- a/leo/cli/commands/example.rs +++ b/leo/cli/commands/example.rs @@ -18,15 +18,13 @@ use super::*; use std::fs; -/// The example programs that can be generated. +/// Initialize a new Leo example. #[derive(Parser, Debug)] -pub enum Example { - #[clap(name = "lottery", about = "A public lottery program")] - Lottery, - #[clap(name = "tictactoe", about = "A standard tic-tac-toe game program")] - TicTacToe, - #[clap(name = "token", about = "A transparent & shielded custom token program")] - Token, +pub struct Example { + #[clap(name = "NAME", help = "The example to initialize.")] + pub(crate) name: String, + #[clap(short = 'n', long, help = "Name of the network to use", default_value = "mainnet")] + pub(crate) network: String, } impl Command for Example { @@ -34,8 +32,8 @@ impl Command for Example { type Output = (); fn prelude(&self, context: Context) -> Result { - // Run leo new EXAMPLE_NAME - (New { name: self.name() }).execute(context) + // Run leo new --network + (New { name: self.name.clone(), network: self.network.clone() }).execute(context) } fn apply(self, context: Context, _: Self::Input) -> Result @@ -44,22 +42,26 @@ impl Command for Example { { let package_dir = context.dir()?; + // Parse the example variant. + let example_variant = + ExampleVariant::try_from(self.name.as_str()).map_err(|_| CliError::invalid_example(self.name.as_str()))?; + // Write the main file. let main_file_path = package_dir.join("src").join("main.leo"); - fs::write(main_file_path, self.main_file_string()).map_err(CliError::failed_to_write_file)?; + fs::write(main_file_path, example_variant.main_file_string()).map_err(CliError::failed_to_write_file)?; // Write the README file. let readme_file_path = package_dir.join("README.md"); let readme_file_path_string = readme_file_path.display().to_string(); - fs::write(readme_file_path, self.readme_file_string()).map_err(CliError::failed_to_write_file)?; + fs::write(readme_file_path, example_variant.readme_file_string()).map_err(CliError::failed_to_write_file)?; // Write the run.sh file. let run_file_path = package_dir.join("run.sh"); - fs::write(run_file_path, self.run_file_string()).map_err(CliError::failed_to_write_file)?; + fs::write(run_file_path, example_variant.run_file_string()).map_err(CliError::failed_to_write_file)?; tracing::info!( "🚀 To run the '{}' program follow the instructions at {}", - self.name().bold(), + example_variant.name().bold(), readme_file_path_string ); @@ -67,12 +69,23 @@ impl Command for Example { } } -impl Example { +/// The example programs that can be generated. +#[derive(Parser, Debug, Copy, Clone)] +pub enum ExampleVariant { + #[clap(name = "lottery", about = "A public lottery program")] + Lottery, + #[clap(name = "tictactoe", about = "A standard tic-tac-toe game program")] + TicTacToe, + #[clap(name = "token", about = "A transparent & shielded custom token program")] + Token, +} + +impl ExampleVariant { fn name(&self) -> String { match self { - Example::Lottery => "lottery".to_string(), - Example::TicTacToe => "tictactoe".to_string(), - Example::Token => "token".to_string(), + Self::Lottery => "lottery".to_string(), + Self::TicTacToe => "tictactoe".to_string(), + Self::Token => "token".to_string(), } } @@ -112,3 +125,16 @@ impl Example { } } } + +impl TryFrom<&str> for ExampleVariant { + type Error = (); + + fn try_from(value: &str) -> std::result::Result { + match value { + "lottery" => Ok(Self::Lottery), + "tictactoe" => Ok(Self::TicTacToe), + "token" => Ok(Self::Token), + _ => Err(()), + } + } +} diff --git a/leo/cli/commands/execute.rs b/leo/cli/commands/execute.rs index b7b135081b..ee60e34f9b 100644 --- a/leo/cli/commands/execute.rs +++ b/leo/cli/commands/execute.rs @@ -16,10 +16,11 @@ use super::*; use clap::Parser; +use leo_retriever::NetworkName; use snarkos_cli::commands::{Developer, Execute as SnarkOSExecute}; use snarkvm::{ cli::{helpers::dotenv_private_key, Execute as SnarkVMExecute}, - prelude::Parser as SnarkVMParser, + prelude::{MainnetV0, Network, Parser as SnarkVMParser, TestnetV0}, }; /// Build, Prove and Run Leo program with inputs @@ -60,132 +61,144 @@ impl Command for Execute { } fn apply(self, context: Context, _input: Self::Input) -> Result { - // If the `broadcast` flag is set, then broadcast the transaction. - if self.broadcast { - // Get the program name. - let program_name = match (self.program, self.local) { - (Some(name), true) => { - let local = context.open_manifest()?.program_id().to_string(); - // Throw error if local name doesn't match the specified name. - if name == local { - local - } else { - return Err(PackageError::conflicting_on_chain_program_name(local, name).into()); - } - } - (Some(name), false) => name, - (None, true) => context.open_manifest()?.program_id().to_string(), - (None, false) => return Err(PackageError::missing_on_chain_program_name().into()), - }; - - // Get the private key. - let private_key = match self.fee_options.private_key { - Some(private_key) => private_key, - None => dotenv_private_key().map_err(CliError::failed_to_read_environment_private_key)?.to_string(), - }; - - // Set deploy arguments. - let mut fee_args = vec![ - "snarkos".to_string(), - "--private-key".to_string(), - private_key.clone(), - "--query".to_string(), - self.compiler_options.endpoint.clone(), - "--priority-fee".to_string(), - self.fee_options.priority_fee.to_string(), - "--broadcast".to_string(), - format!("{}/{}/transaction/broadcast", self.compiler_options.endpoint, self.fee_options.network) - .to_string(), - ]; - - // Use record as payment option if it is provided. - if let Some(record) = self.fee_options.record.clone() { - fee_args.push("--record".to_string()); - fee_args.push(record); - }; - - // Execute program. - Developer::Execute( - SnarkOSExecute::try_parse_from( - [ - // The arguments for determining fee. - fee_args, - // The program ID and function name. - vec![program_name, self.name], - // The function inputs. - self.inputs, - ] - .concat(), - ) - .unwrap(), - ) - .parse() - .map_err(CliError::failed_to_execute_deploy)?; - - return Ok(()); + // Parse the network. + let network = NetworkName::try_from(self.compiler_options.network.as_str())?; + match network { + NetworkName::MainnetV0 => handle_execute::(self, context), + NetworkName::TestnetV0 => handle_execute::(self, context), } - - // If input values are provided, then run the program with those inputs. - // Otherwise, use the input file. - let mut inputs = self.inputs; - - // Compose the `execute` command. - let mut arguments = vec![SNARKVM_COMMAND.to_string(), self.name]; - - // Add the inputs to the arguments. - match self.file { - Some(file) => { - // Get the contents from the file. - let path = context.dir()?.join(file); - let raw_content = std::fs::read_to_string(&path) - .map_err(|err| PackageError::failed_to_read_file(path.display(), err))?; - // Parse the values from the file. - let mut content = raw_content.as_str(); - let mut values = vec![]; - while let Ok((remaining, value)) = snarkvm::prelude::Value::::parse(content) { - content = remaining; - values.push(value); - } - // Check that the remaining content is empty. - if !content.trim().is_empty() { - return Err(PackageError::failed_to_read_input_file(path.display()).into()); - } - // Convert the values to strings. - let mut inputs_from_file = values.into_iter().map(|value| value.to_string()).collect::>(); - // Add the inputs from the file to the arguments. - arguments.append(&mut inputs_from_file); - } - None => arguments.append(&mut inputs), - } - - // Add the compiler options to the arguments. - if self.compiler_options.offline { - arguments.push(String::from("--offline")); - } - - // Add the endpoint to the arguments. - arguments.push(String::from("--endpoint")); - arguments.push(self.compiler_options.endpoint.clone()); - - // Open the Leo build/ directory. - let path = context.dir()?; - let build_directory = BuildDirectory::open(&path)?; - - // Change the cwd to the Leo build/ directory to compile aleo files. - std::env::set_current_dir(&build_directory) - .map_err(|err| PackageError::failed_to_set_cwd(build_directory.display(), err))?; - - // Unset the Leo panic hook. - let _ = std::panic::take_hook(); - - // Call the `execute` command. - println!(); - let command = SnarkVMExecute::try_parse_from(&arguments).map_err(CliError::failed_to_parse_execute)?; - let res = command.parse().map_err(CliError::failed_to_execute_execute)?; - - // Log the output of the `execute` command. - tracing::info!("{}", res); - - Ok(()) } } + +// A helper function to handle the `execute` command. +fn handle_execute(command: Execute, context: Context) -> Result<::Output> { + // If the `broadcast` flag is set, then broadcast the transaction. + if command.broadcast { + // Get the program name. + let program_name = match (command.program, command.local) { + (Some(name), true) => { + let local = context.open_manifest::()?.program_id().to_string(); + // Throw error if local name doesn't match the specified name. + if name == local { + local + } else { + return Err(PackageError::conflicting_on_chain_program_name(local, name).into()); + } + } + (Some(name), false) => name, + (None, true) => context.open_manifest::()?.program_id().to_string(), + (None, false) => return Err(PackageError::missing_on_chain_program_name().into()), + }; + + // Get the private key. + let private_key = match command.fee_options.private_key { + Some(private_key) => private_key, + None => dotenv_private_key().map_err(CliError::failed_to_read_environment_private_key)?.to_string(), + }; + + // Set deploy arguments. + let mut fee_args = vec![ + "snarkos".to_string(), + "--private-key".to_string(), + private_key.clone(), + "--query".to_string(), + command.compiler_options.endpoint.clone(), + "--priority-fee".to_string(), + command.fee_options.priority_fee.to_string(), + "--network".to_string(), + N::ID.to_string(), + "--broadcast".to_string(), + format!("{}/{}/transaction/broadcast", command.compiler_options.endpoint, command.compiler_options.network) + .to_string(), + ]; + + // Use record as payment option if it is provided. + if let Some(record) = command.fee_options.record.clone() { + fee_args.push("--record".to_string()); + fee_args.push(record); + }; + + // Execute program. + Developer::Execute( + SnarkOSExecute::try_parse_from( + [ + // The arguments for determining fee. + fee_args, + // The program ID and function name. + vec![program_name, command.name], + // The function inputs. + command.inputs, + ] + .concat(), + ) + .unwrap(), + ) + .parse() + .map_err(CliError::failed_to_execute_deploy)?; + + return Ok(()); + } + + // If input values are provided, then run the program with those inputs. + // Otherwise, use the input file. + let mut inputs = command.inputs; + + // Compose the `execute` command. + let mut arguments = vec![SNARKVM_COMMAND.to_string(), command.name]; + + // Add the inputs to the arguments. + match command.file { + Some(file) => { + // Get the contents from the file. + let path = context.dir()?.join(file); + let raw_content = + std::fs::read_to_string(&path).map_err(|err| PackageError::failed_to_read_file(path.display(), err))?; + // Parse the values from the file. + let mut content = raw_content.as_str(); + let mut values = vec![]; + while let Ok((remaining, value)) = snarkvm::prelude::Value::::parse(content) { + content = remaining; + values.push(value); + } + // Check that the remaining content is empty. + if !content.trim().is_empty() { + return Err(PackageError::failed_to_read_input_file(path.display()).into()); + } + // Convert the values to strings. + let mut inputs_from_file = values.into_iter().map(|value| value.to_string()).collect::>(); + // Add the inputs from the file to the arguments. + arguments.append(&mut inputs_from_file); + } + None => arguments.append(&mut inputs), + } + + // Add the compiler options to the arguments. + if command.compiler_options.offline { + arguments.push(String::from("--offline")); + } + + // Add the endpoint to the arguments. + arguments.push(String::from("--endpoint")); + arguments.push(command.compiler_options.endpoint.clone()); + + // Open the Leo build/ directory. + let path = context.dir()?; + let build_directory = BuildDirectory::open(&path)?; + + // Change the cwd to the Leo build/ directory to compile aleo files. + std::env::set_current_dir(&build_directory) + .map_err(|err| PackageError::failed_to_set_cwd(build_directory.display(), err))?; + + // Unset the Leo panic hook. + let _ = std::panic::take_hook(); + + // Call the `execute` command. + println!(); + let command = SnarkVMExecute::try_parse_from(&arguments).map_err(CliError::failed_to_parse_execute)?; + let res = command.parse().map_err(CliError::failed_to_execute_execute)?; + + // Log the output of the `execute` command. + tracing::info!("{}", res); + + Ok(()) +} diff --git a/leo/cli/commands/mod.rs b/leo/cli/commands/mod.rs index ee457f71c9..e71415a2bc 100644 --- a/leo/cli/commands/mod.rs +++ b/leo/cli/commands/mod.rs @@ -126,10 +126,12 @@ pub trait Command { /// Compiler Options wrapper for Build command. Also used by other commands which /// require Build command output as their input. -#[derive(Parser, Clone, Debug, Default)] +#[derive(Parser, Clone, Debug)] pub struct BuildOptions { #[clap(long, help = "Endpoint to retrieve network state from.", default_value = "http://api.explorer.aleo.org/v1")] pub endpoint: String, + #[clap(long, help = "Network to broadcast to. Defaults to mainnet.", default_value = "mainnet")] + pub(crate) network: String, #[clap(long, help = "Does not recursively compile dependencies.")] pub non_recursive: bool, #[clap(long, help = "Enables offline mode.")] @@ -168,14 +170,39 @@ pub struct BuildOptions { pub disable_conditional_branch_type_checking: bool, } +impl Default for BuildOptions { + fn default() -> Self { + Self { + endpoint: "http://api.explorer.aleo.org/v1".to_string(), + network: "mainnet".to_string(), + non_recursive: false, + offline: false, + enable_symbol_table_spans: false, + enable_initial_symbol_table_snapshot: false, + enable_type_checked_symbol_table_snapshot: false, + enable_unrolled_symbol_table_snapshot: false, + enable_ast_spans: false, + enable_dce: false, + enable_all_ast_snapshots: false, + enable_initial_ast_snapshot: false, + enable_unrolled_ast_snapshot: false, + enable_ssa_ast_snapshot: false, + enable_flattened_ast_snapshot: false, + enable_destructured_ast_snapshot: false, + enable_inlined_ast_snapshot: false, + enable_dce_ast_snapshot: false, + conditional_block_max_depth: 10, + disable_conditional_branch_type_checking: false, + } + } +} + /// On Chain Execution Options to set preferences for keys, fees and networks. /// Used by Execute and Deploy commands. -#[derive(Parser, Clone, Debug, Default)] +#[derive(Parser, Clone, Debug)] pub struct FeeOptions { #[clap(long, help = "Priority fee in microcredits. Defaults to 0.", default_value = "0")] pub(crate) priority_fee: String, - #[clap(long, help = "Network to broadcast to. Defaults to mainnet.", default_value = "mainnet")] - pub(crate) network: String, #[clap(long, help = "Private key to authorize fee expenditure.")] pub(crate) private_key: Option, #[clap( @@ -185,3 +212,9 @@ pub struct FeeOptions { )] record: Option, } + +impl Default for FeeOptions { + fn default() -> Self { + Self { priority_fee: "0".to_string(), private_key: None, record: None } + } +} diff --git a/leo/cli/commands/new.rs b/leo/cli/commands/new.rs index 0b4fe2528a..6b494bc2c4 100644 --- a/leo/cli/commands/new.rs +++ b/leo/cli/commands/new.rs @@ -15,14 +15,17 @@ // along with the Leo library. If not, see . use super::*; +use snarkvm::prelude::{MainnetV0, TestnetV0}; -use snarkvm::{cli::New as SnarkVMNew, file::AleoFile}; +use leo_retriever::NetworkName; /// Create new Leo project #[derive(Parser, Debug)] pub struct New { #[clap(name = "NAME", help = "Set package name")] pub(crate) name: String, + #[clap(short = 'n', long, help = "Name of the network to use", default_value = "mainnet")] + pub(crate) network: String, } impl Command for New { @@ -38,55 +41,21 @@ impl Command for New { } fn apply(self, context: Context, _: Self::Input) -> Result { + // Parse the network. + let network = NetworkName::try_from(self.network.as_str())?; + // Derive the location of the parent directory to the project. - let mut package_path = context.parent_dir()?; + let package_path = context.parent_dir()?; // Change the cwd to the Leo package directory to initialize all files. std::env::set_current_dir(&package_path) .map_err(|err| PackageError::failed_to_set_cwd(package_path.display(), err))?; - // Call the `aleo new` command from the Aleo SDK. - let command = - SnarkVMNew::try_parse_from([SNARKVM_COMMAND, &self.name]).map_err(CliError::failed_to_parse_new)?; - let result = command.parse().map_err(CliError::failed_to_execute_new)?; - - // Log the output of the `aleo new` command. - tracing::info!("{}", result); - - // Initialize the Leo package in the directory created by `aleo new`. - package_path.push(&self.name); - std::env::set_current_dir(&package_path) - .map_err(|err| PackageError::failed_to_set_cwd(package_path.display(), err))?; - Package::::initialize(&self.name, &package_path)?; - - // Open the program manifest. - let manifest = context.open_manifest()?; - - // Create a path to the build directory. - let mut build_directory = package_path.clone(); - build_directory.push(BUILD_DIRECTORY_NAME); - - // Write the Aleo file into the build directory. - AleoFile::create(&build_directory, manifest.program_id(), true) - .map_err(PackageError::failed_to_create_aleo_file)?; - - // build_aleo_file.push(AleoFile::::main_file_name()); - // - // println!("{}", build_aleo_file.display()); - // - // - // std::fs::File::create(build_aleo_file).map_err() - // aleo_file.write_to(&build_aleo_file).map_err(PackageError::failed_to_write_aleo_file)?; - - // Open the `main.aleo` file path. - let aleo_file = AleoFile::open(&package_path, manifest.program_id(), true) - .map_err(PackageError::failed_to_open_aleo_file)?; - - let mut aleo_file_path = package_path.clone(); - aleo_file_path.push(AleoFile::::main_file_name()); - - // Remove the Aleo file from the package directory. - aleo_file.remove(&aleo_file_path).map_err(PackageError::failed_to_remove_aleo_file)?; + // Initialize the package. + match network { + NetworkName::MainnetV0 => Package::initialize::(&self.name, &package_path), + NetworkName::TestnetV0 => Package::initialize::(&self.name, &package_path), + }?; Ok(()) } diff --git a/leo/cli/commands/query/program.rs b/leo/cli/commands/query/program.rs index 2eee0e8225..24f7af5d9a 100644 --- a/leo/cli/commands/query/program.rs +++ b/leo/cli/commands/query/program.rs @@ -54,7 +54,7 @@ impl Command for Program { // Build custom url to fetch from based on the flags and user's input. let url = if let Some(mapping_info) = self.mapping_value { // Check that the mapping name is valid. - Package::::is_aleo_name_valid(&mapping_info[0]); + Package::is_aleo_name_valid(&mapping_info[0]); format!("program/{}/mapping/{}/{}", program, mapping_info[0], mapping_info[1]) } else if self.mappings { format!("program/{}/mappings", program) diff --git a/leo/cli/commands/query/utils.rs b/leo/cli/commands/query/utils.rs index c038c14356..04cc492009 100644 --- a/leo/cli/commands/query/utils.rs +++ b/leo/cli/commands/query/utils.rs @@ -14,10 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use super::*; - use leo_errors::{LeoError, Result, UtilError}; - use leo_package::package::Package; // A valid hash is 61 characters long, with preface "ab1" and all characters lowercase or numbers. @@ -85,10 +82,10 @@ pub fn is_valid_field(field: &str) -> Result { // Checks if the string is a valid program name in Aleo. pub fn check_valid_program_name(name: String) -> String { if name.ends_with(".aleo") { - Package::::is_aleo_name_valid(&name[0..name.len() - 5]); + Package::is_aleo_name_valid(&name[0..name.len() - 5]); name } else { - Package::::is_aleo_name_valid(&name); + Package::is_aleo_name_valid(&name); format!("{}.aleo", name) } } diff --git a/leo/cli/commands/remove.rs b/leo/cli/commands/remove.rs index 07170fc119..c99319f99f 100644 --- a/leo/cli/commands/remove.rs +++ b/leo/cli/commands/remove.rs @@ -16,7 +16,6 @@ use super::*; use leo_retriever::{Dependency, Manifest}; -use std::path::PathBuf; /// Remove a dependency from the current package. #[derive(Parser, Debug)] @@ -29,12 +28,6 @@ pub struct Remove { )] pub(crate) name: Option, - #[clap(short = 'l', long, help = "Path to local dependency")] - pub(crate) local: Option, - - #[clap(short = 'n', long, help = "Name of the network to use", default_value = "testnet3")] - pub(crate) network: String, - #[clap(long, help = "Clear all previous dependencies.", default_value = "false")] pub(crate) all: bool, } @@ -62,18 +55,8 @@ impl Command for Remove { .map_err(|err| PackageError::failed_to_deserialize_manifest_file(path.to_str().unwrap(), err))?; let dependencies: Vec = if !self.all { - // Make sure the program name is valid. - // Allow both `credits.aleo` and `credits` syntax. - let name: String = match &self.name { - Some(name) - if name.ends_with(".aleo") - && Package::::is_aleo_name_valid(&name[0..name.len() - 5]) => - { - name.clone() - } - Some(name) if Package::::is_aleo_name_valid(name) => format!("{name}.aleo"), - name => return Err(PackageError::invalid_file_name_dependency(name.clone().unwrap()).into()), - }; + // Note that this unwrap is safe since `name` is required if `all` is `false`. + let name: String = self.name.unwrap().clone(); let mut found_match = false; let dep = match manifest.dependencies() { @@ -121,9 +104,7 @@ impl Command for Remove { manifest.license(), Some(dependencies), ); - let new_manifest_data = serde_json::to_string_pretty(&new_manifest) - .map_err(|err| PackageError::failed_to_serialize_manifest_file(path.to_str().unwrap(), err))?; - std::fs::write(path.join("program.json"), new_manifest_data).map_err(PackageError::failed_to_write_manifest)?; + new_manifest.write_to_dir(&path)?; Ok(()) } diff --git a/leo/cli/commands/run.rs b/leo/cli/commands/run.rs index 561b7ede84..83baf9bed4 100644 --- a/leo/cli/commands/run.rs +++ b/leo/cli/commands/run.rs @@ -16,7 +16,11 @@ use super::*; -use snarkvm::{cli::Run as SnarkVMRun, prelude::Parser as SnarkVMParser}; +use leo_retriever::NetworkName; +use snarkvm::{ + cli::Run as SnarkVMRun, + prelude::{MainnetV0, Network, Parser as SnarkVMParser, TestnetV0}, +}; /// Build, Prove and Run Leo program with inputs #[derive(Parser, Debug)] @@ -47,56 +51,66 @@ impl Command for Run { } fn apply(self, context: Context, _: Self::Input) -> Result { - let mut inputs = self.inputs; - - // Compose the `run` command. - let mut arguments = vec![SNARKVM_COMMAND.to_string(), self.name]; - - // Add the inputs to the arguments. - match self.file { - Some(file) => { - // Get the contents from the file. - let path = context.dir()?.join(file); - let raw_content = std::fs::read_to_string(&path) - .map_err(|err| PackageError::failed_to_read_file(path.display(), err))?; - // Parse the values from the file. - let mut content = raw_content.as_str(); - let mut values = vec![]; - while let Ok((remaining, value)) = snarkvm::prelude::Value::::parse(content) { - content = remaining; - values.push(value); - } - // Check that the remaining content is empty. - if !content.trim().is_empty() { - return Err(PackageError::failed_to_read_input_file(path.display()).into()); - } - // Convert the values to strings. - let mut inputs_from_file = values.into_iter().map(|value| value.to_string()).collect::>(); - // Add the inputs from the file to the arguments. - arguments.append(&mut inputs_from_file); - } - None => arguments.append(&mut inputs), + // Parse the network. + let network = NetworkName::try_from(self.compiler_options.network.as_str())?; + match network { + NetworkName::MainnetV0 => handle_run::(self, context), + NetworkName::TestnetV0 => handle_run::(self, context), } - - // Open the Leo build/ directory - let path = context.dir()?; - let build_directory = BuildDirectory::open(&path)?; - - // Change the cwd to the Leo build/ directory to compile aleo files. - std::env::set_current_dir(&build_directory) - .map_err(|err| PackageError::failed_to_set_cwd(build_directory.display(), err))?; - - // Unset the Leo panic hook - let _ = std::panic::take_hook(); - - // Call the `run` command. - println!(); - let command = SnarkVMRun::try_parse_from(&arguments).map_err(CliError::failed_to_parse_run)?; - let res = command.parse().map_err(CliError::failed_to_execute_run)?; - - // Log the output of the `run` command. - tracing::info!("{}", res); - - Ok(()) } } + +// A helper function to handle the run command. +fn handle_run(command: Run, context: Context) -> Result<::Output> { + let mut inputs = command.inputs; + + // Compose the `run` command. + let mut arguments = vec![SNARKVM_COMMAND.to_string(), command.name]; + + // Add the inputs to the arguments. + match command.file { + Some(file) => { + // Get the contents from the file. + let path = context.dir()?.join(file); + let raw_content = + std::fs::read_to_string(&path).map_err(|err| PackageError::failed_to_read_file(path.display(), err))?; + // Parse the values from the file. + let mut content = raw_content.as_str(); + let mut values = vec![]; + while let Ok((remaining, value)) = snarkvm::prelude::Value::::parse(content) { + content = remaining; + values.push(value); + } + // Check that the remaining content is empty. + if !content.trim().is_empty() { + return Err(PackageError::failed_to_read_input_file(path.display()).into()); + } + // Convert the values to strings. + let mut inputs_from_file = values.into_iter().map(|value| value.to_string()).collect::>(); + // Add the inputs from the file to the arguments. + arguments.append(&mut inputs_from_file); + } + None => arguments.append(&mut inputs), + } + + // Open the Leo build/ directory + let path = context.dir()?; + let build_directory = BuildDirectory::open(&path)?; + + // Change the cwd to the Leo build/ directory to compile aleo files. + std::env::set_current_dir(&build_directory) + .map_err(|err| PackageError::failed_to_set_cwd(build_directory.display(), err))?; + + // Unset the Leo panic hook + let _ = std::panic::take_hook(); + + // Call the `run` command. + println!(); + let command = SnarkVMRun::try_parse_from(&arguments).map_err(CliError::failed_to_parse_run)?; + let res = command.parse().map_err(CliError::failed_to_execute_run)?; + + // Log the output of the `run` command. + tracing::info!("{}", res); + + Ok(()) +} diff --git a/leo/cli/helpers/context.rs b/leo/cli/helpers/context.rs index 02a10e0332..e80ec3ddcc 100644 --- a/leo/cli/helpers/context.rs +++ b/leo/cli/helpers/context.rs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use super::*; use aleo_std; use leo_errors::{CliError, PackageError, Result}; use leo_package::build::{BuildDirectory, BUILD_DIRECTORY_NAME}; @@ -24,6 +23,7 @@ use snarkvm::file::Manifest; use aleo_std::aleo_dir; use indexmap::IndexMap; +use snarkvm::prelude::Network; use std::{ env::current_dir, fs::File, @@ -76,10 +76,10 @@ impl Context { /// Returns the package name as a String. /// Opens the manifest file `program.json` and creates the build directory if it doesn't exist. - pub fn open_manifest(&self) -> Result> { + pub fn open_manifest(&self) -> Result> { // Open the manifest file. let path = self.dir()?; - let manifest = Manifest::::open(&path).map_err(PackageError::failed_to_open_manifest)?; + let manifest = Manifest::::open(&path).map_err(PackageError::failed_to_open_manifest)?; // Lookup the program id. // let program_id = manifest.program_id(); @@ -97,7 +97,7 @@ impl Context { std::fs::read_to_string(manifest.path()).map_err(PackageError::failed_to_read_manifest)?; // Construct the file path. - let build_manifest_path = build_path.join(Manifest::::file_name()); + let build_manifest_path = build_path.join(Manifest::::file_name()); // Write the file. File::create(build_manifest_path) diff --git a/leo/cli/helpers/mod.rs b/leo/cli/helpers/mod.rs index de2c63dc93..262b9bc622 100644 --- a/leo/cli/helpers/mod.rs +++ b/leo/cli/helpers/mod.rs @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -pub use super::*; - pub mod context; pub mod logger; pub mod updater; diff --git a/leo/cli/mod.rs b/leo/cli/mod.rs index 4dcfa0a3d7..53c8bd5884 100644 --- a/leo/cli/mod.rs +++ b/leo/cli/mod.rs @@ -23,7 +23,6 @@ pub use commands::*; mod helpers; pub use helpers::*; -pub(crate) type CurrentNetwork = snarkvm::prelude::MainnetV0; pub(crate) const SNARKVM_COMMAND: &str = "snarkvm"; #[cfg(test)] diff --git a/leo/package/src/package.rs b/leo/package/src/package.rs index 5c95d6465c..abc6aad9d5 100644 --- a/leo/package/src/package.rs +++ b/leo/package/src/package.rs @@ -15,28 +15,27 @@ // along with the Leo library. If not, see . use crate::{ - build::BuildDirectory, - inputs::InputsDirectory, root::{Env, Gitignore}, source::{MainFile, SourceDirectory}, }; use leo_errors::{PackageError, Result}; -use snarkvm::console::prelude::Network; +use leo_retriever::{Manifest, NetworkName}; use serde::Deserialize; -use std::{marker::PhantomData, path::Path}; +use snarkvm::prelude::Network; +use std::path::Path; #[derive(Deserialize)] -pub struct Package { +pub struct Package { pub name: String, pub version: String, pub description: Option, pub license: Option, - _phantom: PhantomData, + pub network: NetworkName, } -impl Package { - pub fn new(package_name: &str) -> Result { +impl Package { + pub fn new(package_name: &str, network: NetworkName) -> Result { // Check that the package name is a valid Aleo program name. if !Self::is_aleo_name_valid(package_name) { return Err(PackageError::invalid_package_name(package_name).into()); @@ -47,7 +46,7 @@ impl Package { version: "0.1.0".to_owned(), description: None, license: None, - _phantom: PhantomData, + network, }) } @@ -126,72 +125,79 @@ impl Package { } /// Creates a Leo package at the given path - pub fn initialize(package_name: &str, path: &Path) -> Result<()> { - // Verify that the .gitignore file does not exist. - if !Gitignore::exists_at(path) { - // Create the .gitignore file. - Gitignore::new().write_to(path)?; + pub fn initialize(package_name: &str, path: &Path) -> Result<()> { + // Construct the path to the package directory. + let path = path.join(package_name); + + // Verify that there is no existing directory at the path. + if path.exists() { + return Err( + PackageError::failed_to_initialize_package(package_name, &path, "Directory already exists").into() + ); } - // Verify that the .env file does not exist. - if !Env::::exists_at(path) { - // Create the .env file. - Env::::new()?.write_to(path)?; - } + // Create the package directory. + std::fs::create_dir(&path).map_err(|e| PackageError::failed_to_initialize_package(package_name, &path, e))?; + + // Change the current working directory to the package directory. + std::env::set_current_dir(&path) + .map_err(|e| PackageError::failed_to_initialize_package(package_name, &path, e))?; + + // Create the .gitignore file. + Gitignore::new().write_to(&path)?; + + // Create the .env file. + Env::::new()?.write_to(&path)?; + + // Create a manifest. + let manifest = Manifest::default(package_name); + manifest.write_to_dir(&path)?; // Create the source directory. - SourceDirectory::create(path)?; - - // Create the inputs directory. - InputsDirectory::create(path)?; - - // Create the Leo build/ directory - BuildDirectory::create(path)?; + SourceDirectory::create(&path)?; // Create the main file in the source directory. - MainFile::new(package_name).write_to(path)?; + MainFile::new(package_name).write_to(&path)?; // Next, verify that a valid Leo package has been initialized in this directory - if !Self::is_initialized(package_name, path) { - return Err(PackageError::failed_to_initialize_package(package_name, path.as_os_str()).into()); + if !Self::is_initialized(package_name, &path) { + return Err(PackageError::failed_to_initialize_package( + package_name, + &path, + "Failed to correctly initialize package", + ) + .into()); } Ok(()) } - // - // /// Removes the package at the given path - // pub fn remove_imported_package(package_name: &str, path: &Path) -> Result<()> { - // ImportsDirectory::remove_import(path, package_name) - // } } #[cfg(test)] mod tests { use super::*; - type CurrentNetwork = snarkvm::prelude::MainnetV0; - #[test] fn test_is_package_name_valid() { - assert!(Package::::is_aleo_name_valid("foo")); - assert!(Package::::is_aleo_name_valid("foo_bar")); - assert!(Package::::is_aleo_name_valid("foo1")); - assert!(Package::::is_aleo_name_valid("foo_bar___baz_")); + assert!(Package::is_aleo_name_valid("foo")); + assert!(Package::is_aleo_name_valid("foo_bar")); + assert!(Package::is_aleo_name_valid("foo1")); + assert!(Package::is_aleo_name_valid("foo_bar___baz_")); - assert!(!Package::::is_aleo_name_valid("foo-bar")); - assert!(!Package::::is_aleo_name_valid("foo-bar-baz")); - assert!(!Package::::is_aleo_name_valid("foo-1")); - assert!(!Package::::is_aleo_name_valid("")); - assert!(!Package::::is_aleo_name_valid("-")); - assert!(!Package::::is_aleo_name_valid("-foo")); - assert!(!Package::::is_aleo_name_valid("-foo-")); - assert!(!Package::::is_aleo_name_valid("_foo")); - assert!(!Package::::is_aleo_name_valid("foo--bar")); - assert!(!Package::::is_aleo_name_valid("foo---bar")); - assert!(!Package::::is_aleo_name_valid("foo--bar--baz")); - assert!(!Package::::is_aleo_name_valid("foo---bar---baz")); - assert!(!Package::::is_aleo_name_valid("foo*bar")); - assert!(!Package::::is_aleo_name_valid("foo,bar")); - assert!(!Package::::is_aleo_name_valid("1-foo")); + assert!(!Package::is_aleo_name_valid("foo-bar")); + assert!(!Package::is_aleo_name_valid("foo-bar-baz")); + assert!(!Package::is_aleo_name_valid("foo-1")); + assert!(!Package::is_aleo_name_valid("")); + assert!(!Package::is_aleo_name_valid("-")); + assert!(!Package::is_aleo_name_valid("-foo")); + assert!(!Package::is_aleo_name_valid("-foo-")); + assert!(!Package::is_aleo_name_valid("_foo")); + assert!(!Package::is_aleo_name_valid("foo--bar")); + assert!(!Package::is_aleo_name_valid("foo---bar")); + assert!(!Package::is_aleo_name_valid("foo--bar--baz")); + assert!(!Package::is_aleo_name_valid("foo---bar---baz")); + assert!(!Package::is_aleo_name_valid("foo*bar")); + assert!(!Package::is_aleo_name_valid("foo,bar")); + assert!(!Package::is_aleo_name_valid("1-foo")); } } diff --git a/leo/package/src/root/env.rs b/leo/package/src/root/env.rs index f49f958e71..f909d6270d 100644 --- a/leo/package/src/root/env.rs +++ b/leo/package/src/root/env.rs @@ -16,26 +16,31 @@ //! The `.env` file. use leo_errors::{PackageError, Result}; -use snarkvm::console::{account::PrivateKey, prelude::Network}; +use leo_retriever::NetworkName; +use snarkvm::console::account::PrivateKey; + +use snarkvm::prelude::{MainnetV0, Network, TestnetV0}; use serde::Deserialize; -use std::{borrow::Cow, fs::File, io::Write, marker::PhantomData, path::Path}; +use std::{borrow::Cow, fs::File, io::Write, path::Path}; pub static ENV_FILENAME: &str = ".env"; -#[derive(Deserialize, Default)] +#[derive(Deserialize)] pub struct Env { - data: String, - _phantom: PhantomData, + #[serde(bound(deserialize = ""))] + private_key: PrivateKey, } impl Env { pub fn new() -> Result { - Ok(Self { data: Self::template()?, _phantom: PhantomData }) - } + // Initialize an RNG. + let rng = &mut rand::thread_rng(); - pub fn from(data: String) -> Self { - Self { data, _phantom: PhantomData } + // Generate a development private key. + let private_key = PrivateKey::::new(rng)?; + + Ok(Self { private_key }) } pub fn exists_at(path: &Path) -> bool { @@ -53,17 +58,26 @@ impl Env { } let mut file = File::create(&path).map_err(PackageError::io_error_env_file)?; - file.write_all(self.data.as_bytes()).map_err(PackageError::io_error_env_file)?; + file.write_all(self.to_string().as_bytes()).map_err(PackageError::io_error_env_file)?; Ok(()) } +} - fn template() -> Result { - // Initialize an RNG. - let rng = &mut rand::thread_rng(); - - // Initialize a new development private key. - let private_key = PrivateKey::::new(rng)?; - - Ok(format!("NETWORK=mainnet\nPRIVATE_KEY={private_key}\n")) +impl From> for Env { + fn from(private_key: PrivateKey) -> Self { + Self { private_key } + } +} + +impl ToString for Env { + fn to_string(&self) -> String { + // Get the network name. + let network = match N::ID { + MainnetV0::ID => NetworkName::MainnetV0, + TestnetV0::ID => NetworkName::TestnetV0, + _ => unimplemented!("Unsupported network"), + }; + // Return the formatted string. + format!("NETWORK={network}\nPRIVATE_KEY={}\n", self.private_key) } } diff --git a/utils/retriever/src/program_context/manifest.rs b/utils/retriever/src/program_context/manifest.rs index 36f8ea1709..076959371b 100644 --- a/utils/retriever/src/program_context/manifest.rs +++ b/utils/retriever/src/program_context/manifest.rs @@ -15,7 +15,9 @@ // along with the Leo library. If not, see . use crate::Dependency; +use leo_errors::PackageError; use serde::{Deserialize, Serialize}; +use std::path::Path; // Struct representation of program's `program.json` specification #[derive(Debug, Clone, Serialize, Deserialize)] @@ -44,6 +46,16 @@ impl Manifest { } } + pub fn default(program: &str) -> Self { + Self { + program: format!("{program}.aleo"), + version: "0.1.0".to_owned(), + description: "".to_owned(), + license: "MIT".to_owned(), + dependencies: None, + } + } + pub fn program(&self) -> &String { &self.program } @@ -63,4 +75,21 @@ impl Manifest { pub fn dependencies(&self) -> &Option> { &self.dependencies } + + pub fn write_to_dir(&self, path: &Path) -> Result<(), PackageError> { + // Serialize the manifest to a JSON string. + let contents = serde_json::to_string_pretty(&self) + .map_err(|err| PackageError::failed_to_serialize_manifest_file(path.to_str().unwrap(), err))?; + // Write the manifest to the file. + std::fs::write(path.join("program.json"), contents).map_err(PackageError::failed_to_write_manifest) + } + + pub fn read_from_dir(path: &Path) -> Result { + // Read the manifest file. + let contents = std::fs::read_to_string(path.join("program.json")) + .map_err(|err| PackageError::failed_to_read_file(path.to_str().unwrap(), err))?; + // Deserialize the manifest. + serde_json::from_str(&contents) + .map_err(|err| PackageError::failed_to_deserialize_manifest_file(path.to_str().unwrap(), err)) + } } diff --git a/utils/retriever/src/program_context/network_name.rs b/utils/retriever/src/program_context/network_name.rs index ac623e60f7..9708581e5e 100644 --- a/utils/retriever/src/program_context/network_name.rs +++ b/utils/retriever/src/program_context/network_name.rs @@ -14,7 +14,9 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . +use leo_errors::{CliError, LeoError}; use serde::{Deserialize, Serialize}; +use snarkvm::prelude::{MainnetV0, Network, TestnetV0}; use std::fmt; // Retrievable networks for an external program @@ -26,12 +28,23 @@ pub enum NetworkName { MainnetV0, } -impl From<&String> for NetworkName { - fn from(network: &String) -> Self { - match network.to_ascii_lowercase().as_str() { - "testnet" => NetworkName::TestnetV0, - "mainnet" => NetworkName::MainnetV0, - _ => panic!("Invalid network"), +impl NetworkName { + pub fn id(&self) -> u16 { + match self { + NetworkName::TestnetV0 => TestnetV0::ID, + NetworkName::MainnetV0 => MainnetV0::ID, + } + } +} + +impl TryFrom<&str> for NetworkName { + type Error = LeoError; + + fn try_from(network: &str) -> Result { + match network { + "testnet" => Ok(NetworkName::TestnetV0), + "mainnet" => Ok(NetworkName::MainnetV0), + _ => Err(LeoError::CliError(CliError::invalid_network_name(network))), } } }