Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Umbrella Iroha CLI Pt. I #5274

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ It can be done by running:

```bash
# compile executor without optimizations
cargo run --bin iroha_wasm_builder -- build ./path/to/executor --out-file executor.wasm
cargo run --bin iroha wasm build ./path/to/executor --out-file executor.wasm
```

With profiling feature enabled Iroha exposes endpoint to scrap pprof profiles:
Expand Down
35 changes: 10 additions & 25 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions crates/iroha_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ path = "src/main.rs"
[dependencies]
iroha = { workspace = true }
iroha_primitives = { workspace = true }
iroha_schema = { workspace = true }
iroha_schema_gen = { workspace = true }
iroha_genesis = { workspace = true }
iroha_data_model = { workspace = true }
iroha_wasm_builder = { workspace = true }
spinoff = { workspace = true, features = ["binary"] }
owo-colors = { workspace = true, features = ["supports-colors"] }
wasmtime = { workspace = true }

thiserror = { workspace = true }
error-stack = { workspace = true, features = ["eyre"] }
Expand All @@ -44,7 +52,13 @@ supports-color = { workspace = true }
derive_more = { workspace = true }
tokio = { workspace = true, features = ["rt"] }
futures = { workspace = true }
parity-scale-codec = { workspace = true }
colored = "2.1.0"

[build-dependencies]
vergen = { version = "8.3.1", default-features = false }
color-eyre = "0.6.3"
parity-scale-codec = { workspace = true }
iroha_data_model = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
174 changes: 55 additions & 119 deletions crates/iroha_cli/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# Iroha CLI Client
# Iroha CLI

Iroha Client CLI is a "thin" wrapper around functionality exposed in the `iroha` crate. Specifically, it should be used as a reference for using `iroha`'s features, and not as a production-ready client. As such, the CLI client is not guaranteed to support all features supported by the client library. Check [Iroha 2 documentation](https://docs.iroha.tech/get-started/operate-iroha-2-via-cli.html) for a detailed tutorial on working with Iroha Client CLI.
Iroha cli is a multi-purpose tool for interactions with iroha components.

