Merge pull request #27967 from ProvableHQ/feat/generic-cli

[Feature] Support `--network` selection in CLI.
This commit is contained in:
evan-schott 2024-06-05 17:09:14 -07:00 committed by GitHub
commit 6ef5b3623f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 916 additions and 943 deletions

347
Cargo.lock generated
View File

@ -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",
]

View File

@ -176,9 +176,6 @@ version = "0.1"
version = "0.3.18"
features = [ "fmt" ]
[dependencies.zip]
version = "^2.1"
[dependencies.crossterm]
version = "0.27.0"

View File

@ -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

View File

@ -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::<CurrentNetwork>(h, &node_builder, &code.src, code.start_pos)?;
let ast = match opt.network.as_str() {
"mainnet" => {
leo_parser::parse_ast::<snarkvm::prelude::MainnetV0>(h, &node_builder, &code.src, code.start_pos)
}
"testnet" => {
leo_parser::parse_ast::<snarkvm::prelude::TestnetV0>(h, &node_builder, &code.src, code.start_pos)
}
_ => panic!("Invalid network"),
}?;
let json = Ast::to_json_string(&ast)?;
println!("{json}");
Ok(json)

View File

@ -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,
}
);

View File

@ -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 <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,
}
);

View File

@ -1,4 +1,4 @@
outputs/
*.avm
*.prover
*.verifier
*.verifier

View File

@ -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 = []

View File

@ -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,
},
},

View File

