Skip to content

Commit

Permalink
CLI improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
xevisalle committed Nov 14, 2023
1 parent 34e463f commit cd0119e
Show file tree
Hide file tree
Showing 55 changed files with 182 additions and 401 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[workspace]
members = ["moat-cli", "moat-cli-user", "moat-cli-lp", "moat-cli-sp", "moat-cli-request", "moat-core", "wallet-accessor", "integration-tests", "license-provider", "macros/code-hasher"]
members = ["testing-utils/test-moat-cli", "moat-cli-user", "moat-cli-lp", "moat-cli-sp", "testing-utils/test-moat-request", "moat-core", "wallet-accessor", "integration-tests", "license-provider", "macros/code-hasher"]
202 changes: 31 additions & 171 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,182 +1,42 @@
# dusk moat
# Moat: The Citadel SDK

[![Repository](https://img.shields.io/badge/github-moat-blueviolet?logo=github)](https://github.com/dusk-network/moat)
![Build Status](https://github.com/dusk-network/moat/workflows/dusk_ci/badge.svg)
[![Documentation](https://img.shields.io/badge/docs-moat-blue?logo=rust)](https://docs.rs/moat/)

`moat` is a Rust workspace containing the following crates:
**Moat** (a.k.a. the Citadel SDK) contains all the required tools for using and implementing self-sovereign identity systems using the Citadel protocol integrated into the Blockchain of Dusk.

- `moat-cli`: Command line interface (CLI) for submitting license requests to the Dusk blockchain.
- `moat-core`: Library providing an SDK required for implementing Citadel scenarios with the Dusk blockchain.
- `license-provider`: Reference implementation of a license provider.
- `integration-tests`: Moat library integration tests (test which require access to Dusk Wallet and live Dusk cluster).
- `wallet-accessor`: Library for submitting contract-call transactions to the Dusk blockchain.
## Prerequisites

**Moat** requires a reachable Rusk node installed and running, or selecting a trusted one. You can set up a node as explained [here](https://wiki.dusk.network/en/setting-up-node). It also requires an installed wallet connected to the given Rusk node, as explained [here](https://github.com/dusk-network/wallet-cli/blob/main/src/bin/README.md). Then you should specify the Rusk node address in `config.toml`.

## moat-cli
## Testing the environment

moat-cli utility can be used to submit license request to the Dusk blockchain.
Any license provider can then scan the blockchain for requests, filter out relevant requests and process them accordingly.
You can test if the environment you set up and the library are working properly by executing the following:

Example usage of the moat-cli utility:
```sh
cargo r --release --bin moat-cli -- --wallet-path ~/.dusk/rusk-wallet --config-path ./moat-cli/config.toml --password password ./moat-cli/request.json
```
where:
- `wallet-path`: path to your installed wallet directory
- `config-path`: path to your blockchain access configuration (refer to the configuration section)
- `password`: password for your wallet
- `...request.json`: path to your request json file (as explained in the request section)

Request sending can also be performed programmatically, using moat-core, described below:
```rust
//...
let request_json: RequestJson = RequestJson::from_file(json_path)?;
let rng = &mut StdRng::seed_from_u64(0xcafe);
let request = RequestCreator::create_from_hex_args(
request_json.user_ssk,
request_json.provider_psk,
rng,
)?;
//...
PayloadSender::send_to_contract_method(
request,
&blockchain_access_config,
&wallet_path,
&psw,
gas_limit,
gas_price,
LICENSE_CONTRACT_ID,
NOOP_METHOD_NAME,
)
.await?;
//...
cd integration-tests
cargo t --release --features="exp_tests" -- --test-threads=1
cargo t --release --features="int_tests" -- --test-threads=1
```
In the above example, the user is expected to have a request json file available
at some filesystem path. The code loads contents of the file, extracts request arguments from it and
instantiates a request object. Subsequently, request is being sent to blockchain via
a provided wallet (utilizing wallet path and password, as well as a blockchain access configuration file).

As the `moat-cli` requires a path to a json request file. An example request json file looks as follows:
```json
{
"user_ssk": "c6afd78c8b3902b474d4c0972b62888e4b880dccf8da68e86266fefa45ee7505926f06ab82ac200995f1239d518fdb74903f225f4460d8db62f2449f6d4dc402",
"provider_psk": "29c4336ef24e585f4506e32e269c5363a71f7dcd74586b210c56e569ad2644e832c785f102dd3c985c705008ec188be819bac85b65c9f70decb9adcf4a72cc43"
}

## Usage

The moat-cli utility can be used from the POV of any of the parties involved in the Citadel protocol, let them be:
- **License Provider (LP):** A party receiving onchain requests from users to issue licenses onchain addressed to them.
- **User:** A party requesting licenses to LPs.

### License Provider

LPs can then scan the Blockchain for requests and issue licenses if the requests are valid. To run the LP CLI, simply run:

```sh
cargo r --release --bin moat-cli-lp -- --wallet-path ~/.dusk/rusk-wallet --wallet-pass <PASSWORD>
```
It contains the user secret spend key (user_ssk) and provider public spend key (provider_psk), both in a form of a hexadecimal string.

## moat-core
Provides an SDK for writing user, LP, and SP applications based on the Dusk blockchain.
It provides the following functionality, related to license contract:
- creating requests
- sending license requests
- scanning blockchain for requests
- performing license contract queries: _get_licenses, get_merkle_opening, get_session, get_info_

In addition, it provides the following generic Dusk blockchain functionality, not necessarily related to license contract:
- sending payloads to any method of any contract (e.g., can be used for _issue_license_ and _use_license_)
- retrieving payloads of any type from the blockchain
- performing queries on any method of any contract (with return values passed directly or via a feeder/stream)
- retrieving transactions from blockchain (e.g., by block range)

In addition, websocket functionality for the queries is also provided.

## license-provider
Provides functionality needed for implementors of license provider, including:
- license issuer
- blockchain scanner for relevant request
The crate allows for implementation of a license provider, whose task is to periodically check for license requests in the blockchain, and the to process the request and issue licenses.

## integration-tests
As most of the functionality provided by Moat deals with a blockchain, integration tests play critical role.
As in the case of moat-core functionality, tests include both Citadel-specific tests and blockchain generic test.

## wallet accessor
This is a low-level crate which provides wallet (Blockchain) connectivity for functions of moat-core.
Users of moat-core do not need to be aware of this crate, yet for maintainers and extenders, the crate
provides a convenient low level interface between the higher-level moat-core library and the blockchain.
Note that this crate deals only with contract method calling, it does not deal with contract queries.

## moat-core

### citadel requests

Class: RequestCreator
Methods:
create,
create_from_hex_args
Both methods allow for creation of a request, given user's secret spend key and license provider's public spend key.
The request can then be sent to license provider, off-chain or on-chain.

Class: RequestSender
Methods: send_request
Submits the request into blockchain.
It does so by calling a dummy contract method with request as an argument.

Class: RequestScanner
Methods:
scan_transactions,
scan_last_blocks,
scan_block_range
Scan requests in a given collection of transactions,
contained in a given range of blocks or in a given number of most recent blocks.

### citadel queries

Class: CitadelInquirer
Methods:
get_licenses,
get_merkle_opening,
get_session,
get_info
Execute citadel-specific query methods of the license contract method.

### blockchain payloads

Class: PayloadExtractor
Methods: payload_from_tx
Extracts a payload from the given transaction,
errors if payload of a given type is not present or the transaction is not a contract calling transaction.

Class: PayloadRetriever
Methods: retrieve_payload
Retrieves payload of a given transaction id,
errors if transaction is not found, or it does not contain a payload
(for example, given transaction is not a contract calling transaction)

Class: PayloadSender
Methods: execute_contract_method
Executes given method of a given contract (identified by a contract id), passing to it the payload as an argument.

### contract queries

Class: ContractInquirer
Methods:
query_contract,
query_contract_with_feeder
query_contract - accepts a generic argument, contract id and contract query method name, returns a generic value result
query_contract_with_feeder - accepts a generic argument, contract id and method name, returns result as a Stream of bytes

### blockchain queries

Class: BcInquirer
Methods:
gql_query,
block_height
gql_query - executes a GQL query and returns result as a vector of bytes
block_height - returns the current block height as u64

Class: TxAwaiter
Methods:
wait_for,
wait_for_tx
Waits for a transaction identified by transaction id to be confirmed on the blockchain.

Class: TxInquirer
Methods:
txs_from_block,
txs_from_block_range,
txs_from_last_n_blocks,
retrieve_tx
Retrieve transaction identified by transaction id, or transactions contained in a given block, or a collection of blocks.

### User

Users can request licenses and use them. To run the user CLI, simply run:

```sh
cargo r --release --bin moat-cli-user -- --wallet-path ~/.dusk/rusk-wallet --wallet-pass <PASSWORD>
```

2 changes: 2 additions & 0 deletions config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
rusk_address = "http://127.0.0.1:8080"
prover_address = "http://127.0.0.1:8080"
1 change: 1 addition & 0 deletions data/secret_key_lp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fd611dc2cfe15488e3cb94b410fadd3a5e77057be64574eb9b6acaf967a37d0514d0ce88727a24d3756a08bb8ae072d8aaaa88f88768c8a9487fb50678ba5204
1 change: 1 addition & 0 deletions data/secret_key_user
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
c6afd78c8b3902b474d4c0972b62888e4b880dccf8da68e86266fefa45ee7505926f06ab82ac200995f1239d518fdb74903f225f4460d8db62f2449f6d4dc402
8 changes: 4 additions & 4 deletions integration-tests/tests/blockchain/retrieve_txs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use wallet_accessor::BlockchainAccessConfig;
#[cfg_attr(not(feature = "int_tests"), ignore)]
async fn retrieve_txs_from_block() -> Result<(), Error> {
let config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/config.toml");
concat!(env!("CARGO_MANIFEST_DIR"), "../../config.toml");

let cfg = BlockchainAccessConfig::load_path(config_path)?;

Expand All @@ -33,7 +33,7 @@ async fn retrieve_txs_from_block() -> Result<(), Error> {
#[cfg_attr(not(feature = "int_tests"), ignore)]
async fn retrieve_txs_from_block_range() -> Result<(), Error> {
let config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/config.toml");
concat!(env!("CARGO_MANIFEST_DIR"), "../../config.toml");

let cfg = BlockchainAccessConfig::load_path(config_path)?;

Expand All @@ -59,7 +59,7 @@ async fn retrieve_txs_from_block_range() -> Result<(), Error> {
#[cfg_attr(not(feature = "int_tests"), ignore)]
async fn retrieve_txs_from_last_n_blocks() -> Result<(), Error> {
let config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/config.toml");
concat!(env!("CARGO_MANIFEST_DIR"), "../../config.toml");

let cfg = BlockchainAccessConfig::load_path(config_path)?;

Expand All @@ -80,7 +80,7 @@ async fn retrieve_tx_by_id() -> Result<(), Error> {
"44fe2c6407fc400a2dee6e30c62a02b82f3980da18d3b6306e80f9f83730520d";

let config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/config.toml");
concat!(env!("CARGO_MANIFEST_DIR"), "../../config.toml");

let config = BlockchainAccessConfig::load_path(config_path)?;

Expand Down
4 changes: 2 additions & 2 deletions integration-tests/tests/blockchain/stake_add_owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use wallet_accessor::Password::PwdHash;

const WALLET_PATH: &str = concat!(env!("HOME"), "/.dusk/rusk-wallet");
const PWD_HASH: &str =
"5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8";
"9afbce9f2416520733bacb370315d32b6b2c43d6097576df1c1222859d91eecc";
const GAS_LIMIT: u64 = 5_000_000_000;
const GAS_PRICE: u64 = 1;

Expand All @@ -29,7 +29,7 @@ pub const ADD_OWNER_METHOD_NAME: &str = "add_owner";
#[cfg_attr(not(feature = "int_tests"), ignore)]
async fn stake_add_owner() -> Result<(), Error> {
let blockchain_config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/config.toml");
concat!(env!("CARGO_MANIFEST_DIR"), "../../config.toml");

let blockchain_config =
BlockchainAccessConfig::load_path(blockchain_config_path)?;
Expand Down
14 changes: 7 additions & 7 deletions integration-tests/tests/citadel/int_test_lp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use wallet_accessor::BlockchainAccessConfig;
#[cfg_attr(not(feature = "exp_tests"), ignore)]
async fn lp_scan() -> Result<(), Error> {
let blockchain_config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/config.toml");
concat!(env!("CARGO_MANIFEST_DIR"), "../../config.toml");
let lp_config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/lp.json");
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/test_secret_key_lp");

let blockchain_config =
BlockchainAccessConfig::load_path(blockchain_config_path)?;
Expand All @@ -30,9 +30,9 @@ async fn lp_scan() -> Result<(), Error> {
#[cfg_attr(not(feature = "exp_tests"), ignore)]
async fn lp_scan_last_blocks() -> Result<(), Error> {
let blockchain_config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/config.toml");
concat!(env!("CARGO_MANIFEST_DIR"), "../../config.toml");
let lp_config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/lp2.json");
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/test_secret_key_lp_2");

let blockchain_config =
BlockchainAccessConfig::load_path(blockchain_config_path)?;
Expand All @@ -49,11 +49,11 @@ async fn lp_scan_last_blocks() -> Result<(), Error> {
#[cfg_attr(not(feature = "exp_tests"), ignore)]
async fn lp_scan_2_lps() -> Result<(), Error> {
let blockchain_config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/config.toml");
concat!(env!("CARGO_MANIFEST_DIR"), "../../config.toml");
let lp1_config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/lp.json");
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/test_secret_key_lp");
let lp2_config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/lp2.json");
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/test_secret_key_lp_2");

let blockchain_config =
BlockchainAccessConfig::load_path(blockchain_config_path)?;
Expand Down
6 changes: 3 additions & 3 deletions integration-tests/tests/citadel/int_test_user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use zk_citadel::license::Request;

const WALLET_PATH: &str = concat!(env!("HOME"), "/.dusk/rusk-wallet");
const PWD_HASH: &str =
"5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8";
"9afbce9f2416520733bacb370315d32b6b2c43d6097576df1c1222859d91eecc";
const GAS_LIMIT: u64 = 5_000_000_000;
const GAS_PRICE: u64 = 1;

Expand Down Expand Up @@ -133,10 +133,10 @@ async fn user_round_trip() -> Result<(), Error> {
let request_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/request/request.json");
let blockchain_config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/config.toml");
concat!(env!("CARGO_MANIFEST_DIR"), "../../config.toml");

let lp_config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/lp2.json");
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/test_secret_key_lp_2");

let reference_lp = ReferenceLP::create(&lp_config_path)?;

Expand Down
6 changes: 3 additions & 3 deletions integration-tests/tests/citadel/issue_license.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use wallet_accessor::Password::PwdHash;

const WALLET_PATH: &str = concat!(env!("HOME"), "/.dusk/rusk-wallet");
const PWD_HASH: &str =
"5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8";
"9afbce9f2416520733bacb370315d32b6b2c43d6097576df1c1222859d91eecc";
const GAS_LIMIT: u64 = 5_000_000_000;
const GAS_PRICE: u64 = 1;

Expand All @@ -26,10 +26,10 @@ async fn issue_license() -> Result<(), Error> {
let request_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/request/request.json");
let blockchain_config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/config.toml");
concat!(env!("CARGO_MANIFEST_DIR"), "../../config.toml");

let lp_config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/lp2.json");
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/test_secret_key_lp_2");

let reference_lp = ReferenceLP::create(&lp_config_path)?;

Expand Down
8 changes: 4 additions & 4 deletions integration-tests/tests/citadel/license_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use wallet_accessor::BlockchainAccessConfig;
#[cfg_attr(not(feature = "int_tests"), ignore)]
async fn call_get_licenses() -> Result<(), Error> {
let config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/config.toml");
concat!(env!("CARGO_MANIFEST_DIR"), "../../config.toml");
let config = BlockchainAccessConfig::load_path(config_path)?;

let client = RuskHttpClient::new(config.rusk_address);
Expand All @@ -34,7 +34,7 @@ async fn call_get_licenses() -> Result<(), Error> {
#[cfg_attr(not(feature = "int_tests"), ignore)]
async fn call_get_merkle_opening() -> Result<(), Error> {
let config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/config.toml");
concat!(env!("CARGO_MANIFEST_DIR"), "../../config.toml");
let config = BlockchainAccessConfig::load_path(config_path)?;

let client = RuskHttpClient::new(config.rusk_address);
Expand All @@ -50,7 +50,7 @@ async fn call_get_merkle_opening() -> Result<(), Error> {
#[cfg_attr(not(feature = "int_tests"), ignore)]
async fn call_get_session() -> Result<(), Error> {
let config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/config.toml");
concat!(env!("CARGO_MANIFEST_DIR"), "../../config.toml");
let config = BlockchainAccessConfig::load_path(config_path)?;

let client = RuskHttpClient::new(config.rusk_address);
Expand All @@ -70,7 +70,7 @@ async fn call_get_session() -> Result<(), Error> {
#[cfg_attr(not(feature = "int_tests"), ignore)]
async fn call_get_info() -> Result<(), Error> {
let config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/config.toml");
concat!(env!("CARGO_MANIFEST_DIR"), "../../config.toml");
let config = BlockchainAccessConfig::load_path(config_path)?;

let client = RuskHttpClient::new(config.rusk_address);
Expand Down
Loading

0 comments on commit cd0119e

Please sign in to comment.