Skip to content

Commit

Permalink
Cli/setup (#528)
Browse files Browse the repository at this point in the history
  • Loading branch information
DieMyst authored Mar 5, 2019
1 parent 3e3fa09 commit 0c85197
Show file tree
Hide file tree
Showing 23 changed files with 2,862 additions and 2,348 deletions.
132 changes: 131 additions & 1 deletion cli/Cargo.lock

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "fluence"
version = "0.1.4"
version = "0.1.5"
authors = ["Fluence Labs"]
publish=false
edition = "2018"
Expand All @@ -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"
Expand All @@ -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"
Expand Down
43 changes: 24 additions & 19 deletions cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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:
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
```
Expand Down Expand Up @@ -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
```

Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -256,7 +261,7 @@ There is a flag `--contract_address` to use all commands to interact with non-de
```bash
./fluence <command>
...
--contract_address 0x9995882876ae612bfd829498ccd73dd962ec950a \
--contract_address 0x074a79f29c613f4f7035cec582d0f7e4d3cda2e7 \
...
```

Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion cli/src/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
94 changes: 30 additions & 64 deletions cli/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Address>,
pub contract_address: Option<Address>,
pub eth_url: Option<String>,
pub wait_tx_include: bool,
pub wait_eth_sync: bool,
}
Expand All @@ -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")
}
Expand All @@ -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> {
Expand Down Expand Up @@ -127,7 +123,7 @@ pub fn with_ethereum_args<'a, 'b>(args: &[Arg<'a, 'b>]) -> Vec<Arg<'a, 'b>> {
.long(ACCOUNT)
.short("a")
.value_name("eth address")
.required(true)
.required(false)
.takes_value(true)
.help("Ethereum account"),
Arg::with_name(PASSWORD)
Expand Down Expand Up @@ -189,70 +185,38 @@ pub fn with_ethereum_args<'a, 'b>(args: &[Arg<'a, 'b>]) -> Vec<Arg<'a, 'b>> {
eth_args
}

pub fn parse_contract_address(args: &ArgMatches) -> Result<Address, Error> {
Ok(utils::parse_hex_opt(args, CONTRACT_ADDRESS)?
.parse::<Address>()
.context("Error parsing contract address")?)
}

pub fn parse_eth_url(args: &ArgMatches) -> Result<String, clap::Error> {
value_t!(args, ETH_URL, String)
}

fn load_keystore(path: String, password: String) -> Result<Secret, Error> {
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<Option<Address>, Error> {
Ok(parse_hex(args.value_of(CONTRACT_ADDRESS))?)
}

fn load_credentials(
keystore: Option<String>,
password: Option<String>,
secret_key: Option<Secret>,
) -> Result<Credentials, Error> {
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<String> {
args.value_of(ETH_URL).map(|s| s.to_owned())
}

pub fn parse_ethereum_args(args: &ArgMatches) -> Result<EthereumArgs, Error> {
let secret_key = utils::parse_secret_key(args, SECRET_KEY)?;
pub fn parse_ethereum_args(
args: &ArgMatches,
config: &SetupConfig,
) -> Result<EthereumParams, Error> {
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::<Address>()
.context("Error parsing account address")?;
let account: Option<Address> = utils::parse_hex(args.value_of(ACCOUNT))?;

let contract_address: Address = parse_contract_address(args)?;
let contract_address: Option<Address> = 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,
Expand All @@ -261,11 +225,13 @@ pub fn parse_ethereum_args(args: &ArgMatches) -> Result<EthereumArgs, Error> {
eth_url,
wait_tx_include: wait,
wait_eth_sync: wait_syncing,
});
};

Ok(EthereumParams::generate(&eth_args, config)?)
}

pub fn parse_tendermint_key(args: &ArgMatches) -> Result<H256, Error> {
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);
Expand Down Expand Up @@ -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,
}
Expand All @@ -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
}
}
Loading

0 comments on commit 0c85197

Please sign in to comment.