@ -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<PrivateKey<CurrentNetwork>>,
private_key: Option<String>,
/// 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<PrivateKey<CurrentNetwork>>,
private_key: Option<String>,
/// Specify the path to a file containing the account private key of the node
#[clap(long = "private-key-file")]
private_key_file: Option<String>,
@ -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<CurrentNetwork>,
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::<MainnetV0>(seed, write, discreet, &ctx),
NetworkName::TestnetV0 => generate_new_account::<TestnetV0>(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::<MainnetV0>(private_key, write, discreet, &ctx),
NetworkName::TestnetV0 => import_account::<TestnetV0>(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::<PathBuf>()
.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::<CurrentNetwork>::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::<MainnetV0>(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::<CurrentNetwork>::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::<TestnetV0>(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::<MainnetV0>(address, signature, message, raw),
NetworkName::TestnetV0 => verify_message::<TestnetV0>(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<N: Network>(seed: Option<u64>, 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::<N>::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<N: Network>(private_key: Option<String>, 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::<N>(priv_key, discreet)?;
// Save key data to .env file.
if write {
write_to_env_file::<N>(priv_key, ctx)?;
}
Ok(())
}
// Print keys as a formatted string without log level.
fn print_keys(private_key: PrivateKey<CurrentNetwork>, discreet: bool) -> Result<()> {
fn print_keys<N: Network>(private_key: PrivateKey<N>, discreet: bool) -> Result<()> {
let view_key = ViewKey::try_from(&private_key)?;
let address = Address::<CurrentNetwork>::try_from(&view_key)?;
let address = Address::<N>::try_from(&view_key)?;
if !discreet {
println!(
@ -209,14 +232,100 @@ fn print_keys(private_key: PrivateKey<CurrentNetwork>, 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<N: Network>(
message: String,
seed: Option<u64>,
raw: bool,
private_key: Option<String>,
private_key_file: Option<String>,
) -> Result<String> {
let private_key = match (private_key, private_key_file) {
(Some(private_key), None) => PrivateKey::<N>::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::<PathBuf>()
.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::<N>::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::<N>::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::<N>::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<N: Network>(
address: String,
signature: String,
message: String,
raw: bool,
) -> Result<String> {
// Parse the address.
let address = Address::<N>::from_str(&address)?;
let signature = Signature::<N>::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::<N>::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<CurrentNetwork>, ctx: &Context) -> Result<()> {
let data = format!("NETWORK=mainnet\nPRIVATE_KEY={private_key}\n");
fn write_to_env_file<N: Network>(private_key: PrivateKey<N>, ctx: &Context) -> Result<()> {
let program_dir = ctx.dir()?;
Env::<CurrentNetwork>::from(data).write_to(&program_dir)?;
Env::<N>::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<CurrentNetwork>,
message: String,
seed: Option<u64>,
raw: bool,
) -> Result<String> {
// 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::<CurrentNetwork>::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<CurrentNetwork>,
signature: String,
message: String,
raw: bool,
) -> Result<String> {
let signature = Signature::<CurrentNetwork>::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::<CurrentNetwork>::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::<CurrentNetwork>(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::<CurrentNetwork>(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::<CurrentNetwork>(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::<CurrentNetwork>(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::<CurrentNetwork>(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::<CurrentNetwork>(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::<CurrentNetwork>(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::<CurrentNetwork>(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::<CurrentNetwork>(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::<CurrentNetwork>(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::<CurrentNetwork>(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::<CurrentNetwork>(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::<CurrentNetwork>(address, signature, message, false).is_ok());
}
}

View File

@ -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::<CurrentNetwork>::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::<CurrentNetwork>::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(())
}

View File

@ -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<BuildOptions> for CompilerOptions {
@ -88,101 +92,96 @@ impl Command for Build {
}
fn apply(self, context: Context, _: Self::Input) -> Result<Self::Output> {
// 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::<MainnetV0>(&self, context),
NetworkName::TestnetV0 => handle_build::<TestnetV0>(&self, context),
}
}
}
// Open the build directory.
let build_directory = BuildDirectory::create(&package_path)?;
// A helper function to handle the build command.
fn handle_build<N: Network>(command: &Build, context: Context) -> Result<<Build as Command>::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::<N>::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::<CurrentNetwork>::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::<N>::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::<CurrentNetwork>::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::<N>::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::<CurrentNetwork>::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::<N>::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<N: Network>(
file_path: PathBuf,
program_id: &ProgramID<CurrentNetwork>,
program_id: &ProgramID<N>,
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::<CurrentNetwork>::new(
let mut compiler = Compiler::<N>::new(
program_name.clone(),
program_id.network().to_string(),
handler,

View File

@ -15,8 +15,12 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
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<Self::Output> {
// 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::<MainnetV0>()?.program_id().to_string(),
NetworkName::TestnetV0 => context.open_manifest::<TestnetV0>()?.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(),
];

View File

@ -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<Self::Input> {
// Run leo new EXAMPLE_NAME
(New { name: self.name() }).execute(context)
// Run leo new <name> --network <network>
(New { name: self.name.clone(), network: self.network.clone() }).execute(context)
}
fn apply(self, context: Context, _: Self::Input) -> Result<Self::Output>
@ -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<Self, Self::Error> {
match value {
"lottery" => Ok(Self::Lottery),
"tictactoe" => Ok(Self::TicTacToe),
"token" => Ok(Self::Token),
_ => Err(()),
}
}
}

View File

@ -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<Self::Output> {
// 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::<MainnetV0>(self, context),
NetworkName::TestnetV0 => handle_execute::<TestnetV0>(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::<CurrentNetwork>::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::<Vec<String>>();
// 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<N: Network>(command: Execute, context: Context) -> Result<<Execute as Command>::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::<N>()?.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::<N>()?.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::<N>::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::<Vec<String>>();
// 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(())
}

View File

@ -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<String>,
#[clap(
@ -185,3 +212,9 @@ pub struct FeeOptions {
)]
record: Option<String>,
}
impl Default for FeeOptions {
fn default() -> Self {
Self { priority_fee: "0".to_string(), private_key: None, record: None }
}
}

View File

@ -15,14 +15,17 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
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<Self::Output> {
// 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::<CurrentNetwork>::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::<Network>::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::<CurrentNetwork>::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::<MainnetV0>(&self.name, &package_path),
NetworkName::TestnetV0 => Package::initialize::<TestnetV0>(&self.name, &package_path),
}?;
Ok(())
}

View File

@ -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::<CurrentNetwork>::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)

View File

@ -14,10 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
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<String, LeoError> {
// 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::<CurrentNetwork>::is_aleo_name_valid(&name[0..name.len() - 5]);
Package::is_aleo_name_valid(&name[0..name.len() - 5]);
name
} else {
Package::<CurrentNetwork>::is_aleo_name_valid(&name);
Package::is_aleo_name_valid(&name);
format!("{}.aleo", name)
}
}

View File

@ -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<String>,
#[clap(short = 'l', long, help = "Path to local dependency")]
pub(crate) local: Option<PathBuf>,
#[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<Dependency> = 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::<CurrentNetwork>::is_aleo_name_valid(&name[0..name.len() - 5]) =>
{
name.clone()
}
Some(name) if Package::<CurrentNetwork>::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(())
}

View File

@ -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<Self::Output> {
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::<CurrentNetwork>::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::<Vec<String>>();
// 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::<MainnetV0>(self, context),
NetworkName::TestnetV0 => handle_run::<TestnetV0>(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<N: Network>(command: Run, context: Context) -> Result<<Run as Command>::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::<N>::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::<Vec<String>>();
// 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(())
}

View File

@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
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<Manifest<CurrentNetwork>> {
pub fn open_manifest<N: Network>(&self) -> Result<Manifest<N>> {
// Open the manifest file.
let path = self.dir()?;
let manifest = Manifest::<CurrentNetwork>::open(&path).map_err(PackageError::failed_to_open_manifest)?;
let manifest = Manifest::<N>::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::<CurrentNetwork>::file_name());
let build_manifest_path = build_path.join(Manifest::<N>::file_name());
// Write the file.
File::create(build_manifest_path)

View File

@ -14,8 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
pub use super::*;
pub mod context;
pub mod logger;
pub mod updater;

View File

@ -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)]

View File

@ -15,28 +15,27 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
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<N: Network> {
pub struct Package {
pub name: String,
pub version: String,
pub description: Option<String>,
pub license: Option<String>,
_phantom: PhantomData<N>,
pub network: NetworkName,
}
impl<N: Network> Package<N> {
pub fn new(package_name: &str) -> Result<Self> {
impl Package {
pub fn new(package_name: &str, network: NetworkName) -> Result<Self> {
// 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<N: Network> Package<N> {
version: "0.1.0".to_owned(),
description: None,
license: None,
_phantom: PhantomData,
network,
})
}
@ -126,72 +125,79 @@ impl<N: Network> Package<N> {
}
/// 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<N: Network>(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::<N>::exists_at(path) {
// Create the .env file.
Env::<N>::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::<N>::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::<CurrentNetwork>::is_aleo_name_valid("foo"));
assert!(Package::<CurrentNetwork>::is_aleo_name_valid("foo_bar"));
assert!(Package::<CurrentNetwork>::is_aleo_name_valid("foo1"));
assert!(Package::<CurrentNetwork>::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::<CurrentNetwork>::is_aleo_name_valid("foo-bar"));
assert!(!Package::<CurrentNetwork>::is_aleo_name_valid("foo-bar-baz"));
assert!(!Package::<CurrentNetwork>::is_aleo_name_valid("foo-1"));
assert!(!Package::<CurrentNetwork>::is_aleo_name_valid(""));
assert!(!Package::<CurrentNetwork>::is_aleo_name_valid("-"));
assert!(!Package::<CurrentNetwork>::is_aleo_name_valid("-foo"));
assert!(!Package::<CurrentNetwork>::is_aleo_name_valid("-foo-"));
assert!(!Package::<CurrentNetwork>::is_aleo_name_valid("_foo"));
assert!(!Package::<CurrentNetwork>::is_aleo_name_valid("foo--bar"));
assert!(!Package::<CurrentNetwork>::is_aleo_name_valid("foo---bar"));
assert!(!Package::<CurrentNetwork>::is_aleo_name_valid("foo--bar--baz"));
assert!(!Package::<CurrentNetwork>::is_aleo_name_valid("foo---bar---baz"));
assert!(!Package::<CurrentNetwork>::is_aleo_name_valid("foo*bar"));
assert!(!Package::<CurrentNetwork>::is_aleo_name_valid("foo,bar"));
assert!(!Package::<CurrentNetwork>::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"));
}
}

View File

@ -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<N: Network> {
data: String,
_phantom: PhantomData<N>,
#[serde(bound(deserialize = ""))]
private_key: PrivateKey<N>,
}
impl<N: Network> Env<N> {
pub fn new() -> Result<Self> {
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::<N>::new(rng)?;
Ok(Self { private_key })
}
pub fn exists_at(path: &Path) -> bool {
@ -53,17 +58,26 @@ impl<N: Network> Env<N> {
}
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<String> {
// Initialize an RNG.
let rng = &mut rand::thread_rng();
// Initialize a new development private key.
let private_key = PrivateKey::<N>::new(rng)?;
Ok(format!("NETWORK=mainnet\nPRIVATE_KEY={private_key}\n"))
impl<N: Network> From<PrivateKey<N>> for Env<N> {
fn from(private_key: PrivateKey<N>) -> Self {
Self { private_key }
}
}
impl<N: Network> ToString for Env<N> {
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)
}
}

View File

@ -15,7 +15,9 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
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<Vec<Dependency>> {
&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<Self, PackageError> {
// 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))
}
}

View File

@ -14,7 +14,9 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
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<Self, LeoError> {
match network {
"testnet" => Ok(NetworkName::TestnetV0),
"mainnet" => Ok(NetworkName::MainnetV0),
_ => Err(LeoError::CliError(CliError::invalid_network_name(network))),
}
}
}