diff --git a/cli/Cargo.lock b/cli/Cargo.lock index e6f0a88376..c3b4bdee9c 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -30,6 +30,15 @@ dependencies = [ "xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "argon2rs" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "arrayvec" version = "0.4.8" @@ -109,6 +118,15 @@ name = "bitflags" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "blake2-rfc" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "byteorder" version = "1.2.7" @@ -228,6 +246,11 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "constant_time_eq" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "core-foundation" version = "0.5.1" @@ -305,6 +328,16 @@ dependencies = [ "journaldb 0.2.0 (git+https://github.com/paritytech/parity.git?tag=v2.2.7)", ] +[[package]] +name = "dirs" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "dtoa" version = "0.4.3" @@ -572,7 +605,7 @@ dependencies = [ [[package]] name = "fluence" -version = "0.1.4" +version = "0.1.5" dependencies = [ "base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -597,6 +630,7 @@ dependencies = [ "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustyline 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -623,6 +657,11 @@ name = "foreign-types-shared" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -1115,6 +1154,18 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "nix" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "nodrop" version = "0.1.13" @@ -1451,6 +1502,11 @@ name = "rand_core" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rand_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rand_hc" version = "0.1.0" @@ -1467,6 +1523,19 @@ dependencies = [ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_os" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_pcg" version = "0.1.1" @@ -1484,6 +1553,14 @@ dependencies = [ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "redox_syscall" version = "0.1.43" @@ -1497,6 +1574,17 @@ dependencies = [ "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "redox_users" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "regex" version = "1.1.0" @@ -1622,6 +1710,22 @@ dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustyline" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ryu" version = "0.2.7" @@ -1646,6 +1750,11 @@ name = "scoped-tls" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "scoped_threadpool" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "scopeguard" version = "0.3.3" @@ -1688,6 +1797,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "serde" version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "serde_derive" @@ -2222,6 +2334,11 @@ name = "utf8-ranges" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "utf8parse" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "uuid" version = "0.7.1" @@ -2375,6 +2492,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum app_dirs 1.2.1 (git+https://github.com/paritytech/app-dirs-rs)" = "" +"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392" "checksum arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f405cc4c21cd8b784f6c8fc2adf9bc00f59558f0049b5ec21517f875963040cc" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" @@ -2385,6 +2503,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" "checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" "checksum cassowary 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" @@ -2397,6 +2516,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum common-types 0.1.0 (git+https://github.com/paritytech/parity.git?tag=v2.2.7)" = "" "checksum console 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd48adf136733979b49e15bc3b4c43cc0d3c85ece7bd08e6daa414c6fcb13e6" "checksum console 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ba5561f4d4d89e0f246d4dd83846d96f617e886b96c7aee36e68791c98f89ce" +"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "286e0b41c3a20da26536c6000a280585d519fd07b3956b43aed8a79e9edce980" "checksum core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "716c271e8613ace48344f723b60b900a93150271e5be206212d052bbc0883efa" "checksum crc32fast 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e0e685559fa8bccfa46afd0f876047ee5d87c536d71d0c2b3a08cc9e880f73eb" @@ -2406,6 +2526,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" "checksum derive-getters 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "46e122eb9a0dddd006cc7b6c256de8806e935be67d6d28db825a4ec958420f3c" "checksum dir 0.1.2 (git+https://github.com/paritytech/parity.git?tag=v2.2.7)" = "" +"checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" "checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd" "checksum edit-distance 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3bd26878c3d921f89797a4e1a1711919f999a9f6946bb6f5a4ffda126d297b7e" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" @@ -2433,6 +2554,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" @@ -2487,6 +2609,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff8e08de0070bbf4c31f452ea2a70db092f36f6f2e4d897adf5674477d488fb2" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" +"checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" @@ -2525,12 +2648,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "771b009e3a508cb67e8823dda454aaa5368c7bc1c16829fb77d3e980440dd34a" "checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" "checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d" "checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" "checksum rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effa3fcaa47e18db002bdde6060944b6d2f9cfd8db471c30e873448ad9187be3" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "679da7508e9a6390aeaf7fbd02a800fdc64b73fe2204dd2c8ae66d22d9d5ad5d" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +"checksum redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe5204c3a17e97dde73f285d49be585df59ed84b50a872baf416e73b62c3828" "checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f" "checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" @@ -2544,10 +2671,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "403bb3a286107a04825a5f82e1270acc1e14028d3d554d7a1e08914549575ab8" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum rustyline 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eb02ba7748691403057542ee60a1e7688fdfb46bd3bee752b8977537ee003ae2" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" "checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" "checksum schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0e1a231dc10abf6749cfa5d7767f25888d484201accbd919b66ab5413c502d56" "checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" +"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum security-framework 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "697d3f3c23a618272ead9e1fb259c1411102b31c6af8b93f1d64cca9c3b0e8e0" "checksum security-framework-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab01dfbe5756785b5b4d46e0289e5a18071dfa9a7c2b24213ea00b9ef9b665bf" @@ -2613,6 +2742,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" +"checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" "checksum uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dab5c5526c5caa3d106653401a267fed923e7046f35895ffcb5ca42db64942e6" "checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index b28c3d2f1f..22eb503344 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fluence" -version = "0.1.4" +version = "0.1.5" authors = ["Fluence Labs"] publish=false edition = "2018" @@ -19,7 +19,7 @@ console = "0.6.2" reqwest = "0.9.3" hex = "0.3.2" web3 = { git = "https://github.com/fluencelabs/rust-web3", branch = "master" } -serde = "1.0" +serde = { version = "1.0", features = ["derive"]} serde_json = "1.0" serde_derive = "1.0" ethereum-types-serialize = "0.2.1" @@ -38,6 +38,7 @@ error-chain = "0.12.0" parity-wasm = "0.35" tui = {git = "https://github.com/fdehau/tui-rs.git", rev = "52a40ec99"} termion = "1.5" +rustyline = "3.0.0" [dev-dependencies] futures = "0.1.25" diff --git a/cli/README.md b/cli/README.md index 1056e9d62b..a5b54b63ca 100644 --- a/cli/README.md +++ b/cli/README.md @@ -25,7 +25,7 @@ Fluence CLI is an automation tool for tasks of app management (deployment and de ## Requirements -CLI assumes running Ethereum and Swarm on `http://localhost:8545/` and `http://localhost:8500/` respectively. Use `--eth_url` and `--swarm_url` to specify actual addresses as you need. +CLI assumes running Ethereum and Swarm on `http://data.fluence.one:8545/` and `http://data.fluence:8500/` respectively. Use `--eth_url` and `--swarm_url` to specify actual addresses as you need. Please note, that your Ethereum account should have sufficient funds for issuing transactions to smart-contract. It's only for transaction fees, Fluence itself doesn't currently charge miners or developers. That could change in the future, for example when miners' deposits are implemented. @@ -48,6 +48,21 @@ To look at all possible arguments and options use `./fluence --help`: You can use `./fluence [SUBCOMMAND] --help` to learn how to use commands. ## Usage examples +### Setup CLI +Use `setup` command to enter main arguments into a config file. It will allow not to use common arguments in every command. +```bash +./fluence setup +``` +Contract address, Ethereum, and Swarm node addresses have defaults, but account address and credentials (secret key or Ethereum keystore and password) should be filled for correct transaction sending. +Arguments description and examples: +- `0x074a79f29c613f4f7035cec582d0f7e4d3cda2e7` is a contract address, register transaction will be sent there +- `http://data.fluence.one:8545` is an URL to Ethereum node +- `http://data.fluence.one:8500` is an URL to Swarm node +- `0x4180fc65d613ba7e1a385181a219f1dbfe7bf11d` will be used as Ethereum account for issuing transactions. _Use your Ethereum account here_ +- `0xcb0799337df06a6c73881bab91304a68199a430ccd4bc378e37e51fd1b118133` denotes an Ethereum private key, used for offline transaction signing. _Use your Ethereum private key here_ +- it is possible to use keystore file and password instead of secret key + +All arguments could be overridden by flags in commands. ### Register a node To provide your computation resources to Fluence network, you need to register your computer within smart-contract. The simplest way to do that is through CLI. The following command will register a node: @@ -56,9 +71,7 @@ The following command will register a node: --node_ip 85.82.118.4 \ --tendermint_key 1GVDICzgrw1qahPfSbwCfYw0zrw91OMZ46QoKvJMjjM= \ --tendermint_node_id 5e4eedba85fda7451356a03caffb0716e599679b \ - --account 0x4180fc65d613ba7e1a385181a219f1dbfe7bf11d \ --base64_tendermint_key \ - --secret_key 0xcb0799337df06a6c73881bab91304a68199a430ccd4bc378e37e51fd1b118133 \ --wait_syncing \ --api_port 25000 \ --capacity 10 @@ -71,10 +84,6 @@ Parameters are: - currently, Tendermint key can be found in logs of `fluencelabs/node` Docker container - note that key should be unique, i.e. you can't register several nodes with the same key - Tendermint p2p node ID `5e4eedba85fda7451356a03caffb0716e599679b` is needed to securely connect nodes in Tendermint cluster -- `0x9995882876ae612bfd829498ccd73dd962ec950a` is a contract address, register transaction will be sent there -- `0x4180fc65d613ba7e1a385181a219f1dbfe7bf11d` will be used as Ethereum account for issuing transactions. _Use your Ethereum account here_ -- `--secret_key 0xcb0799337df06a6c73881bab91304a68199a430ccd4bc378e37e51fd1b118133` denotes an Ethereum private key, used for offline transaction signing. _Use your Ethereum private key here_ - - using `--password` is possible instead of private key, but private key is preferred - `--wait_syncing` so CLI waits until Ethereum node is fully synced - `--api_port 25000` specifies the main port of the Fluence node, so other nodes and users know where to connect - `--capacity 10` limits number of apps that could be run on the node by 10 @@ -86,10 +95,8 @@ To deploy your app on Fluence network, you must upload it to Swarm and publish h The following command will publish app `counter.wasm`. ``` ./fluence publish \ - --code_path fluence/vm/examples/counter/target/wasm32-unknown-unknown/release/deps/counter.wasm \ - --account 0x4180fc65d613ba7e1a385181a219f1dbfe7bf11d \ + --code_path fluence/vm/examples/counter/target/wasm32-unknown-unknown/release/deps/counter.wasm \ --cluster_size 4 \ - --secret_key 0xcb0799337df06a6c73881bab91304a68199a430ccd4bc378e37e51fd1b118133 \ --pin_to 1GVDICzgrw1qahPfSbwCfYw0zrw91OMZ46QoKvJMjjM= \ --base64 ``` @@ -134,13 +141,11 @@ App enqueued. ### Delete an app If you want to delete your app from smart contract, you can use `delete_app` command. -The following will delete app with id `0x0000000000000000000000000000000000000000000000000000000000000002`. App id could be retrieved either from status (see below) or from smart-contract. +The following will delete app with id `2`. App id could be retrieved either from status (see below) or from smart-contract. ``` -./fluence delete_app \ - --account 0x4180fc65d613ba7e1a385181a219f1dbfe7bf11d \ - --app_id 0x0000000000000000000000000000000000000000000000000000000000000002 \ - --secret_key 4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7 \ +./fluence delete_app \ + --app_id 2 \ --deployed ``` @@ -159,7 +164,7 @@ The results will be in JSON and should resemble the following { "apps": [ { - "app_id": "0x0000000000000000000000000000000000000000000000000000000000000001", + "app_id": "1", "storage_hash": "0xeb2a623210c080d0702cc520b790151861601c46d90179a6e8efe6bda8ac5477", "storage_receipt": "0x0000000000000000000000000000000000000000000000000000000000000000", "cluster_size": 5, @@ -168,7 +173,7 @@ The results will be in JSON and should resemble the following "cluster": null }, { - "app_id": "0x0000000000000000000000000000000000000000000000000000000000000005", + "app_id": "5", "storage_hash": "0xeb2a623210c080d0702cc520b790151861601c46d90179a6e8efe6bda8ac5477", "storage_receipt": "0x0000000000000000000000000000000000000000000000000000000000000000", "cluster_size": 5, @@ -256,7 +261,7 @@ There is a flag `--contract_address` to use all commands to interact with non-de ```bash ./fluence ... - --contract_address 0x9995882876ae612bfd829498ccd73dd962ec950a \ + --contract_address 0x074a79f29c613f4f7035cec582d0f7e4d3cda2e7 \ ... ``` @@ -312,7 +317,7 @@ For example, with `delete_app` ```bash ./fluence delete_app \ --account 0x4180fc65d613ba7e1a385181a219f1dbfe7bf11d \ - --app_id 0x0000000000000000000000000000000000000000000000000000000000000002 \ + --app_id 2 \ --keystore ~/Library/Ethereum/keystore/UTC--2017-03-03T13-24-07.826187674Z--4e6cf0ed2d8bbf1fbbc9f2a100602ceba4bf1319 \ --password my_secure_passw0rd \ --deployed diff --git a/cli/src/check.rs b/cli/src/check.rs index 8640d5f15d..48df5079cd 100644 --- a/cli/src/check.rs +++ b/cli/src/check.rs @@ -16,7 +16,7 @@ use std::collections::HashMap; -use clap::{App, Arg, ArgMatches, SubCommand}; +use clap::{App, AppSettings, Arg, ArgMatches, SubCommand}; use console::style; use parity_wasm::elements::Error as ParityError; use parity_wasm::elements::Module; @@ -72,6 +72,7 @@ pub fn process(args: &ArgMatches) -> Result<(), Error> { pub fn subcommand<'a, 'b>() -> App<'a, 'b> { SubCommand::with_name("check") .about("Verifies wasm file, issue warning for using functions from banned modules.") + .setting(AppSettings::ArgRequiredElseHelp) .args(&[Arg::with_name(INPUT_ARG) .required(true) .takes_value(true) diff --git a/cli/src/command.rs b/cli/src/command.rs index dfb86ebbc5..85cb848d80 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -14,19 +14,17 @@ * limitations under the License. */ +use crate::config::SetupConfig; +use crate::credentials; use crate::credentials::Credentials; +use crate::ethereum_params::EthereumParams; use crate::utils; +use crate::utils::parse_hex; use clap::value_t; use clap::Arg; use clap::ArgMatches; -use ethkey::Password; -use ethkey::Secret; -use ethstore::accounts_dir::{DiskKeyFileManager, KeyFileManager}; -use ethstore::SafeAccount; -use failure::err_msg; use failure::Error; use failure::ResultExt; -use std::fs::File; use std::net::IpAddr; use web3::types::Address; use web3::types::H160; @@ -54,9 +52,9 @@ pub struct EthereumArgs { pub credentials: Credentials, pub gas: u32, pub gas_price: u64, - pub account: Address, - pub contract_address: Address, - pub eth_url: String, + pub account: Option
, + pub contract_address: Option
, + pub eth_url: Option, pub wait_tx_include: bool, pub wait_eth_sync: bool, } @@ -66,7 +64,6 @@ pub fn contract_address<'a, 'b>() -> Arg<'a, 'b> { .long(CONTRACT_ADDRESS) .short("d") .value_name("eth address") - .default_value(include_str!("../../tools/deploy/scripts/contract.txt").trim()) .takes_value(true) .help("Fluence contract address") } @@ -79,7 +76,6 @@ pub fn eth_url<'a, 'b>() -> Arg<'a, 'b> { .required(false) .takes_value(true) .help("Http address to ethereum node") - .default_value("http://localhost:8545/") } pub fn tendermint_key<'a, 'b>() -> Arg<'a, 'b> { @@ -127,7 +123,7 @@ pub fn with_ethereum_args<'a, 'b>(args: &[Arg<'a, 'b>]) -> Vec> { .long(ACCOUNT) .short("a") .value_name("eth address") - .required(true) + .required(false) .takes_value(true) .help("Ethereum account"), Arg::with_name(PASSWORD) @@ -189,70 +185,38 @@ pub fn with_ethereum_args<'a, 'b>(args: &[Arg<'a, 'b>]) -> Vec> { eth_args } -pub fn parse_contract_address(args: &ArgMatches) -> Result { - Ok(utils::parse_hex_opt(args, CONTRACT_ADDRESS)? - .parse::
() - .context("Error parsing contract address")?) -} - -pub fn parse_eth_url(args: &ArgMatches) -> Result { - value_t!(args, ETH_URL, String) -} - -fn load_keystore(path: String, password: String) -> Result { - let keystore = File::open(path).context("can't open keystore file")?; - let dkfm = DiskKeyFileManager {}; - let keystore: SafeAccount = dkfm - .read(None, keystore) - .map_err(|e| err_msg(e.to_string())) - .context("can't parse keystore file")?; - - let password: Password = password.into(); - keystore - .crypto - .secret(&password) - .map_err(|e| err_msg(e.to_string())) - .context("can't parse secret from keystore file") - .map_err(Into::into) +pub fn parse_contract_address(args: &ArgMatches) -> Result, Error> { + Ok(parse_hex(args.value_of(CONTRACT_ADDRESS))?) } -fn load_credentials( - keystore: Option, - password: Option, - secret_key: Option, -) -> Result { - match keystore { - Some(keystore) => match password { - Some(password) => load_keystore(keystore, password).map(Credentials::Secret), - None => Err(err_msg("password is required for keystore")), - }, - None => Ok(Credentials::get(secret_key, password.clone())), - } +pub fn parse_eth_url(args: &ArgMatches) -> Option { + args.value_of(ETH_URL).map(|s| s.to_owned()) } -pub fn parse_ethereum_args(args: &ArgMatches) -> Result { - let secret_key = utils::parse_secret_key(args, SECRET_KEY)?; +pub fn parse_ethereum_args( + args: &ArgMatches, + config: &SetupConfig, +) -> Result { + let secret_key = utils::parse_secret_key(args.value_of(SECRET_KEY))?; let password = args.value_of(PASSWORD).map(|s| s.to_string()); let keystore = args.value_of(KEYSTORE).map(|s| s.to_string()); - let credentials = load_credentials(keystore, password, secret_key)?; + let credentials = credentials::load_credentials(keystore, password, secret_key)?; let gas = value_t!(args, GAS, u32)?; let gas_price = value_t!(args, GAS_PRICE, u64)?; // TODO: it could panic here on overflow let gas_price = gas_price * TO_GWEI_MUL; - let account: Address = utils::parse_hex_opt(args, ACCOUNT)? - .parse::
() - .context("Error parsing account address")?; + let account: Option
= utils::parse_hex(args.value_of(ACCOUNT))?; - let contract_address: Address = parse_contract_address(args)?; + let contract_address: Option
= parse_contract_address(args)?; - let eth_url = parse_eth_url(args)?; + let eth_url = parse_eth_url(args); let wait = args.is_present(WAIT); let wait_syncing = args.is_present(WAIT_SYNCING); - return Ok(EthereumArgs { + let eth_args = EthereumArgs { credentials, gas, gas_price, @@ -261,11 +225,13 @@ pub fn parse_ethereum_args(args: &ArgMatches) -> Result { eth_url, wait_tx_include: wait, wait_eth_sync: wait_syncing, - }); + }; + + Ok(EthereumParams::generate(ð_args, config)?) } pub fn parse_tendermint_key(args: &ArgMatches) -> Result { - let tendermint_key = utils::parse_hex_opt(args, TENDERMINT_KEY) + let tendermint_key = utils::parse_hex_string(args, TENDERMINT_KEY) .context("error parsing tendermint key")? .to_owned(); let base64 = args.is_present(BASE64_TENDERMINT_KEY); @@ -305,9 +271,9 @@ impl Default for EthereumArgs { credentials: Credentials::No, gas: 1_000_000, gas_price: 1_000_000_000, - account: "4180FC65D613bA7E1a385181a219F1DBfE7Bf11d".parse().unwrap(), - contract_address: "9995882876ae612bfd829498ccd73dd962ec950a".parse().unwrap(), - eth_url: String::from("http://localhost:8545"), + account: Some("4180FC65D613bA7E1a385181a219F1DBfE7Bf11d".parse().unwrap()), + contract_address: Some("9995882876ae612bfd829498ccd73dd962ec950a".parse().unwrap()), + eth_url: Some(String::from("http://localhost:8545")), wait_tx_include: false, wait_eth_sync: false, } @@ -318,7 +284,7 @@ impl EthereumArgs { pub fn with_acc_creds(account: Address, credentials: Credentials) -> EthereumArgs { let mut args = EthereumArgs::default(); args.credentials = credentials; - args.account = account; + args.account = Some(account); args } } diff --git a/cli/src/config.rs b/cli/src/config.rs new file mode 100644 index 0000000000..393f532d78 --- /dev/null +++ b/cli/src/config.rs @@ -0,0 +1,112 @@ +/* + * Copyright 2019 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use failure::Error; +use serde::{Deserialize, Serialize}; +use std::fs::create_dir_all; +use std::fs::{read_to_string, File}; +use std::io::prelude::*; +use std::path::Path; +use web3::types::Address; +use web3::types::H256; + +pub const HOME_DIR: &str = "~/.local/share/.fluence/"; +pub const DEFAULT_CONTRACT_ADDRESS: &str = include_str!("../../tools/deploy/scripts/contract.txt"); +pub const DEFAULT_ETH_URL: &str = "http://data.fluence.one:8545/"; +pub const DEFAULT_SWARM_URL: &str = "http://data.fluence.one:8500/"; + +const CONFIG_FILENAME: &str = "cli.json"; + +#[derive(Serialize, Deserialize, Clone)] +pub struct SetupConfig { + pub contract_address: Address, + pub account: Option
, + pub eth_url: String, + pub swarm_url: String, + pub secret_key: Option, + pub keystore_path: Option, + pub password: Option, +} + +// returns None if string value is empty and Some if non empty +pub fn none_if_empty(value: &str) -> Option<&str> { + if value.is_empty() { + None + } else { + Some(value) + } +} + +impl SetupConfig { + pub fn new( + contract_address: Address, + account: Option
, + eth_url: String, + swarm_url: String, + secret_key: Option, + keystore_path: Option, + password: Option, + ) -> SetupConfig { + return SetupConfig { + contract_address, + account, + eth_url, + swarm_url, + secret_key, + keystore_path, + password, + }; + } + + pub fn default() -> Result { + let contract: Address = DEFAULT_CONTRACT_ADDRESS + .to_owned() + .trim_start_matches("0x") + .parse()?; + let eth_url = DEFAULT_ETH_URL.to_owned(); + let swarm_url = DEFAULT_SWARM_URL.to_owned(); + Ok(SetupConfig::new( + contract, None, eth_url, swarm_url, None, None, None, + )) + } + + // reads config file or generates default config if file does not exist + pub fn read_from_file_or_default(home_dir: &str) -> Result { + let path = format!("{}{}", home_dir, CONFIG_FILENAME); + let path = Path::new(path.as_str()); + + if !path.exists() { + SetupConfig::default() + } else { + let content = read_to_string(path)?; + let config: SetupConfig = serde_json::from_str(content.as_str())?; + Ok(config) + } + } + + // writes config to file + pub fn write_to_file(&self, home_dir: &str) -> Result<(), Error> { + create_dir_all(HOME_DIR)?; + let config_str = serde_json::to_string(&self)?; + let path = format!("{}{}", home_dir, CONFIG_FILENAME); + println!("path: {}", path); + let mut file = File::create(path)?; + + file.write_all(config_str.as_bytes())?; + + Ok(()) + } +} diff --git a/cli/src/contract_func.rs b/cli/src/contract_func.rs index 0993ebf304..c629df3f03 100644 --- a/cli/src/contract_func.rs +++ b/cli/src/contract_func.rs @@ -14,7 +14,6 @@ * limitations under the License. */ -use crate::command::EthereumArgs; use ethabi_contract::use_contract; use ethcore_transaction::{Action, Transaction}; use ethkey::Secret; @@ -27,6 +26,7 @@ use web3::Web3; use failure::{err_msg, Error, ResultExt, SyncFailure}; use crate::credentials::Credentials; +use crate::ethereum_params::EthereumParams; use crate::utils; use ethabi::RawLog; use std::time::Duration; @@ -36,7 +36,7 @@ use_contract!(contract, "../bootstrap/contracts/compiled/Network.abi"); /// Calls contract method and returns hash of the transaction pub fn call_contract( web3: &Web3, - eth: &EthereumArgs, + eth: &EthereumParams, call_data: ethabi::Bytes, nonce: Option, ) -> Result { @@ -56,7 +56,7 @@ fn call_contract_local_sign( web3: &Web3, secret: &Secret, call_data: ethabi::Bytes, - eth: &EthereumArgs, + eth: &EthereumParams, nonce: Option, ) -> Result { let nonce = nonce.unwrap_or( @@ -91,7 +91,7 @@ fn call_contract_trusted_node( web3: &Web3, password: Option<&str>, call_data: ethabi::Bytes, - eth: &EthereumArgs, + eth: &EthereumParams, nonce: Option, ) -> Result { let options = utils::options(); diff --git a/cli/src/contract_status/mod.rs b/cli/src/contract_status/mod.rs index 0182b0f8af..fafd98978b 100644 --- a/cli/src/contract_status/mod.rs +++ b/cli/src/contract_status/mod.rs @@ -20,11 +20,12 @@ pub mod ui; use self::status::Status; use crate::command::*; +use crate::config::SetupConfig; use crate::contract_status::app::{App, Node}; use crate::contract_status::ui::rich_status; use crate::utils; use clap::Arg; -use clap::{App as ClapApp, ArgMatches, SubCommand, _clap_count_exprs, arg_enum}; +use clap::{App as ClapApp, ArgMatches, SubCommand, _clap_count_exprs, arg_enum, AppSettings}; use console::style; use failure::{err_msg, Error, ResultExt, SyncFailure}; use lazy_static::lazy_static; @@ -227,6 +228,7 @@ pub fn subcommand<'a, 'b>() -> ClapApp<'a, 'b> { SubCommand::with_name("status") .about("Show state of the Fluence network as seen by the smart-contract") .after_help(AFTER_HELP.as_str()) + .setting(AppSettings::ArgRequiredElseHelp) .args(&[ contract_address().display_order(0), eth_url().display_order(1), @@ -273,10 +275,14 @@ pub fn subcommand<'a, 'b>() -> ClapApp<'a, 'b> { } /// Gets status about Fluence contract from ethereum blockchain. -pub fn get_status_by_args(args: &ArgMatches) -> Result, Error> { - let eth_url = parse_eth_url(args)?; +pub fn get_status_by_args( + args: &ArgMatches, + config: &SetupConfig, +) -> Result, Error> { + let eth_url = parse_eth_url(args).unwrap_or(config.eth_url.clone()); - let contract_address: Address = parse_contract_address(args)?; + let contract_address: Option
= parse_contract_address(args)?; + let contract_address = contract_address.unwrap_or(config.contract_address.clone()); let filter = StatusFilter::from_args(args)?; diff --git a/cli/src/credentials.rs b/cli/src/credentials.rs index 8fa543486c..2e48e1ac95 100644 --- a/cli/src/credentials.rs +++ b/cli/src/credentials.rs @@ -14,7 +14,13 @@ * limitations under the License. */ +use ethkey::Password; use ethkey::Secret; +use ethstore::accounts_dir::{DiskKeyFileManager, KeyFileManager}; +use ethstore::SafeAccount; +use failure::ResultExt; +use failure::{err_msg, Error}; +use std::fs::File; /// Authorization to call contract methods #[derive(Debug, Clone)] @@ -40,3 +46,34 @@ impl Credentials { } } } + +pub fn load_credentials( + keystore: Option, + password: Option, + secret_key: Option, +) -> Result { + match keystore { + Some(keystore) => match password { + Some(password) => load_keystore(keystore, password).map(Credentials::Secret), + None => Err(err_msg("password is required for keystore")), + }, + None => Ok(Credentials::get(secret_key, password)), + } +} + +pub fn load_keystore(path: String, password: String) -> Result { + let keystore = File::open(path).context("can't open keystore file")?; + let dkfm = DiskKeyFileManager {}; + let keystore: SafeAccount = dkfm + .read(None, keystore) + .map_err(|e| err_msg(e.to_string())) + .context("can't parse keystore file")?; + + let password: Password = password.into(); + keystore + .crypto + .secret(&password) + .map_err(|e| err_msg(e.to_string())) + .context("can't parse secret from keystore file") + .map_err(Into::into) +} diff --git a/cli/src/delete_all.rs b/cli/src/delete_all.rs index 71cf9bf46f..334229d857 100644 --- a/cli/src/delete_all.rs +++ b/cli/src/delete_all.rs @@ -19,17 +19,19 @@ use clap::{App, AppSettings, SubCommand}; use web3::transports::Http; use crate::command; +use crate::config::SetupConfig; use crate::contract_func::call_contract; use crate::contract_func::contract::functions::delete_app; use crate::contract_func::contract::functions::delete_node; use crate::contract_func::contract::functions::dequeue_app; use crate::contract_status::status; +use crate::ethereum_params::EthereumParams; use failure::{Error, SyncFailure}; use web3::futures::Future; #[derive(Debug)] pub struct DeleteAll { - eth: command::EthereumArgs, + eth: EthereumParams, } pub fn subcommand<'a, 'b>() -> App<'a, 'b> { @@ -37,16 +39,17 @@ pub fn subcommand<'a, 'b>() -> App<'a, 'b> { .about("Delete all apps and nodes from contract. For the test net for contract owner only.") .args(command::with_ethereum_args(&[]).as_slice()) .setting(AppSettings::Hidden) + .setting(AppSettings::ArgRequiredElseHelp) } -pub fn parse(args: &ArgMatches) -> Result { - let eth = command::parse_ethereum_args(args)?; +pub fn parse(args: &ArgMatches, config: &SetupConfig) -> Result { + let eth = command::parse_ethereum_args(args, config)?; return Ok(DeleteAll { eth }); } impl DeleteAll { - pub fn new(eth: command::EthereumArgs) -> DeleteAll { + pub fn new(eth: EthereumParams) -> DeleteAll { DeleteAll { eth } } diff --git a/cli/src/delete_app.rs b/cli/src/delete_app.rs index 92c90f0468..5c5d66bcae 100644 --- a/cli/src/delete_app.rs +++ b/cli/src/delete_app.rs @@ -16,11 +16,12 @@ use clap::value_t; use clap::ArgMatches; -use clap::{App, Arg, SubCommand}; +use clap::{App, AppSettings, Arg, SubCommand}; use web3::transports::Http; use web3::types::H256; use crate::command; +use crate::config::SetupConfig; use crate::contract_func::call_contract; use crate::contract_func::contract::events::app_deleted; use crate::contract_func::contract::events::app_dequeued; @@ -28,6 +29,7 @@ use crate::contract_func::contract::functions::delete_app; use crate::contract_func::contract::functions::dequeue_app; use crate::contract_func::wait_sync; use crate::contract_func::{get_transaction_logs, wait_tx_included}; +use crate::ethereum_params::EthereumParams; use crate::step_counter::StepCounter; use crate::utils; use ethabi::RawLog; @@ -40,7 +42,7 @@ const DEPLOYED: &str = "deployed"; pub struct DeleteApp { app_id: u64, deployed: bool, - eth: command::EthereumArgs, + eth: EthereumParams, } pub fn subcommand<'a, 'b>() -> App<'a, 'b> { @@ -64,13 +66,14 @@ pub fn subcommand<'a, 'b>() -> App<'a, 'b> { SubCommand::with_name("delete_app") .about("Delete app from smart-contract") .args(command::with_ethereum_args(args).as_slice()) + .setting(AppSettings::ArgRequiredElseHelp) } -pub fn parse(args: &ArgMatches) -> Result { +pub fn parse(args: &ArgMatches, config: &SetupConfig) -> Result { let app_id: u64 = value_t!(args, APP_ID, u64)?; let deployed = args.is_present(DEPLOYED); - let eth = command::parse_ethereum_args(args)?; + let eth = command::parse_ethereum_args(args, config)?; return Ok(DeleteApp { app_id, @@ -80,7 +83,7 @@ pub fn parse(args: &ArgMatches) -> Result { } impl DeleteApp { - pub fn new(app_id: u64, deployed: bool, eth: command::EthereumArgs) -> DeleteApp { + pub fn new(app_id: u64, deployed: bool, eth: EthereumParams) -> DeleteApp { DeleteApp { app_id, deployed, diff --git a/cli/src/delete_node.rs b/cli/src/delete_node.rs index fe721fe9bc..d4444f10dd 100644 --- a/cli/src/delete_node.rs +++ b/cli/src/delete_node.rs @@ -15,18 +15,20 @@ */ use clap::ArgMatches; -use clap::{App, SubCommand}; +use clap::{App, AppSettings, SubCommand}; use web3::types::H256; use crate::contract_func::contract::events::node_deleted; use crate::command::*; use crate::contract_func::call_contract; +use crate::ethereum_params::EthereumParams; use crate::step_counter::StepCounter; use crate::utils; use failure::{err_msg, Error, SyncFailure}; use web3::transports::Http; +use crate::config::SetupConfig; use crate::contract_func::contract::functions::delete_node; use crate::contract_func::get_transaction_logs; use crate::contract_func::wait_sync; @@ -34,7 +36,7 @@ use crate::contract_func::wait_tx_included; pub struct DeleteNode { tendermint_key: H256, - eth: EthereumArgs, + eth: EthereumParams, } pub fn subcommand<'a, 'b>() -> App<'a, 'b> { @@ -45,11 +47,12 @@ pub fn subcommand<'a, 'b>() -> App<'a, 'b> { SubCommand::with_name("delete_node") .about("Delete node from smart-contract") .args(with_ethereum_args(args).as_slice()) + .setting(AppSettings::ArgRequiredElseHelp) } -pub fn parse(args: &ArgMatches) -> Result { +pub fn parse(args: &ArgMatches, config: &SetupConfig) -> Result { let tendermint_key = parse_tendermint_key(args)?; - let eth = parse_ethereum_args(args)?; + let eth = parse_ethereum_args(args, config)?; Ok(DeleteNode { tendermint_key, @@ -58,7 +61,7 @@ pub fn parse(args: &ArgMatches) -> Result { } impl DeleteNode { - pub fn new(tendermint_key: H256, eth: EthereumArgs) -> DeleteNode { + pub fn new(tendermint_key: H256, eth: EthereumParams) -> DeleteNode { DeleteNode { tendermint_key, eth, diff --git a/cli/src/ethereum_params.rs b/cli/src/ethereum_params.rs new file mode 100644 index 0000000000..1ca625c011 --- /dev/null +++ b/cli/src/ethereum_params.rs @@ -0,0 +1,74 @@ +/* + * Copyright 2019 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::command::EthereumArgs; +use crate::config::SetupConfig; +use crate::credentials; +use crate::credentials::Credentials; +use ethkey::Secret; +use failure::err_msg; +use failure::Error; +use web3::types::Address; + +#[derive(Debug, Clone)] +pub struct EthereumParams { + pub credentials: Credentials, + pub gas: u32, + pub gas_price: u64, + pub account: Address, + pub contract_address: Address, + pub eth_url: String, + pub wait_tx_include: bool, + pub wait_eth_sync: bool, +} + +impl EthereumParams { + pub fn generate(args: &EthereumArgs, config: &SetupConfig) -> Result { + let secret_key = config.secret_key.map(|s| Secret::from(s)); + + let creds = args.credentials.clone(); + let creds = match creds { + Credentials::No => credentials::load_credentials( + config.keystore_path.clone(), + config.password.clone(), + secret_key, + )?, + other => other, + }; + + let contract_address = args + .contract_address + .unwrap_or(config.contract_address.clone()); + + let account = args + .account + .or_else(|| config.account) + .ok_or_else(|| err_msg("Specify account address in config or in argument"))?; + + let eth_url = args.eth_url.clone().unwrap_or(config.eth_url.clone()); + + Ok(EthereumParams { + credentials: creds, + gas: args.gas, + gas_price: args.gas_price, + account: account, + contract_address: contract_address, + eth_url: eth_url, + wait_tx_include: args.wait_tx_include, + wait_eth_sync: args.wait_eth_sync, + }) + } +} diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 851c902612..cfc4b9c7b8 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -6,14 +6,17 @@ pub extern crate ethabi_derive; pub mod check; pub mod command; +pub mod config; pub mod contract_func; pub mod contract_status; pub mod credentials; pub mod delete_all; pub mod delete_app; pub mod delete_node; +pub mod ethereum_params; pub mod publisher; pub mod register; +pub mod setup; pub mod step_counter; pub mod types; pub mod utils; diff --git a/cli/src/main.rs b/cli/src/main.rs index 290d69d0ff..6770d9ea14 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -20,18 +20,24 @@ use console::style; use exitfailure::ExitFailure; use failure::{err_msg, ResultExt}; +use fluence::config::SetupConfig; +use fluence::config::HOME_DIR; use fluence::publisher::Published; use fluence::register::Registered; use fluence::utils; -use fluence::{check, contract_status, delete_all, delete_app, delete_node, publisher, register}; +use fluence::{ + check, contract_status, delete_all, delete_app, delete_node, publisher, register, setup, +}; use web3::types::H256; const VERSION: &str = env!("CARGO_PKG_VERSION"); fn main() -> Result<(), ExitFailure> { + let config = &SetupConfig::read_from_file_or_default(HOME_DIR)?; + let app = App::new("Fluence CLI") - .global_setting(AppSettings::ArgRequiredElseHelp) .global_setting(AppSettings::UnifiedHelpMessage) + .setting(AppSettings::SubcommandRequiredElseHelp) .version(VERSION) .author("Fluence Labs") .about("Console utility for deploying code to fluence cluster") @@ -41,11 +47,12 @@ fn main() -> Result<(), ExitFailure> { .subcommand(check::subcommand()) .subcommand(delete_app::subcommand()) .subcommand(delete_node::subcommand()) - .subcommand(delete_all::subcommand()); + .subcommand(delete_all::subcommand()) + .subcommand(setup::subcommand()); match app.get_matches().subcommand() { ("publish", Some(args)) => { - let publisher = publisher::parse(args).context("Error parsing arguments")?; + let publisher = publisher::parse(args, config).context("Error parsing arguments")?; let published = publisher .publish(true) .context("Error sending transaction")?; @@ -64,7 +71,7 @@ fn main() -> Result<(), ExitFailure> { } ("register", Some(args)) => { - let register = register::parse(args).context("Error parsing arguments")?; + let register = register::parse(args, config).context("Error parsing arguments")?; let registered = register .register(true) .context("Error sending transaction")?; @@ -97,8 +104,8 @@ fn main() -> Result<(), ExitFailure> { } ("status", Some(args)) => { - let status = - contract_status::get_status_by_args(args).context("Error retrieving status")?; + let status = contract_status::get_status_by_args(args, config) + .context("Error retrieving status")?; if let Some(status) = status { let json = serde_json::to_string_pretty(&status) @@ -111,7 +118,7 @@ fn main() -> Result<(), ExitFailure> { ("check", Some(args)) => check::process(args)?, ("delete_app", Some(args)) => { - let delete_app = delete_app::parse(args).context("Error parsing arguments")?; + let delete_app = delete_app::parse(args, config).context("Error parsing arguments")?; let tx: H256 = delete_app .delete_app(true) .context("Error sending transaction")?; @@ -120,7 +127,8 @@ fn main() -> Result<(), ExitFailure> { } ("delete_node", Some(args)) => { - let delete_node = delete_node::parse(args).context("Error parsing arguments")?; + let delete_node = + delete_node::parse(args, config).context("Error parsing arguments")?; let tx: H256 = delete_node .delete_node(true) .context("Error sending transaction")?; @@ -129,7 +137,7 @@ fn main() -> Result<(), ExitFailure> { } ("delete_all", Some(args)) => { - let delete_all = delete_all::parse(args).context("Error parsing arguments")?; + let delete_all = delete_all::parse(args, config).context("Error parsing arguments")?; delete_all .delete_all() .context("Error sending transaction")?; @@ -137,6 +145,12 @@ fn main() -> Result<(), ExitFailure> { println!("All nodes and apps should be deleted. Check contract with `status` command."); } + ("setup", _) => { + setup::interactive_setup(config).context("Error making setup of Fluence CLI")?; + + println!("Setup completed."); + } + c => Err(err_msg(format!("Unexpected command: {}", c.0)))?, } diff --git a/cli/src/publisher.rs b/cli/src/publisher.rs index 2da9d4df64..f5725eb605 100644 --- a/cli/src/publisher.rs +++ b/cli/src/publisher.rs @@ -20,18 +20,20 @@ use std::io::prelude::*; use failure::{err_msg, Error, ResultExt, SyncFailure}; use clap::ArgMatches; -use clap::{value_t, App, Arg, SubCommand}; +use clap::{value_t, App, AppSettings, Arg, SubCommand}; use derive_getters::Getters; use ethabi::RawLog; use reqwest::Client; use web3::transports::Http; use web3::types::H256; -use crate::command::{parse_ethereum_args, with_ethereum_args, EthereumArgs}; +use crate::command::{parse_ethereum_args, with_ethereum_args}; +use crate::config::SetupConfig; use crate::contract_func::contract::events::app_deployed::parse_log as parse_deployed; use crate::contract_func::contract::events::app_enqueued::parse_log as parse_enqueued; use crate::contract_func::contract::functions::add_app; use crate::contract_func::{call_contract, get_transaction_logs_raw, wait_tx_included}; +use crate::ethereum_params::EthereumParams; use crate::step_counter::StepCounter; use crate::utils; @@ -48,7 +50,7 @@ pub struct Publisher { swarm_url: String, cluster_size: u8, pin_to_nodes: Vec, - eth: EthereumArgs, + eth: EthereumParams, } #[derive(Debug)] @@ -74,7 +76,7 @@ impl Publisher { swarm_url: String, cluster_size: u8, pin_to_nodes: Vec, - eth: EthereumArgs, + eth: EthereumParams, ) -> Publisher { Publisher { bytes, @@ -207,15 +209,17 @@ fn parse_pinned(args: &ArgMatches) -> Result, Error> { } /// Creates `Publisher` from arguments -pub fn parse(matches: &ArgMatches) -> Result { +pub fn parse(matches: &ArgMatches, config: &SetupConfig) -> Result { let path = value_t!(matches, CODE_PATH, String)?; //TODO use is_file from clap_validators let mut file = File::open(path).context("can't open WASM file")?; let mut buf = Vec::new(); file.read_to_end(&mut buf)?; - let swarm_url = value_t!(matches, SWARM_URL, String)?; + let swarm_url = matches + .value_of(SWARM_URL) + .unwrap_or(config.swarm_url.as_str()); let cluster_size = value_t!(matches, CLUSTER_SIZE, u8)?; - let eth = parse_ethereum_args(matches)?; + let eth = parse_ethereum_args(matches, config)?; let pin_to_nodes = parse_pinned(matches)?; if pin_to_nodes.len() > 0 && pin_to_nodes.len() > (cluster_size as usize) { @@ -233,7 +237,7 @@ pub fn parse(matches: &ArgMatches) -> Result { Ok(Publisher::new( buf.to_owned(), - swarm_url, + swarm_url.clone().to_owned(), cluster_size, pin_to_nodes, eth, @@ -279,13 +283,13 @@ pub fn subcommand<'a, 'b>() -> App<'a, 'b> { .required(false) .takes_value(true) .help("Http address to swarm node") - .default_value("http://localhost:8500/") .display_order(3), ]; SubCommand::with_name("publish") .about("Upload code to Swarm and publish app to Ethereum blockchain") .args(with_ethereum_args(args).as_slice()) + .setting(AppSettings::ArgRequiredElseHelp) } /// Uploads bytes of code to the Swarm @@ -315,7 +319,9 @@ mod tests { use failure::Error; use crate::command::EthereumArgs; + use crate::config::SetupConfig; use crate::credentials::Credentials; + use crate::ethereum_params::EthereumParams; use crate::publisher::Publisher; const OWNER: &str = "4180FC65D613bA7E1a385181a219F1DBfE7Bf11d"; @@ -324,13 +330,16 @@ mod tests { let bytes = vec![1, 2, 3]; let eth = EthereumArgs::with_acc_creds(account.parse().unwrap(), creds); + let config = SetupConfig::default().unwrap(); + + let eth_params = EthereumParams::generate(ð, &config).unwrap(); Publisher::new( bytes, String::from("http://localhost:8500/"), 5, vec![], - eth, + eth_params, ) } diff --git a/cli/src/register.rs b/cli/src/register.rs index a94555766d..b6c9d782e3 100644 --- a/cli/src/register.rs +++ b/cli/src/register.rs @@ -18,16 +18,18 @@ use std::net::IpAddr; use failure::{Error, SyncFailure}; -use clap::{value_t, App, Arg, ArgMatches, SubCommand}; +use clap::{value_t, App, AppSettings, Arg, ArgMatches, SubCommand}; use derive_getters::Getters; use hex; use web3::types::H256; use crate::command::*; +use crate::config::SetupConfig; use crate::contract_func::contract::events::app_deployed::parse_log as parse_deployed; use crate::contract_func::contract::functions::add_node; use crate::contract_func::{call_contract, get_transaction_logs, wait_sync, wait_tx_included}; use crate::contract_status::{find_by_tendermint_key, status}; +use crate::ethereum_params::EthereumParams; use crate::step_counter::StepCounter; use crate::types::{NodeAddress, IP_LEN, TENDERMINT_NODE_ID_LEN}; use crate::utils; @@ -48,7 +50,7 @@ pub struct Register { capacity: u16, private: bool, no_status_check: bool, - eth: EthereumArgs, + eth: EthereumParams, } #[derive(PartialEq, Debug)] @@ -73,7 +75,7 @@ impl Register { capacity: u16, private: bool, no_status_check: bool, - eth: EthereumArgs, + eth: EthereumParams, ) -> Result { Ok(Register { node_ip: node_address, @@ -250,7 +252,7 @@ impl Register { } } -pub fn parse(args: &ArgMatches) -> Result { +pub fn parse(args: &ArgMatches, config: &SetupConfig) -> Result { let tendermint_key: H256 = parse_tendermint_key(args)?; let tendermint_node_id: H160 = parse_tendermint_node_id(args)?; @@ -261,7 +263,7 @@ pub fn parse(args: &ArgMatches) -> Result { let private: bool = args.is_present(PRIVATE); let no_status_check: bool = args.is_present(NO_STATUS_CHECK); - let eth = parse_ethereum_args(args)?; + let eth = parse_ethereum_args(args, config)?; let node_address = parse_node_ip(&args)?; @@ -315,6 +317,7 @@ pub fn subcommand<'a, 'b>() -> App<'a, 'b> { SubCommand::with_name("register") .about("Register a node in the smart contract") .args(with_ethereum_args(args).as_slice()) + .setting(AppSettings::ArgRequiredElseHelp) } #[cfg(test)] @@ -326,7 +329,9 @@ pub mod tests { use web3::types::*; use crate::command::EthereumArgs; + use crate::config::SetupConfig; use crate::credentials::Credentials; + use crate::ethereum_params::EthereumParams; use super::Register; @@ -345,6 +350,10 @@ pub mod tests { let eth = generate_eth_args(credentials); + let config = SetupConfig::default().unwrap(); + + let eth_params = EthereumParams::generate(ð, &config).unwrap(); + Register::new( "127.0.0.1".parse().unwrap(), tendermint_key, @@ -353,7 +362,7 @@ pub mod tests { 25100, false, false, - eth, + eth_params, ) .unwrap() } diff --git a/cli/src/setup.rs b/cli/src/setup.rs new file mode 100644 index 0000000000..8677f26a49 --- /dev/null +++ b/cli/src/setup.rs @@ -0,0 +1,105 @@ +/* + * Copyright 2019 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::config::none_if_empty; +use crate::config::SetupConfig; +use crate::config::HOME_DIR; +use crate::utils::parse_hex; +use clap::{App, AppSettings, SubCommand}; +use failure::Error; +use rustyline::Editor; + +pub fn interactive_setup(config: &SetupConfig) -> Result<(), Error> { + let mut rl = Editor::<()>::new(); + + let contract_address_prompt = format!("Contract Address [{:?}]:", config.contract_address); + let contract_address = loop { + let contract_address = rl.readline(&contract_address_prompt)?; + let contract_address = parse_hex(none_if_empty(&contract_address)); + match contract_address { + Ok(r) => break r.unwrap_or(config.contract_address), + Err(e) => { + println!("error occured {}", e); + println!("try again"); + } + } + }; + + let ethereum_url_prompt = format!("Ethereum Node Url [{}]: ", config.eth_url); + let ethereum_address = rl.readline(ðereum_url_prompt)?; + let ethereum_address = none_if_empty(ðereum_address) + .unwrap_or(&config.eth_url) + .to_owned(); + + let swarm_url_prompt = format!("Swarm Node Url [{}]: ", config.swarm_url); + let swarm_address = rl.readline(&swarm_url_prompt)?; + let swarm_address = none_if_empty(&swarm_address) + .unwrap_or(&config.swarm_url) + .to_owned(); + + let account_address_prompt = format!("Account Address [{:?}]: ", config.account); + let account_address = loop { + let account_address = rl.readline(&account_address_prompt)?; + match parse_hex(none_if_empty(&account_address)) { + Ok(r) => break r.or_else(|| config.account), + Err(e) => { + println!("error occured {}", e); + println!("try again"); + } + } + }; + + let secret_key_prompt = format!("Secret Key [{:?}]: ", config.secret_key); + let secret_key = loop { + let secret_key = rl.readline(&secret_key_prompt)?; + match parse_hex(none_if_empty(&secret_key)) { + Ok(r) => break r.or_else(|| config.secret_key), + Err(e) => { + println!("error occured {}", e); + println!("try again"); + } + }; + }; + + let keystore_path_prompt = format!("Keystore Path [{:?}]: ", config.keystore_path); + let keystore_path = rl.readline(&keystore_path_prompt)?; + let keystore_path = none_if_empty(&keystore_path); + + let password_prompt = format!("Password [{:?}]: ", config.password); + let password = rl.readline(&password_prompt)?; + let password = none_if_empty(&password); + println!("password is: {:?}", password); + + let config = SetupConfig::new( + contract_address, + account_address, + ethereum_address, + swarm_address, + secret_key, + keystore_path.map(|s| s.to_owned()), + password.map(|s| s.to_owned()), + ); + config.write_to_file(HOME_DIR)?; + + Ok(()) +} + +pub fn subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("setup") + .about("Setup Fluence CLI with common parameters.") + .unset_setting(AppSettings::ArgRequiredElseHelp) + .unset_setting(AppSettings::SubcommandRequiredElseHelp) +} diff --git a/cli/src/utils.rs b/cli/src/utils.rs index ee4ba4cfbd..8fd5083a1e 100644 --- a/cli/src/utils.rs +++ b/cli/src/utils.rs @@ -124,18 +124,32 @@ pub fn options() -> Options { } // Gets the value of option `key` and removes '0x' prefix -pub fn parse_hex_opt(args: &ArgMatches, key: &str) -> Result { +pub fn parse_hex_string(args: &ArgMatches, key: &str) -> Result { Ok(value_t!(args, key, String).map(|v| v.trim_start_matches("0x").to_string())?) } -pub fn parse_secret_key(args: &ArgMatches, key: &str) -> Result, Error> { - Ok(args - .value_of(key) +pub fn parse_hex_opt(args: &ArgMatches, key: &str) -> Option { + args.value_of(key) + .map(|v| v.trim_start_matches("0x").to_string()) +} + +pub fn parse_secret_key(secret_key: Option<&str>) -> Result, Error> { + Ok(secret_key .map(|s| s.trim_start_matches("0x").parse::()) .map_or(Ok(None), |r| r.map(Some).into()) // Option -> Result