Skip to content

Commit 0c85197

Browse files
authored
Cli/setup (#528)
1 parent 3e3fa09 commit 0c85197

23 files changed

+2862
-2348
lines changed

Diff for: cli/Cargo.lock

+131-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: cli/Cargo.toml

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "fluence"
3-
version = "0.1.4"
3+
version = "0.1.5"
44
authors = ["Fluence Labs"]
55
publish=false
66
edition = "2018"
@@ -19,7 +19,7 @@ console = "0.6.2"
1919
reqwest = "0.9.3"
2020
hex = "0.3.2"
2121
web3 = { git = "https://github.com/fluencelabs/rust-web3", branch = "master" }
22-
serde = "1.0"
22+
serde = { version = "1.0", features = ["derive"]}
2323
serde_json = "1.0"
2424
serde_derive = "1.0"
2525
ethereum-types-serialize = "0.2.1"
@@ -38,6 +38,7 @@ error-chain = "0.12.0"
3838
parity-wasm = "0.35"
3939
tui = {git = "https://github.com/fdehau/tui-rs.git", rev = "52a40ec99"}
4040
termion = "1.5"
41+
rustyline = "3.0.0"
4142

4243
[dev-dependencies]
4344
futures = "0.1.25"

Diff for: cli/README.md

+24-19
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Fluence CLI is an automation tool for tasks of app management (deployment and de
2525

2626
## Requirements
2727

28-
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.
28+
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.
2929

3030
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.
3131

@@ -48,6 +48,21 @@ To look at all possible arguments and options use `./fluence --help`:
4848
You can use `./fluence [SUBCOMMAND] --help` to learn how to use commands.
4949

5050
## Usage examples
51+
### Setup CLI
52+
Use `setup` command to enter main arguments into a config file. It will allow not to use common arguments in every command.
53+
```bash
54+
./fluence setup
55+
```
56+
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.
57+
Arguments description and examples:
58+
- `0x074a79f29c613f4f7035cec582d0f7e4d3cda2e7` is a contract address, register transaction will be sent there
59+
- `http://data.fluence.one:8545` is an URL to Ethereum node
60+
- `http://data.fluence.one:8500` is an URL to Swarm node
61+
- `0x4180fc65d613ba7e1a385181a219f1dbfe7bf11d` will be used as Ethereum account for issuing transactions. _Use your Ethereum account here_
62+
- `0xcb0799337df06a6c73881bab91304a68199a430ccd4bc378e37e51fd1b118133` denotes an Ethereum private key, used for offline transaction signing. _Use your Ethereum private key here_
63+
- it is possible to use keystore file and password instead of secret key
64+
65+
All arguments could be overridden by flags in commands.
5166
### Register a node
5267
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.
5368
The following command will register a node:
@@ -56,9 +71,7 @@ The following command will register a node:
5671
--node_ip 85.82.118.4 \
5772
--tendermint_key 1GVDICzgrw1qahPfSbwCfYw0zrw91OMZ46QoKvJMjjM= \
5873
--tendermint_node_id 5e4eedba85fda7451356a03caffb0716e599679b \
59-
--account 0x4180fc65d613ba7e1a385181a219f1dbfe7bf11d \
6074
--base64_tendermint_key \
61-
--secret_key 0xcb0799337df06a6c73881bab91304a68199a430ccd4bc378e37e51fd1b118133 \
6275
--wait_syncing \
6376
--api_port 25000 \
6477
--capacity 10
@@ -71,10 +84,6 @@ Parameters are:
7184
- currently, Tendermint key can be found in logs of `fluencelabs/node` Docker container
7285
- note that key should be unique, i.e. you can't register several nodes with the same key
7386
- Tendermint p2p node ID `5e4eedba85fda7451356a03caffb0716e599679b` is needed to securely connect nodes in Tendermint cluster
74-
- `0x9995882876ae612bfd829498ccd73dd962ec950a` is a contract address, register transaction will be sent there
75-
- `0x4180fc65d613ba7e1a385181a219f1dbfe7bf11d` will be used as Ethereum account for issuing transactions. _Use your Ethereum account here_
76-
- `--secret_key 0xcb0799337df06a6c73881bab91304a68199a430ccd4bc378e37e51fd1b118133` denotes an Ethereum private key, used for offline transaction signing. _Use your Ethereum private key here_
77-
- using `--password` is possible instead of private key, but private key is preferred
7887
- `--wait_syncing` so CLI waits until Ethereum node is fully synced
7988
- `--api_port 25000` specifies the main port of the Fluence node, so other nodes and users know where to connect
8089
- `--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
8695
The following command will publish app `counter.wasm`.
8796
```
8897
./fluence publish \
89-
--code_path fluence/vm/examples/counter/target/wasm32-unknown-unknown/release/deps/counter.wasm \
90-
--account 0x4180fc65d613ba7e1a385181a219f1dbfe7bf11d \
98+
--code_path fluence/vm/examples/counter/target/wasm32-unknown-unknown/release/deps/counter.wasm \
9199
--cluster_size 4 \
92-
--secret_key 0xcb0799337df06a6c73881bab91304a68199a430ccd4bc378e37e51fd1b118133 \
93100
--pin_to 1GVDICzgrw1qahPfSbwCfYw0zrw91OMZ46QoKvJMjjM= \
94101
--base64
95102
```
@@ -134,13 +141,11 @@ App enqueued.
134141
### Delete an app
135142
If you want to delete your app from smart contract, you can use `delete_app` command.
136143

137-
The following will delete app with id `0x0000000000000000000000000000000000000000000000000000000000000002`. App id could be retrieved either from status (see below) or from smart-contract.
144+
The following will delete app with id `2`. App id could be retrieved either from status (see below) or from smart-contract.
138145

139146
```
140-
./fluence delete_app \
141-
--account 0x4180fc65d613ba7e1a385181a219f1dbfe7bf11d \
142-
--app_id 0x0000000000000000000000000000000000000000000000000000000000000002 \
143-
--secret_key 4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7 \
147+
./fluence delete_app \
148+
--app_id 2 \
144149
--deployed
145150
```
146151

@@ -159,7 +164,7 @@ The results will be in JSON and should resemble the following
159164
{
160165
"apps": [
161166
{
162-
"app_id": "0x0000000000000000000000000000000000000000000000000000000000000001",
167+
"app_id": "1",
163168
"storage_hash": "0xeb2a623210c080d0702cc520b790151861601c46d90179a6e8efe6bda8ac5477",
164169
"storage_receipt": "0x0000000000000000000000000000000000000000000000000000000000000000",
165170
"cluster_size": 5,
@@ -168,7 +173,7 @@ The results will be in JSON and should resemble the following
168173
"cluster": null
169174
},
170175
{
171-
"app_id": "0x0000000000000000000000000000000000000000000000000000000000000005",
176+
"app_id": "5",
172177
"storage_hash": "0xeb2a623210c080d0702cc520b790151861601c46d90179a6e8efe6bda8ac5477",
173178
"storage_receipt": "0x0000000000000000000000000000000000000000000000000000000000000000",
174179
"cluster_size": 5,
@@ -256,7 +261,7 @@ There is a flag `--contract_address` to use all commands to interact with non-de
256261
```bash
257262
./fluence <command>
258263
...
259-
--contract_address 0x9995882876ae612bfd829498ccd73dd962ec950a \
264+
--contract_address 0x074a79f29c613f4f7035cec582d0f7e4d3cda2e7 \
260265
...
261266
```
262267

@@ -312,7 +317,7 @@ For example, with `delete_app`
312317
```bash
313318
./fluence delete_app \
314319
--account 0x4180fc65d613ba7e1a385181a219f1dbfe7bf11d \
315-
--app_id 0x0000000000000000000000000000000000000000000000000000000000000002 \
320+
--app_id 2 \
316321
--keystore ~/Library/Ethereum/keystore/UTC--2017-03-03T13-24-07.826187674Z--4e6cf0ed2d8bbf1fbbc9f2a100602ceba4bf1319 \
317322
--password my_secure_passw0rd \
318323
--deployed

Diff for: cli/src/check.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
use std::collections::HashMap;
1818

19-
use clap::{App, Arg, ArgMatches, SubCommand};
19+
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
2020
use console::style;
2121
use parity_wasm::elements::Error as ParityError;
2222
use parity_wasm::elements::Module;
@@ -72,6 +72,7 @@ pub fn process(args: &ArgMatches) -> Result<(), Error> {
7272
pub fn subcommand<'a, 'b>() -> App<'a, 'b> {
7373
SubCommand::with_name("check")
7474
.about("Verifies wasm file, issue warning for using functions from banned modules.")
75+
.setting(AppSettings::ArgRequiredElseHelp)
7576
.args(&[Arg::with_name(INPUT_ARG)
7677
.required(true)
7778
.takes_value(true)

Diff for: cli/src/command.rs

+30-64
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,17 @@
1414
* limitations under the License.
1515
*/
1616

17+
use crate::config::SetupConfig;
18+
use crate::credentials;
1719
use crate::credentials::Credentials;
20+
use crate::ethereum_params::EthereumParams;
1821
use crate::utils;
22+
use crate::utils::parse_hex;
1923
use clap::value_t;
2024
use clap::Arg;
2125
use clap::ArgMatches;
22-
use ethkey::Password;
23-
use ethkey::Secret;
24-
use ethstore::accounts_dir::{DiskKeyFileManager, KeyFileManager};
25-
use ethstore::SafeAccount;
26-
use failure::err_msg;
2726
use failure::Error;
2827
use failure::ResultExt;
29-
use std::fs::File;
3028
use std::net::IpAddr;
3129
use web3::types::Address;
3230
use web3::types::H160;
@@ -54,9 +52,9 @@ pub struct EthereumArgs {
5452
pub credentials: Credentials,
5553
pub gas: u32,
5654
pub gas_price: u64,
57-
pub account: Address,
58-
pub contract_address: Address,
59-
pub eth_url: String,
55+
pub account: Option<Address>,
56+
pub contract_address: Option<Address>,
57+
pub eth_url: Option<String>,
6058
pub wait_tx_include: bool,
6159
pub wait_eth_sync: bool,
6260
}
@@ -66,7 +64,6 @@ pub fn contract_address<'a, 'b>() -> Arg<'a, 'b> {
6664
.long(CONTRACT_ADDRESS)
6765
.short("d")
6866
.value_name("eth address")
69-
.default_value(include_str!("../../tools/deploy/scripts/contract.txt").trim())
7067
.takes_value(true)
7168
.help("Fluence contract address")
7269
}
@@ -79,7 +76,6 @@ pub fn eth_url<'a, 'b>() -> Arg<'a, 'b> {
7976
.required(false)
8077
.takes_value(true)
8178
.help("Http address to ethereum node")
82-
.default_value("http://localhost:8545/")
8379
}
8480

8581
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<Arg<'a, 'b>> {
127123
.long(ACCOUNT)
128124
.short("a")
129125
.value_name("eth address")
130-
.required(true)
126+
.required(false)
131127
.takes_value(true)
132128
.help("Ethereum account"),
133129
Arg::with_name(PASSWORD)
@@ -189,70 +185,38 @@ pub fn with_ethereum_args<'a, 'b>(args: &[Arg<'a, 'b>]) -> Vec<Arg<'a, 'b>> {
189185
eth_args
190186
}
191187

192-
pub fn parse_contract_address(args: &ArgMatches) -> Result<Address, Error> {
193-
Ok(utils::parse_hex_opt(args, CONTRACT_ADDRESS)?
194-
.parse::<Address>()
195-
.context("Error parsing contract address")?)
196-
}
197-
198-
pub fn parse_eth_url(args: &ArgMatches) -> Result<String, clap::Error> {
199-
value_t!(args, ETH_URL, String)
200-
}
201-
202-
fn load_keystore(path: String, password: String) -> Result<Secret, Error> {
203-
let keystore = File::open(path).context("can't open keystore file")?;
204-
let dkfm = DiskKeyFileManager {};
205-
let keystore: SafeAccount = dkfm
206-
.read(None, keystore)
207-
.map_err(|e| err_msg(e.to_string()))
208-
.context("can't parse keystore file")?;
209-
210-
let password: Password = password.into();
211-
keystore
212-
.crypto
213-
.secret(&password)
214-
.map_err(|e| err_msg(e.to_string()))
215-
.context("can't parse secret from keystore file")
216-
.map_err(Into::into)
188+
pub fn parse_contract_address(args: &ArgMatches) -> Result<Option<Address>, Error> {
189+
Ok(parse_hex(args.value_of(CONTRACT_ADDRESS))?)
217190
}
218191

219-
fn load_credentials(
220-
keystore: Option<String>,
221-
password: Option<String>,
222-
secret_key: Option<Secret>,
223-
) -> Result<Credentials, Error> {
224-
match keystore {
225-
Some(keystore) => match password {
226-
Some(password) => load_keystore(keystore, password).map(Credentials::Secret),
227-
None => Err(err_msg("password is required for keystore")),
228-
},
229-
None => Ok(Credentials::get(secret_key, password.clone())),
230-
}
192+
pub fn parse_eth_url(args: &ArgMatches) -> Option<String> {
193+
args.value_of(ETH_URL).map(|s| s.to_owned())
231194
}
232195

233-
pub fn parse_ethereum_args(args: &ArgMatches) -> Result<EthereumArgs, Error> {
234-
let secret_key = utils::parse_secret_key(args, SECRET_KEY)?;
196+
pub fn parse_ethereum_args(
197+
args: &ArgMatches,
198+
config: &SetupConfig,
199+
) -> Result<EthereumParams, Error> {
200+
let secret_key = utils::parse_secret_key(args.value_of(SECRET_KEY))?;
235201
let password = args.value_of(PASSWORD).map(|s| s.to_string());
236202
let keystore = args.value_of(KEYSTORE).map(|s| s.to_string());
237203

238-
let credentials = load_credentials(keystore, password, secret_key)?;
204+
let credentials = credentials::load_credentials(keystore, password, secret_key)?;
239205

240206
let gas = value_t!(args, GAS, u32)?;
241207
let gas_price = value_t!(args, GAS_PRICE, u64)?;
242208
// TODO: it could panic here on overflow
243209
let gas_price = gas_price * TO_GWEI_MUL;
244-
let account: Address = utils::parse_hex_opt(args, ACCOUNT)?
245-
.parse::<Address>()
246-
.context("Error parsing account address")?;
210+
let account: Option<Address> = utils::parse_hex(args.value_of(ACCOUNT))?;
247211

248-
let contract_address: Address = parse_contract_address(args)?;
212+
let contract_address: Option<Address> = parse_contract_address(args)?;
249213

250-
let eth_url = parse_eth_url(args)?;
214+
let eth_url = parse_eth_url(args);
251215

252216
let wait = args.is_present(WAIT);
253217
let wait_syncing = args.is_present(WAIT_SYNCING);
254218

255-
return Ok(EthereumArgs {
219+
let eth_args = EthereumArgs {
256220
credentials,
257221
gas,
258222
gas_price,
@@ -261,11 +225,13 @@ pub fn parse_ethereum_args(args: &ArgMatches) -> Result<EthereumArgs, Error> {
261225
eth_url,
262226
wait_tx_include: wait,
263227
wait_eth_sync: wait_syncing,
264-
});
228+
};
229+
230+
Ok(EthereumParams::generate(&eth_args, config)?)
265231
}
266232

267233
pub fn parse_tendermint_key(args: &ArgMatches) -> Result<H256, Error> {
268-
let tendermint_key = utils::parse_hex_opt(args, TENDERMINT_KEY)
234+
let tendermint_key = utils::parse_hex_string(args, TENDERMINT_KEY)
269235
.context("error parsing tendermint key")?
270236
.to_owned();
271237
let base64 = args.is_present(BASE64_TENDERMINT_KEY);
@@ -305,9 +271,9 @@ impl Default for EthereumArgs {
305271
credentials: Credentials::No,
306272
gas: 1_000_000,
307273
gas_price: 1_000_000_000,
308-
account: "4180FC65D613bA7E1a385181a219F1DBfE7Bf11d".parse().unwrap(),
309-
contract_address: "9995882876ae612bfd829498ccd73dd962ec950a".parse().unwrap(),
310-
eth_url: String::from("http://localhost:8545"),
274+
account: Some("4180FC65D613bA7E1a385181a219F1DBfE7Bf11d".parse().unwrap()),
275+
contract_address: Some("9995882876ae612bfd829498ccd73dd962ec950a".parse().unwrap()),
276+
eth_url: Some(String::from("http://localhost:8545")),
311277
wait_tx_include: false,
312278
wait_eth_sync: false,
313279
}
@@ -318,7 +284,7 @@ impl EthereumArgs {
318284
pub fn with_acc_creds(account: Address, credentials: Credentials) -> EthereumArgs {
319285
let mut args = EthereumArgs::default();
320286
args.credentials = credentials;
321-
args.account = account;
287+
args.account = Some(account);
322288
args
323289
}
324290
}

0 commit comments

Comments
 (0)