# Table of Contents
1. [Installation](#installation)
2. [Usage](#usage)
3. [Examples](#examples)

## Installation

Expand All @@ -14,137 +19,68 @@ cargo build

The above command will produce the `iroha` ELF executable file for Linux/BSD, the `iroha` executable for MacOS, and the `iroha.exe` executable for Windows, depending on your platform and configuration.

Alternatively, check out the [documentation](https://docs.iroha.tech/get-started/install-iroha-2.html) for system-wide installation instructions.
<!-- TODO: Update documentation -->
Alternatively, check out the [documentation](https://docs.iroha.tech/get-started/install-iroha-2.html) (**TBU**) for system-wide installation instructions.

## Usage

Run Iroha Client CLI:
Run Iroha CLI:

```
iroha [OPTIONS] <SUBCOMMAND>
iroha <SUBCOMMANDS> [OPTIONS]
```

### Options

| Option | Description |
| --------------------- | -------------------------------------------------- |
| -c, --config <config> | Set a config file path (`config.json` by default). |

### Subcommands
| Command | Description |
|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
| codec | Execute commands related to [Parity Scale Codec](https://github.com/paritytech/parity-scale-codec): list available types, decode SCALE to iroha types, decode SCALE to json, encode SCALE from json. |
| wasm | Execute commands related to smartcontracts: build and check source files, run wasm tests. |
| client | Execute commands relatedto interactions with iroha peers Web API. |

<details> <summary>Codec subcommands</summary>

| Command | Description |
|-----------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------|
| `list-types` | List all available data types. |
| `scale-to-json` | Decode the data type from SCALE to JSON. |
| `json-to-scale` | Encode the data type from JSON to SCALE. |
| `scale-to-rust` | Decode the data type from SCALE binary file to Rust debug format.<br>Can be used to analyze binary input if data type is not known. |
| `help` | Print the help message for the tool or a subcommand. |
</details>

<details> <summary>Wasm subcommands</summary>

| Command | Description |
|-----------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------|
| `check` | Check if smartcontract sources are valid (`cargo check`). |
| `build` | Build smartcontracs from given sources (`cargo build`). |
| `test` | Run WebAssembly tests. |
| `help` | Print the help message for the tool or a subcommand. |
</details>
</details>

<details> <summary>Client subcommands</summary>

`client` commands require a valid configuration file, refer to `defaults/client.toml` as example.

| Command | Description |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `account` | Execute commands related to accounts: register a new one, list all accounts, grant a permission to an account, list all account permissions |
| `asset` | Execute commands related to assets: register a new one, mint or transfer assets, get info about an asset, list all assets |
| `blocks` | Get block stream from Iroha peer |
| `domain` | Execute commands related to domains: register a new one, list all domains |
| `events` | Get event stream from Iroha peer |
| `json` | Submit multi-instructions or request query as JSON |
| `peer` | Execute commands related to peer administration and networking |
| `wasm` | Execute commands related to WASM |
| `help` | Print the help message for `iroha` and/or the current subcommand other than `help` subcommand |
| `account` | Execute commands related to accounts: register a new one, list all accounts, grant a permission to an account, list all account permissions. |
| `asset` | Execute commands related to assets: register a new one, mint or transfer assets, get info about an asset, list all assets. |
| `blocks` | Get block stream from Iroha peer. |
| `domain` | Execute commands related to domains: register a new one, list all domains. |
| `events` | Get event stream from Iroha peer. |
| `json` | Submit multi-instructions or request query as JSON. |
| `peer` | Execute commands related to peer administration and networking. |
| `wasm` | Execute commands related to WASM. |
| `help` | Print the help message for `iroha` and/or the current subcommand other than `help` subcommand. |

Refer to [Iroha Special Instructions](https://docs.iroha.tech/blockchain/instructions.html) for more information about Iroha instructions such as register, mint, grant, and so on.
</details>

## Examples

:grey_exclamation: All examples below are Unix-oriented. If you're working on Windows, we would highly encourage you to consider using WSL, as most documentation assumes a POSIX-like shell running on your system. Please be advised that the differences in the syntax may go beyond executing `iroha.exe` instead of `iroha`.

```bash
./iroha domain register --id="Soramitsu"
./iroha account register --id="ed01204A3C5A6B77BBE439969F95F0AA4E01AE31EC45A0D68C131B2C622751FCC5E3B6@Soramitsu"
./iroha asset register --id="XOR#Soramitsu" --type=Numeric
./iroha asset mint --account="ed01204A3C5A6B77BBE439969F95F0AA4E01AE31EC45A0D68C131B2C622751FCC5E3B6@Soramitsu" --asset="XOR#Soramitsu" --quantity=1010
./iroha asset get --account="ed01204A3C5A6B77BBE439969F95F0AA4E01AE31EC45A0D68C131B2C622751FCC5E3B6@Soramitsu" --asset="XOR#Soramitsu"
```

In this section we will show you how to use Iroha CLI Client to do the following:

- [Create new Domain](#create-new-domain)
- [Create new Account](#create-new-account)
- [Mint Asset to Account](#mint-asset-to-account)
- [Query Account Assets Quantity](#query-account-assets-quantity)
- [Execute WASM transaction](#execute-wasm-transaction)
- [Execute Multi-instruction Transactions](#execute-multi-instruction-transactions)

### Create new Domain

To create a domain, you need to specify the entity type first (`domain` in our case) and then the command (`register`) with a list of required parameters. For the `domain` entity, you only need to provide the `id` argument as a string that doesn't contain the `@` and `#` symbols.

```bash
./iroha domain register --id="Soramitsu"
```

### Create new Account

To create an account, specify the entity type (`account`) and the command (`register`). Then define the value of the `id` argument in "signatory@domain" format, where signatory is the account's public key in multihash representation:

```bash
./iroha account register --id="ed01204A3C5A6B77BBE439969F95F0AA4E01AE31EC45A0D68C131B2C622751FCC5E3B6@Soramitsu"
```

### Mint Asset to Account

To add assets to the account, you must first register an Asset Definition. Specify the `asset` entity and then use the `register` and `mint` commands respectively. Here is an example of adding Assets of the type `Quantity` to the account:

```bash
./iroha asset register --id="XOR#Soramitsu" --type=Numeric
./iroha asset mint --account="ed01204A3C5A6B77BBE439969F95F0AA4E01AE31EC45A0D68C131B2C622751FCC5E3B6@Soramitsu" --asset="XOR#Soramitsu" --quantity=1010
```

With this, you created `XOR#Soramitsu`, an asset of type `Numeric`, and then gave `1010` units of this asset to the account `ed01204A3C5A6B77BBE439969F95F0AA4E01AE31EC45A0D68C131B2C622751FCC5E3B6@Soramitsu`.

### Query Account Assets Quantity

You can use Query API to check that your instructions were applied and the _world_ is in the desired state. For example, to know how many units of a particular asset an account has, use `asset get` with the specified account and asset:

```bash
./iroha asset get --account="ed01204A3C5A6B77BBE439969F95F0AA4E01AE31EC45A0D68C131B2C622751FCC5E3B6@Soramitsu" --asset="XOR#Soramitsu"
```

This query returns the quantity of `XOR#Soramitsu` asset for the `ed01204A3C5A6B77BBE439969F95F0AA4E01AE31EC45A0D68C131B2C622751FCC5E3B6@Soramitsu` account.

You can also filter based on either account, asset or domain id by using the filtering API provided by the Iroha client CLI. Generally, filtering follows the `./iroha ENTITY list filter PREDICATE` pattern, where ENTITY is asset, account or domain and PREDICATE is condition used for filtering serialized using JSON5 (check `iroha::data_model::predicate::value::ValuePredicate` type).

Here are some examples of filtering:

```bash
# Filter domains by id
./iroha domain list filter '{"Identifiable": {"Is": "wonderland"}}'
# Filter accounts by domain
./iroha account list filter '{"Identifiable": {"EndsWith": "@wonderland"}}'
# Filter asset by domain
./iroha asset list filter '{"Or": [{"Identifiable": {"Contains": "#wonderland#"}}, {"And": [{"Identifiable": {"Contains": "##"}}, {"Identifiable": {"EndsWith": "@wonderland"}}]}]}'
```

### Execute WASM transaction

Use `--file` to specify a path to the WASM file:

```bash
./iroha wasm --file=/path/to/file.wasm
```

Or skip `--file` to read WASM from standard input:

```bash
cat /path/to/file.wasm | ./iroha wasm
```

These subcommands submit the provided wasm binary as an `Executable` to be executed outside a trigger context.

### Execute Multi-instruction Transactions

The reference implementation of the Rust client, `iroha`, is often used for diagnosing problems in other implementations.

To test transactions in the JSON format (used in the genesis block and by other SDKs), pipe the transaction into the client and add the `json` subcommand to the arguments:

```bash
cat /path/to/file.json | ./iroha json transaction
```

### Request arbitrary query

```bash
echo '{ "FindAllParameters": null }' | ./iroha --config client.toml json query
```
- [Codec](examples/codec.md) tutorial and examples
- [Wasm](examples/wasm.md) basic usage examples
- [Client](examples/client.md) basic usage examples
38 changes: 37 additions & 1 deletion crates/iroha_cli/build.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,50 @@
//! Build script to extract git hash of Iroha build

use std::{fs, path::PathBuf};

use color_eyre::{
eyre::{eyre, WrapErr},
Result,
};
use iroha_data_model::{account::NewAccount, domain::NewDomain, prelude::*};
use parity_scale_codec::Encode;
use serde::de::DeserializeOwned;

fn main() -> Result<()> {
vergen::EmitBuilder::builder()
.git_sha(true)
.emit()
.map_err(|err| eyre!(Box::new(err)))
.wrap_err("Failed to extract git hash")
.wrap_err("Failed to extract git hash")?;

// Codec
sample_into_binary_file::<NewAccount>("account").expect("Failed to encode into account.bin.");
sample_into_binary_file::<NewDomain>("domain").expect("Failed to encode into domain.bin.");
sample_into_binary_file::<Trigger>("trigger").expect("Failed to encode into trigger.bin.");

Ok(())
}

fn sample_into_binary_file<T>(filename: &str) -> Result<()>
where
T: Encode + DeserializeOwned,
{
let mut path_to = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path_to.push("../../");
path_to.push("samples/codec/");
path_to.push(filename);

let path_to_json = path_to.with_extension("json");
let path_to_binary = path_to.with_extension("bin");

println!("cargo:rerun-if-changed={}", path_to_json.to_str().unwrap());
let buf = fs::read_to_string(path_to_json)?;

let sample = serde_json::from_str::<T>(buf.as_str())?;

let buf = sample.encode();

fs::write(path_to_binary, buf)?;

Ok(())
}
Loading
Loading