From 080aa4d57f160cb1525d34b63a4a1e2afeb81aa9 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 24 Oct 2023 16:59:58 +0200 Subject: [PATCH 01/51] renamed moat-cli to moat-request-cli --- Cargo.toml | 2 +- moat-cli/src/main.rs | 111 ------------------ moat-request-cli/Cargo.toml | 15 +++ moat-request-cli/config.toml | 4 + {moat-cli => moat-request-cli}/request.json | 0 {moat-cli => moat-request-cli}/src/args.rs | 0 moat-request-cli/src/main.rs | 123 ++++++++++++++++++++ 7 files changed, 143 insertions(+), 112 deletions(-) create mode 100644 moat-request-cli/Cargo.toml create mode 100644 moat-request-cli/config.toml rename {moat-cli => moat-request-cli}/request.json (100%) rename {moat-cli => moat-request-cli}/src/args.rs (100%) create mode 100644 moat-request-cli/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index d16c2f8..d6d2b40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["moat-cli", "moat-core", "wallet-accessor", "integration-tests", "license-provider", "macros/code-hasher"] +members = ["moat-cli", "moat-request-cli", "moat-core", "wallet-accessor", "integration-tests", "license-provider", "macros/code-hasher"] diff --git a/moat-cli/src/main.rs b/moat-cli/src/main.rs index d2501a9..390ea13 100644 --- a/moat-cli/src/main.rs +++ b/moat-cli/src/main.rs @@ -4,120 +4,9 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -//! Command line utility for submitting requests to the Dusk blockchain. -//! -//! In order to use the moat-cli utility you need to install Dusk wallet first. -//! Typically, your Dusk wallet is installed in ~/.dusk/rusk-wallet. -//! Path to your wallet's directory needs to be provided as `wallet-path` -//! argument when using moat-cli. -//! Before usage you need to make sure that the default address of your wallet -//! holds some Dusk funds, otherwise the utility won't be able to submit your -//! request, as it needs funds for gas in order to do so. -//! The CLI will also need password to your wallet, as well as a path to -//! a configuration file containing blockchain urls. Example configuration file -//! is provided in the moat-cli project main directory, under the name -//! `config.toml`. The last thing you will need is an actual request. You will -//! be able to provide it in a form of a json file. An example request file is -//! provided in the moat-cli project's main directory as `request.json`. -//! -//! Note that your wallet cannot be active when running this utility. -//! -//! To sum up - you'll need a wallet with some funds in its default address, -//! a path to its location, wallet's password, blockchain access configuration -//! file `config.toml`, and a request file. -//! -//! In addition, you may also want to provide gas limit and gas price, also via -//! command line parameters. -//! -//! To sum up, the exact list of command line parameters is as follows: -//! -//! - `wallet_path` - a path to wallet's location, e.g.: `--wallet_path -//! ~/.dusk/rusk-wallet` -//! - `config_path` - a path to configuratin file, e.g.: `--config_path -//! ./moat-cli/config.toml` -//! - `password` - wallet's password in the clear, e.g: `--password mypass2!` -//! - `psw_hash` - wallet's password's blake3 hash, e.g: `--psw_hash -//! 7f2611ba158b6dcea4a69c229c303358c5e04493abeadee106a4bfa464d5aabb` -//! - `gas_limit` - gas limit, e.g.: `--gas_limit 500000000` -//! - `gas_price` - gas price, e.g.: `--gas_price 1` -//! - a full path (with a name) of the request file, e.g.: -//! `./moat-cli/request.json` -//! -//! Example full command line invocation of `moat-cli` may look as follows: -//! -//! `cargo r --release --bin moat-cli -- --wallet-path ~/.dusk/rusk-wallet -//! --config-path ./moat-cli/config.toml -//! --psw_hash 7f2611ba158b6dcea4a69c229c303358c5e04493abeadee106a4bfa464d5aabb -//! ./moat-cli/request.json` -//! -//! Note that when psw_hash argument is provided, password argument may be -//! omitted or if given, it will be ignored. - -#![feature(stmt_expr_attributes)] -mod args; - -use crate::args::Args; - -use clap::Parser; -use dusk_wallet::WalletPath; -use moat_core::{JsonLoader, RequestCreator, RequestJson, RequestSender}; -use rand::rngs::StdRng; -use rand::SeedableRng; use std::error::Error; -use toml_base_config::BaseConfig; -use tracing::Level; -use wallet_accessor::{ - BlockchainAccessConfig, Password::Pwd, Password::PwdHash, -}; #[tokio::main] async fn main() -> Result<(), Box> { - let subscriber = tracing_subscriber::fmt::Subscriber::builder() - .with_max_level(Level::INFO) - .with_writer(std::io::stderr); - tracing::subscriber::set_global_default(subscriber.finish())?; - - let cli = Args::parse(); - - let json_path = cli.json_path.as_path(); - let config_path = cli.config_path.as_path(); - let wallet_path = cli.wallet_path.as_path(); - let password = cli.password; - let pwd_hash = cli.pwd_hash; - let gas_limit = cli.gas_limit; - let gas_price = cli.gas_price; - - 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, - )?; - - let wallet_path = WalletPath::from(wallet_path.join("wallet.dat")); - let blockchain_access_config = - BlockchainAccessConfig::load_path(config_path)?; - let psw = if pwd_hash.is_empty() { - Pwd(password) - } else { - PwdHash(pwd_hash) - }; - - RequestSender::send_request( - request, - &blockchain_access_config, - &wallet_path, - &psw, - gas_limit, - gas_price, - ) - .await?; - - #[rustfmt::skip] - // cargo r --release --bin moat-cli -- --wallet-path ~/.dusk/rusk-wallet --config-path ./moat-cli/config.toml --password password ./moat-cli/request.json - // cargo r --release --bin moat-cli -- --wallet-path ~/.dusk/rusk-wallet --config-path ./moat-cli/config.toml --pwd-hash 7f2611ba158b6dcea4a69c229c303358c5e04493abeadee106a4bfa464d55787 ./moat-cli/request.json // blake3 encoding of "password" - // cargo r --release --bin moat-cli -- --wallet-path ~/.dusk/rusk-wallet --config-path ./moat-cli/config.toml --pwd-hash 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8 ./moat-cli/request.json // sha256 encoding of "password" - Ok(()) } diff --git a/moat-request-cli/Cargo.toml b/moat-request-cli/Cargo.toml new file mode 100644 index 0000000..ed76172 --- /dev/null +++ b/moat-request-cli/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "moat-request-cli" +version = "0.1.0" +edition = "2021" + +[dependencies] +dusk-wallet = "0.20.0-rc.0" +wallet-accessor = { path = "../wallet-accessor" } +moat-core = { path = "../moat-core" } +toml-base-config = "0.1" +clap = { version = "4.0", features = ["derive", "env"] } +tokio = { version = "1.21", features = ["full"] } +tracing = "0.1" +tracing-subscriber = "0.3" +rand = "0.8" diff --git a/moat-request-cli/config.toml b/moat-request-cli/config.toml new file mode 100644 index 0000000..a413b04 --- /dev/null +++ b/moat-request-cli/config.toml @@ -0,0 +1,4 @@ +rusk_address = "http://127.0.0.1:8080" +prover_address = "http://127.0.0.1:8080" +#rusk_address = "http://devnet.nodes.dusk.network:8585" +#prover_address = "http://devnet.provers.dusk.network:8686" diff --git a/moat-cli/request.json b/moat-request-cli/request.json similarity index 100% rename from moat-cli/request.json rename to moat-request-cli/request.json diff --git a/moat-cli/src/args.rs b/moat-request-cli/src/args.rs similarity index 100% rename from moat-cli/src/args.rs rename to moat-request-cli/src/args.rs diff --git a/moat-request-cli/src/main.rs b/moat-request-cli/src/main.rs new file mode 100644 index 0000000..444592a --- /dev/null +++ b/moat-request-cli/src/main.rs @@ -0,0 +1,123 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) DUSK NETWORK. All rights reserved. + +//! Command line utility for submitting requests to the Dusk blockchain. +//! +//! In order to use the moat-request-cli utility you need to install Dusk wallet +//! first. Typically, your Dusk wallet is installed in ~/.dusk/rusk-wallet. +//! Path to your wallet's directory needs to be provided as `wallet-path` +//! argument when using moat-request-cli. +//! Before usage you need to make sure that the default address of your wallet +//! holds some Dusk funds, otherwise the utility won't be able to submit your +//! request, as it needs funds for gas in order to do so. +//! The CLI will also need password to your wallet, as well as a path to +//! a configuration file containing blockchain urls. Example configuration file +//! is provided in the moat-request-cli project main directory, under the name +//! `config.toml`. The last thing you will need is an actual request. You will +//! be able to provide it in a form of a json file. An example request file is +//! provided in the moat-request-cli project's main directory as `request.json`. +//! +//! Note that your wallet cannot be active when running this utility. +//! +//! To sum up - you'll need a wallet with some funds in its default address, +//! a path to its location, wallet's password, blockchain access configuration +//! file `config.toml`, and a request file. +//! +//! In addition, you may also want to provide gas limit and gas price, also via +//! command line parameters. +//! +//! To sum up, the exact list of command line parameters is as follows: +//! +//! - `wallet_path` - a path to wallet's location, e.g.: `--wallet_path +//! ~/.dusk/rusk-wallet` +//! - `config_path` - a path to configuratin file, e.g.: `--config_path +//! ./moat-request-cli/config.toml` +//! - `password` - wallet's password in the clear, e.g: `--password mypass2!` +//! - `psw_hash` - wallet's password's blake3 hash, e.g: `--psw_hash +//! 7f2611ba158b6dcea4a69c229c303358c5e04493abeadee106a4bfa464d5aabb` +//! - `gas_limit` - gas limit, e.g.: `--gas_limit 500000000` +//! - `gas_price` - gas price, e.g.: `--gas_price 1` +//! - a full path (with a name) of the request file, e.g.: +//! `./moat-request-cli/request.json` +//! +//! Example full command line invocation of `moat-request-cli` may look as +//! follows: +//! +//! `cargo r --release --bin moat-request-cli -- --wallet-path +//! ~/.dusk/rusk-wallet --config-path ./moat-request-cli/config.toml +//! --psw_hash 7f2611ba158b6dcea4a69c229c303358c5e04493abeadee106a4bfa464d5aabb +//! ./moat-request-cli/request.json` +//! +//! Note that when psw_hash argument is provided, the password argument will be +//! ignored. + +#![feature(stmt_expr_attributes)] +mod args; + +use crate::args::Args; + +use clap::Parser; +use dusk_wallet::WalletPath; +use moat_core::{JsonLoader, RequestCreator, RequestJson, RequestSender}; +use rand::rngs::StdRng; +use rand::SeedableRng; +use std::error::Error; +use toml_base_config::BaseConfig; +use tracing::Level; +use wallet_accessor::{ + BlockchainAccessConfig, Password::Pwd, Password::PwdHash, +}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let subscriber = tracing_subscriber::fmt::Subscriber::builder() + .with_max_level(Level::INFO) + .with_writer(std::io::stderr); + tracing::subscriber::set_global_default(subscriber.finish())?; + + let cli = Args::parse(); + + let json_path = cli.json_path.as_path(); + let config_path = cli.config_path.as_path(); + let wallet_path = cli.wallet_path.as_path(); + let password = cli.password; + let pwd_hash = cli.pwd_hash; + let gas_limit = cli.gas_limit; + let gas_price = cli.gas_price; + + 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, + )?; + + let wallet_path = WalletPath::from(wallet_path.join("wallet.dat")); + let blockchain_access_config = + BlockchainAccessConfig::load_path(config_path)?; + let psw = if pwd_hash.is_empty() { + Pwd(password) + } else { + PwdHash(pwd_hash) + }; + + RequestSender::send_request( + request, + &blockchain_access_config, + &wallet_path, + &psw, + gas_limit, + gas_price, + ) + .await?; + + #[rustfmt::skip] + // cargo r --release --bin moat-request-cli -- --wallet-path ~/.dusk/rusk-wallet --config-path ./moat-request-cli/config.toml --pwd-hash 7f2611ba158b6dcea4a69c229c303358c5e04493abeadee106a4bfa464d55787 ./moat-request-cli/request.json // blake3 encoding of "password" + // cargo r --release --bin moat-request-cli -- --wallet-path ~/.dusk/rusk-wallet --config-path ./moat-request-cli/config.toml --pwd-hash 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8 ./moat-request-cli/request.json // sha256 encoding of "password" + + Ok(()) +} From 523440adc6129b7045ee970fc257ad6fd2eef5f5 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Wed, 25 Oct 2023 11:11:07 +0200 Subject: [PATCH 02/51] Insipient interaction --- moat-cli/Cargo.toml | 1 + moat-cli/src/args.rs | 17 +++++++ moat-cli/src/interactive.rs | 49 +++++++++++++++++++ moat-cli/src/main.rs | 13 +++++ moat-cli/src/menu.rs | 97 +++++++++++++++++++++++++++++++++++++ 5 files changed, 177 insertions(+) create mode 100644 moat-cli/src/args.rs create mode 100644 moat-cli/src/interactive.rs create mode 100644 moat-cli/src/menu.rs diff --git a/moat-cli/Cargo.toml b/moat-cli/Cargo.toml index 81d71fb..8b1fb87 100644 --- a/moat-cli/Cargo.toml +++ b/moat-cli/Cargo.toml @@ -13,3 +13,4 @@ tokio = { version = "1.21", features = ["full"] } tracing = "0.1" tracing-subscriber = "0.3" rand = "0.8" +requestty = "0.4.1" diff --git a/moat-cli/src/args.rs b/moat-cli/src/args.rs new file mode 100644 index 0000000..933e184 --- /dev/null +++ b/moat-cli/src/args.rs @@ -0,0 +1,17 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) DUSK NETWORK. All rights reserved. + +use std::path::PathBuf; + +use clap::Parser; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +#[command(propagate_version = true)] +pub struct Args { + /// Path of the JSON file to be processed + pub json_path: PathBuf, +} diff --git a/moat-cli/src/interactive.rs b/moat-cli/src/interactive.rs new file mode 100644 index 0000000..4fa4180 --- /dev/null +++ b/moat-cli/src/interactive.rs @@ -0,0 +1,49 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) DUSK NETWORK. All rights reserved. + +use crate::Menu; +use requestty::{ErrorKind, Question}; + +#[derive(PartialEq, Eq, Hash, Clone, Debug)] +enum CommandMenuItem { + SubmitRequest, + ListRequests, + Exit, +} + +fn menu_operation() -> Result<(), ErrorKind> { + let cmd_menu = Menu::new() + .add(CommandMenuItem::SubmitRequest, "Submit Request") + .add(CommandMenuItem::ListRequests, "List Requests") + .separator() + .add(CommandMenuItem::Exit, "Exit"); + + let q = Question::select("theme") + .message("What would you like to do?") + .choices(cmd_menu.clone()) + .build(); + + let answer = requestty::prompt_one(q)?; + let cmd = cmd_menu.answer(&answer).to_owned(); + match cmd { + CommandMenuItem::SubmitRequest => println!("do submit request"), + CommandMenuItem::ListRequests => println!("do list requests"), + CommandMenuItem::Exit => { + println!("do exit, bye bye"); + return Err(ErrorKind::Aborted); + } + }; + Ok(()) +} + +pub async fn run_loop() -> Result<(), ErrorKind> { + loop { + let op = menu_operation(); + if op.is_err() { + return Ok(()); + } + } +} diff --git a/moat-cli/src/main.rs b/moat-cli/src/main.rs index 390ea13..2c33def 100644 --- a/moat-cli/src/main.rs +++ b/moat-cli/src/main.rs @@ -4,9 +4,22 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. +mod args; +mod interactive; +mod menu; + +use crate::args::Args; +use crate::menu::Menu; + +use clap::Parser; + use std::error::Error; #[tokio::main] async fn main() -> Result<(), Box> { + let cli = Args::parse(); + let _json_path = cli.json_path.as_path(); + interactive::run_loop().await?; + Ok(()) } diff --git a/moat-cli/src/menu.rs b/moat-cli/src/menu.rs new file mode 100644 index 0000000..f34ec03 --- /dev/null +++ b/moat-cli/src/menu.rs @@ -0,0 +1,97 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) DUSK NETWORK. All rights reserved. + +use core::fmt::Debug; +use std::collections::HashMap; +use std::hash::Hash; + +use requestty::question::Choice; +use requestty::{Answer, DefaultSeparator, Separator}; + +#[derive(Clone, Debug)] +pub struct Menu { + items: Vec>, + keys: HashMap, +} + +impl Default for Menu +where + K: Eq + Hash + Debug, +{ + fn default() -> Self { + Self::new() + } +} + +#[allow(dead_code)] +impl Menu +where + K: Eq + Hash + Debug, +{ + pub fn new() -> Self { + Self { + items: vec![], + keys: HashMap::new(), + } + } + + pub fn title(title: T) -> Self + where + T: Into, + { + let title = format!("─ {:─<12}", format!("{} ", title.into())); + let title = Separator(title); + let items = vec![title]; + let keys = HashMap::new(); + + Self { items, keys } + } + + pub fn add(mut self, key: K, item: V) -> Self + where + V: Into>, + { + self.items.push(item.into()); + self.keys.insert(self.items.len() - 1, key); + self + } + + pub fn separator(mut self) -> Self { + self.items.push(DefaultSeparator); + self + } + + pub fn separator_msg(mut self, msg: String) -> Self { + self.items.push(Separator(msg)); + self + } + + pub fn answer(&self, answer: &Answer) -> &K { + let index = answer.as_list_item().unwrap().index; + let key = self.keys.get(&index); + key.unwrap() + } + + pub fn extend(mut self, other: Self) -> Self { + let len = self.items.len(); + + self.items.extend(other.items); + + for (key, val) in other.keys.into_iter() { + self.keys.insert(key + len, val); + } + + self + } +} + +impl IntoIterator for Menu { + type Item = Choice; + type IntoIter = std::vec::IntoIter>; + fn into_iter(self) -> Self::IntoIter { + self.items.into_iter() + } +} From bcc19cf9aec2d332362745885389cb044951c19b Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Wed, 25 Oct 2023 14:37:46 +0200 Subject: [PATCH 03/51] Incipient command --- moat-cli/README.md | 67 +++++++++++++++++++++++++++++++++++++ moat-cli/src/command.rs | 18 ++++++++++ moat-cli/src/interactive.rs | 30 +++++++++++------ moat-cli/src/main.rs | 2 ++ 4 files changed, 106 insertions(+), 11 deletions(-) create mode 100644 moat-cli/README.md create mode 100644 moat-cli/src/command.rs diff --git a/moat-cli/README.md b/moat-cli/README.md new file mode 100644 index 0000000..1fc5576 --- /dev/null +++ b/moat-cli/README.md @@ -0,0 +1,67 @@ +# Moat CLI + +Command line interface to Dusk Citadel + +Available commands: + +- submit a license request to blockchain (USER) +- list requests present on blockchain (USER) +- list relevant license requests (LP) +- issue license for a given request (LP) +- list user's licenses (USER) +- compute proof and use license (USER) +- obtain service from SP (USER & SP) + +## Submit a license request to blockchain (User) + +arguments: +- data for wallet connection +- data for Rusk cluster connection +- user SSK (Secret Spend Key) +- provider PSK (Public Spend Key) +- gas limit +- gas price + +## Retrieve from blockchain the requests which were sent by the user (User) + +arguments: +- scope: either an entire blockchain, or block range, or N last blocks +- data for Rusk cluster connection +- user's view key (created from user's SSK) + +## Retrieve relevant license requests (LP) + +arguments: +- scope: either an entire blockchain, or block range, or N last blocks +- data for Rusk cluster connection +- LP's view key (created from LP's SSK) + +## Issue license for a given request (LP) + +arguments: +- data for wallet connection +- data for Rusk cluster connection +- gas limit +- gas price +- license (created from the relevant request and LP's SSK) + +## List user's licenses (User) + +arguments: +- scope: block height range +- data for Rusk cluster connection +- user's view key (created from user's SSK) + +## Use license (User) + +arguments: +- data for wallet connection +- data for Rusk cluster connection +- license +- more - TBD + +## Obtains service from SP (User and SP) + +arguments: +TBD as we need to mock SP + diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs new file mode 100644 index 0000000..c833973 --- /dev/null +++ b/moat-cli/src/command.rs @@ -0,0 +1,18 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) DUSK NETWORK. All rights reserved. + +/// Commands that can be run against the Moat +#[derive(PartialEq, Eq, Hash, Clone, Debug)] +pub(crate) enum Command { + /// Submit request + SubmitRequest { + dummy: bool, + }, + /// List requests + ListRequests { + dummy: bool, + } +} diff --git a/moat-cli/src/interactive.rs b/moat-cli/src/interactive.rs index 4fa4180..2da3347 100644 --- a/moat-cli/src/interactive.rs +++ b/moat-cli/src/interactive.rs @@ -4,9 +4,15 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -use crate::Menu; +use crate::{Command, Menu}; use requestty::{ErrorKind, Question}; +#[derive(PartialEq, Eq, Hash, Debug, Clone)] +enum OpSelection { + Run(Box), + Exit, +} + #[derive(PartialEq, Eq, Hash, Clone, Debug)] enum CommandMenuItem { SubmitRequest, @@ -14,7 +20,7 @@ enum CommandMenuItem { Exit, } -fn menu_operation() -> Result<(), ErrorKind> { +fn menu_operation() -> Result { let cmd_menu = Menu::new() .add(CommandMenuItem::SubmitRequest, "Submit Request") .add(CommandMenuItem::ListRequests, "List Requests") @@ -28,21 +34,23 @@ fn menu_operation() -> Result<(), ErrorKind> { let answer = requestty::prompt_one(q)?; let cmd = cmd_menu.answer(&answer).to_owned(); - match cmd { - CommandMenuItem::SubmitRequest => println!("do submit request"), - CommandMenuItem::ListRequests => println!("do list requests"), + Ok(match cmd { + CommandMenuItem::SubmitRequest => { + OpSelection::Run(Box::from(Command::SubmitRequest { dummy: true })) + }, + CommandMenuItem::ListRequests => { + OpSelection::Run(Box::from(Command::ListRequests { dummy: true })) + }, CommandMenuItem::Exit => { - println!("do exit, bye bye"); - return Err(ErrorKind::Aborted); + OpSelection::Exit } - }; - Ok(()) + }) } pub async fn run_loop() -> Result<(), ErrorKind> { loop { - let op = menu_operation(); - if op.is_err() { + let op = menu_operation()?; + if op == OpSelection::Exit { return Ok(()); } } diff --git a/moat-cli/src/main.rs b/moat-cli/src/main.rs index 2c33def..69e868a 100644 --- a/moat-cli/src/main.rs +++ b/moat-cli/src/main.rs @@ -7,9 +7,11 @@ mod args; mod interactive; mod menu; +mod command; use crate::args::Args; use crate::menu::Menu; +use crate::command::Command; use clap::Parser; From 6ec8e5e4ed15a4bbfac9c46e65f8e2750a5f804b Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Wed, 25 Oct 2023 16:37:00 +0200 Subject: [PATCH 04/51] Sumbitting request WIP --- moat-cli/Cargo.toml | 1 + moat-cli/request.json | 4 +++ moat-cli/src/args.rs | 24 +++++++++++++ moat-cli/src/command.rs | 63 +++++++++++++++++++++++++++++++--- moat-cli/src/interactive.rs | 37 +++++++++++++++----- moat-cli/src/main.rs | 45 +++++++++++++++++++++--- moat-core/src/citadel_types.rs | 2 +- 7 files changed, 158 insertions(+), 18 deletions(-) create mode 100644 moat-cli/request.json diff --git a/moat-cli/Cargo.toml b/moat-cli/Cargo.toml index 8b1fb87..8ed1135 100644 --- a/moat-cli/Cargo.toml +++ b/moat-cli/Cargo.toml @@ -14,3 +14,4 @@ tracing = "0.1" tracing-subscriber = "0.3" rand = "0.8" requestty = "0.4.1" +hex = "0.4" diff --git a/moat-cli/request.json b/moat-cli/request.json new file mode 100644 index 0000000..f678c8b --- /dev/null +++ b/moat-cli/request.json @@ -0,0 +1,4 @@ +{ + "user_ssk": "c6afd78c8b3902b474d4c0972b62888e4b880dccf8da68e86266fefa45ee7505926f06ab82ac200995f1239d518fdb74903f225f4460d8db62f2449f6d4dc402", + "provider_psk": "136d747ff489bd06077f937508b9237ac093ff868dc2e232ab3af0ecd038873288560dbd8aa851e055bc408ebeb89509b26eb6e34b4b43214de467e3ef09594e" +} diff --git a/moat-cli/src/args.rs b/moat-cli/src/args.rs index 933e184..635d775 100644 --- a/moat-cli/src/args.rs +++ b/moat-cli/src/args.rs @@ -14,4 +14,28 @@ use clap::Parser; pub struct Args { /// Path of the JSON file to be processed pub json_path: PathBuf, + + /// Wallet directory [default: `$HOME/.dusk/rusk-wallet`] + #[clap(short, long)] + pub wallet_path: PathBuf, + + /// Config directory + #[clap(short, long)] + pub config_path: PathBuf, + + /// Password for the wallet + #[clap(long, default_value_t = String::from(""), env = "RUSK_WALLET_PWD")] + pub password: String, + + /// Hash of the password for the wallet [default: ``] + #[clap(short, long, default_value_t = String::from(""))] + pub pwd_hash: String, + + /// Gas limit [default: `500000000`] + #[clap(long, default_value_t = 500000000)] + pub gas_limit: u64, + + /// Gas price [default: `1`] + #[clap(long, default_value_t = 1)] + pub gas_price: u64, } diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index c833973..a4bff1c 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -4,15 +4,68 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. +use crate::SeedableRng; +use dusk_wallet::{RuskHttpClient, WalletPath}; +use moat_core::{Error, RequestCreator, RequestJson, RequestSender, TxAwaiter}; +use rand::rngs::StdRng; +use wallet_accessor::{BlockchainAccessConfig, Password}; + /// Commands that can be run against the Moat #[derive(PartialEq, Eq, Hash, Clone, Debug)] pub(crate) enum Command { /// Submit request - SubmitRequest { - dummy: bool, - }, + SubmitRequest { dummy: bool }, /// List requests - ListRequests { - dummy: bool, + ListRequests { dummy: bool }, +} + +impl Command { + pub async fn run( + self, + wallet_path: &WalletPath, + psw: &Password, + blockchain_access_config: &BlockchainAccessConfig, + gas_limit: u64, + gas_price: u64, + request_json: Option, + ) -> Result<(), Error> { + match self { + Command::SubmitRequest { dummy: true } => { + let request_json = + request_json.expect("request should be provided"); // todo + // todo - this request creation belongs somewhere else because + // we might + // also want to create request on the fly, from data provided by + // user interactively + let rng = &mut StdRng::seed_from_u64(0xcafe); + let request = RequestCreator::create_from_hex_args( + request_json.user_ssk, + request_json.provider_psk, + rng, + )?; + println!("submitting request"); + let tx_id = RequestSender::send_request( + request, + blockchain_access_config, + wallet_path, + psw, + gas_limit, + gas_price, + ) + .await?; + println!( + "tx {} submitted, waiting for confirmation", + hex::encode(tx_id.to_bytes()) + ); + let client = RuskHttpClient::new( + blockchain_access_config.rusk_address.clone(), + ); + TxAwaiter::wait_for(&client, tx_id).await?; + println!("tx {} confirmed", hex::encode(tx_id.to_bytes())); + } + Command::ListRequests { dummy: true } => (), + _ => (), + } + Ok(()) } } diff --git a/moat-cli/src/interactive.rs b/moat-cli/src/interactive.rs index 2da3347..5878d38 100644 --- a/moat-cli/src/interactive.rs +++ b/moat-cli/src/interactive.rs @@ -5,7 +5,10 @@ // Copyright (c) DUSK NETWORK. All rights reserved. use crate::{Command, Menu}; +use dusk_wallet::WalletPath; +use moat_core::RequestJson; use requestty::{ErrorKind, Question}; +use wallet_accessor::{BlockchainAccessConfig, Password}; #[derive(PartialEq, Eq, Hash, Debug, Clone)] enum OpSelection { @@ -37,21 +40,39 @@ fn menu_operation() -> Result { Ok(match cmd { CommandMenuItem::SubmitRequest => { OpSelection::Run(Box::from(Command::SubmitRequest { dummy: true })) - }, + } CommandMenuItem::ListRequests => { OpSelection::Run(Box::from(Command::ListRequests { dummy: true })) - }, - CommandMenuItem::Exit => { - OpSelection::Exit } + CommandMenuItem::Exit => OpSelection::Exit, }) } -pub async fn run_loop() -> Result<(), ErrorKind> { +pub async fn run_loop( + wallet_path: &WalletPath, + psw: &Password, + blockchain_access_config: &BlockchainAccessConfig, + gas_limit: u64, + gas_price: u64, + request_json: Option, +) -> Result<(), moat_core::Error> { + // todo: error type loop { - let op = menu_operation()?; - if op == OpSelection::Exit { - return Ok(()); + let request_json = request_json.clone(); // todo: introduce object with state here + let op = menu_operation().map_err(|_| moat_core::Error::Rkyv)?; // todo: change the bogus error here + match op { + OpSelection::Exit => return Ok(()), + OpSelection::Run(bx) => { + bx.run( + wallet_path, + psw, + blockchain_access_config, + gas_limit.clone(), + gas_price.clone(), + request_json, + ) + .await? + } } } } diff --git a/moat-cli/src/main.rs b/moat-cli/src/main.rs index 69e868a..97f4511 100644 --- a/moat-cli/src/main.rs +++ b/moat-cli/src/main.rs @@ -4,24 +4,61 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. +#![feature(stmt_expr_attributes)] + mod args; +mod command; mod interactive; mod menu; -mod command; use crate::args::Args; -use crate::menu::Menu; use crate::command::Command; +use crate::menu::Menu; use clap::Parser; +use dusk_wallet::WalletPath; +use moat_core::{JsonLoader, RequestJson}; +use rand::SeedableRng; use std::error::Error; +use toml_base_config::BaseConfig; +use wallet_accessor::BlockchainAccessConfig; +use wallet_accessor::Password::{Pwd, PwdHash}; #[tokio::main] async fn main() -> Result<(), Box> { let cli = Args::parse(); - let _json_path = cli.json_path.as_path(); - interactive::run_loop().await?; + + let json_path = cli.json_path.as_path(); + let config_path = cli.config_path.as_path(); + let wallet_path = cli.wallet_path.as_path(); + let password = cli.password; + let pwd_hash = cli.pwd_hash; + let gas_limit = cli.gas_limit; + let gas_price = cli.gas_price; + + let request_json: RequestJson = RequestJson::from_file(json_path)?; + let wallet_path = WalletPath::from(wallet_path.join("wallet.dat")); + let blockchain_access_config = + BlockchainAccessConfig::load_path(config_path)?; + let psw = if pwd_hash.is_empty() { + Pwd(password) + } else { + PwdHash(pwd_hash) + }; + + interactive::run_loop( + &wallet_path, + &psw, + &blockchain_access_config, + gas_limit, + gas_price, + Some(request_json), + ) + .await?; + + #[rustfmt::skip] + // cargo r --release --bin moat-cli -- --wallet-path ~/.dusk/rusk-wallet --config-path ./moat-cli/config.toml --pwd-hash 7f2611ba158b6dcea4a69c229c303358c5e04493abeadee106a4bfa464d55787 ./moat-cli/request.json Ok(()) } diff --git a/moat-core/src/citadel_types.rs b/moat-core/src/citadel_types.rs index 5e5fa20..60d7d2d 100644 --- a/moat-core/src/citadel_types.rs +++ b/moat-core/src/citadel_types.rs @@ -25,7 +25,7 @@ pub const GET_MERKLE_OPENING_METHOD_NAME: &str = "get_merkle_opening"; pub const GET_SESSION_METHOD_NAME: &str = "get_session"; pub const GET_INFO_METHOD_NAME: &str = "get_info"; -#[derive(Debug, Default, serde::Deserialize, serde::Serialize)] +#[derive(Debug, Clone, Default, serde::Deserialize, serde::Serialize)] pub struct RequestJson { pub user_ssk: String, pub provider_psk: String, From f5b41aedf803f4a72a32b67778721533ff4ecbf1 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Thu, 26 Oct 2023 11:10:01 +0200 Subject: [PATCH 05/51] Incipient submit request and list requests --- .../tests/citadel/send_request.rs | 31 +++++++++++++++++-- moat-cli/Cargo.toml | 2 ++ moat-cli/src/command.rs | 25 +++++++++++++-- moat-core/src/bc_types.rs | 2 +- .../src/blockchain_queries/tx_inquirer.rs | 14 ++++++--- 5 files changed, 63 insertions(+), 11 deletions(-) diff --git a/integration-tests/tests/citadel/send_request.rs b/integration-tests/tests/citadel/send_request.rs index 258c3fe..e9db9c3 100644 --- a/integration-tests/tests/citadel/send_request.rs +++ b/integration-tests/tests/citadel/send_request.rs @@ -6,8 +6,8 @@ use dusk_wallet::{RuskHttpClient, WalletPath}; use moat_core::{ - Error, PayloadRetriever, RequestCreator, RequestJson, RequestSender, - MAX_REQUEST_SIZE, + Error, PayloadExtractor, PayloadRetriever, RequestCreator, RequestJson, + RequestSender, TxInquirer, MAX_REQUEST_SIZE, }; use moat_core::{JsonLoader, TxAwaiter}; use rand::rngs::StdRng; @@ -73,7 +73,17 @@ async fn send_request() -> Result<(), Error> { let tx_id_hex = hex::encode(tx_id.to_bytes()); let retrieved_request = - get_request_from_blockchain(tx_id_hex, &client).await?; + get_request_from_blockchain(&tx_id_hex, &client).await?; + assert_eq!( + request_vec, + rkyv::to_bytes::<_, MAX_REQUEST_SIZE>(&retrieved_request) + .unwrap() + .to_vec(), + "requests not equal" + ); + + let retrieved_request = + get_request_from_blockchain_bulk(&tx_id_hex, &client).await?; assert_eq!( request_vec, rkyv::to_bytes::<_, MAX_REQUEST_SIZE>(&retrieved_request) @@ -102,3 +112,18 @@ async fn get_request_from_blockchain>( } unreachable!() } + +async fn get_request_from_blockchain_bulk>( + tx_id: S, + client: &RuskHttpClient, +) -> Result { + const LAST_N_BLOCKS: usize = 1000; + let txs = + TxInquirer::txs_from_last_n_blocks(&client, LAST_N_BLOCKS).await?; + for tx in txs.transactions.iter() { + if tx.id == tx_id.as_ref() { + return PayloadExtractor::payload_from_tx(&tx); + } + } + unreachable!() +} diff --git a/moat-cli/Cargo.toml b/moat-cli/Cargo.toml index 8ed1135..be1ace2 100644 --- a/moat-cli/Cargo.toml +++ b/moat-cli/Cargo.toml @@ -15,3 +15,5 @@ tracing-subscriber = "0.3" rand = "0.8" requestty = "0.4.1" hex = "0.4" +dusk-bytes = "0.1" +group = "0.13" diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index a4bff1c..f2a3931 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -6,7 +6,10 @@ use crate::SeedableRng; use dusk_wallet::{RuskHttpClient, WalletPath}; -use moat_core::{Error, RequestCreator, RequestJson, RequestSender, TxAwaiter}; +use moat_core::{ + Error, RequestCreator, RequestJson, RequestScanner, RequestSender, + TxAwaiter, +}; use rand::rngs::StdRng; use wallet_accessor::{BlockchainAccessConfig, Password}; @@ -63,7 +66,25 @@ impl Command { TxAwaiter::wait_for(&client, tx_id).await?; println!("tx {} confirmed", hex::encode(tx_id.to_bytes())); } - Command::ListRequests { dummy: true } => (), + Command::ListRequests { dummy: true } => { + println!("got here - listing requests"); + const LAST_N_BLOCKS: usize = 20000; // todo: temporary poc code + let requests = RequestScanner::scan_last_blocks( + LAST_N_BLOCKS, + blockchain_access_config, + ) + .await?; + println!("scanned last {} blocks for requests, num requests found={}", LAST_N_BLOCKS, requests.len()); + for request in requests.iter() { + use dusk_bytes::Serializable; + use group::GroupEncoding; + println!( + "found request rsa={} {}", + hex::encode(request.rsa.R().to_bytes()), + hex::encode(request.rsa.pk_r().to_bytes()) + ); + } + } _ => (), } Ok(()) diff --git a/moat-core/src/bc_types.rs b/moat-core/src/bc_types.rs index 30d3457..a60373a 100644 --- a/moat-core/src/bc_types.rs +++ b/moat-core/src/bc_types.rs @@ -47,7 +47,7 @@ pub struct Block { #[derive(Debug, Default, serde::Deserialize, serde::Serialize)] pub struct QueryResult { #[serde(alias = "blockTxs", default)] - pub block_txs: Vec, + pub block_txs: Vec, } // {"block":{"header":{"height":77065}}} diff --git a/moat-core/src/blockchain_queries/tx_inquirer.rs b/moat-core/src/blockchain_queries/tx_inquirer.rs index 739ec2d..d09277a 100644 --- a/moat-core/src/blockchain_queries/tx_inquirer.rs +++ b/moat-core/src/blockchain_queries/tx_inquirer.rs @@ -6,8 +6,8 @@ use crate::bc_types::*; use crate::error::Error; +use crate::BcInquirer; use crate::Error::TransactionNotFound; -use crate::{BcInquirer, QueryResult}; use dusk_wallet::RuskHttpClient; pub struct TxInquirer; @@ -31,11 +31,13 @@ impl TxInquirer { ) -> Result<(Transactions, u64), Error> { let mut transactions = Transactions::default(); let range_str = format!("{},{}", height_beg, height_end); - let tx_query = "query { blockTxs(range: [####] ) { id, raw, tx { callData {contractId, fnName, data} } } }".replace("####", range_str.as_str()); + let tx_query = "query { blockTxs(range: [####] ) { tx { id, raw, callData {contractId, fnName, data} } } }".replace("####", range_str.as_str()); let tx_response = BcInquirer::gql_query(client, tx_query.as_str()).await?; let tx_result = serde_json::from_slice::(&tx_response)?; - transactions.transactions.extend(tx_result.block_txs); + transactions + .transactions + .extend(tx_result.block_txs.into_iter().map(|t| t.tx)); let height = BcInquirer::block_height(client).await?; Ok((transactions, height)) } @@ -46,11 +48,13 @@ impl TxInquirer { ) -> Result { let mut transactions = Transactions::default(); let n_str = format!("{}", n); - let tx_query = "query { blockTxs(last:####) { id, raw, tx { callData {contractId, fnName, data} } } }".replace("####", n_str.as_str()); + let tx_query = "query { blockTxs(last:####) { tx { id, raw, callData {contractId, fnName, data} } } }".replace("####", n_str.as_str()); let tx_response = BcInquirer::gql_query(client, tx_query.as_str()).await?; let tx_result = serde_json::from_slice::(&tx_response)?; - transactions.transactions.extend(tx_result.block_txs); + transactions + .transactions + .extend(tx_result.block_txs.into_iter().map(|t| t.tx)); Ok(transactions) } From 4d93c75a847dcf8d19a174f556895d2dea56755a Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Thu, 26 Oct 2023 11:57:29 +0200 Subject: [PATCH 06/51] Scanning the entire blockchain for requests --- moat-cli/src/command.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index f2a3931..1a25c21 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -67,15 +67,21 @@ impl Command { println!("tx {} confirmed", hex::encode(tx_id.to_bytes())); } Command::ListRequests { dummy: true } => { - println!("got here - listing requests"); - const LAST_N_BLOCKS: usize = 20000; // todo: temporary poc code - let requests = RequestScanner::scan_last_blocks( - LAST_N_BLOCKS, - blockchain_access_config, - ) - .await?; - println!("scanned last {} blocks for requests, num requests found={}", LAST_N_BLOCKS, requests.len()); - for request in requests.iter() { + let mut found_requests = vec![]; + let mut height = 0; + loop { + let height_end = height + 10000; + let (requests, top) = + RequestScanner::scan_block_range(height.clone(), height_end.clone(), &blockchain_access_config).await?; + found_requests.extend(requests); + if top <= height_end { + height = top; + break; + } + height = height_end; + } + println!("scanned {} blocks, found {} requests", height, found_requests.len()); + for request in found_requests.iter() { use dusk_bytes::Serializable; use group::GroupEncoding; println!( From b2c8174345783e11a8705ca2bb87c4589eec47a0 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Thu, 26 Oct 2023 16:22:58 +0200 Subject: [PATCH 07/51] Added interactor struct and cli error enum --- moat-cli/src/command.rs | 14 +++-- moat-cli/src/error.rs | 43 +++++++++++++++ .../src/{interactive.rs => interactor.rs} | 52 ++++++++++--------- moat-cli/src/main.rs | 23 ++++---- 4 files changed, 95 insertions(+), 37 deletions(-) create mode 100644 moat-cli/src/error.rs rename moat-cli/src/{interactive.rs => interactor.rs} (62%) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 1a25c21..de383df 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -71,8 +71,12 @@ impl Command { let mut height = 0; loop { let height_end = height + 10000; - let (requests, top) = - RequestScanner::scan_block_range(height.clone(), height_end.clone(), &blockchain_access_config).await?; + let (requests, top) = RequestScanner::scan_block_range( + height, + height_end, + blockchain_access_config, + ) + .await?; found_requests.extend(requests); if top <= height_end { height = top; @@ -80,7 +84,11 @@ impl Command { } height = height_end; } - println!("scanned {} blocks, found {} requests", height, found_requests.len()); + println!( + "scanned {} blocks, found {} requests", + height, + found_requests.len() + ); for request in found_requests.iter() { use dusk_bytes::Serializable; use group::GroupEncoding; diff --git a/moat-cli/src/error.rs b/moat-cli/src/error.rs new file mode 100644 index 0000000..37c1919 --- /dev/null +++ b/moat-cli/src/error.rs @@ -0,0 +1,43 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) DUSK NETWORK. All rights reserved. + +use std::sync::Arc; + +#[derive(Debug)] +pub enum CliError { + /// Moat core error + Moat(Arc), + /// Interaction error + Interaction(Arc), + /// Parsing error + Parsing(Arc), + /// IO Error + IO(Arc), +} + +impl From for CliError { + fn from(e: moat_core::Error) -> Self { + CliError::Moat(Arc::from(e)) + } +} + +impl From for CliError { + fn from(e: requestty::ErrorKind) -> Self { + CliError::Interaction(Arc::from(e)) + } +} + +impl From for CliError { + fn from(e: clap::error::ErrorKind) -> Self { + CliError::Parsing(Arc::from(e)) + } +} + +impl From for CliError { + fn from(e: std::io::Error) -> Self { + CliError::IO(Arc::from(e)) + } +} diff --git a/moat-cli/src/interactive.rs b/moat-cli/src/interactor.rs similarity index 62% rename from moat-cli/src/interactive.rs rename to moat-cli/src/interactor.rs index 5878d38..174eb76 100644 --- a/moat-cli/src/interactive.rs +++ b/moat-cli/src/interactor.rs @@ -4,6 +4,7 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. +use crate::error::CliError; use crate::{Command, Menu}; use dusk_wallet::WalletPath; use moat_core::RequestJson; @@ -48,30 +49,33 @@ fn menu_operation() -> Result { }) } -pub async fn run_loop( - wallet_path: &WalletPath, - psw: &Password, - blockchain_access_config: &BlockchainAccessConfig, - gas_limit: u64, - gas_price: u64, - request_json: Option, -) -> Result<(), moat_core::Error> { - // todo: error type - loop { - let request_json = request_json.clone(); // todo: introduce object with state here - let op = menu_operation().map_err(|_| moat_core::Error::Rkyv)?; // todo: change the bogus error here - match op { - OpSelection::Exit => return Ok(()), - OpSelection::Run(bx) => { - bx.run( - wallet_path, - psw, - blockchain_access_config, - gas_limit.clone(), - gas_price.clone(), - request_json, - ) - .await? +pub struct Interactor { + pub wallet_path: WalletPath, + pub psw: Password, + pub blockchain_access_config: BlockchainAccessConfig, + pub gas_limit: u64, + pub gas_price: u64, + pub request_json: Option, +} + +impl Interactor { + pub async fn run_loop(&self) -> Result<(), CliError> { + loop { + let op = menu_operation()?; + match op { + OpSelection::Exit => return Ok(()), + OpSelection::Run(command) => { + command + .run( + &self.wallet_path, + &self.psw, + &self.blockchain_access_config, + self.gas_limit, + self.gas_price, + self.request_json.clone(), + ) + .await? + } } } } diff --git a/moat-cli/src/main.rs b/moat-cli/src/main.rs index 97f4511..248c779 100644 --- a/moat-cli/src/main.rs +++ b/moat-cli/src/main.rs @@ -8,7 +8,8 @@ mod args; mod command; -mod interactive; +mod error; +mod interactor; mod menu; use crate::args::Args; @@ -17,16 +18,17 @@ use crate::menu::Menu; use clap::Parser; +use crate::error::CliError; +use crate::interactor::Interactor; use dusk_wallet::WalletPath; use moat_core::{JsonLoader, RequestJson}; use rand::SeedableRng; -use std::error::Error; use toml_base_config::BaseConfig; use wallet_accessor::BlockchainAccessConfig; use wallet_accessor::Password::{Pwd, PwdHash}; #[tokio::main] -async fn main() -> Result<(), Box> { +async fn main() -> Result<(), CliError> { let cli = Args::parse(); let json_path = cli.json_path.as_path(); @@ -47,15 +49,16 @@ async fn main() -> Result<(), Box> { PwdHash(pwd_hash) }; - interactive::run_loop( - &wallet_path, - &psw, - &blockchain_access_config, + let interactor = Interactor { + wallet_path, + psw, + blockchain_access_config, gas_limit, gas_price, - Some(request_json), - ) - .await?; + request_json: Some(request_json), + }; + + interactor.run_loop().await?; #[rustfmt::skip] // cargo r --release --bin moat-cli -- --wallet-path ~/.dusk/rusk-wallet --config-path ./moat-cli/config.toml --pwd-hash 7f2611ba158b6dcea4a69c229c303358c5e04493abeadee106a4bfa464d55787 ./moat-cli/request.json From ffb098472480f45e21b8a2ed63500d53ab3f7e61 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Mon, 30 Oct 2023 10:16:03 +0100 Subject: [PATCH 08/51] Filtering only relevant user transactions --- moat-cli/Cargo.toml | 3 ++ moat-cli/src/command.rs | 23 +++++++-- .../src/citadel_requests/request_scanner.rs | 47 +++++++++++++++++++ wallet-accessor/src/wallet_accessor.rs | 44 +++++++++++------ 4 files changed, 98 insertions(+), 19 deletions(-) diff --git a/moat-cli/Cargo.toml b/moat-cli/Cargo.toml index be1ace2..299481d 100644 --- a/moat-cli/Cargo.toml +++ b/moat-cli/Cargo.toml @@ -7,6 +7,9 @@ edition = "2021" dusk-wallet = "0.20.0-rc.0" wallet-accessor = { path = "../wallet-accessor" } moat-core = { path = "../moat-core" } +zk-citadel = "0.5" +dusk-pki = "0.13" +dusk-bls12_381 = "0.12" toml-base-config = "0.1" clap = { version = "4.0", features = ["derive", "env"] } tokio = { version = "1.21", features = ["full"] } diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index de383df..9e23c10 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -5,13 +5,15 @@ // Copyright (c) DUSK NETWORK. All rights reserved. use crate::SeedableRng; +use dusk_bls12_381::BlsScalar; +use dusk_bytes::Serializable; use dusk_wallet::{RuskHttpClient, WalletPath}; use moat_core::{ Error, RequestCreator, RequestJson, RequestScanner, RequestSender, TxAwaiter, }; use rand::rngs::StdRng; -use wallet_accessor::{BlockchainAccessConfig, Password}; +use wallet_accessor::{BlockchainAccessConfig, Password, WalletAccessor}; /// Commands that can be run against the Moat #[derive(PartialEq, Eq, Hash, Clone, Debug)] @@ -67,14 +69,26 @@ impl Command { println!("tx {} confirmed", hex::encode(tx_id.to_bytes())); } Command::ListRequests { dummy: true } => { + let wallet_accessor = + WalletAccessor::new(wallet_path.clone(), psw.clone()); + let note_hashes: Vec = wallet_accessor + .get_notes(blockchain_access_config) + .await? + .iter() + .flat_map(|n| n.nullified_by) + .collect(); + println!("current address has {} notes", note_hashes.len()); + let mut found_requests = vec![]; let mut height = 0; loop { let height_end = height + 10000; - let (requests, top) = RequestScanner::scan_block_range( + let (requests, top) = + RequestScanner::scan_related_to_notes_in_block_range( height, height_end, blockchain_access_config, + ¬e_hashes, ) .await?; found_requests.extend(requests); @@ -84,13 +98,12 @@ impl Command { } height = height_end; } + let all_found_requests = found_requests.len(); println!( "scanned {} blocks, found {} requests", - height, - found_requests.len() + height, all_found_requests, ); for request in found_requests.iter() { - use dusk_bytes::Serializable; use group::GroupEncoding; println!( "found request rsa={} {}", diff --git a/moat-core/src/citadel_requests/request_scanner.rs b/moat-core/src/citadel_requests/request_scanner.rs index 67f94df..41f8b11 100644 --- a/moat-core/src/citadel_requests/request_scanner.rs +++ b/moat-core/src/citadel_requests/request_scanner.rs @@ -7,7 +7,9 @@ use crate::blockchain_payloads::PayloadExtractor; use crate::error::Error; use crate::{Transactions, TxInquirer}; +use dusk_bls12_381::BlsScalar; use dusk_wallet::RuskHttpClient; +use phoenix_core::Transaction; use wallet_accessor::BlockchainAccessConfig; use zk_citadel::license::Request; @@ -27,6 +29,34 @@ impl RequestScanner { requests } + pub fn scan_transactions_related_to_notes( + txs: Transactions, + note_hashes: &[BlsScalar], + ) -> Vec { + let mut requests = Vec::new(); + for tx in &txs.transactions { + if let Ok(request) = + PayloadExtractor::payload_from_tx::(tx) + { + let tx_raw = hex::decode(&tx.raw) + .expect("Decoding raw transaction should succeed"); + let ph_tx = Transaction::from_slice(&tx_raw) + .expect("Transaction creation from slice should succeed"); + for note_hash in note_hashes.iter() { + if ph_tx + .nullifiers() + .iter() + .any(|&nullifier| nullifier.eq(note_hash)) + { + requests.push(request); + break; + } + } + } + } + requests + } + /// Returns collection of requests found withing n last blocks pub async fn scan_last_blocks( last_n_blocks: usize, @@ -52,4 +82,21 @@ impl RequestScanner { let requests = RequestScanner::scan_transactions(txs); Ok((requests, top)) } + + pub async fn scan_related_to_notes_in_block_range( + height_beg: u64, + height_end: u64, + cfg: &BlockchainAccessConfig, + note_hashes: &[BlsScalar], + ) -> Result<(Vec, u64), Error> { + let client = RuskHttpClient::new(cfg.rusk_address.clone()); + let (txs, top) = + TxInquirer::txs_from_block_range(&client, height_beg, height_end) + .await?; + let requests = RequestScanner::scan_transactions_related_to_notes( + txs, + note_hashes, + ); + Ok((requests, top)) + } } diff --git a/wallet-accessor/src/wallet_accessor.rs b/wallet-accessor/src/wallet_accessor.rs index b2018e9..444e38e 100644 --- a/wallet-accessor/src/wallet_accessor.rs +++ b/wallet-accessor/src/wallet_accessor.rs @@ -8,7 +8,7 @@ use crate::wallet_accessor::Password::{Pwd, PwdHash}; use crate::BlockchainAccessConfig; use dusk_bls12_381::BlsScalar; use dusk_wallet::gas::Gas; -use dusk_wallet::{SecureWalletFile, Wallet, WalletPath}; +use dusk_wallet::{DecodedNote, SecureWalletFile, Wallet, WalletPath}; use dusk_wallet_core::MAX_CALL_SIZE; use phoenix_core::transaction::ModuleId; use rkyv::ser::serializers::AllocSerializer; @@ -58,20 +58,10 @@ impl WalletAccessor { } } - /// submits a transaction which will execute a given method - /// of a given contract - pub async fn execute_contract_method( + async fn get_wallet( &self, - data: C, - contract_id: ModuleId, - call_name: String, cfg: &BlockchainAccessConfig, - gas_limit: u64, - gas_price: u64, - ) -> Result - where - C: rkyv::Serialize>, - { + ) -> Result, dusk_wallet::Error> { let wallet_accessor = WalletAccessor::new(self.path.clone(), self.pwd.clone()); let mut wallet = Wallet::from_file(wallet_accessor)?; @@ -85,8 +75,25 @@ impl WalletAccessor { ) .await?; wallet.sync().await?; - assert!(wallet.is_online().await, "Wallet should be online"); + Ok(wallet) + } + + /// submits a transaction which will execute a given method + /// of a given contract + pub async fn execute_contract_method( + &self, + data: C, + contract_id: ModuleId, + call_name: String, + cfg: &BlockchainAccessConfig, + gas_limit: u64, + gas_price: u64, + ) -> Result + where + C: rkyv::Serialize>, + { + let wallet = self.get_wallet(cfg).await?; debug!( "Sending tx with a call to method '{}' of contract='{}'", @@ -104,4 +111,13 @@ impl WalletAccessor { let tx_id = rusk_abi::hash::Hasher::digest(tx.to_hash_input_bytes()); Ok(tx_id) } + + /// provides hashes of all notes belonging to the default address + pub async fn get_notes( + &self, + cfg: &BlockchainAccessConfig, + ) -> Result, dusk_wallet::Error> { + let wallet = self.get_wallet(cfg).await?; + wallet.get_all_notes(wallet.default_address()).await + } } From a2125ad59764dee298d5bb464528b24855d5d585 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Mon, 30 Oct 2023 11:17:10 +0100 Subject: [PATCH 09/51] Added listing requests for an LP --- moat-cli/Cargo.toml | 1 + moat-cli/lp.json | 4 ++ moat-cli/src/args.rs | 6 ++- moat-cli/src/command.rs | 41 +++++++++++++++---- moat-cli/src/interactor.rs | 18 ++++++-- moat-cli/src/main.rs | 5 ++- .../src/citadel_requests/request_scanner.rs | 2 + 7 files changed, 62 insertions(+), 15 deletions(-) create mode 100644 moat-cli/lp.json diff --git a/moat-cli/Cargo.toml b/moat-cli/Cargo.toml index 299481d..a9d08c2 100644 --- a/moat-cli/Cargo.toml +++ b/moat-cli/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" dusk-wallet = "0.20.0-rc.0" wallet-accessor = { path = "../wallet-accessor" } moat-core = { path = "../moat-core" } +license-provider = { path = "../license-provider" } zk-citadel = "0.5" dusk-pki = "0.13" dusk-bls12_381 = "0.12" diff --git a/moat-cli/lp.json b/moat-cli/lp.json new file mode 100644 index 0000000..9986fe4 --- /dev/null +++ b/moat-cli/lp.json @@ -0,0 +1,4 @@ +{ + "psk_lp": "136d747ff489bd06077f937508b9237ac093ff868dc2e232ab3af0ecd038873288560dbd8aa851e055bc408ebeb89509b26eb6e34b4b43214de467e3ef09594e", + "ssk_lp": "fd611dc2cfe15488e3cb94b410fadd3a5e77057be64574eb9b6acaf967a37d0514d0ce88727a24d3756a08bb8ae072d8aaaa88f88768c8a9487fb50678ba5204" +} diff --git a/moat-cli/src/args.rs b/moat-cli/src/args.rs index 635d775..5a49e5e 100644 --- a/moat-cli/src/args.rs +++ b/moat-cli/src/args.rs @@ -19,10 +19,14 @@ pub struct Args { #[clap(short, long)] pub wallet_path: PathBuf, - /// Config directory + /// Blockchain access config directory #[clap(short, long)] pub config_path: PathBuf, + /// LP Config directory + #[clap(short, long)] + pub lp_config_path: PathBuf, + /// Password for the wallet #[clap(long, default_value_t = String::from(""), env = "RUSK_WALLET_PWD")] pub password: String, diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 9e23c10..ad4524e 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -8,11 +8,13 @@ use crate::SeedableRng; use dusk_bls12_381::BlsScalar; use dusk_bytes::Serializable; use dusk_wallet::{RuskHttpClient, WalletPath}; +use license_provider::ReferenceLP; use moat_core::{ Error, RequestCreator, RequestJson, RequestScanner, RequestSender, TxAwaiter, }; use rand::rngs::StdRng; +use std::path::Path; use wallet_accessor::{BlockchainAccessConfig, Password, WalletAccessor}; /// Commands that can be run against the Moat @@ -20,16 +22,20 @@ use wallet_accessor::{BlockchainAccessConfig, Password, WalletAccessor}; pub(crate) enum Command { /// Submit request SubmitRequest { dummy: bool }, - /// List requests - ListRequests { dummy: bool }, + /// List requests (User) + ListRequestsUser { dummy: bool }, + /// List requests (LP) + ListRequestsLP { dummy: bool }, } impl Command { + #[allow(clippy::too_many_arguments)] pub async fn run( self, wallet_path: &WalletPath, psw: &Password, blockchain_access_config: &BlockchainAccessConfig, + lp_config: &Path, gas_limit: u64, gas_price: u64, request_json: Option, @@ -68,7 +74,7 @@ impl Command { TxAwaiter::wait_for(&client, tx_id).await?; println!("tx {} confirmed", hex::encode(tx_id.to_bytes())); } - Command::ListRequests { dummy: true } => { + Command::ListRequestsUser { dummy: true } => { let wallet_accessor = WalletAccessor::new(wallet_path.clone(), psw.clone()); let note_hashes: Vec = wallet_accessor @@ -85,12 +91,12 @@ impl Command { let height_end = height + 10000; let (requests, top) = RequestScanner::scan_related_to_notes_in_block_range( - height, - height_end, - blockchain_access_config, + height, + height_end, + blockchain_access_config, ¬e_hashes, - ) - .await?; + ) + .await?; found_requests.extend(requests); if top <= height_end { height = top; @@ -106,7 +112,24 @@ impl Command { for request in found_requests.iter() { use group::GroupEncoding; println!( - "found request rsa={} {}", + "found request rsa={}-{}", + hex::encode(request.rsa.R().to_bytes()), + hex::encode(request.rsa.pk_r().to_bytes()) + ); + } + } + Command::ListRequestsLP { dummy: true } => { + let mut reference_lp = ReferenceLP::create(lp_config)?; + let (total_count, this_lp_count) = + reference_lp.scan(blockchain_access_config).await?; + println!( + "found {} requests total, {} requests for this LP ", + total_count, this_lp_count + ); + for request in reference_lp.requests_to_process.iter() { + use group::GroupEncoding; + println!( + "request to process by LP: rsa={}-{}", hex::encode(request.rsa.R().to_bytes()), hex::encode(request.rsa.pk_r().to_bytes()) ); diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index 174eb76..ade8eba 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -9,6 +9,7 @@ use crate::{Command, Menu}; use dusk_wallet::WalletPath; use moat_core::RequestJson; use requestty::{ErrorKind, Question}; +use std::path::PathBuf; use wallet_accessor::{BlockchainAccessConfig, Password}; #[derive(PartialEq, Eq, Hash, Debug, Clone)] @@ -20,14 +21,16 @@ enum OpSelection { #[derive(PartialEq, Eq, Hash, Clone, Debug)] enum CommandMenuItem { SubmitRequest, - ListRequests, + ListRequestsUser, + ListRequestsLP, Exit, } fn menu_operation() -> Result { let cmd_menu = Menu::new() .add(CommandMenuItem::SubmitRequest, "Submit Request") - .add(CommandMenuItem::ListRequests, "List Requests") + .add(CommandMenuItem::ListRequestsUser, "List Requests (User)") + .add(CommandMenuItem::ListRequestsLP, "List Requests (LP)") .separator() .add(CommandMenuItem::Exit, "Exit"); @@ -42,8 +45,13 @@ fn menu_operation() -> Result { CommandMenuItem::SubmitRequest => { OpSelection::Run(Box::from(Command::SubmitRequest { dummy: true })) } - CommandMenuItem::ListRequests => { - OpSelection::Run(Box::from(Command::ListRequests { dummy: true })) + CommandMenuItem::ListRequestsUser => { + OpSelection::Run(Box::from(Command::ListRequestsUser { + dummy: true, + })) + } + CommandMenuItem::ListRequestsLP => { + OpSelection::Run(Box::from(Command::ListRequestsLP { dummy: true })) } CommandMenuItem::Exit => OpSelection::Exit, }) @@ -53,6 +61,7 @@ pub struct Interactor { pub wallet_path: WalletPath, pub psw: Password, pub blockchain_access_config: BlockchainAccessConfig, + pub lp_config_path: PathBuf, pub gas_limit: u64, pub gas_price: u64, pub request_json: Option, @@ -70,6 +79,7 @@ impl Interactor { &self.wallet_path, &self.psw, &self.blockchain_access_config, + &self.lp_config_path, self.gas_limit, self.gas_price, self.request_json.clone(), diff --git a/moat-cli/src/main.rs b/moat-cli/src/main.rs index 248c779..b743198 100644 --- a/moat-cli/src/main.rs +++ b/moat-cli/src/main.rs @@ -15,6 +15,7 @@ mod menu; use crate::args::Args; use crate::command::Command; use crate::menu::Menu; +use std::path::PathBuf; use clap::Parser; @@ -33,6 +34,7 @@ async fn main() -> Result<(), CliError> { let json_path = cli.json_path.as_path(); let config_path = cli.config_path.as_path(); + let lp_config_path = PathBuf::from(cli.lp_config_path.as_path()); let wallet_path = cli.wallet_path.as_path(); let password = cli.password; let pwd_hash = cli.pwd_hash; @@ -53,6 +55,7 @@ async fn main() -> Result<(), CliError> { wallet_path, psw, blockchain_access_config, + lp_config_path, gas_limit, gas_price, request_json: Some(request_json), @@ -61,7 +64,7 @@ async fn main() -> Result<(), CliError> { interactor.run_loop().await?; #[rustfmt::skip] - // cargo r --release --bin moat-cli -- --wallet-path ~/.dusk/rusk-wallet --config-path ./moat-cli/config.toml --pwd-hash 7f2611ba158b6dcea4a69c229c303358c5e04493abeadee106a4bfa464d55787 ./moat-cli/request.json + // cargo r --release --bin moat-cli -- --wallet-path ~/.dusk/rusk-wallet --config-path ./moat-cli/config.toml --lp-config-path ./moat-cli/lp.json --pwd-hash 7f2611ba158b6dcea4a69c229c303358c5e04493abeadee106a4bfa464d55787 ./moat-cli/request.json Ok(()) } diff --git a/moat-core/src/citadel_requests/request_scanner.rs b/moat-core/src/citadel_requests/request_scanner.rs index 41f8b11..2bc110a 100644 --- a/moat-core/src/citadel_requests/request_scanner.rs +++ b/moat-core/src/citadel_requests/request_scanner.rs @@ -29,6 +29,7 @@ impl RequestScanner { requests } + /// Returns requests related to notes from a given list of note hashes. pub fn scan_transactions_related_to_notes( txs: Transactions, note_hashes: &[BlsScalar], @@ -83,6 +84,7 @@ impl RequestScanner { Ok((requests, top)) } + /// Scans requests related to notes from a given list of note hashes. pub async fn scan_related_to_notes_in_block_range( height_beg: u64, height_end: u64, From 99efb088d7e9593eb6cd5c9188f186bd65a3a4ea Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Mon, 30 Oct 2023 13:35:30 +0100 Subject: [PATCH 10/51] Added prompt for psk when submitting request --- moat-cli/src/command.rs | 17 +++++++++++++---- moat-cli/src/interactor.rs | 5 ++++- moat-cli/src/main.rs | 1 + moat-cli/src/prompt.rs | 23 +++++++++++++++++++++++ 4 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 moat-cli/src/prompt.rs diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index ad4524e..8326998 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -21,7 +21,7 @@ use wallet_accessor::{BlockchainAccessConfig, Password, WalletAccessor}; #[derive(PartialEq, Eq, Hash, Clone, Debug)] pub(crate) enum Command { /// Submit request - SubmitRequest { dummy: bool }, + SubmitRequest { provider_psk: String }, /// List requests (User) ListRequestsUser { dummy: bool }, /// List requests (LP) @@ -41,7 +41,7 @@ impl Command { request_json: Option, ) -> Result<(), Error> { match self { - Command::SubmitRequest { dummy: true } => { + Command::SubmitRequest { provider_psk } => { let request_json = request_json.expect("request should be provided"); // todo // todo - this request creation belongs somewhere else because @@ -49,12 +49,21 @@ impl Command { // also want to create request on the fly, from data provided by // user interactively let rng = &mut StdRng::seed_from_u64(0xcafe); + println!("obtained provider psk={}", provider_psk); + let provider_psk_str = if provider_psk.is_empty() { + request_json.provider_psk + } else { + provider_psk + }; let request = RequestCreator::create_from_hex_args( request_json.user_ssk, - request_json.provider_psk, + provider_psk_str.clone(), rng, )?; - println!("submitting request"); + println!( + "submitting request to provider psk: {}", + provider_psk_str + ); let tx_id = RequestSender::send_request( request, blockchain_access_config, diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index ade8eba..cc1a2e2 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -5,6 +5,7 @@ // Copyright (c) DUSK NETWORK. All rights reserved. use crate::error::CliError; +use crate::prompt; use crate::{Command, Menu}; use dusk_wallet::WalletPath; use moat_core::RequestJson; @@ -43,7 +44,9 @@ fn menu_operation() -> Result { let cmd = cmd_menu.answer(&answer).to_owned(); Ok(match cmd { CommandMenuItem::SubmitRequest => { - OpSelection::Run(Box::from(Command::SubmitRequest { dummy: true })) + OpSelection::Run(Box::from(Command::SubmitRequest { + provider_psk: prompt::request_provider_psk()?, + })) } CommandMenuItem::ListRequestsUser => { OpSelection::Run(Box::from(Command::ListRequestsUser { diff --git a/moat-cli/src/main.rs b/moat-cli/src/main.rs index b743198..06032cf 100644 --- a/moat-cli/src/main.rs +++ b/moat-cli/src/main.rs @@ -11,6 +11,7 @@ mod command; mod error; mod interactor; mod menu; +mod prompt; use crate::args::Args; use crate::command::Command; diff --git a/moat-cli/src/prompt.rs b/moat-cli/src/prompt.rs new file mode 100644 index 0000000..d87fd00 --- /dev/null +++ b/moat-cli/src/prompt.rs @@ -0,0 +1,23 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) DUSK NETWORK. All rights reserved. + +use requestty::{ErrorKind, Question}; + +pub(crate) fn request_provider_psk() -> Result { + let q = Question::input("psk") + .message("Please enter the provider public spend key:".to_string()) + .validate_on_key(|_, _| { + true // todo: add some validation of the psk + }) + .validate(|_, _| { + Ok(()) // todo: add some validation of the psk + }) + .build(); + + let a = requestty::prompt_one(q)?; + let a_str = a.as_string().expect("answer to be a string").to_string(); + Ok(a_str) +} From 9e6c476aa2b4955fb7de593da17c93f2dc2bbe0d Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Mon, 30 Oct 2023 14:06:24 +0100 Subject: [PATCH 11/51] Possibility of listing requests for a different LP --- moat-cli/lp2.json | 4 ++++ moat-cli/src/command.rs | 13 +++++++++---- moat-cli/src/interactor.rs | 6 +++++- moat-cli/src/prompt.rs | 23 +++++++++++++++++++++++ 4 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 moat-cli/lp2.json diff --git a/moat-cli/lp2.json b/moat-cli/lp2.json new file mode 100644 index 0000000..5c6f643 --- /dev/null +++ b/moat-cli/lp2.json @@ -0,0 +1,4 @@ +{ + "psk_lp": "29c4336ef24e585f4506e32e269c5363a71f7dcd74586b210c56e569ad2644e832c785f102dd3c985c705008ec188be819bac85b65c9f70decb9adcf4a72cc43", + "ssk_lp": "530046f569d26740eaa703b7f88bfb82a31aae1cef96732609e4b8f1e59802039f5afb7c1d5576e51c71d5afe8f6e06977c68641fae11abd3ce0b2196d1f3608" +} diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 8326998..18ea01b 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -14,7 +14,7 @@ use moat_core::{ TxAwaiter, }; use rand::rngs::StdRng; -use std::path::Path; +use std::path::{Path, PathBuf}; use wallet_accessor::{BlockchainAccessConfig, Password, WalletAccessor}; /// Commands that can be run against the Moat @@ -25,7 +25,7 @@ pub(crate) enum Command { /// List requests (User) ListRequestsUser { dummy: bool }, /// List requests (LP) - ListRequestsLP { dummy: bool }, + ListRequestsLP { lp_config_path: Option }, } impl Command { @@ -127,8 +127,13 @@ impl Command { ); } } - Command::ListRequestsLP { dummy: true } => { - let mut reference_lp = ReferenceLP::create(lp_config)?; + Command::ListRequestsLP { lp_config_path } => { + println!("obtained LP config path={:?}", lp_config_path); + let lp_config_path = match lp_config_path { + Some(lp_config_path) => lp_config_path, + _ => PathBuf::from(lp_config), + }; + let mut reference_lp = ReferenceLP::create(lp_config_path)?; let (total_count, this_lp_count) = reference_lp.scan(blockchain_access_config).await?; println!( diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index cc1a2e2..98e028f 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -54,7 +54,11 @@ fn menu_operation() -> Result { })) } CommandMenuItem::ListRequestsLP => { - OpSelection::Run(Box::from(Command::ListRequestsLP { dummy: true })) + OpSelection::Run(Box::from(Command::ListRequestsLP { + lp_config_path: prompt::request_pathbuf( + "LP config (e.g. moat-cli/lp2.json)", + )?, + })) } CommandMenuItem::Exit => OpSelection::Exit, }) diff --git a/moat-cli/src/prompt.rs b/moat-cli/src/prompt.rs index d87fd00..e13ee79 100644 --- a/moat-cli/src/prompt.rs +++ b/moat-cli/src/prompt.rs @@ -5,6 +5,7 @@ // Copyright (c) DUSK NETWORK. All rights reserved. use requestty::{ErrorKind, Question}; +use std::path::PathBuf; pub(crate) fn request_provider_psk() -> Result { let q = Question::input("psk") @@ -21,3 +22,25 @@ pub(crate) fn request_provider_psk() -> Result { let a_str = a.as_string().expect("answer to be a string").to_string(); Ok(a_str) } + +pub(crate) fn request_pathbuf( + hint: &str, +) -> Result, ErrorKind> { + let q = Question::input("psk") + .message(format!("Please enter path for {}:", hint)) + .validate_on_key(|_, _| { + true // todo: add some validation of the psk + }) + .validate(|_, _| { + Ok(()) // todo: add some validation of the psk + }) + .build(); + + let a = requestty::prompt_one(q)?; + let a_str = a.as_string().expect("answer to be a string").to_string(); + Ok(if a_str.is_empty() { + None + } else { + Some(PathBuf::from(a_str)) + }) +} From 46d02fbb101e47e4a54ee1eeae3728c1a7be102b Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Mon, 30 Oct 2023 14:59:56 +0100 Subject: [PATCH 12/51] Added issue license --- license-provider/src/reference_lp.rs | 3 +- moat-cli/src/command.rs | 47 +++++++++++++++++++++++++--- moat-cli/src/interactor.rs | 9 ++++++ 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/license-provider/src/reference_lp.rs b/license-provider/src/reference_lp.rs index edaa722..368ac8c 100644 --- a/license-provider/src/reference_lp.rs +++ b/license-provider/src/reference_lp.rs @@ -124,8 +124,7 @@ impl ReferenceLP { } } - #[allow(dead_code)] - fn take_request(&mut self) -> Option { + pub fn take_request(&mut self) -> Option { self.requests_to_process.pop().map(|request| { self.requests_hashes.remove(&Self::hash_request(&request)); request diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 18ea01b..680ffdb 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -8,7 +8,8 @@ use crate::SeedableRng; use dusk_bls12_381::BlsScalar; use dusk_bytes::Serializable; use dusk_wallet::{RuskHttpClient, WalletPath}; -use license_provider::ReferenceLP; +use group::GroupEncoding; +use license_provider::{LicenseIssuer, ReferenceLP}; use moat_core::{ Error, RequestCreator, RequestJson, RequestScanner, RequestSender, TxAwaiter, @@ -26,6 +27,8 @@ pub(crate) enum Command { ListRequestsUser { dummy: bool }, /// List requests (LP) ListRequestsLP { lp_config_path: Option }, + /// Issue license (LP) + IssueLicenseLP { lp_config_path: Option }, } impl Command { @@ -119,9 +122,8 @@ impl Command { height, all_found_requests, ); for request in found_requests.iter() { - use group::GroupEncoding; println!( - "found request rsa={}-{}", + "request: rsa={}-{}", hex::encode(request.rsa.R().to_bytes()), hex::encode(request.rsa.pk_r().to_bytes()) ); @@ -141,7 +143,6 @@ impl Command { total_count, this_lp_count ); for request in reference_lp.requests_to_process.iter() { - use group::GroupEncoding; println!( "request to process by LP: rsa={}-{}", hex::encode(request.rsa.R().to_bytes()), @@ -149,6 +150,44 @@ impl Command { ); } } + Command::IssueLicenseLP { lp_config_path } => { + let mut rng = StdRng::seed_from_u64(0xbeef); + println!("obtained LP config path={:?}", lp_config_path); + let lp_config_path = match lp_config_path { + Some(lp_config_path) => lp_config_path, + _ => PathBuf::from(lp_config), + }; + let mut reference_lp = ReferenceLP::create(lp_config_path)?; + let (total_count, this_lp_count) = + reference_lp.scan(blockchain_access_config).await?; + println!( + "found {} requests total, {} requests for this LP ", + total_count, this_lp_count + ); + let request = + reference_lp.take_request().expect("at least one request"); + + let license_issuer = LicenseIssuer::new( + blockchain_access_config.clone(), + wallet_path.clone(), + psw.clone(), + gas_limit, + gas_price, + ); + + println!( + "issuing license for request: {}-{}", + hex::encode(request.rsa.R().to_bytes()), + hex::encode(request.rsa.pk_r().to_bytes()) + ); + let tx_id = license_issuer + .issue_license(&mut rng, &request, &reference_lp.ssk_lp) + .await?; + println!( + "license issuing transaction {} submitted and confirmed", + hex::encode(tx_id.to_bytes()) + ); + } _ => (), } Ok(()) diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index 98e028f..bce09ac 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -24,6 +24,7 @@ enum CommandMenuItem { SubmitRequest, ListRequestsUser, ListRequestsLP, + IssueLicenseLP, Exit, } @@ -32,6 +33,7 @@ fn menu_operation() -> Result { .add(CommandMenuItem::SubmitRequest, "Submit Request") .add(CommandMenuItem::ListRequestsUser, "List Requests (User)") .add(CommandMenuItem::ListRequestsLP, "List Requests (LP)") + .add(CommandMenuItem::IssueLicenseLP, "Issue License (LP)") .separator() .add(CommandMenuItem::Exit, "Exit"); @@ -60,6 +62,13 @@ fn menu_operation() -> Result { )?, })) } + CommandMenuItem::IssueLicenseLP => { + OpSelection::Run(Box::from(Command::IssueLicenseLP { + lp_config_path: prompt::request_pathbuf( + "LP config (e.g. moat-cli/lp2.json)", + )?, + })) + } CommandMenuItem::Exit => OpSelection::Exit, }) } From 177f3d2c53258de963e4af1918b27d74b0872a1b Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Mon, 30 Oct 2023 16:05:29 +0100 Subject: [PATCH 13/51] Get licenses - single license version --- moat-cli/Cargo.toml | 4 ++ moat-cli/src/command.rs | 86 ++++++++++++++++++++++++++++++++++++-- moat-cli/src/interactor.rs | 7 +++- 3 files changed, 93 insertions(+), 4 deletions(-) diff --git a/moat-cli/Cargo.toml b/moat-cli/Cargo.toml index a9d08c2..e27cef0 100644 --- a/moat-cli/Cargo.toml +++ b/moat-cli/Cargo.toml @@ -9,6 +9,7 @@ wallet-accessor = { path = "../wallet-accessor" } moat-core = { path = "../moat-core" } license-provider = { path = "../license-provider" } zk-citadel = "0.5" +rkyv = { version = "=0.7.39" } dusk-pki = "0.13" dusk-bls12_381 = "0.12" toml-base-config = "0.1" @@ -21,3 +22,6 @@ requestty = "0.4.1" hex = "0.4" dusk-bytes = "0.1" group = "0.13" +bytes = "1.4" +futures-core = "0.3" +reqwest = "0.11" diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 680ffdb..4bfc490 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -5,18 +5,23 @@ // Copyright (c) DUSK NETWORK. All rights reserved. use crate::SeedableRng; +use bytes::Bytes; use dusk_bls12_381::BlsScalar; -use dusk_bytes::Serializable; +use dusk_bytes::{DeserializableSlice, Serializable}; +use dusk_pki::SecretSpendKey; use dusk_wallet::{RuskHttpClient, WalletPath}; use group::GroupEncoding; use license_provider::{LicenseIssuer, ReferenceLP}; +use moat_core::Error::InvalidQueryResponse; use moat_core::{ - Error, RequestCreator, RequestJson, RequestScanner, RequestSender, - TxAwaiter, + BcInquirer, CitadelInquirer, Error, RequestCreator, RequestJson, + RequestScanner, RequestSender, StreamAux, TxAwaiter, }; use rand::rngs::StdRng; +use rkyv::{check_archived_root, Deserialize, Infallible}; use std::path::{Path, PathBuf}; use wallet_accessor::{BlockchainAccessConfig, Password, WalletAccessor}; +use zk_citadel::license::License; /// Commands that can be run against the Moat #[derive(PartialEq, Eq, Hash, Clone, Debug)] @@ -29,6 +34,41 @@ pub(crate) enum Command { ListRequestsLP { lp_config_path: Option }, /// Issue license (LP) IssueLicenseLP { lp_config_path: Option }, + /// List licenses (User) + ListLicenses { dummy: bool }, +} + +// todo: move this function somewhere else +/// Deserializes license, panics if deserialization fails. +fn deserialise_license(v: &Vec) -> License { + let response_data = check_archived_root::(v.as_slice()) + .map_err(|_| { + InvalidQueryResponse(Box::from("rkyv deserialization error")) + }) + .expect("License should deserialize correctly"); + let license: License = response_data + .deserialize(&mut Infallible) + .expect("Infallible"); + license +} + +// todo: move this function somewhere else +/// Finds owned license in a stream of licenses. +/// It searches in a reverse order to return a newest license. +fn find_owned_license( + ssk_user: SecretSpendKey, + stream: impl futures_core::Stream> + + std::marker::Unpin, +) -> Result<(u64, License), Error> { + const ITEM_LEN: usize = CitadelInquirer::GET_LICENSES_ITEM_LEN; + let (pos, lic_ser) = StreamAux::find_item::<(u64, Vec), ITEM_LEN>( + |(_, lic_vec)| { + let license = deserialise_license(lic_vec); + Ok(ssk_user.view_key().owns(&license.lsa)) + }, + stream, + )?; + Ok((pos, deserialise_license(&lic_ser))) } impl Command { @@ -188,6 +228,46 @@ impl Command { hex::encode(tx_id.to_bytes()) ); } + Command::ListLicenses { dummy: true } => { + let client = RuskHttpClient::new( + blockchain_access_config.rusk_address.clone(), + ); + let end_height = BcInquirer::block_height(&client).await?; + println!("end_height={}", end_height); + const BLOCK_RANGE: u64 = 10000; + let start_height = if end_height > BLOCK_RANGE { + end_height - BLOCK_RANGE + } else { + 0u64 + }; + let block_heights = start_height..(end_height + 1); + + println!("calling get_licenses with range {:?}", block_heights); + let licenses_stream = + CitadelInquirer::get_licenses(&client, block_heights) + .await?; + + let ssk_user = SecretSpendKey::from_slice( + hex::decode( + request_json + .expect("request should be provided") + .user_ssk, + )? + .as_slice(), + )?; + + let result = find_owned_license(ssk_user, licenses_stream); + if result.is_ok() { + let (_, license) = result.unwrap(); + println!( + "found license: {}-{}", + hex::encode(license.lsa.R().to_bytes()), + hex::encode(license.lsa.pk_r().to_bytes()) + ) + } else { + println!("license not found: {:?}", result); + } + } _ => (), } Ok(()) diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index bce09ac..5aa07e3 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -25,15 +25,17 @@ enum CommandMenuItem { ListRequestsUser, ListRequestsLP, IssueLicenseLP, + ListLicenses, Exit, } fn menu_operation() -> Result { let cmd_menu = Menu::new() - .add(CommandMenuItem::SubmitRequest, "Submit Request") + .add(CommandMenuItem::SubmitRequest, "Submit Request (User)") .add(CommandMenuItem::ListRequestsUser, "List Requests (User)") .add(CommandMenuItem::ListRequestsLP, "List Requests (LP)") .add(CommandMenuItem::IssueLicenseLP, "Issue License (LP)") + .add(CommandMenuItem::ListLicenses, "List Licenses (User)") .separator() .add(CommandMenuItem::Exit, "Exit"); @@ -69,6 +71,9 @@ fn menu_operation() -> Result { )?, })) } + CommandMenuItem::ListLicenses => { + OpSelection::Run(Box::from(Command::ListLicenses { dummy: true })) + } CommandMenuItem::Exit => OpSelection::Exit, }) } From 7a14269cf1bc1ef8ed3544b44b87033aa89eefe5 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Mon, 30 Oct 2023 18:01:19 +0100 Subject: [PATCH 14/51] Returning multiple licenses in get_licenses --- .../tests/citadel/int_test_user.rs | 8 +-- moat-cli/src/command.rs | 54 +++++++++++-------- moat-core/src/contract_queries/stream_aux.rs | 4 +- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/integration-tests/tests/citadel/int_test_user.rs b/integration-tests/tests/citadel/int_test_user.rs index 2781f37..3f2d52f 100644 --- a/integration-tests/tests/citadel/int_test_user.rs +++ b/integration-tests/tests/citadel/int_test_user.rs @@ -199,8 +199,8 @@ async fn show_state( /// It searches in a reverse order to return a newest license. fn find_owned_license( ssk_user: SecretSpendKey, - stream: impl futures_core::Stream> - + std::marker::Unpin, + stream: &mut (impl futures_core::Stream> + + std::marker::Unpin), ) -> Result<(u64, License), Error> { const ITEM_LEN: usize = CitadelInquirer::GET_LICENSES_ITEM_LEN; let (pos, lic_ser) = StreamAux::find_item::<(u64, Vec), ITEM_LEN>( @@ -332,10 +332,10 @@ async fn user_round_trip() -> Result<(), Error> { "calling get_licenses with range {:?} (as a user)", block_heights ); - let licenses_stream = + let mut licenses_stream = CitadelInquirer::get_licenses(&client, block_heights).await?; - let (pos, license) = find_owned_license(ssk_user, licenses_stream) + let (pos, license) = find_owned_license(ssk_user, &mut licenses_stream) .expect("owned license found"); // as a User, call get_merkle_opening, obtain opening diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 4bfc490..9eb08d5 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -55,20 +55,28 @@ fn deserialise_license(v: &Vec) -> License { // todo: move this function somewhere else /// Finds owned license in a stream of licenses. /// It searches in a reverse order to return a newest license. -fn find_owned_license( +fn find_owned_licenses( ssk_user: SecretSpendKey, - stream: impl futures_core::Stream> - + std::marker::Unpin, -) -> Result<(u64, License), Error> { + stream: &mut (impl futures_core::Stream> + + std::marker::Unpin), +) -> Result, Error> { const ITEM_LEN: usize = CitadelInquirer::GET_LICENSES_ITEM_LEN; - let (pos, lic_ser) = StreamAux::find_item::<(u64, Vec), ITEM_LEN>( - |(_, lic_vec)| { - let license = deserialise_license(lic_vec); - Ok(ssk_user.view_key().owns(&license.lsa)) - }, - stream, - )?; - Ok((pos, deserialise_license(&lic_ser))) + let mut pairs = vec![]; + loop { + let r = StreamAux::find_item::<(u64, Vec), ITEM_LEN>( + |(_, lic_vec)| { + let license = deserialise_license(lic_vec); + Ok(ssk_user.view_key().owns(&license.lsa)) + }, + stream, + ); + if r.is_err() { + break; + } + let (pos, lic_ser) = r?; + pairs.push((pos, deserialise_license(&lic_ser))) + } + Ok(pairs) } impl Command { @@ -243,7 +251,7 @@ impl Command { let block_heights = start_height..(end_height + 1); println!("calling get_licenses with range {:?}", block_heights); - let licenses_stream = + let mut licenses_stream = CitadelInquirer::get_licenses(&client, block_heights) .await?; @@ -256,16 +264,18 @@ impl Command { .as_slice(), )?; - let result = find_owned_license(ssk_user, licenses_stream); - if result.is_ok() { - let (_, license) = result.unwrap(); - println!( - "found license: {}-{}", - hex::encode(license.lsa.R().to_bytes()), - hex::encode(license.lsa.pk_r().to_bytes()) - ) - } else { + let result = + find_owned_licenses(ssk_user, &mut licenses_stream)?; + if result.is_empty() { println!("license not found: {:?}", result); + } else { + for (_, license) in result { + println!( + "license: {}-{}", + hex::encode(license.lsa.R().to_bytes()), + hex::encode(license.lsa.pk_r().to_bytes()) + ) + } } } _ => (), diff --git a/moat-core/src/contract_queries/stream_aux.rs b/moat-core/src/contract_queries/stream_aux.rs index cf606ad..4f0f07e 100644 --- a/moat-core/src/contract_queries/stream_aux.rs +++ b/moat-core/src/contract_queries/stream_aux.rs @@ -21,8 +21,8 @@ impl StreamAux { /// returns error if no such item was found pub fn find_item( filter: impl Fn(&R) -> Result, - mut stream: impl futures_core::Stream> - + std::marker::Unpin, + stream: &mut (impl futures_core::Stream> + + std::marker::Unpin), ) -> Result where R: Archive, From 1d00bcaa9d1c02e27732455294534db66893f031 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 31 Oct 2023 12:54:12 +0100 Subject: [PATCH 15/51] Added use license --- moat-cli/Cargo.toml | 2 + moat-cli/src/command.rs | 239 +++++++++++++++++++++++++++++++------ moat-cli/src/interactor.rs | 11 +- 3 files changed, 210 insertions(+), 42 deletions(-) diff --git a/moat-cli/Cargo.toml b/moat-cli/Cargo.toml index e27cef0..49230ef 100644 --- a/moat-cli/Cargo.toml +++ b/moat-cli/Cargo.toml @@ -9,6 +9,7 @@ wallet-accessor = { path = "../wallet-accessor" } moat-core = { path = "../moat-core" } license-provider = { path = "../license-provider" } zk-citadel = "0.5" +dusk-plonk = { version = "0.16", default-features = false, features = ["rkyv-impl", "alloc"] } rkyv = { version = "=0.7.39" } dusk-pki = "0.13" dusk-bls12_381 = "0.12" @@ -25,3 +26,4 @@ group = "0.13" bytes = "1.4" futures-core = "0.3" reqwest = "0.11" +bytecheck = "0.6" diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 9eb08d5..a914ed1 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -5,28 +5,31 @@ // Copyright (c) DUSK NETWORK. All rights reserved. use crate::SeedableRng; +use bytecheck::CheckBytes; use bytes::Bytes; use dusk_bls12_381::BlsScalar; use dusk_bytes::{DeserializableSlice, Serializable}; use dusk_pki::SecretSpendKey; +use dusk_plonk::prelude::*; use dusk_wallet::{RuskHttpClient, WalletPath}; use group::GroupEncoding; use license_provider::{LicenseIssuer, ReferenceLP}; use moat_core::Error::InvalidQueryResponse; use moat_core::{ - BcInquirer, CitadelInquirer, Error, RequestCreator, RequestJson, - RequestScanner, RequestSender, StreamAux, TxAwaiter, + BcInquirer, CitadelInquirer, Error, LicenseCircuit, PayloadSender, + RequestCreator, RequestJson, RequestScanner, RequestSender, StreamAux, + TxAwaiter, LICENSE_CONTRACT_ID, USE_LICENSE_METHOD_NAME, }; use rand::rngs::StdRng; -use rkyv::{check_archived_root, Deserialize, Infallible}; +use rkyv::{check_archived_root, Archive, Deserialize, Infallible, Serialize}; use std::path::{Path, PathBuf}; use wallet_accessor::{BlockchainAccessConfig, Password, WalletAccessor}; -use zk_citadel::license::License; +use zk_citadel::license::{CitadelProverParameters, License}; /// Commands that can be run against the Moat #[derive(PartialEq, Eq, Hash, Clone, Debug)] pub(crate) enum Command { - /// Submit request + /// Submit request (User) SubmitRequest { provider_psk: String }, /// List requests (User) ListRequestsUser { dummy: bool }, @@ -36,6 +39,8 @@ pub(crate) enum Command { IssueLicenseLP { lp_config_path: Option }, /// List licenses (User) ListLicenses { dummy: bool }, + /// Use license (User) + UseLicense { dummy: bool }, } // todo: move this function somewhere else @@ -79,6 +84,19 @@ fn find_owned_licenses( Ok(pairs) } +// todo: move this struct to its proper place +/// Use License Argument. +#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)] +#[archive_attr(derive(CheckBytes))] +pub struct UseLicenseArg { + pub proof: Proof, + pub public_inputs: Vec, +} + +// todo: move these consts to their proper place +static LABEL: &[u8] = b"dusk-network"; +const CAPACITY: usize = 17; // capacity required for the setup + impl Command { #[allow(clippy::too_many_arguments)] pub async fn run( @@ -237,44 +255,54 @@ impl Command { ); } Command::ListLicenses { dummy: true } => { - let client = RuskHttpClient::new( - blockchain_access_config.rusk_address.clone(), - ); - let end_height = BcInquirer::block_height(&client).await?; - println!("end_height={}", end_height); - const BLOCK_RANGE: u64 = 10000; - let start_height = if end_height > BLOCK_RANGE { - end_height - BLOCK_RANGE - } else { - 0u64 - }; - let block_heights = start_height..(end_height + 1); - - println!("calling get_licenses with range {:?}", block_heights); - let mut licenses_stream = - CitadelInquirer::get_licenses(&client, block_heights) - .await?; - - let ssk_user = SecretSpendKey::from_slice( - hex::decode( - request_json - .expect("request should be provided") - .user_ssk, - )? - .as_slice(), - )?; - - let result = - find_owned_licenses(ssk_user, &mut licenses_stream)?; - if result.is_empty() { - println!("license not found: {:?}", result); - } else { - for (_, license) in result { + let _ = self + .list_licenses( + blockchain_access_config, + request_json.as_ref(), + true, + ) + .await?; + } + Command::UseLicense { dummy: true } => { + let pos_license = self + .list_licenses( + blockchain_access_config, + request_json.as_ref(), + false, + ) + .await?; + match pos_license { + Some((pos, license)) => { println!( - "license: {}-{}", + "using license: {}-{}", hex::encode(license.lsa.R().to_bytes()), hex::encode(license.lsa.pk_r().to_bytes()) + ); + let ssk_user = SecretSpendKey::from_slice( + hex::decode( + request_json + .expect("request should be provided") + .user_ssk, + )? + .as_slice(), + )?; + Self::prove_and_send_use_license( + blockchain_access_config, + wallet_path, + psw, + lp_config, + ssk_user, + &license, + pos, + gas_limit, + gas_price, ) + .await?; + } + _ => { + println!( + "No license available, please obtain a license" + ); } } } @@ -282,4 +310,137 @@ impl Command { } Ok(()) } + + async fn list_licenses( + self, + blockchain_access_config: &BlockchainAccessConfig, + request_json: Option<&RequestJson>, + ui: bool, + ) -> Result, Error> { + let client = + RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); + let end_height = BcInquirer::block_height(&client).await?; + if ui { + println!("end_height={}", end_height); + } + let block_heights = 0..(end_height + 1); + + if ui { + println!("calling get_licenses with range {:?}", block_heights); + } + let mut licenses_stream = + CitadelInquirer::get_licenses(&client, block_heights).await?; + + let ssk_user = SecretSpendKey::from_slice( + hex::decode( + request_json + .expect("request should be provided") + .user_ssk + .clone(), + )? + .as_slice(), + )?; + + let pairs = find_owned_licenses(ssk_user, &mut licenses_stream)?; + Ok(if pairs.is_empty() { + if ui { + println!("license not found: {:?}", pairs); + } + None + } else { + if ui { + for (_, license) in pairs.iter() { + println!( + "license: {}-{}", + hex::encode(license.lsa.R().to_bytes()), + hex::encode(license.lsa.pk_r().to_bytes()) + ) + } + } + pairs.last().map(|(pos, license)| (*pos, license.clone())) + }) + } + + #[allow(clippy::too_many_arguments)] + async fn prove_and_send_use_license( + blockchain_access_config: &BlockchainAccessConfig, + wallet_path: &WalletPath, + psw: &Password, + lp_config: &Path, + ssk_user: SecretSpendKey, + license: &License, + pos: u64, + gas_limit: u64, + gas_price: u64, + ) -> Result { + let client = + RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); + // let (_, _, num_sessions) = CitadelInquirer::get_info(&client).await?; + let reference_lp = ReferenceLP::create(lp_config)?; + // let challenge = JubJubScalar::from(num_sessions as u64 + 1); + let challenge = JubJubScalar::from(0xcafebabeu64); + let mut rng = StdRng::seed_from_u64(0xbeef); + + println!("performing setup"); + let pp = PublicParameters::setup(1 << CAPACITY, &mut rng) + .expect("Initializing public parameters should succeed"); + + println!("compiling circuit"); + let (prover, verifier) = + Compiler::compile::(&pp, LABEL) + .expect("Compiling circuit should succeed"); + + let opening = CitadelInquirer::get_merkle_opening(&client, pos) + .await? + .expect("Opening obtained successfully"); + + let (cpp, sc) = CitadelProverParameters::compute_parameters( + &ssk_user, + license, + &reference_lp.psk_lp, + &reference_lp.psk_lp, + &challenge, + &mut rng, + opening, + ); + let circuit = LicenseCircuit::new(&cpp, &sc); + + println!("calculating proof"); + let (proof, public_inputs) = prover + .prove(&mut rng, &circuit) + .expect("Proving should succeed"); + + assert!(!public_inputs.is_empty()); + let session_id = public_inputs[0]; + + verifier + .verify(&proof, &public_inputs) + .expect("Verifying the circuit should succeed"); + println!("proof validated locally"); + + let use_license_arg = UseLicenseArg { + proof, + public_inputs, + }; + + println!("calling license contract's use_license"); + let tx_id = PayloadSender::execute_contract_method( + use_license_arg, + blockchain_access_config, + wallet_path, + psw, + gas_limit, + gas_price, + LICENSE_CONTRACT_ID, + USE_LICENSE_METHOD_NAME, + ) + .await?; + println!( + "tx {} submitted, waiting for confirmation", + hex::encode(tx_id.to_bytes()) + ); + TxAwaiter::wait_for(&client, tx_id).await?; + println!("tx {} confirmed", hex::encode(tx_id.to_bytes())); + Ok(session_id) + } } diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index 5aa07e3..0f635b2 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -26,16 +26,18 @@ enum CommandMenuItem { ListRequestsLP, IssueLicenseLP, ListLicenses, + UseLicense, Exit, } fn menu_operation() -> Result { let cmd_menu = Menu::new() - .add(CommandMenuItem::SubmitRequest, "Submit Request (User)") - .add(CommandMenuItem::ListRequestsUser, "List Requests (User)") + .add(CommandMenuItem::SubmitRequest, "Submit Request") + .add(CommandMenuItem::ListRequestsUser, "List Requests") .add(CommandMenuItem::ListRequestsLP, "List Requests (LP)") .add(CommandMenuItem::IssueLicenseLP, "Issue License (LP)") - .add(CommandMenuItem::ListLicenses, "List Licenses (User)") + .add(CommandMenuItem::ListLicenses, "List Licenses") + .add(CommandMenuItem::UseLicense, "Use License") .separator() .add(CommandMenuItem::Exit, "Exit"); @@ -74,6 +76,9 @@ fn menu_operation() -> Result { CommandMenuItem::ListLicenses => { OpSelection::Run(Box::from(Command::ListLicenses { dummy: true })) } + CommandMenuItem::UseLicense => { + OpSelection::Run(Box::from(Command::UseLicense { dummy: true })) + } CommandMenuItem::Exit => OpSelection::Exit, }) } From d1fc0aba6901130ddd46d70b83b8a45a686e8fec Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 31 Oct 2023 13:15:48 +0100 Subject: [PATCH 16/51] Added show state --- moat-cli/src/command.rs | 35 ++++++++++++++++++++++++++++++----- moat-cli/src/interactor.rs | 5 +++++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index a914ed1..136e85c 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -41,6 +41,8 @@ pub(crate) enum Command { ListLicenses { dummy: bool }, /// Use license (User) UseLicense { dummy: bool }, + /// Show state + ShowState { dummy: bool }, } // todo: move this function somewhere else @@ -151,6 +153,7 @@ impl Command { ); TxAwaiter::wait_for(&client, tx_id).await?; println!("tx {} confirmed", hex::encode(tx_id.to_bytes())); + println!(); } Command::ListRequestsUser { dummy: true } => { let wallet_accessor = @@ -194,6 +197,7 @@ impl Command { hex::encode(request.rsa.pk_r().to_bytes()) ); } + println!(); } Command::ListRequestsLP { lp_config_path } => { println!("obtained LP config path={:?}", lp_config_path); @@ -215,6 +219,7 @@ impl Command { hex::encode(request.rsa.pk_r().to_bytes()) ); } + println!(); } Command::IssueLicenseLP { lp_config_path } => { let mut rng = StdRng::seed_from_u64(0xbeef); @@ -253,6 +258,7 @@ impl Command { "license issuing transaction {} submitted and confirmed", hex::encode(tx_id.to_bytes()) ); + println!(); } Command::ListLicenses { dummy: true } => { let _ = self @@ -262,6 +268,7 @@ impl Command { true, ) .await?; + println!(); } Command::UseLicense { dummy: true } => { let pos_license = self @@ -286,7 +293,7 @@ impl Command { )? .as_slice(), )?; - Self::prove_and_send_use_license( + let session_id = Self::prove_and_send_use_license( blockchain_access_config, wallet_path, psw, @@ -298,6 +305,10 @@ impl Command { gas_price, ) .await?; + println!( + "license used, obtained session id: {}", + hex::encode(session_id.to_bytes()) + ); } _ => { println!( @@ -305,6 +316,19 @@ impl Command { ); } } + println!(); + } + Command::ShowState { dummy: true } => { + let client = RuskHttpClient::new( + blockchain_access_config.rusk_address.clone(), + ); + let (num_licenses, _, num_sessions) = + CitadelInquirer::get_info(&client).await?; + println!( + "license contract state - licenses:{}, sessions:{}", + num_licenses, num_sessions + ); + println!(); } _ => (), } @@ -375,10 +399,9 @@ impl Command { ) -> Result { let client = RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); - // let (_, _, num_sessions) = CitadelInquirer::get_info(&client).await?; - let reference_lp = ReferenceLP::create(lp_config)?; - // let challenge = JubJubScalar::from(num_sessions as u64 + 1); - let challenge = JubJubScalar::from(0xcafebabeu64); + let (_, _, num_sessions) = CitadelInquirer::get_info(&client).await?; + let challenge = JubJubScalar::from(num_sessions as u64 + 1); + // let challenge = JubJubScalar::from(0xcafebabeu64); let mut rng = StdRng::seed_from_u64(0xbeef); println!("performing setup"); @@ -394,6 +417,8 @@ impl Command { .await? .expect("Opening obtained successfully"); + let reference_lp = ReferenceLP::create(lp_config)?; + let (cpp, sc) = CitadelProverParameters::compute_parameters( &ssk_user, license, diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index 0f635b2..20ee0ed 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -27,6 +27,7 @@ enum CommandMenuItem { IssueLicenseLP, ListLicenses, UseLicense, + ShowState, Exit, } @@ -38,6 +39,7 @@ fn menu_operation() -> Result { .add(CommandMenuItem::IssueLicenseLP, "Issue License (LP)") .add(CommandMenuItem::ListLicenses, "List Licenses") .add(CommandMenuItem::UseLicense, "Use License") + .add(CommandMenuItem::ShowState, "Show state") .separator() .add(CommandMenuItem::Exit, "Exit"); @@ -79,6 +81,9 @@ fn menu_operation() -> Result { CommandMenuItem::UseLicense => { OpSelection::Run(Box::from(Command::UseLicense { dummy: true })) } + CommandMenuItem::ShowState => { + OpSelection::Run(Box::from(Command::ShowState { dummy: true })) + } CommandMenuItem::Exit => OpSelection::Exit, }) } From 5b528fc79ad96786c226a33bf58c77e9b6a3c2ca Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 31 Oct 2023 13:34:55 +0100 Subject: [PATCH 17/51] Added total requests count in addition to owned requests --- moat-cli/src/command.rs | 12 +++++++----- .../src/citadel_requests/request_scanner.rs | 19 +++++++++++-------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 136e85c..35f6e7d 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -168,9 +168,10 @@ impl Command { let mut found_requests = vec![]; let mut height = 0; + let mut total_requests = 0usize; loop { let height_end = height + 10000; - let (requests, top) = + let (requests, top, total) = RequestScanner::scan_related_to_notes_in_block_range( height, height_end, @@ -179,16 +180,17 @@ impl Command { ) .await?; found_requests.extend(requests); + total_requests += total; if top <= height_end { height = top; break; } height = height_end; } - let all_found_requests = found_requests.len(); + let owned_requests = found_requests.len(); println!( - "scanned {} blocks, found {} requests", - height, all_found_requests, + "scanned {} blocks, found {} requests, {} owned requests", + height, total_requests, owned_requests, ); for request in found_requests.iter() { println!( @@ -255,7 +257,7 @@ impl Command { .issue_license(&mut rng, &request, &reference_lp.ssk_lp) .await?; println!( - "license issuing transaction {} submitted and confirmed", + "license issuing transaction {} confirmed", hex::encode(tx_id.to_bytes()) ); println!(); diff --git a/moat-core/src/citadel_requests/request_scanner.rs b/moat-core/src/citadel_requests/request_scanner.rs index 2bc110a..f8cd242 100644 --- a/moat-core/src/citadel_requests/request_scanner.rs +++ b/moat-core/src/citadel_requests/request_scanner.rs @@ -33,12 +33,14 @@ impl RequestScanner { pub fn scan_transactions_related_to_notes( txs: Transactions, note_hashes: &[BlsScalar], - ) -> Vec { + ) -> (usize, Vec) { let mut requests = Vec::new(); + let mut total_count = 0usize; for tx in &txs.transactions { if let Ok(request) = PayloadExtractor::payload_from_tx::(tx) { + total_count += 1; let tx_raw = hex::decode(&tx.raw) .expect("Decoding raw transaction should succeed"); let ph_tx = Transaction::from_slice(&tx_raw) @@ -55,7 +57,7 @@ impl RequestScanner { } } } - requests + (total_count, requests) } /// Returns collection of requests found withing n last blocks @@ -90,15 +92,16 @@ impl RequestScanner { height_end: u64, cfg: &BlockchainAccessConfig, note_hashes: &[BlsScalar], - ) -> Result<(Vec, u64), Error> { + ) -> Result<(Vec, u64, usize), Error> { let client = RuskHttpClient::new(cfg.rusk_address.clone()); let (txs, top) = TxInquirer::txs_from_block_range(&client, height_beg, height_end) .await?; - let requests = RequestScanner::scan_transactions_related_to_notes( - txs, - note_hashes, - ); - Ok((requests, top)) + let (total, requests) = + RequestScanner::scan_transactions_related_to_notes( + txs, + note_hashes, + ); + Ok((requests, top, total)) } } From 1e4d8b1930498f251f9cbd1e14cea008a264b657 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 31 Oct 2023 14:49:33 +0100 Subject: [PATCH 18/51] Added getting a session --- moat-cli/src/command.rs | 31 ++++++++++++++++++++++++++++--- moat-cli/src/interactor.rs | 7 +++++++ moat-cli/src/prompt.rs | 20 ++++++++++++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 35f6e7d..8e754bd 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -16,9 +16,9 @@ use group::GroupEncoding; use license_provider::{LicenseIssuer, ReferenceLP}; use moat_core::Error::InvalidQueryResponse; use moat_core::{ - BcInquirer, CitadelInquirer, Error, LicenseCircuit, PayloadSender, - RequestCreator, RequestJson, RequestScanner, RequestSender, StreamAux, - TxAwaiter, LICENSE_CONTRACT_ID, USE_LICENSE_METHOD_NAME, + BcInquirer, CitadelInquirer, Error, LicenseCircuit, LicenseSessionId, + PayloadSender, RequestCreator, RequestJson, RequestScanner, RequestSender, + StreamAux, TxAwaiter, LICENSE_CONTRACT_ID, USE_LICENSE_METHOD_NAME, }; use rand::rngs::StdRng; use rkyv::{check_archived_root, Archive, Deserialize, Infallible, Serialize}; @@ -41,6 +41,8 @@ pub(crate) enum Command { ListLicenses { dummy: bool }, /// Use license (User) UseLicense { dummy: bool }, + /// Get session (SP) + GetSession { session_id: String }, /// Show state ShowState { dummy: bool }, } @@ -320,6 +322,29 @@ impl Command { } println!(); } + Command::GetSession { session_id } => { + let client = RuskHttpClient::new( + blockchain_access_config.rusk_address.clone(), + ); + let id = LicenseSessionId { + id: BlsScalar::from_slice( + hex::decode(session_id.clone())?.as_slice(), + )?, + }; + match CitadelInquirer::get_session(&client, id).await? { + Some(session) => { + println!("obtained session with id={}:", session_id); + println!(); + for s in session.public_inputs.iter() { + println!("{}", hex::encode(s.to_bytes())); + } + } + _ => { + println!("session not found"); + } + } + println!(); + } Command::ShowState { dummy: true } => { let client = RuskHttpClient::new( blockchain_access_config.rusk_address.clone(), diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index 20ee0ed..2052296 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -27,6 +27,7 @@ enum CommandMenuItem { IssueLicenseLP, ListLicenses, UseLicense, + GetSession, ShowState, Exit, } @@ -39,6 +40,7 @@ fn menu_operation() -> Result { .add(CommandMenuItem::IssueLicenseLP, "Issue License (LP)") .add(CommandMenuItem::ListLicenses, "List Licenses") .add(CommandMenuItem::UseLicense, "Use License") + .add(CommandMenuItem::GetSession, "Get Session (SP)") .add(CommandMenuItem::ShowState, "Show state") .separator() .add(CommandMenuItem::Exit, "Exit"); @@ -81,6 +83,11 @@ fn menu_operation() -> Result { CommandMenuItem::UseLicense => { OpSelection::Run(Box::from(Command::UseLicense { dummy: true })) } + CommandMenuItem::GetSession => { + OpSelection::Run(Box::from(Command::GetSession { + session_id: prompt::request_session_id()?, + })) + } CommandMenuItem::ShowState => { OpSelection::Run(Box::from(Command::ShowState { dummy: true })) } diff --git a/moat-cli/src/prompt.rs b/moat-cli/src/prompt.rs index e13ee79..8b6233b 100644 --- a/moat-cli/src/prompt.rs +++ b/moat-cli/src/prompt.rs @@ -23,6 +23,26 @@ pub(crate) fn request_provider_psk() -> Result { Ok(a_str) } +pub(crate) fn request_session_id() -> Result { + let q = Question::input("session_id") + .message("Please enter session id:".to_string()) + .validate_on_key(|_, _| { + true // todo: add some validation of the session id + }) + .validate(|id, _| { + if id.is_empty() { + Err("Please enter a valid session id".to_string()) + } else { + Ok(()) + } + }) + .build(); + + let a = requestty::prompt_one(q)?; + let a_str = a.as_string().expect("answer to be a string").to_string(); + Ok(a_str) +} + pub(crate) fn request_pathbuf( hint: &str, ) -> Result, ErrorKind> { From 031619e2da80dd30ab6846354653ae19aaf30a93 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 31 Oct 2023 15:33:46 +0100 Subject: [PATCH 19/51] Possibility of entering alternative request --- moat-cli/request2.json | 4 ++++ moat-cli/src/command.rs | 34 ++++++++++++++-------------------- moat-cli/src/interactor.rs | 7 ++++++- moat-cli/src/prompt.rs | 19 +++---------------- moat-core/tests/utils.rs | 9 +++++++++ 5 files changed, 36 insertions(+), 37 deletions(-) create mode 100644 moat-cli/request2.json diff --git a/moat-cli/request2.json b/moat-cli/request2.json new file mode 100644 index 0000000..d3182e1 --- /dev/null +++ b/moat-cli/request2.json @@ -0,0 +1,4 @@ +{ + "user_ssk": "c6afd78c8b3902b474d4c0972b62888e4b880dccf8da68e86266fefa45ee7505926f06ab82ac200995f1239d518fdb74903f225f4460d8db62f2449f6d4dc402", + "provider_psk": "29c4336ef24e585f4506e32e269c5363a71f7dcd74586b210c56e569ad2644e832c785f102dd3c985c705008ec188be819bac85b65c9f70decb9adcf4a72cc43" +} diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 8e754bd..4573bea 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -16,9 +16,10 @@ use group::GroupEncoding; use license_provider::{LicenseIssuer, ReferenceLP}; use moat_core::Error::InvalidQueryResponse; use moat_core::{ - BcInquirer, CitadelInquirer, Error, LicenseCircuit, LicenseSessionId, - PayloadSender, RequestCreator, RequestJson, RequestScanner, RequestSender, - StreamAux, TxAwaiter, LICENSE_CONTRACT_ID, USE_LICENSE_METHOD_NAME, + BcInquirer, CitadelInquirer, Error, JsonLoader, LicenseCircuit, + LicenseSessionId, PayloadSender, RequestCreator, RequestJson, + RequestScanner, RequestSender, StreamAux, TxAwaiter, LICENSE_CONTRACT_ID, + USE_LICENSE_METHOD_NAME, }; use rand::rngs::StdRng; use rkyv::{check_archived_root, Archive, Deserialize, Infallible, Serialize}; @@ -30,7 +31,7 @@ use zk_citadel::license::{CitadelProverParameters, License}; #[derive(PartialEq, Eq, Hash, Clone, Debug)] pub(crate) enum Command { /// Submit request (User) - SubmitRequest { provider_psk: String }, + SubmitRequest { request_path: Option }, /// List requests (User) ListRequestsUser { dummy: bool }, /// List requests (LP) @@ -114,28 +115,21 @@ impl Command { request_json: Option, ) -> Result<(), Error> { match self { - Command::SubmitRequest { provider_psk } => { - let request_json = - request_json.expect("request should be provided"); // todo - // todo - this request creation belongs somewhere else because - // we might - // also want to create request on the fly, from data provided by - // user interactively - let rng = &mut StdRng::seed_from_u64(0xcafe); - println!("obtained provider psk={}", provider_psk); - let provider_psk_str = if provider_psk.is_empty() { - request_json.provider_psk - } else { - provider_psk + Command::SubmitRequest { request_path } => { + println!("obtained request path={:?}", request_path); + let request_json = match request_path { + Some(request_path) => RequestJson::from_file(request_path)?, + _ => request_json.expect("request should be provided"), }; + let rng = &mut StdRng::seed_from_u64(0xcafe); let request = RequestCreator::create_from_hex_args( request_json.user_ssk, - provider_psk_str.clone(), + request_json.provider_psk.clone(), rng, )?; println!( "submitting request to provider psk: {}", - provider_psk_str + request_json.provider_psk ); let tx_id = RequestSender::send_request( request, @@ -352,7 +346,7 @@ impl Command { let (num_licenses, _, num_sessions) = CitadelInquirer::get_info(&client).await?; println!( - "license contract state - licenses:{}, sessions:{}", + "license contract state - licenses: {}, sessions: {}", num_licenses, num_sessions ); println!(); diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index 2052296..a79153a 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -55,7 +55,10 @@ fn menu_operation() -> Result { Ok(match cmd { CommandMenuItem::SubmitRequest => { OpSelection::Run(Box::from(Command::SubmitRequest { - provider_psk: prompt::request_provider_psk()?, + request_path: prompt::request_pathbuf( + "request (e.g. moat-cli/request2.json)", + "moat-cli/request2.json", + )?, })) } CommandMenuItem::ListRequestsUser => { @@ -67,6 +70,7 @@ fn menu_operation() -> Result { OpSelection::Run(Box::from(Command::ListRequestsLP { lp_config_path: prompt::request_pathbuf( "LP config (e.g. moat-cli/lp2.json)", + "moat-cli/lp2.json", )?, })) } @@ -74,6 +78,7 @@ fn menu_operation() -> Result { OpSelection::Run(Box::from(Command::IssueLicenseLP { lp_config_path: prompt::request_pathbuf( "LP config (e.g. moat-cli/lp2.json)", + "moat-cli/lp2.json", )?, })) } diff --git a/moat-cli/src/prompt.rs b/moat-cli/src/prompt.rs index 8b6233b..32ab7db 100644 --- a/moat-cli/src/prompt.rs +++ b/moat-cli/src/prompt.rs @@ -7,22 +7,6 @@ use requestty::{ErrorKind, Question}; use std::path::PathBuf; -pub(crate) fn request_provider_psk() -> Result { - let q = Question::input("psk") - .message("Please enter the provider public spend key:".to_string()) - .validate_on_key(|_, _| { - true // todo: add some validation of the psk - }) - .validate(|_, _| { - Ok(()) // todo: add some validation of the psk - }) - .build(); - - let a = requestty::prompt_one(q)?; - let a_str = a.as_string().expect("answer to be a string").to_string(); - Ok(a_str) -} - pub(crate) fn request_session_id() -> Result { let q = Question::input("session_id") .message("Please enter session id:".to_string()) @@ -45,6 +29,7 @@ pub(crate) fn request_session_id() -> Result { pub(crate) fn request_pathbuf( hint: &str, + dflt: &str, ) -> Result, ErrorKind> { let q = Question::input("psk") .message(format!("Please enter path for {}:", hint)) @@ -60,6 +45,8 @@ pub(crate) fn request_pathbuf( let a_str = a.as_string().expect("answer to be a string").to_string(); Ok(if a_str.is_empty() { None + } else if a_str.len() == 1 { + Some(PathBuf::from(dflt)) } else { Some(PathBuf::from(a_str)) }) diff --git a/moat-core/tests/utils.rs b/moat-core/tests/utils.rs index 85d979c..a2111bd 100644 --- a/moat-core/tests/utils.rs +++ b/moat-core/tests/utils.rs @@ -57,3 +57,12 @@ fn encode_password_old() -> Result<(), Error> { println!("password={}", hex::encode(hash.as_bytes())); Ok(()) } + +#[test] +#[ignore] +fn new_ssk() -> Result<(), Error> { + let rng = &mut StdRng::seed_from_u64(0xcafe); + let ssk = SecretSpendKey::random(rng); + println!("ssk={}", hex::encode(ssk.to_bytes())); + Ok(()) +} From 2514e0dbded498de205f08d77d480406a6b7f1f5 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 31 Oct 2023 15:50:07 +0100 Subject: [PATCH 20/51] UI improvements and make challenge constant --- moat-cli/src/command.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 4573bea..29db5e2 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -365,13 +365,13 @@ impl Command { let client = RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); let end_height = BcInquirer::block_height(&client).await?; - if ui { - println!("end_height={}", end_height); - } let block_heights = 0..(end_height + 1); if ui { - println!("calling get_licenses with range {:?}", block_heights); + println!( + "getting licenses within the block height range {:?}:", + block_heights + ); } let mut licenses_stream = CitadelInquirer::get_licenses(&client, block_heights).await?; @@ -389,7 +389,7 @@ impl Command { let pairs = find_owned_licenses(ssk_user, &mut licenses_stream)?; Ok(if pairs.is_empty() { if ui { - println!("license not found: {:?}", pairs); + println!("licenses not found"); } None } else { @@ -420,9 +420,9 @@ impl Command { ) -> Result { let client = RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); - let (_, _, num_sessions) = CitadelInquirer::get_info(&client).await?; - let challenge = JubJubScalar::from(num_sessions as u64 + 1); - // let challenge = JubJubScalar::from(0xcafebabeu64); + // let (_, _, num_sessions) = CitadelInquirer::get_info(&client).await?; + // let challenge = JubJubScalar::from(num_sessions as u64 + 1); + let challenge = JubJubScalar::from(0xcafebabeu64); let mut rng = StdRng::seed_from_u64(0xbeef); println!("performing setup"); From ff6688df3c0c09954f3bdea840cd07d7cf34c157 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 31 Oct 2023 16:50:30 +0100 Subject: [PATCH 21/51] Corrected counters, displaying shas of licenses and requests --- license-provider/src/reference_lp.rs | 15 ++++--- moat-cli/Cargo.toml | 1 + moat-cli/src/command.rs | 59 ++++++++++++++-------------- 3 files changed, 40 insertions(+), 35 deletions(-) diff --git a/license-provider/src/reference_lp.rs b/license-provider/src/reference_lp.rs index 368ac8c..330cfff 100644 --- a/license-provider/src/reference_lp.rs +++ b/license-provider/src/reference_lp.rs @@ -72,9 +72,10 @@ impl ReferenceLP { .await?; total += requests.len(); let owned_requests = self.retain_owned_requests(requests); - total_owned += owned_requests.len(); for owned_request in owned_requests { - self.insert_request(owned_request); + if self.insert_request(owned_request) { + total_owned += 1; + } } if top <= height_end { return Ok((total, total_owned)); @@ -96,9 +97,10 @@ impl ReferenceLP { let requests = RequestScanner::scan_last_blocks(n, cfg).await?; total += requests.len(); let owned_requests = self.retain_owned_requests(requests); - total_owned += owned_requests.len(); for owned_request in owned_requests { - self.insert_request(owned_request); + if self.insert_request(owned_request) { + total_owned += 1; + } } Ok((total, total_owned)) } @@ -117,10 +119,13 @@ impl ReferenceLP { self.vk_lp.owns(&request.rsa) } - fn insert_request(&mut self, request: Request) { + fn insert_request(&mut self, request: Request) -> bool { let hash = Self::hash_request(&request); if self.requests_hashes.insert(hash) { self.requests_to_process.push(request); + true + } else { + false } } diff --git a/moat-cli/Cargo.toml b/moat-cli/Cargo.toml index 49230ef..954c64a 100644 --- a/moat-cli/Cargo.toml +++ b/moat-cli/Cargo.toml @@ -27,3 +27,4 @@ bytes = "1.4" futures-core = "0.3" reqwest = "0.11" bytecheck = "0.6" +sha3 = "0.10" diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 29db5e2..34a29b5 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -8,11 +8,10 @@ use crate::SeedableRng; use bytecheck::CheckBytes; use bytes::Bytes; use dusk_bls12_381::BlsScalar; -use dusk_bytes::{DeserializableSlice, Serializable}; +use dusk_bytes::DeserializableSlice; use dusk_pki::SecretSpendKey; use dusk_plonk::prelude::*; use dusk_wallet::{RuskHttpClient, WalletPath}; -use group::GroupEncoding; use license_provider::{LicenseIssuer, ReferenceLP}; use moat_core::Error::InvalidQueryResponse; use moat_core::{ @@ -22,7 +21,9 @@ use moat_core::{ USE_LICENSE_METHOD_NAME, }; use rand::rngs::StdRng; +use rkyv::ser::serializers::AllocSerializer; use rkyv::{check_archived_root, Archive, Deserialize, Infallible, Serialize}; +use sha3::{Digest, Sha3_256}; use std::path::{Path, PathBuf}; use wallet_accessor::{BlockchainAccessConfig, Password, WalletAccessor}; use zk_citadel::license::{CitadelProverParameters, License}; @@ -121,12 +122,13 @@ impl Command { Some(request_path) => RequestJson::from_file(request_path)?, _ => request_json.expect("request should be provided"), }; - let rng = &mut StdRng::seed_from_u64(0xcafe); + let rng = &mut StdRng::from_entropy(); // seed_from_u64(0xcafe); let request = RequestCreator::create_from_hex_args( request_json.user_ssk, request_json.provider_psk.clone(), rng, )?; + let request_hash_hex = Self::to_hash_hex(&request); println!( "submitting request to provider psk: {}", request_json.provider_psk @@ -149,6 +151,7 @@ impl Command { ); TxAwaiter::wait_for(&client, tx_id).await?; println!("tx {} confirmed", hex::encode(tx_id.to_bytes())); + println!("request submitted: {}", request_hash_hex); println!(); } Command::ListRequestsUser { dummy: true } => { @@ -189,16 +192,11 @@ impl Command { height, total_requests, owned_requests, ); for request in found_requests.iter() { - println!( - "request: rsa={}-{}", - hex::encode(request.rsa.R().to_bytes()), - hex::encode(request.rsa.pk_r().to_bytes()) - ); + println!("request: {}", Self::to_hash_hex(request)); } println!(); } Command::ListRequestsLP { lp_config_path } => { - println!("obtained LP config path={:?}", lp_config_path); let lp_config_path = match lp_config_path { Some(lp_config_path) => lp_config_path, _ => PathBuf::from(lp_config), @@ -212,27 +210,21 @@ impl Command { ); for request in reference_lp.requests_to_process.iter() { println!( - "request to process by LP: rsa={}-{}", - hex::encode(request.rsa.R().to_bytes()), - hex::encode(request.rsa.pk_r().to_bytes()) + "request to process by LP: {}", + Self::to_hash_hex(request) ); } println!(); } Command::IssueLicenseLP { lp_config_path } => { - let mut rng = StdRng::seed_from_u64(0xbeef); - println!("obtained LP config path={:?}", lp_config_path); + let mut rng = StdRng::from_entropy(); // seed_from_u64(0xbeef); let lp_config_path = match lp_config_path { Some(lp_config_path) => lp_config_path, _ => PathBuf::from(lp_config), }; let mut reference_lp = ReferenceLP::create(lp_config_path)?; - let (total_count, this_lp_count) = + let (_total_count, _this_lp_count) = reference_lp.scan(blockchain_access_config).await?; - println!( - "found {} requests total, {} requests for this LP ", - total_count, this_lp_count - ); let request = reference_lp.take_request().expect("at least one request"); @@ -245,9 +237,8 @@ impl Command { ); println!( - "issuing license for request: {}-{}", - hex::encode(request.rsa.R().to_bytes()), - hex::encode(request.rsa.pk_r().to_bytes()) + "issuing license for request: {}", + Self::to_hash_hex(&request) ); let tx_id = license_issuer .issue_license(&mut rng, &request, &reference_lp.ssk_lp) @@ -279,9 +270,8 @@ impl Command { match pos_license { Some((pos, license)) => { println!( - "using license: {}-{}", - hex::encode(license.lsa.R().to_bytes()), - hex::encode(license.lsa.pk_r().to_bytes()) + "using license: {}", + Self::to_hash_hex(&license) ); let ssk_user = SecretSpendKey::from_slice( hex::decode( @@ -395,11 +385,7 @@ impl Command { } else { if ui { for (_, license) in pairs.iter() { - println!( - "license: {}-{}", - hex::encode(license.lsa.R().to_bytes()), - hex::encode(license.lsa.pk_r().to_bytes()) - ) + println!("license: {}", Self::to_hash_hex(license)) } } pairs.last().map(|(pos, license)| (*pos, license.clone())) @@ -489,4 +475,17 @@ impl Command { println!("tx {} confirmed", hex::encode(tx_id.to_bytes())); Ok(session_id) } + + fn to_hash_hex(object: &T) -> String + where + T: rkyv::Serialize>, + { + let blob = rkyv::to_bytes::<_, 16386>(object) + .expect("type should serialize correctly") + .to_vec(); + let mut hasher = Sha3_256::new(); + hasher.update(blob); + let result = hasher.finalize(); + hex::encode(result) + } } From 1d353476d4478d1a3f322b23febb67472f5b1e89 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Thu, 2 Nov 2023 12:45:51 +0100 Subject: [PATCH 22/51] Show license hash after issuing license --- license-provider/src/license_issuer.rs | 6 +++--- moat-cli/src/command.rs | 24 +++++++++++++++--------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/license-provider/src/license_issuer.rs b/license-provider/src/license_issuer.rs index 475fc6f..b73408a 100644 --- a/license-provider/src/license_issuer.rs +++ b/license-provider/src/license_issuer.rs @@ -50,7 +50,7 @@ impl LicenseIssuer { rng: &mut R, request: &Request, ssk_lp: &SecretSpendKey, - ) -> Result { + ) -> Result<(BlsScalar, Vec), Error> { let attr = JubJubScalar::from(USER_ATTRIBUTES); let license = License::new(&attr, ssk_lp, request, rng); let license_blob = rkyv::to_bytes::<_, MAX_LICENSE_SIZE>(&license) @@ -58,7 +58,7 @@ impl LicenseIssuer { .to_vec(); let lpk = JubJubAffine::from(license.lsa.pk_r().as_ref()); let license_hash = sponge::hash(&[lpk.get_u(), lpk.get_v()]); - let tuple = (license_blob, license_hash); + let tuple = (license_blob.clone(), license_hash); trace!( "sending issue license with license blob size={}", tuple.0.len() @@ -76,6 +76,6 @@ impl LicenseIssuer { .await?; let client = RuskHttpClient::new(self.config.rusk_address.clone()); TxAwaiter::wait_for(&client, tx_id).await?; - Ok(tx_id) + Ok((tx_id, license_blob)) } } diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 34a29b5..92ad1e2 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -142,15 +142,14 @@ impl Command { gas_price, ) .await?; - println!( - "tx {} submitted, waiting for confirmation", - hex::encode(tx_id.to_bytes()) - ); let client = RuskHttpClient::new( blockchain_access_config.rusk_address.clone(), ); TxAwaiter::wait_for(&client, tx_id).await?; - println!("tx {} confirmed", hex::encode(tx_id.to_bytes())); + println!( + "request submitting transaction {} confirmed", + hex::encode(tx_id.to_bytes()) + ); println!("request submitted: {}", request_hash_hex); println!(); } @@ -240,13 +239,17 @@ impl Command { "issuing license for request: {}", Self::to_hash_hex(&request) ); - let tx_id = license_issuer + let (tx_id, license_blob) = license_issuer .issue_license(&mut rng, &request, &reference_lp.ssk_lp) .await?; println!( "license issuing transaction {} confirmed", hex::encode(tx_id.to_bytes()) ); + println!( + "issued license: {}", + Self::blob_to_hash_hex(license_blob.as_slice()) + ); println!(); } Command::ListLicenses { dummy: true } => { @@ -467,12 +470,11 @@ impl Command { USE_LICENSE_METHOD_NAME, ) .await?; + TxAwaiter::wait_for(&client, tx_id).await?; println!( - "tx {} submitted, waiting for confirmation", + "use license executing transaction {} confirmed", hex::encode(tx_id.to_bytes()) ); - TxAwaiter::wait_for(&client, tx_id).await?; - println!("tx {} confirmed", hex::encode(tx_id.to_bytes())); Ok(session_id) } @@ -483,6 +485,10 @@ impl Command { let blob = rkyv::to_bytes::<_, 16386>(object) .expect("type should serialize correctly") .to_vec(); + Self::blob_to_hash_hex(blob.as_slice()) + } + + fn blob_to_hash_hex(blob: &[u8]) -> String { let mut hasher = Sha3_256::new(); hasher.update(blob); let result = hasher.finalize(); From 879198dcb85fb46d1f5ebedba18e1ba184aca15d Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Thu, 2 Nov 2023 13:39:23 +0100 Subject: [PATCH 23/51] possibility of entering license to use --- moat-cli/src/command.rs | 93 ++++++++++++++++++++++++-------------- moat-cli/src/interactor.rs | 4 +- moat-cli/src/prompt.rs | 14 ++++++ 3 files changed, 75 insertions(+), 36 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 92ad1e2..b0248ec 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -42,7 +42,7 @@ pub(crate) enum Command { /// List licenses (User) ListLicenses { dummy: bool }, /// Use license (User) - UseLicense { dummy: bool }, + UseLicense { license_hash: String }, /// Get session (SP) GetSession { session_id: String }, /// Show state @@ -253,23 +253,20 @@ impl Command { println!(); } Command::ListLicenses { dummy: true } => { - let _ = self - .list_licenses( - blockchain_access_config, - request_json.as_ref(), - true, - ) - .await?; + Self::list_licenses( + blockchain_access_config, + request_json.as_ref(), + ) + .await?; println!(); } - Command::UseLicense { dummy: true } => { - let pos_license = self - .list_licenses( - blockchain_access_config, - request_json.as_ref(), - false, - ) - .await?; + Command::UseLicense { license_hash } => { + let pos_license = Self::get_license_to_use( + blockchain_access_config, + request_json.as_ref(), + license_hash.clone(), + ) + .await?; match pos_license { Some((pos, license)) => { println!( @@ -297,14 +294,13 @@ impl Command { ) .await?; println!( - "license used, obtained session id: {}", + "license {} used, obtained session id: {}", + Self::to_hash_hex(&license), hex::encode(session_id.to_bytes()) ); } _ => { - println!( - "No license available, please obtain a license" - ); + println!("Please obtain a license"); } } println!(); @@ -350,22 +346,52 @@ impl Command { } async fn list_licenses( - self, blockchain_access_config: &BlockchainAccessConfig, request_json: Option<&RequestJson>, - ui: bool, + ) -> Result<(), Error> { + let client = + RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); + let end_height = BcInquirer::block_height(&client).await?; + let block_heights = 0..(end_height + 1); + + println!( + "getting licenses within the block height range {:?}:", + block_heights + ); + let mut licenses_stream = + CitadelInquirer::get_licenses(&client, block_heights).await?; + + let ssk_user = SecretSpendKey::from_slice( + hex::decode( + request_json + .expect("request should be provided") + .user_ssk + .clone(), + )? + .as_slice(), + )?; + + let pairs = find_owned_licenses(ssk_user, &mut licenses_stream)?; + if pairs.is_empty() { + println!("licenses not found"); + } else { + for (_pos, license) in pairs.iter() { + println!("license: {}", Self::to_hash_hex(license)) + } + }; + Ok(()) + } + + async fn get_license_to_use( + blockchain_access_config: &BlockchainAccessConfig, + request_json: Option<&RequestJson>, + license_hash: String, ) -> Result, Error> { let client = RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); let end_height = BcInquirer::block_height(&client).await?; let block_heights = 0..(end_height + 1); - if ui { - println!( - "getting licenses within the block height range {:?}:", - block_heights - ); - } let mut licenses_stream = CitadelInquirer::get_licenses(&client, block_heights).await?; @@ -381,17 +407,14 @@ impl Command { let pairs = find_owned_licenses(ssk_user, &mut licenses_stream)?; Ok(if pairs.is_empty() { - if ui { - println!("licenses not found"); - } None } else { - if ui { - for (_, license) in pairs.iter() { - println!("license: {}", Self::to_hash_hex(license)) + for (pos, license) in pairs.iter() { + if license_hash == Self::to_hash_hex(license) { + return Ok(Some((*pos, license.clone()))); } } - pairs.last().map(|(pos, license)| (*pos, license.clone())) + None }) } diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index a79153a..fc34e54 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -86,7 +86,9 @@ fn menu_operation() -> Result { OpSelection::Run(Box::from(Command::ListLicenses { dummy: true })) } CommandMenuItem::UseLicense => { - OpSelection::Run(Box::from(Command::UseLicense { dummy: true })) + OpSelection::Run(Box::from(Command::UseLicense { + license_hash: prompt::request_license_hash()?, + })) } CommandMenuItem::GetSession => { OpSelection::Run(Box::from(Command::GetSession { diff --git a/moat-cli/src/prompt.rs b/moat-cli/src/prompt.rs index 32ab7db..3c3d9e7 100644 --- a/moat-cli/src/prompt.rs +++ b/moat-cli/src/prompt.rs @@ -27,6 +27,20 @@ pub(crate) fn request_session_id() -> Result { Ok(a_str) } +pub(crate) fn request_license_hash() -> Result { + let q = Question::input("license_hash") + .message("Please enter license hash:".to_string()) + .validate_on_key(|_, _| { + true // todo: add some validation of the license hash + }) + .validate(|_, _| Ok(())) + .build(); + + let a = requestty::prompt_one(q)?; + let a_str = a.as_string().expect("answer to be a string").to_string(); + Ok(a_str) +} + pub(crate) fn request_pathbuf( hint: &str, dflt: &str, From bd107710389a21b5c80f5674e625b6eb9148669d Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Thu, 2 Nov 2023 15:20:21 +0100 Subject: [PATCH 24/51] Showing if license is owned --- .../tests/citadel/int_test_user.rs | 5 ++- moat-cli/request2.json | 2 +- moat-cli/src/command.rs | 42 ++++++++++++++++++- moat-core/tests/utils.rs | 2 +- 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/integration-tests/tests/citadel/int_test_user.rs b/integration-tests/tests/citadel/int_test_user.rs index 3f2d52f..2cecba6 100644 --- a/integration-tests/tests/citadel/int_test_user.rs +++ b/integration-tests/tests/citadel/int_test_user.rs @@ -101,9 +101,10 @@ async fn issue_license( GAS_PRICE, ); - license_issuer + let (tx_id, _) = license_issuer .issue_license(rng, &request, &reference_lp.ssk_lp) - .await + .await?; + Ok(tx_id) } /// Calculates and verified proof, sends proof along with public parameters diff --git a/moat-cli/request2.json b/moat-cli/request2.json index d3182e1..bb65dbf 100644 --- a/moat-cli/request2.json +++ b/moat-cli/request2.json @@ -1,4 +1,4 @@ { - "user_ssk": "c6afd78c8b3902b474d4c0972b62888e4b880dccf8da68e86266fefa45ee7505926f06ab82ac200995f1239d518fdb74903f225f4460d8db62f2449f6d4dc402", + "user_ssk": "45654c72b065e143645ae5877524b96126c222005a8d6a1eca24c99627a45803a48481395dabdbe33cec4f89b36878b3c2f638c9796e34cffac0a02f27c21702", "provider_psk": "29c4336ef24e585f4506e32e269c5363a71f7dcd74586b210c56e569ad2644e832c785f102dd3c985c705008ec188be819bac85b65c9f70decb9adcf4a72cc43" } diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index b0248ec..22fcb07 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -90,6 +90,30 @@ fn find_owned_licenses( Ok(pairs) } +// todo: move this function somewhere else and possibly merge with +// find_owned_licenses +/// Finds owned license in a stream of licenses. +/// It searches in a reverse order to return a newest license. +fn find_all_licenses( + stream: &mut (impl futures_core::Stream> + + std::marker::Unpin), +) -> Result, Error> { + const ITEM_LEN: usize = CitadelInquirer::GET_LICENSES_ITEM_LEN; + let mut pairs = vec![]; + loop { + let r = StreamAux::find_item::<(u64, Vec), ITEM_LEN>( + |_| Ok(true), + stream, + ); + if r.is_err() { + break; + } + let (pos, lic_ser) = r?; + pairs.push((pos, deserialise_license(&lic_ser))) + } + Ok(pairs) +} + // todo: move this struct to its proper place /// Use License Argument. #[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)] @@ -371,12 +395,26 @@ impl Command { .as_slice(), )?; - let pairs = find_owned_licenses(ssk_user, &mut licenses_stream)?; + // let owned_pairs = find_owned_licenses(ssk_user, &mut + // licenses_stream)?; if owned_pairs.is_empty() { + // println!("licenses not found"); + // } else { + // for (_pos, license) in owned_pairs.iter() { + // println!("license: {}", Self::to_hash_hex(license)) + // } + // }; + let pairs = find_all_licenses(&mut licenses_stream)?; if pairs.is_empty() { println!("licenses not found"); } else { + let vk = ssk_user.view_key(); for (_pos, license) in pairs.iter() { - println!("license: {}", Self::to_hash_hex(license)) + let is_owned = vk.owns(&license.lsa); + println!( + "license: {} {}", + Self::to_hash_hex(license), + if is_owned { "owned" } else { "" } + ) } }; Ok(()) diff --git a/moat-core/tests/utils.rs b/moat-core/tests/utils.rs index a2111bd..c2f8e65 100644 --- a/moat-core/tests/utils.rs +++ b/moat-core/tests/utils.rs @@ -61,7 +61,7 @@ fn encode_password_old() -> Result<(), Error> { #[test] #[ignore] fn new_ssk() -> Result<(), Error> { - let rng = &mut StdRng::seed_from_u64(0xcafe); + let rng = &mut StdRng::from_entropy(); let ssk = SecretSpendKey::random(rng); println!("ssk={}", hex::encode(ssk.to_bytes())); Ok(()) From 9d3fd69b8a3155af9d9bcaca282f5c6912a6976b Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Thu, 2 Nov 2023 15:30:52 +0100 Subject: [PATCH 25/51] listing licenses for specific user --- moat-cli/src/command.rs | 11 +++++++---- moat-cli/src/interactor.rs | 7 ++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 22fcb07..2fd5c23 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -40,7 +40,7 @@ pub(crate) enum Command { /// Issue license (LP) IssueLicenseLP { lp_config_path: Option }, /// List licenses (User) - ListLicenses { dummy: bool }, + ListLicenses { request_path: Option }, /// Use license (User) UseLicense { license_hash: String }, /// Get session (SP) @@ -141,7 +141,6 @@ impl Command { ) -> Result<(), Error> { match self { Command::SubmitRequest { request_path } => { - println!("obtained request path={:?}", request_path); let request_json = match request_path { Some(request_path) => RequestJson::from_file(request_path)?, _ => request_json.expect("request should be provided"), @@ -276,10 +275,14 @@ impl Command { ); println!(); } - Command::ListLicenses { dummy: true } => { + Command::ListLicenses { request_path } => { + let request_json = match request_path { + Some(request_path) => RequestJson::from_file(request_path)?, + _ => request_json.expect("request should be provided"), + }; Self::list_licenses( blockchain_access_config, - request_json.as_ref(), + Some(&request_json), ) .await?; println!(); diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index fc34e54..fdc56ef 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -83,7 +83,12 @@ fn menu_operation() -> Result { })) } CommandMenuItem::ListLicenses => { - OpSelection::Run(Box::from(Command::ListLicenses { dummy: true })) + OpSelection::Run(Box::from(Command::ListLicenses { + request_path: prompt::request_pathbuf( + "request (e.g. moat-cli/request2.json)", + "moat-cli/request2.json", + )?, + })) } CommandMenuItem::UseLicense => { OpSelection::Run(Box::from(Command::UseLicense { From 3c762463fc5fa3079d9c80a94bf968a8bea58185 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Thu, 2 Nov 2023 16:02:52 +0100 Subject: [PATCH 26/51] Issuing particular request --- license-provider/Cargo.toml | 1 + license-provider/src/reference_lp.rs | 29 ++++++++++++ moat-cli/src/command.rs | 69 +++++++++++++++++----------- moat-cli/src/interactor.rs | 1 + moat-cli/src/prompt.rs | 14 ++++++ 5 files changed, 88 insertions(+), 26 deletions(-) diff --git a/license-provider/Cargo.toml b/license-provider/Cargo.toml index f1edc26..633a957 100644 --- a/license-provider/Cargo.toml +++ b/license-provider/Cargo.toml @@ -26,6 +26,7 @@ rand = "0.8" dusk-bytes = "0.1" blake3 = "1.3" tracing = "0.1" +sha3 = "0.10" [dev-dependencies] tokio = { version = "1.15", features = ["rt-multi-thread", "time", "fs", "macros"] } diff --git a/license-provider/src/reference_lp.rs b/license-provider/src/reference_lp.rs index 330cfff..1aae847 100644 --- a/license-provider/src/reference_lp.rs +++ b/license-provider/src/reference_lp.rs @@ -8,6 +8,8 @@ use blake3::OUT_LEN; use dusk_bytes::DeserializableSlice; use dusk_pki::{PublicSpendKey, SecretSpendKey, ViewKey}; use moat_core::{Error, JsonLoader, RequestScanner, MAX_REQUEST_SIZE}; +use rkyv::ser::serializers::AllocSerializer; +use sha3::{Digest, Sha3_256}; use std::collections::BTreeSet; use std::path::Path; use wallet_accessor::BlockchainAccessConfig; @@ -136,6 +138,16 @@ impl ReferenceLP { }) } + pub fn get_request(&mut self, request_hash: &String) -> Option { + for (index, request) in self.requests_to_process.iter().enumerate() { + if Self::to_hash_hex(request) == *request_hash { + self.requests_hashes.remove(&Self::hash_request(request)); + return Some(self.requests_to_process.remove(index)); + } + } + None + } + fn hash_request(request: &Request) -> [u8; OUT_LEN] { *blake3::hash( rkyv::to_bytes::<_, MAX_REQUEST_SIZE>(request) @@ -144,4 +156,21 @@ impl ReferenceLP { ) .as_bytes() } + + fn to_hash_hex(object: &T) -> String + where + T: rkyv::Serialize>, + { + let blob = rkyv::to_bytes::<_, 16386>(object) + .expect("type should serialize correctly") + .to_vec(); + Self::blob_to_hash_hex(blob.as_slice()) + } + + fn blob_to_hash_hex(blob: &[u8]) -> String { + let mut hasher = Sha3_256::new(); + hasher.update(blob); + let result = hasher.finalize(); + hex::encode(result) + } } diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 2fd5c23..022c7c9 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -38,7 +38,10 @@ pub(crate) enum Command { /// List requests (LP) ListRequestsLP { lp_config_path: Option }, /// Issue license (LP) - IssueLicenseLP { lp_config_path: Option }, + IssueLicenseLP { + lp_config_path: Option, + request_hash: String, + }, /// List licenses (User) ListLicenses { request_path: Option }, /// Use license (User) @@ -238,7 +241,10 @@ impl Command { } println!(); } - Command::IssueLicenseLP { lp_config_path } => { + Command::IssueLicenseLP { + lp_config_path, + request_hash, + } => { let mut rng = StdRng::from_entropy(); // seed_from_u64(0xbeef); let lp_config_path = match lp_config_path { Some(lp_config_path) => lp_config_path, @@ -247,32 +253,43 @@ impl Command { let mut reference_lp = ReferenceLP::create(lp_config_path)?; let (_total_count, _this_lp_count) = reference_lp.scan(blockchain_access_config).await?; - let request = - reference_lp.take_request().expect("at least one request"); - let license_issuer = LicenseIssuer::new( - blockchain_access_config.clone(), - wallet_path.clone(), - psw.clone(), - gas_limit, - gas_price, - ); + let request = reference_lp.get_request(&request_hash); + match request { + Some(request) => { + let license_issuer = LicenseIssuer::new( + blockchain_access_config.clone(), + wallet_path.clone(), + psw.clone(), + gas_limit, + gas_price, + ); + + println!( + "issuing license for request: {}", + Self::to_hash_hex(&request) + ); + let (tx_id, license_blob) = license_issuer + .issue_license( + &mut rng, + &request, + &reference_lp.ssk_lp, + ) + .await?; + println!( + "license issuing transaction {} confirmed", + hex::encode(tx_id.to_bytes()) + ); + println!( + "issued license: {}", + Self::blob_to_hash_hex(license_blob.as_slice()) + ); + } + _ => { + println!("Request not found"); + } + } - println!( - "issuing license for request: {}", - Self::to_hash_hex(&request) - ); - let (tx_id, license_blob) = license_issuer - .issue_license(&mut rng, &request, &reference_lp.ssk_lp) - .await?; - println!( - "license issuing transaction {} confirmed", - hex::encode(tx_id.to_bytes()) - ); - println!( - "issued license: {}", - Self::blob_to_hash_hex(license_blob.as_slice()) - ); println!(); } Command::ListLicenses { request_path } => { diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index fdc56ef..a7dbe01 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -80,6 +80,7 @@ fn menu_operation() -> Result { "LP config (e.g. moat-cli/lp2.json)", "moat-cli/lp2.json", )?, + request_hash: prompt::request_request_hash()?, })) } CommandMenuItem::ListLicenses => { diff --git a/moat-cli/src/prompt.rs b/moat-cli/src/prompt.rs index 3c3d9e7..38c8b59 100644 --- a/moat-cli/src/prompt.rs +++ b/moat-cli/src/prompt.rs @@ -27,6 +27,20 @@ pub(crate) fn request_session_id() -> Result { Ok(a_str) } +pub(crate) fn request_request_hash() -> Result { + let q = Question::input("request_hash") + .message("Please enter request hash:".to_string()) + .validate_on_key(|_, _| { + true // todo: add some validation of the request hash + }) + .validate(|_, _| Ok(())) + .build(); + + let a = requestty::prompt_one(q)?; + let a_str = a.as_string().expect("answer to be a string").to_string(); + Ok(a_str) +} + pub(crate) fn request_license_hash() -> Result { let q = Question::input("license_hash") .message("Please enter license hash:".to_string()) From 7dd0afa97e780b2bc5fdbfa3b66c51083df8add1 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Thu, 2 Nov 2023 17:10:07 +0100 Subject: [PATCH 27/51] Fixed the secondary flow --- moat-cli/src/command.rs | 44 ++++++++++++++++++++------------------ moat-cli/src/interactor.rs | 4 ++++ 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 022c7c9..d8569c3 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -9,7 +9,7 @@ use bytecheck::CheckBytes; use bytes::Bytes; use dusk_bls12_381::BlsScalar; use dusk_bytes::DeserializableSlice; -use dusk_pki::SecretSpendKey; +use dusk_pki::{PublicSpendKey, SecretSpendKey}; use dusk_plonk::prelude::*; use dusk_wallet::{RuskHttpClient, WalletPath}; use license_provider::{LicenseIssuer, ReferenceLP}; @@ -45,7 +45,10 @@ pub(crate) enum Command { /// List licenses (User) ListLicenses { request_path: Option }, /// Use license (User) - UseLicense { license_hash: String }, + UseLicense { + request_path: Option, + license_hash: String, + }, /// Get session (SP) GetSession { session_id: String }, /// Show state @@ -304,10 +307,17 @@ impl Command { .await?; println!(); } - Command::UseLicense { license_hash } => { + Command::UseLicense { + request_path, + license_hash, + } => { + let request_json = match request_path { + Some(request_path) => RequestJson::from_file(request_path)?, + _ => request_json.expect("request should be provided"), + }; let pos_license = Self::get_license_to_use( blockchain_access_config, - request_json.as_ref(), + Some(&request_json), license_hash.clone(), ) .await?; @@ -317,19 +327,19 @@ impl Command { "using license: {}", Self::to_hash_hex(&license) ); + println!("user_ssk={}", request_json.user_ssk); + println!("lp_psk={}", request_json.provider_psk); let ssk_user = SecretSpendKey::from_slice( - hex::decode( - request_json - .expect("request should be provided") - .user_ssk, - )? - .as_slice(), + hex::decode(request_json.user_ssk)?.as_slice(), + )?; + let psk_lp = PublicSpendKey::from_slice( + hex::decode(request_json.provider_psk)?.as_slice(), )?; let session_id = Self::prove_and_send_use_license( blockchain_access_config, wallet_path, psw, - lp_config, + psk_lp, ssk_user, &license, pos, @@ -481,7 +491,7 @@ impl Command { blockchain_access_config: &BlockchainAccessConfig, wallet_path: &WalletPath, psw: &Password, - lp_config: &Path, + psk_lp: PublicSpendKey, ssk_user: SecretSpendKey, license: &License, pos: u64, @@ -508,16 +518,8 @@ impl Command { .await? .expect("Opening obtained successfully"); - let reference_lp = ReferenceLP::create(lp_config)?; - let (cpp, sc) = CitadelProverParameters::compute_parameters( - &ssk_user, - license, - &reference_lp.psk_lp, - &reference_lp.psk_lp, - &challenge, - &mut rng, - opening, + &ssk_user, license, &psk_lp, &psk_lp, &challenge, &mut rng, opening, ); let circuit = LicenseCircuit::new(&cpp, &sc); diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index a7dbe01..1b2b451 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -93,6 +93,10 @@ fn menu_operation() -> Result { } CommandMenuItem::UseLicense => { OpSelection::Run(Box::from(Command::UseLicense { + request_path: prompt::request_pathbuf( + "request (e.g. moat-cli/request2.json)", + "moat-cli/request2.json", + )?, license_hash: prompt::request_license_hash()?, })) } From 794e0ab41d10d38ec0d0d5ab98184a55e655b826 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Thu, 2 Nov 2023 18:10:03 +0100 Subject: [PATCH 28/51] Performing setup only once --- moat-cli/src/command.rs | 19 ++++++++++++++----- moat-cli/src/interactor.rs | 5 ++++- moat-cli/src/main.rs | 3 ++- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index d8569c3..1b82295 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -144,6 +144,7 @@ impl Command { gas_limit: u64, gas_price: u64, request_json: Option, + pp: &mut Option, ) -> Result<(), Error> { match self { Command::SubmitRequest { request_path } => { @@ -345,6 +346,7 @@ impl Command { pos, gas_limit, gas_price, + pp, ) .await?; println!( @@ -497,6 +499,7 @@ impl Command { pos: u64, gas_limit: u64, gas_price: u64, + pp_opt: &mut Option, ) -> Result { let client = RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); @@ -506,13 +509,19 @@ impl Command { let mut rng = StdRng::seed_from_u64(0xbeef); println!("performing setup"); - let pp = PublicParameters::setup(1 << CAPACITY, &mut rng) - .expect("Initializing public parameters should succeed"); + let pp: &PublicParameters = match pp_opt { + Some(pp) => pp, + _ => { + let pp = PublicParameters::setup(1 << CAPACITY, &mut rng) + .expect("Initializing public parameters should succeed"); + *pp_opt = Some(pp); + pp_opt.as_ref().unwrap() + } + }; println!("compiling circuit"); - let (prover, verifier) = - Compiler::compile::(&pp, LABEL) - .expect("Compiling circuit should succeed"); + let (prover, verifier) = Compiler::compile::(pp, LABEL) + .expect("Compiling circuit should succeed"); let opening = CitadelInquirer::get_merkle_opening(&client, pos) .await? diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index 1b2b451..1301120 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -7,6 +7,7 @@ use crate::error::CliError; use crate::prompt; use crate::{Command, Menu}; +use dusk_plonk::prelude::PublicParameters; use dusk_wallet::WalletPath; use moat_core::RequestJson; use requestty::{ErrorKind, Question}; @@ -120,10 +121,11 @@ pub struct Interactor { pub gas_limit: u64, pub gas_price: u64, pub request_json: Option, + pub pp: Option, } impl Interactor { - pub async fn run_loop(&self) -> Result<(), CliError> { + pub async fn run_loop(&mut self) -> Result<(), CliError> { loop { let op = menu_operation()?; match op { @@ -138,6 +140,7 @@ impl Interactor { self.gas_limit, self.gas_price, self.request_json.clone(), + &mut self.pp, ) .await? } diff --git a/moat-cli/src/main.rs b/moat-cli/src/main.rs index 06032cf..4ddfef8 100644 --- a/moat-cli/src/main.rs +++ b/moat-cli/src/main.rs @@ -52,7 +52,7 @@ async fn main() -> Result<(), CliError> { PwdHash(pwd_hash) }; - let interactor = Interactor { + let mut interactor = Interactor { wallet_path, psw, blockchain_access_config, @@ -60,6 +60,7 @@ async fn main() -> Result<(), CliError> { gas_limit, gas_price, request_json: Some(request_json), + pp: None, }; interactor.run_loop().await?; From 5876907cdf173ad3bfb5fd16c0d8930a43196af3 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Fri, 3 Nov 2023 12:43:46 +0100 Subject: [PATCH 29/51] Displaying cookie --- moat-cli/src/command.rs | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 1b82295..8708cb4 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -328,15 +328,15 @@ impl Command { "using license: {}", Self::to_hash_hex(&license) ); - println!("user_ssk={}", request_json.user_ssk); - println!("lp_psk={}", request_json.provider_psk); + // println!("user_ssk={}", request_json.user_ssk); + // println!("lp_psk={}", request_json.provider_psk); let ssk_user = SecretSpendKey::from_slice( hex::decode(request_json.user_ssk)?.as_slice(), )?; let psk_lp = PublicSpendKey::from_slice( hex::decode(request_json.provider_psk)?.as_slice(), )?; - let session_id = Self::prove_and_send_use_license( + let _session_id = Self::prove_and_send_use_license( blockchain_access_config, wallet_path, psw, @@ -349,11 +349,6 @@ impl Command { pp, ) .await?; - println!( - "license {} used, obtained session id: {}", - Self::to_hash_hex(&license), - hex::encode(session_id.to_bytes()) - ); } _ => { println!("Please obtain a license"); @@ -567,6 +562,11 @@ impl Command { "use license executing transaction {} confirmed", hex::encode(tx_id.to_bytes()) ); + println!(); + println!("license {} used", Self::to_hash_hex(license),); + println!("session cookie: {}", Self::to_blob_hex(&sc)); + println!("user attributes: {}", hex::encode(sc.attr.to_bytes())); + println!("session id: {}", hex::encode(sc.session_id.to_bytes())); Ok(session_id) } @@ -586,4 +586,14 @@ impl Command { let result = hasher.finalize(); hex::encode(result) } + + fn to_blob_hex(object: &T) -> String + where + T: rkyv::Serialize>, + { + let blob = rkyv::to_bytes::<_, 16386>(object) + .expect("type should serialize correctly") + .to_vec(); + hex::encode(blob) + } } From 2a5299328d2096f1c6a2fe18cc867c420e51f10e Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Fri, 3 Nov 2023 13:17:16 +0100 Subject: [PATCH 30/51] Added request service --- moat-cli/src/command.rs | 6 ++++++ moat-cli/src/interactor.rs | 7 +++++++ moat-cli/src/prompt.rs | 20 ++++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 8708cb4..e1d31c3 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -49,6 +49,8 @@ pub(crate) enum Command { request_path: Option, license_hash: String, }, + /// Request Service (User) + RequestService { session_cookie: String }, /// Get session (SP) GetSession { session_id: String }, /// Show state @@ -356,6 +358,10 @@ impl Command { } println!(); } + Command::RequestService { session_cookie: _ } => { + println!("Off-chain request service to be placed here"); + println!(); + } Command::GetSession { session_id } => { let client = RuskHttpClient::new( blockchain_access_config.rusk_address.clone(), diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index 1301120..0a2b34e 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -28,6 +28,7 @@ enum CommandMenuItem { IssueLicenseLP, ListLicenses, UseLicense, + RequestService, GetSession, ShowState, Exit, @@ -41,6 +42,7 @@ fn menu_operation() -> Result { .add(CommandMenuItem::IssueLicenseLP, "Issue License (LP)") .add(CommandMenuItem::ListLicenses, "List Licenses") .add(CommandMenuItem::UseLicense, "Use License") + .add(CommandMenuItem::RequestService, "Request Service (Off-Chain)") .add(CommandMenuItem::GetSession, "Get Session (SP)") .add(CommandMenuItem::ShowState, "Show state") .separator() @@ -101,6 +103,11 @@ fn menu_operation() -> Result { license_hash: prompt::request_license_hash()?, })) } + CommandMenuItem::RequestService => { + OpSelection::Run(Box::from(Command::RequestService { + session_cookie: prompt::request_session_cookie()?, + })) + } CommandMenuItem::GetSession => { OpSelection::Run(Box::from(Command::GetSession { session_id: prompt::request_session_id()?, diff --git a/moat-cli/src/prompt.rs b/moat-cli/src/prompt.rs index 38c8b59..8943753 100644 --- a/moat-cli/src/prompt.rs +++ b/moat-cli/src/prompt.rs @@ -27,6 +27,26 @@ pub(crate) fn request_session_id() -> Result { Ok(a_str) } +pub(crate) fn request_session_cookie() -> Result { + let q = Question::input("session_cookie") + .message("Please enter session cookie:".to_string()) + .validate_on_key(|_, _| { + true // todo: add some validation of the session id + }) + .validate(|id, _| { + if id.is_empty() { + Err("Please enter a valid session cookie".to_string()) + } else { + Ok(()) + } + }) + .build(); + + let a = requestty::prompt_one(q)?; + let a_str = a.as_string().expect("answer to be a string").to_string(); + Ok(a_str) +} + pub(crate) fn request_request_hash() -> Result { let q = Question::input("request_hash") .message("Please enter request hash:".to_string()) From c8e66039da20e5fdcdf7a88563ae3faf2f6a1da4 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Fri, 3 Nov 2023 15:13:39 +0100 Subject: [PATCH 31/51] Improved error processing --- moat-cli/src/command.rs | 6 +++--- moat-cli/src/interactor.rs | 26 ++++++++++++++++++++++---- moat-cli/src/prompt.rs | 16 ++++++++++++++-- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index e1d31c3..c5906a5 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -194,7 +194,7 @@ impl Command { .iter() .flat_map(|n| n.nullified_by) .collect(); - println!("current address has {} notes", note_hashes.len()); + // println!("current address has {} notes", note_hashes.len()); let mut found_requests = vec![]; let mut height = 0; @@ -219,7 +219,7 @@ impl Command { } let owned_requests = found_requests.len(); println!( - "scanned {} blocks, found {} requests, {} owned requests", + "scanned {} blocks, found {} requests, {} owned requests:", height, total_requests, owned_requests, ); for request in found_requests.iter() { @@ -236,7 +236,7 @@ impl Command { let (total_count, this_lp_count) = reference_lp.scan(blockchain_access_config).await?; println!( - "found {} requests total, {} requests for this LP ", + "found {} requests total, {} requests for this LP:", total_count, this_lp_count ); for request in reference_lp.requests_to_process.iter() { diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index 0a2b34e..848b72c 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -9,7 +9,7 @@ use crate::prompt; use crate::{Command, Menu}; use dusk_plonk::prelude::PublicParameters; use dusk_wallet::WalletPath; -use moat_core::RequestJson; +use moat_core::{Error, RequestJson}; use requestty::{ErrorKind, Question}; use std::path::PathBuf; use wallet_accessor::{BlockchainAccessConfig, Password}; @@ -42,7 +42,10 @@ fn menu_operation() -> Result { .add(CommandMenuItem::IssueLicenseLP, "Issue License (LP)") .add(CommandMenuItem::ListLicenses, "List Licenses") .add(CommandMenuItem::UseLicense, "Use License") - .add(CommandMenuItem::RequestService, "Request Service (Off-Chain)") + .add( + CommandMenuItem::RequestService, + "Request Service (Off-Chain)", + ) .add(CommandMenuItem::GetSession, "Get Session (SP)") .add(CommandMenuItem::ShowState, "Show state") .separator() @@ -138,7 +141,7 @@ impl Interactor { match op { OpSelection::Exit => return Ok(()), OpSelection::Run(command) => { - command + let result = command .run( &self.wallet_path, &self.psw, @@ -149,7 +152,22 @@ impl Interactor { self.request_json.clone(), &mut self.pp, ) - .await? + .await; + if result.is_err() { + let error = result.unwrap_err(); + match error { + Error::IO(arc) => { + println!("{}", arc.as_ref().to_string()); + } + Error::Transaction(bx) => { + println!("{}", bx.as_ref().to_string()); + } + _ => { + println!("{:?}", error); + } + } + } + continue; } } } diff --git a/moat-cli/src/prompt.rs b/moat-cli/src/prompt.rs index 8943753..fcca437 100644 --- a/moat-cli/src/prompt.rs +++ b/moat-cli/src/prompt.rs @@ -53,7 +53,13 @@ pub(crate) fn request_request_hash() -> Result { .validate_on_key(|_, _| { true // todo: add some validation of the request hash }) - .validate(|_, _| Ok(())) + .validate(|request_hash, _| { + if request_hash.is_empty() { + Err("Please enter a valid request hash".to_string()) + } else { + Ok(()) + } + }) .build(); let a = requestty::prompt_one(q)?; @@ -67,7 +73,13 @@ pub(crate) fn request_license_hash() -> Result { .validate_on_key(|_, _| { true // todo: add some validation of the license hash }) - .validate(|_, _| Ok(())) + .validate(|license_hash, _| { + if license_hash.is_empty() { + Err("Please enter a valid license hash".to_string()) + } else { + Ok(()) + } + }) .build(); let a = requestty::prompt_one(q)?; From 642f9ae1cdbc02b0f41d8e999df6740b4d76c474 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Fri, 3 Nov 2023 15:44:34 +0100 Subject: [PATCH 32/51] Cosmetic - better display of session cookie --- moat-cli/src/command.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index c5906a5..99b4221 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -570,7 +570,9 @@ impl Command { ); println!(); println!("license {} used", Self::to_hash_hex(license),); + println!(); println!("session cookie: {}", Self::to_blob_hex(&sc)); + println!(); println!("user attributes: {}", hex::encode(sc.attr.to_bytes())); println!("session id: {}", hex::encode(sc.session_id.to_bytes())); Ok(session_id) From fde8236dc2c0641a0118f93751b857362d4510a1 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Fri, 3 Nov 2023 16:14:09 +0100 Subject: [PATCH 33/51] Improved request extractor, filters out not noop calls --- license-provider/tests/tx/transactions.json | 18 +++++++++--------- .../blockchain_payloads/payload_extractor.rs | 8 ++++++++ moat-core/tests/tx/transactions.json | 18 +++++++++--------- moat-core/tests/tx/tx_bad_payload.json | 2 +- moat-core/tests/tx/tx_with_request.json | 2 +- 5 files changed, 28 insertions(+), 20 deletions(-) diff --git a/license-provider/tests/tx/transactions.json b/license-provider/tests/tx/transactions.json index cf43adb..db4eccd 100644 --- a/license-provider/tests/tx/transactions.json +++ b/license-provider/tests/tx/transactions.json @@ -3,7 +3,7 @@ { "id": "f6169643578a158d3d838ff01cce73ac1ad7fc74f520fedb0000bab9e9cae60d", "call_data": { - "fn_name": "root", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data":"7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f55f49bcbb6a59bd0baa1e1c0854b94881187f0d3c18446ac27eefcda5c7bc224432e960f8b7f82b99e45ed36186599fa8e35a1844c86c33b9b3448dc0d2d34e7340b22475160969109d5b17d38cfc4b05cd890da210d1f931f25af10cc4f6d8031b9be435c2069b269edafa4db85e54bacdf3f187023e019ffcf00c2de0032c80c65e49101ffaf0a01ba7671f6234ac65ee75db5879633ebc4c6d8f58248bfcb147c9ccef50619983501b6209e1daba3ebd081d2b2378c25bcf772d028183d35324c3e94698074d429dd705cac5302595fe2abc1f5f6a6e5ef7f432f99c3c6304424073a65fd7b8218cd56bbe3773cd1734b4b83db47657b423a79aaae8794ca2a29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df3118f72811ee8fe4615b7a0e9a3de512da5c22abea12f8d3ac6e897e3538e8c414a48eca7135fe1b7443707c4e316ad53d6425101bacb937217ad60f3cb5b9a24ee126c518f5543f670dcfcafa128b42570a2469594c104d8c6817cdb978d983328a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117f21cf488ada2dfdb75aa77fb081790e71f9d39d14dd325e11af78e47fc74a3ae0fc60b8bf3db4c4653ce095da46c33b91063cf632889b4c8b6d12ec0045fc0d4427d550e6b7f4b06793b7bd8692123a77b3ba6a546eed123a05475dc7cf56545396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df420100000000000000feffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418" }, @@ -12,7 +12,7 @@ { "id": "9fa57f54bf2aa77bbfbfff5d16bbe3f9954a408bc9ec5b6e64425afdd35baa07", "call_data": { - "fn_name": "root", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data": "7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f55f49bcbb6a59bd0baa1e1c0854b94881187f0d3c18446ac27eefcda5c7bc224432e960f8b7f82b99e45ed36186599fa8e35a1844c86c33b9b3448dc0d2d34e7340b22475160969109d5b17d38cfc4b05cd890da210d1f931f25af10cc4f6d8031b9be435c2069b269edafa4db85e54bacdf3f187023e019ffcf00c2de0032c80c65e49101ffaf0a01ba7671f6234ac65ee75db5879633ebc4c6d8f58248bfcb147c9ccef50619983501b6209e1daba3ebd081d2b2378c25bcf772d028183d35324c3e94698074d429dd705cac5302595fe2abc1f5f6a6e5ef7f432f99c3c6304424073a65fd7b8218cd56bbe3773cd1734b4b83db47657b423a79aaae8794ca2a29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df3118f72811ee8fe4615b7a0e9a3de512da5c22abea12f8d3ac6e897e3538e8c414a48eca7135fe1b7443707c4e316ad53d6425101bacb937217ad60f3cb5b9a24ee126c518f5543f670dcfcafa128b42570a2469594c104d8c6817cdb978d983328a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117f21cf488ada2dfdb75aa77fb081790e71f9d39d14dd325e11af78e47fc74a3ae0fc60b8bf3db4c4653ce095da46c33b91063cf632889b4c8b6d12ec0045fc0d4427d550e6b7f4b06793b7bd8692123a77b3ba6a546eed123a05475dc7cf56545396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df420100000000000000feffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418" }, @@ -21,7 +21,7 @@ { "id": "721df4ff385b0ccdef8d5c075b7ccf6b2573ca25e6be1181fca8f3f0f8b81204", "call_data": { - "fn_name": "root", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data": "7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f55f49bcbb6a59bd0baa1e1c0854b94881187f0d3c18446ac27eefcda5c7bc224432e960f8b7f82b99e45ed36186599fa8e35a1844c86c33b9b3448dc0d2d34e7340b22475160969109d5b17d38cfc4b05cd890da210d1f931f25af10cc4f6d8031b9be435c2069b269edafa4db85e54bacdf3f187023e019ffcf00c2de0032c80c65e49101ffaf0a01ba7671f6234ac65ee75db5879633ebc4c6d8f58248bfcb147c9ccef50619983501b6209e1daba3ebd081d2b2378c25bcf772d028183d35324c3e94698074d429dd705cac5302595fe2abc1f5f6a6e5ef7f432f99c3c6304424073a65fd7b8218cd56bbe3773cd1734b4b83db47657b423a79aaae8794ca2a29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df3118f72811ee8fe4615b7a0e9a3de512da5c22abea12f8d3ac6e897e3538e8c414a48eca7135fe1b7443707c4e316ad53d6425101bacb937217ad60f3cb5b9a24ee126c518f5543f670dcfcafa128b42570a2469594c104d8c6817cdb978d983328a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117f21cf488ada2dfdb75aa77fb081790e71f9d39d14dd325e11af78e47fc74a3ae0fc60b8bf3db4c4653ce095da46c33b91063cf632889b4c8b6d12ec0045fc0d4427d550e6b7f4b06793b7bd8692123a77b3ba6a546eed123a05475dc7cf56545396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df420100000000000000feffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418" }, @@ -30,7 +30,7 @@ { "id": "2600d54c97b74afc4e826a5666f5aab2edf5211aeba9e712d987bf1760712800", "call_data": { - "fn_name": "root", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data": "7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f55f49bcbb6a59bd0baa1e1c0854b94881187f0d3c18446ac27eefcda5c7bc224432e960f8b7f82b99e45ed36186599fa8e35a1844c86c33b9b3448dc0d2d34e7340b22475160969109d5b17d38cfc4b05cd890da210d1f931f25af10cc4f6d8031b9be435c2069b269edafa4db85e54bacdf3f187023e019ffcf00c2de0032c80c65e49101ffaf0a01ba7671f6234ac65ee75db5879633ebc4c6d8f58248bfcb147c9ccef50619983501b6209e1daba3ebd081d2b2378c25bcf772d028183d35324c3e94698074d429dd705cac5302595fe2abc1f5f6a6e5ef7f432f99c3c6304424073a65fd7b8218cd56bbe3773cd1734b4b83db47657b423a79aaae8794ca2a29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df3118f72811ee8fe4615b7a0e9a3de512da5c22abea12f8d3ac6e897e3538e8c414a48eca7135fe1b7443707c4e316ad53d6425101bacb937217ad60f3cb5b9a24ee126c518f5543f670dcfcafa128b42570a2469594c104d8c6817cdb978d983328a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117f21cf488ada2dfdb75aa77fb081790e71f9d39d14dd325e11af78e47fc74a3ae0fc60b8bf3db4c4653ce095da46c33b91063cf632889b4c8b6d12ec0045fc0d4427d550e6b7f4b06793b7bd8692123a77b3ba6a546eed123a05475dc7cf56545396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df420100000000000000feffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418" }, @@ -39,7 +39,7 @@ { "id": "94c2440ff1c4d468e53406904ae8a8fcf38434ac1da3caaec9a7bc0c45f5c10f", "call_data": { - "fn_name": "root", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data": "7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f55f49bcbb6a59bd0baa1e1c0854b94881187f0d3c18446ac27eefcda5c7bc224432e960f8b7f82b99e45ed36186599fa8e35a1844c86c33b9b3448dc0d2d34e7340b22475160969109d5b17d38cfc4b05cd890da210d1f931f25af10cc4f6d8031b9be435c2069b269edafa4db85e54bacdf3f187023e019ffcf00c2de0032c80c65e49101ffaf0a01ba7671f6234ac65ee75db5879633ebc4c6d8f58248bfcb147c9ccef50619983501b6209e1daba3ebd081d2b2378c25bcf772d028183d35324c3e94698074d429dd705cac5302595fe2abc1f5f6a6e5ef7f432f99c3c6304424073a65fd7b8218cd56bbe3773cd1734b4b83db47657b423a79aaae8794ca2a29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df3118f72811ee8fe4615b7a0e9a3de512da5c22abea12f8d3ac6e897e3538e8c414a48eca7135fe1b7443707c4e316ad53d6425101bacb937217ad60f3cb5b9a24ee126c518f5543f670dcfcafa128b42570a2469594c104d8c6817cdb978d983328a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117f21cf488ada2dfdb75aa77fb081790e71f9d39d14dd325e11af78e47fc74a3ae0fc60b8bf3db4c4653ce095da46c33b91063cf632889b4c8b6d12ec0045fc0d4427d550e6b7f4b06793b7bd8692123a77b3ba6a546eed123a05475dc7cf56545396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df420100000000000000feffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418" }, @@ -48,7 +48,7 @@ { "id": "7d41af12acad0673dea0bcc663d0f3e07be03d433ba06b47279266b231401a0b", "call_data": { - "fn_name": "root", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data": "7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f55f49bcbb6a59bd0baa1e1c0854b94881187f0d3c18446ac27eefcda5c7bc224432e960f8b7f82b99e45ed36186599fa8e35a1844c86c33b9b3448dc0d2d34e7340b22475160969109d5b17d38cfc4b05cd890da210d1f931f25af10cc4f6d8031b9be435c2069b269edafa4db85e54bacdf3f187023e019ffcf00c2de0032c80c65e49101ffaf0a01ba7671f6234ac65ee75db5879633ebc4c6d8f58248bfcb147c9ccef50619983501b6209e1daba3ebd081d2b2378c25bcf772d028183d35324c3e94698074d429dd705cac5302595fe2abc1f5f6a6e5ef7f432f99c3c6304424073a65fd7b8218cd56bbe3773cd1734b4b83db47657b423a79aaae8794ca2a29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df3118f72811ee8fe4615b7a0e9a3de512da5c22abea12f8d3ac6e897e3538e8c414a48eca7135fe1b7443707c4e316ad53d6425101bacb937217ad60f3cb5b9a24ee126c518f5543f670dcfcafa128b42570a2469594c104d8c6817cdb978d983328a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117f21cf488ada2dfdb75aa77fb081790e71f9d39d14dd325e11af78e47fc74a3ae0fc60b8bf3db4c4653ce095da46c33b91063cf632889b4c8b6d12ec0045fc0d4427d550e6b7f4b06793b7bd8692123a77b3ba6a546eed123a05475dc7cf56545396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df420100000000000000feffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418" }, @@ -57,7 +57,7 @@ { "id": "66409583a5ed10840619608549ec0340f87e8ca645b1798e747a255c7657c208", "call_data": { - "fn_name": "root", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data": "7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f55f49bcbb6a59bd0baa1e1c0854b94881187f0d3c18446ac27eefcda5c7bc224432e960f8b7f82b99e45ed36186599fa8e35a1844c86c33b9b3448dc0d2d34e7340b22475160969109d5b17d38cfc4b05cd890da210d1f931f25af10cc4f6d8031b9be435c2069b269edafa4db85e54bacdf3f187023e019ffcf00c2de0032c80c65e49101ffaf0a01ba7671f6234ac65ee75db5879633ebc4c6d8f58248bfcb147c9ccef50619983501b6209e1daba3ebd081d2b2378c25bcf772d028183d35324c3e94698074d429dd705cac5302595fe2abc1f5f6a6e5ef7f432f99c3c6304424073a65fd7b8218cd56bbe3773cd1734b4b83db47657b423a79aaae8794ca2a29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df3118f72811ee8fe4615b7a0e9a3de512da5c22abea12f8d3ac6e897e3538e8c414a48eca7135fe1b7443707c4e316ad53d6425101bacb937217ad60f3cb5b9a24ee126c518f5543f670dcfcafa128b42570a2469594c104d8c6817cdb978d983328a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117f21cf488ada2dfdb75aa77fb081790e71f9d39d14dd325e11af78e47fc74a3ae0fc60b8bf3db4c4653ce095da46c33b91063cf632889b4c8b6d12ec0045fc0d4427d550e6b7f4b06793b7bd8692123a77b3ba6a546eed123a05475dc7cf56545396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df420100000000000000feffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418" }, @@ -66,7 +66,7 @@ { "id": "798dae0637c7a7a6d88010ebfe953568a6c89cb158d74f16f7a6ac7939d80a09", "call_data": { - "fn_name": "root", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data": "7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f552327ac75c4aba87513dc54e4a5c2e2e36835828113ef92fea59dbf2457575903bf3156016acac7a44a1d6b546f4199bba7b24966c739ddc433a521ee5a776148349a0a53a6cd16d1cd20e13120bd404fd23a752a8f3facd53b78d360d3f3a03e57bf726eed5f1d8d4c530cd187919796fbb4cdc4dceb809f3839bcb453ae7022ae10a0f7ee7f4355e9d74fbf55d3221bb0beb1bf9ae1f6927e9d3cce9f24581640d55c7bf2cd4b6f130ef439a20b990223bb9022446b7e02e502619b4dd3f80d31e6ca8a4c8785453c9a4886d5e9159bcd1974030e70d1cdd008f3408845871c4cbfb0554963f5f47b91a81a0d1f7370be7c072d77a9e03489921981f503ec2f29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df31256fac5c58b056a49ffe0c23e8e583944e0252529b1c8438fbd22be0d89d5838bc023097bb353188a830dc1a280a0d36ad045d0691354f4a3cdf06724101be6bc23a3f90ad62b7eb699b215644326e61c546068bb46871cc5007e81aa117c1538a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117a7e8542930b0d81da721a28e246a451c995bcc2f6a1961b56c6e0c030563068b32b6a97b404c884d9430e60d070354accd59c9e4e01f816c149898241f7f42e8724c0af7e5e84b28c9d830add2ab94c78dc474e06ca84d444267d37c86697615396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df42" }, @@ -75,7 +75,7 @@ { "id": "9ed97797e895706db4a025cf5a4e1d831014c530c511eead202100a46babc40d", "call_data": { - "fn_name": "root", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data": "7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f552327ac75c4aba87513dc54e4a5c2e2e36835828113ef92fea59dbf2457575903bf3156016acac7a44a1d6b546f4199bba7b24966c739ddc433a521ee5a776148349a0a53a6cd16d1cd20e13120bd404fd23a752a8f3facd53b78d360d3f3a03e57bf726eed5f1d8d4c530cd187919796fbb4cdc4dceb809f3839bcb453ae7022ae10a0f7ee7f4355e9d74fbf55d3221bb0beb1bf9ae1f6927e9d3cce9f24581640d55c7bf2cd4b6f130ef439a20b990223bb9022446b7e02e502619b4dd3f80d31e6ca8a4c8785453c9a4886d5e9159bcd1974030e70d1cdd008f3408845871c4cbfb0554963f5f47b91a81a0d1f7370be7c072d77a9e03489921981f503ec2f29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df31256fac5c58b056a49ffe0c23e8e583944e0252529b1c8438fbd22be0d89d5838bc023097bb353188a830dc1a280a0d36ad045d0691354f4a3cdf06724101be6bc23a3f90ad62b7eb699b215644326e61c546068bb46871cc5007e81aa117c1538a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117a7e8542930b0d81da721a28e246a451c995bcc2f6a1961b56c6e0c030563068b32b6a97b404c884d9430e60d070354accd59c9e4e01f816c149898241f7f42e8724c0af7e5e84b28c9d830add2ab94c78dc474e06ca84d444267d37c86697615396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df42" }, diff --git a/moat-core/src/blockchain_payloads/payload_extractor.rs b/moat-core/src/blockchain_payloads/payload_extractor.rs index 47fda2f..9211b7a 100644 --- a/moat-core/src/blockchain_payloads/payload_extractor.rs +++ b/moat-core/src/blockchain_payloads/payload_extractor.rs @@ -9,6 +9,7 @@ use rkyv::{check_archived_root, Archive, Deserialize, Infallible}; use crate::bc_types::Tx; use crate::error::Error; use crate::Error::PayloadNotPresent; +use crate::NOOP_METHOD_NAME; use bytecheck::CheckBytes; use rkyv::validation::validators::DefaultValidator; @@ -21,6 +22,13 @@ impl PayloadExtractor { P::Archived: Deserialize + for<'b> CheckBytes>, { + if let Some(call_info) = tx.call_data.as_ref() { + if call_info.fn_name != NOOP_METHOD_NAME { + return Err(Error::PayloadNotPresent(Box::from( + "fn name not noop", + ))); + } + } let r = tx .call_data .as_ref() diff --git a/moat-core/tests/tx/transactions.json b/moat-core/tests/tx/transactions.json index e942c11..c8f3688 100644 --- a/moat-core/tests/tx/transactions.json +++ b/moat-core/tests/tx/transactions.json @@ -3,7 +3,7 @@ { "id": "f6169643578a158d3d838ff01cce73ac1ad7fc74f520fedb0000bab9e9cae60d", "call_data": { - "fn_name": "root", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data":"7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f55f49bcbb6a59bd0baa1e1c0854b94881187f0d3c18446ac27eefcda5c7bc224432e960f8b7f82b99e45ed36186599fa8e35a1844c86c33b9b3448dc0d2d34e7340b22475160969109d5b17d38cfc4b05cd890da210d1f931f25af10cc4f6d8031b9be435c2069b269edafa4db85e54bacdf3f187023e019ffcf00c2de0032c80c65e49101ffaf0a01ba7671f6234ac65ee75db5879633ebc4c6d8f58248bfcb147c9ccef50619983501b6209e1daba3ebd081d2b2378c25bcf772d028183d35324c3e94698074d429dd705cac5302595fe2abc1f5f6a6e5ef7f432f99c3c6304424073a65fd7b8218cd56bbe3773cd1734b4b83db47657b423a79aaae8794ca2a29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df3118f72811ee8fe4615b7a0e9a3de512da5c22abea12f8d3ac6e897e3538e8c414a48eca7135fe1b7443707c4e316ad53d6425101bacb937217ad60f3cb5b9a24ee126c518f5543f670dcfcafa128b42570a2469594c104d8c6817cdb978d983328a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117f21cf488ada2dfdb75aa77fb081790e71f9d39d14dd325e11af78e47fc74a3ae0fc60b8bf3db4c4653ce095da46c33b91063cf632889b4c8b6d12ec0045fc0d4427d550e6b7f4b06793b7bd8692123a77b3ba6a546eed123a05475dc7cf56545396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df420100000000000000feffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418" }, @@ -12,7 +12,7 @@ { "id": "9fa57f54bf2aa77bbfbfff5d16bbe3f9954a408bc9ec5b6e64425afdd35baa07", "call_data": { - "fn_name": "root", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data": "7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f55f49bcbb6a59bd0baa1e1c0854b94881187f0d3c18446ac27eefcda5c7bc224432e960f8b7f82b99e45ed36186599fa8e35a1844c86c33b9b3448dc0d2d34e7340b22475160969109d5b17d38cfc4b05cd890da210d1f931f25af10cc4f6d8031b9be435c2069b269edafa4db85e54bacdf3f187023e019ffcf00c2de0032c80c65e49101ffaf0a01ba7671f6234ac65ee75db5879633ebc4c6d8f58248bfcb147c9ccef50619983501b6209e1daba3ebd081d2b2378c25bcf772d028183d35324c3e94698074d429dd705cac5302595fe2abc1f5f6a6e5ef7f432f99c3c6304424073a65fd7b8218cd56bbe3773cd1734b4b83db47657b423a79aaae8794ca2a29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df3118f72811ee8fe4615b7a0e9a3de512da5c22abea12f8d3ac6e897e3538e8c414a48eca7135fe1b7443707c4e316ad53d6425101bacb937217ad60f3cb5b9a24ee126c518f5543f670dcfcafa128b42570a2469594c104d8c6817cdb978d983328a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117f21cf488ada2dfdb75aa77fb081790e71f9d39d14dd325e11af78e47fc74a3ae0fc60b8bf3db4c4653ce095da46c33b91063cf632889b4c8b6d12ec0045fc0d4427d550e6b7f4b06793b7bd8692123a77b3ba6a546eed123a05475dc7cf56545396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df420100000000000000feffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418" }, @@ -21,7 +21,7 @@ { "id": "721df4ff385b0ccdef8d5c075b7ccf6b2573ca25e6be1181fca8f3f0f8b81204", "call_data": { - "fn_name": "root", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data": "7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f55f49bcbb6a59bd0baa1e1c0854b94881187f0d3c18446ac27eefcda5c7bc224432e960f8b7f82b99e45ed36186599fa8e35a1844c86c33b9b3448dc0d2d34e7340b22475160969109d5b17d38cfc4b05cd890da210d1f931f25af10cc4f6d8031b9be435c2069b269edafa4db85e54bacdf3f187023e019ffcf00c2de0032c80c65e49101ffaf0a01ba7671f6234ac65ee75db5879633ebc4c6d8f58248bfcb147c9ccef50619983501b6209e1daba3ebd081d2b2378c25bcf772d028183d35324c3e94698074d429dd705cac5302595fe2abc1f5f6a6e5ef7f432f99c3c6304424073a65fd7b8218cd56bbe3773cd1734b4b83db47657b423a79aaae8794ca2a29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df3118f72811ee8fe4615b7a0e9a3de512da5c22abea12f8d3ac6e897e3538e8c414a48eca7135fe1b7443707c4e316ad53d6425101bacb937217ad60f3cb5b9a24ee126c518f5543f670dcfcafa128b42570a2469594c104d8c6817cdb978d983328a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117f21cf488ada2dfdb75aa77fb081790e71f9d39d14dd325e11af78e47fc74a3ae0fc60b8bf3db4c4653ce095da46c33b91063cf632889b4c8b6d12ec0045fc0d4427d550e6b7f4b06793b7bd8692123a77b3ba6a546eed123a05475dc7cf56545396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df420100000000000000feffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418" }, @@ -30,7 +30,7 @@ { "id": "2600d54c97b74afc4e826a5666f5aab2edf5211aeba9e712d987bf1760712800", "call_data": { - "fn_name": "root", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data": "7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f55f49bcbb6a59bd0baa1e1c0854b94881187f0d3c18446ac27eefcda5c7bc224432e960f8b7f82b99e45ed36186599fa8e35a1844c86c33b9b3448dc0d2d34e7340b22475160969109d5b17d38cfc4b05cd890da210d1f931f25af10cc4f6d8031b9be435c2069b269edafa4db85e54bacdf3f187023e019ffcf00c2de0032c80c65e49101ffaf0a01ba7671f6234ac65ee75db5879633ebc4c6d8f58248bfcb147c9ccef50619983501b6209e1daba3ebd081d2b2378c25bcf772d028183d35324c3e94698074d429dd705cac5302595fe2abc1f5f6a6e5ef7f432f99c3c6304424073a65fd7b8218cd56bbe3773cd1734b4b83db47657b423a79aaae8794ca2a29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df3118f72811ee8fe4615b7a0e9a3de512da5c22abea12f8d3ac6e897e3538e8c414a48eca7135fe1b7443707c4e316ad53d6425101bacb937217ad60f3cb5b9a24ee126c518f5543f670dcfcafa128b42570a2469594c104d8c6817cdb978d983328a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117f21cf488ada2dfdb75aa77fb081790e71f9d39d14dd325e11af78e47fc74a3ae0fc60b8bf3db4c4653ce095da46c33b91063cf632889b4c8b6d12ec0045fc0d4427d550e6b7f4b06793b7bd8692123a77b3ba6a546eed123a05475dc7cf56545396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df420100000000000000feffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418" }, @@ -39,7 +39,7 @@ { "id": "94c2440ff1c4d468e53406904ae8a8fcf38434ac1da3caaec9a7bc0c45f5c10f", "call_data": { - "fn_name": "root", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data": "7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f55f49bcbb6a59bd0baa1e1c0854b94881187f0d3c18446ac27eefcda5c7bc224432e960f8b7f82b99e45ed36186599fa8e35a1844c86c33b9b3448dc0d2d34e7340b22475160969109d5b17d38cfc4b05cd890da210d1f931f25af10cc4f6d8031b9be435c2069b269edafa4db85e54bacdf3f187023e019ffcf00c2de0032c80c65e49101ffaf0a01ba7671f6234ac65ee75db5879633ebc4c6d8f58248bfcb147c9ccef50619983501b6209e1daba3ebd081d2b2378c25bcf772d028183d35324c3e94698074d429dd705cac5302595fe2abc1f5f6a6e5ef7f432f99c3c6304424073a65fd7b8218cd56bbe3773cd1734b4b83db47657b423a79aaae8794ca2a29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df3118f72811ee8fe4615b7a0e9a3de512da5c22abea12f8d3ac6e897e3538e8c414a48eca7135fe1b7443707c4e316ad53d6425101bacb937217ad60f3cb5b9a24ee126c518f5543f670dcfcafa128b42570a2469594c104d8c6817cdb978d983328a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117f21cf488ada2dfdb75aa77fb081790e71f9d39d14dd325e11af78e47fc74a3ae0fc60b8bf3db4c4653ce095da46c33b91063cf632889b4c8b6d12ec0045fc0d4427d550e6b7f4b06793b7bd8692123a77b3ba6a546eed123a05475dc7cf56545396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df420100000000000000feffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418" }, @@ -48,7 +48,7 @@ { "id": "7d41af12acad0673dea0bcc663d0f3e07be03d433ba06b47279266b231401a0b", "call_data": { - "fn_name": "root", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data": "7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f55f49bcbb6a59bd0baa1e1c0854b94881187f0d3c18446ac27eefcda5c7bc224432e960f8b7f82b99e45ed36186599fa8e35a1844c86c33b9b3448dc0d2d34e7340b22475160969109d5b17d38cfc4b05cd890da210d1f931f25af10cc4f6d8031b9be435c2069b269edafa4db85e54bacdf3f187023e019ffcf00c2de0032c80c65e49101ffaf0a01ba7671f6234ac65ee75db5879633ebc4c6d8f58248bfcb147c9ccef50619983501b6209e1daba3ebd081d2b2378c25bcf772d028183d35324c3e94698074d429dd705cac5302595fe2abc1f5f6a6e5ef7f432f99c3c6304424073a65fd7b8218cd56bbe3773cd1734b4b83db47657b423a79aaae8794ca2a29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df3118f72811ee8fe4615b7a0e9a3de512da5c22abea12f8d3ac6e897e3538e8c414a48eca7135fe1b7443707c4e316ad53d6425101bacb937217ad60f3cb5b9a24ee126c518f5543f670dcfcafa128b42570a2469594c104d8c6817cdb978d983328a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117f21cf488ada2dfdb75aa77fb081790e71f9d39d14dd325e11af78e47fc74a3ae0fc60b8bf3db4c4653ce095da46c33b91063cf632889b4c8b6d12ec0045fc0d4427d550e6b7f4b06793b7bd8692123a77b3ba6a546eed123a05475dc7cf56545396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df420100000000000000feffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418" }, @@ -57,7 +57,7 @@ { "id": "66409583a5ed10840619608549ec0340f87e8ca645b1798e747a255c7657c208", "call_data": { - "fn_name": "root", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data": "7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f55f49bcbb6a59bd0baa1e1c0854b94881187f0d3c18446ac27eefcda5c7bc224432e960f8b7f82b99e45ed36186599fa8e35a1844c86c33b9b3448dc0d2d34e7340b22475160969109d5b17d38cfc4b05cd890da210d1f931f25af10cc4f6d8031b9be435c2069b269edafa4db85e54bacdf3f187023e019ffcf00c2de0032c80c65e49101ffaf0a01ba7671f6234ac65ee75db5879633ebc4c6d8f58248bfcb147c9ccef50619983501b6209e1daba3ebd081d2b2378c25bcf772d028183d35324c3e94698074d429dd705cac5302595fe2abc1f5f6a6e5ef7f432f99c3c6304424073a65fd7b8218cd56bbe3773cd1734b4b83db47657b423a79aaae8794ca2a29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df3118f72811ee8fe4615b7a0e9a3de512da5c22abea12f8d3ac6e897e3538e8c414a48eca7135fe1b7443707c4e316ad53d6425101bacb937217ad60f3cb5b9a24ee126c518f5543f670dcfcafa128b42570a2469594c104d8c6817cdb978d983328a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117f21cf488ada2dfdb75aa77fb081790e71f9d39d14dd325e11af78e47fc74a3ae0fc60b8bf3db4c4653ce095da46c33b91063cf632889b4c8b6d12ec0045fc0d4427d550e6b7f4b06793b7bd8692123a77b3ba6a546eed123a05475dc7cf56545396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df420100000000000000feffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418" }, @@ -66,7 +66,7 @@ { "id": "798dae0637c7a7a6d88010ebfe953568a6c89cb158d74f16f7a6ac7939d80a09", "call_data": { - "fn_name": "root", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data": "7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f55f49bcbb6a59bd0baa1e1c0854b94881187f0d3c18446ac27eefcda5c7bc224432e960f8b7f82b99e45ed36186599fa8e35a1844c86c33b9b3448dc0d2d34e7340b22475160969109d5b17d38cfc4b05cd890da210d1f931f25af10cc4f6d8031b9be435c2069b269edafa4db85e54bacdf3f187023e019ffcf00c2de0032c80c65e49101ffaf0a01ba7671f6234ac65ee75db5879633ebc4c6d8f58248bfcb147c9ccef50619983501b6209e1daba3ebd081d2b2378c25bcf772d028183d35324c3e94698074d429dd705cac5302595fe2abc1f5f6a6e5ef7f432f99c3c6304424073a65fd7b8218cd56bbe3773cd1734b4b83db47657b423a79aaae8794ca2a29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df3118f72811ee8fe4615b7a0e9a3de512da5c22abea12f8d3ac6e897e3538e8c414a48eca7135fe1b7443707c4e316ad53d6425101bacb937217ad60f3cb5b9a24ee126c518f5543f670dcfcafa128b42570a2469594c104d8c6817cdb978d983328a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117f21cf488ada2dfdb75aa77fb081790e71f9d39d14dd325e11af78e47fc74a3ae0fc60b8bf3db4c4653ce095da46c33b91063cf632889b4c8b6d12ec0045fc0d4427d550e6b7f4b06793b7bd8692123a77b3ba6a546eed123a05475dc7cf56545396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df420100000000000000feffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418" }, @@ -75,7 +75,7 @@ { "id": "9ed97797e895706db4a025cf5a4e1d831014c530c511eead202100a46babc40d", "call_data": { - "fn_name": "root", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data": "7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f55f49bcbb6a59bd0baa1e1c0854b94881187f0d3c18446ac27eefcda5c7bc224432e960f8b7f82b99e45ed36186599fa8e35a1844c86c33b9b3448dc0d2d34e7340b22475160969109d5b17d38cfc4b05cd890da210d1f931f25af10cc4f6d8031b9be435c2069b269edafa4db85e54bacdf3f187023e019ffcf00c2de0032c80c65e49101ffaf0a01ba7671f6234ac65ee75db5879633ebc4c6d8f58248bfcb147c9ccef50619983501b6209e1daba3ebd081d2b2378c25bcf772d028183d35324c3e94698074d429dd705cac5302595fe2abc1f5f6a6e5ef7f432f99c3c6304424073a65fd7b8218cd56bbe3773cd1734b4b83db47657b423a79aaae8794ca2a29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df3118f72811ee8fe4615b7a0e9a3de512da5c22abea12f8d3ac6e897e3538e8c414a48eca7135fe1b7443707c4e316ad53d6425101bacb937217ad60f3cb5b9a24ee126c518f5543f670dcfcafa128b42570a2469594c104d8c6817cdb978d983328a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117f21cf488ada2dfdb75aa77fb081790e71f9d39d14dd325e11af78e47fc74a3ae0fc60b8bf3db4c4653ce095da46c33b91063cf632889b4c8b6d12ec0045fc0d4427d550e6b7f4b06793b7bd8692123a77b3ba6a546eed123a05475dc7cf56545396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df420100000000000000feffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418" }, diff --git a/moat-core/tests/tx/tx_bad_payload.json b/moat-core/tests/tx/tx_bad_payload.json index 850bb1f..5d873b5 100644 --- a/moat-core/tests/tx/tx_bad_payload.json +++ b/moat-core/tests/tx/tx_bad_payload.json @@ -2,7 +2,7 @@ "id": "634fd079ddb0170707844727b229a3fefca60680852a6ab09aa4bacbce322e0d", "call_data": { - "fn_name": "7a", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data": "abc7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f55f49bcbb6a59bd0baa1e1c0854b94881187f0d3c18446ac27eefcda5c7bc224432e960f8b7f82b99e45ed36186599fa8e35a1844c86c33b9b3448dc0d2d34e7340b22475160969109d5b17d38cfc4b05cd890da210d1f931f25af10cc4f6d8031b9be435c2069b269edafa4db85e54bacdf3f187023e019ffcf00c2de0032c80c65e49101ffaf0a01ba7671f6234ac65ee75db5879633ebc4c6d8f58248bfcb147c9ccef50619983501b6209e1daba3ebd081d2b2378c25bcf772d028183d35324c3e94698074d429dd705cac5302595fe2abc1f5f6a6e5ef7f432f99c3c6304424073a65fd7b8218cd56bbe3773cd1734b4b83db47657b423a79aaae8794ca2a29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df3118f72811ee8fe4615b7a0e9a3de512da5c22abea12f8d3ac6e897e3538e8c414a48eca7135fe1b7443707c4e316ad53d6425101bacb937217ad60f3cb5b9a24ee126c518f5543f670dcfcafa128b42570a2469594c104d8c6817cdb978d983328a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117f21cf488ada2dfdb75aa77fb081790e71f9d39d14dd325e11af78e47fc74a3ae0fc60b8bf3db4c4653ce095da46c33b91063cf632889b4c8b6d12ec0045fc0d4427d550e6b7f4b06793b7bd8692123a77b3ba6a546eed123a05475dc7cf56545396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df420100000000000000feffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418" }, diff --git a/moat-core/tests/tx/tx_with_request.json b/moat-core/tests/tx/tx_with_request.json index b0f22f1..3162743 100644 --- a/moat-core/tests/tx/tx_with_request.json +++ b/moat-core/tests/tx/tx_with_request.json @@ -2,7 +2,7 @@ "id": "634fd079ddb0170707844727b229a3fefca60680852a6ab09aa4bacbce322e0d", "call_data": { - "fn_name": "7a", + "fn_name": "noop", "contract_id": "0100000000000000000000000000000000000000000000000000000000000000", "data": "7aaa96c657582d963de258f184da3d7c95042920db92a2b2591c181466ea5a5311b5ef84f135b3d567120eaae941f35f8d5d62a8f42c8c9dacd2c78cc6f02e558d0d18fc4e78997967851fef237755ee6ee490036925c7fb100eefdbec1c033b8332252314a8fd0c05a01f9a8b87372381ee179818e8ffff36dc94a411c0d75e9ded4fcdf533fd58fc80c8dae586d783ed32168744d0f952dee4f02ce4e25f55f49bcbb6a59bd0baa1e1c0854b94881187f0d3c18446ac27eefcda5c7bc224432e960f8b7f82b99e45ed36186599fa8e35a1844c86c33b9b3448dc0d2d34e7340b22475160969109d5b17d38cfc4b05cd890da210d1f931f25af10cc4f6d8031b9be435c2069b269edafa4db85e54bacdf3f187023e019ffcf00c2de0032c80c65e49101ffaf0a01ba7671f6234ac65ee75db5879633ebc4c6d8f58248bfcb147c9ccef50619983501b6209e1daba3ebd081d2b2378c25bcf772d028183d35324c3e94698074d429dd705cac5302595fe2abc1f5f6a6e5ef7f432f99c3c6304424073a65fd7b8218cd56bbe3773cd1734b4b83db47657b423a79aaae8794ca2a29a07829b2b4f9f285e2ff0d50378d59b12ad2fb8386001e561c3c3c5e66df3118f72811ee8fe4615b7a0e9a3de512da5c22abea12f8d3ac6e897e3538e8c414a48eca7135fe1b7443707c4e316ad53d6425101bacb937217ad60f3cb5b9a24ee126c518f5543f670dcfcafa128b42570a2469594c104d8c6817cdb978d983328a9297e803ff05b1f631d15791d5f3e179718a3a752649ef7c13f4e03f0390117f21cf488ada2dfdb75aa77fb081790e71f9d39d14dd325e11af78e47fc74a3ae0fc60b8bf3db4c4653ce095da46c33b91063cf632889b4c8b6d12ec0045fc0d4427d550e6b7f4b06793b7bd8692123a77b3ba6a546eed123a05475dc7cf56545396cd4c74e95815fafd25e0f96ea952a9d2de0fbb646e83bf25147ed597df420100000000000000feffffff0100000002480300fab78458f54fbcecef4f8c996f05c5ac59b12418" }, From 35ef5f1e477a520dc38f4088c96937690e68daf2 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Fri, 3 Nov 2023 17:14:31 +0100 Subject: [PATCH 34/51] Setup holder to hold setup, prover and verifier --- moat-cli/src/command.rs | 35 +++++++++++++++++++++-------------- moat-cli/src/interactor.rs | 22 ++++++++++++++-------- moat-cli/src/main.rs | 2 +- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 99b4221..ccb81d8 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -4,6 +4,7 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. +use crate::interactor::SetupHolder; use crate::SeedableRng; use bytecheck::CheckBytes; use bytes::Bytes; @@ -146,7 +147,7 @@ impl Command { gas_limit: u64, gas_price: u64, request_json: Option, - pp: &mut Option, + setup_holder: &mut Option, ) -> Result<(), Error> { match self { Command::SubmitRequest { request_path } => { @@ -348,7 +349,7 @@ impl Command { pos, gas_limit, gas_price, - pp, + setup_holder, ) .await?; } @@ -500,7 +501,7 @@ impl Command { pos: u64, gas_limit: u64, gas_price: u64, - pp_opt: &mut Option, + sh_opt: &mut Option, ) -> Result { let client = RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); @@ -509,21 +510,26 @@ impl Command { let challenge = JubJubScalar::from(0xcafebabeu64); let mut rng = StdRng::seed_from_u64(0xbeef); - println!("performing setup"); - let pp: &PublicParameters = match pp_opt { - Some(pp) => pp, + let setup_holder = match sh_opt { + Some(sh) => sh, _ => { + println!("performing setup"); let pp = PublicParameters::setup(1 << CAPACITY, &mut rng) .expect("Initializing public parameters should succeed"); - *pp_opt = Some(pp); - pp_opt.as_ref().unwrap() + println!("compiling circuit"); + let (prover, verifier) = + Compiler::compile::(&pp, LABEL) + .expect("Compiling circuit should succeed"); + let sh = SetupHolder { + pp, + prover, + verifier, + }; + *sh_opt = Some(sh); + sh_opt.as_ref().unwrap() } }; - println!("compiling circuit"); - let (prover, verifier) = Compiler::compile::(pp, LABEL) - .expect("Compiling circuit should succeed"); - let opening = CitadelInquirer::get_merkle_opening(&client, pos) .await? .expect("Opening obtained successfully"); @@ -534,14 +540,15 @@ impl Command { let circuit = LicenseCircuit::new(&cpp, &sc); println!("calculating proof"); - let (proof, public_inputs) = prover + let (proof, public_inputs) = setup_holder + .prover .prove(&mut rng, &circuit) .expect("Proving should succeed"); assert!(!public_inputs.is_empty()); let session_id = public_inputs[0]; - verifier + setup_holder.verifier .verify(&proof, &public_inputs) .expect("Verifying the circuit should succeed"); println!("proof validated locally"); diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index 848b72c..42b3c0b 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -7,7 +7,7 @@ use crate::error::CliError; use crate::prompt; use crate::{Command, Menu}; -use dusk_plonk::prelude::PublicParameters; +use dusk_plonk::prelude::{Prover, PublicParameters, Verifier}; use dusk_wallet::WalletPath; use moat_core::{Error, RequestJson}; use requestty::{ErrorKind, Question}; @@ -62,7 +62,7 @@ fn menu_operation() -> Result { CommandMenuItem::SubmitRequest => { OpSelection::Run(Box::from(Command::SubmitRequest { request_path: prompt::request_pathbuf( - "request (e.g. moat-cli/request2.json)", + "request", "moat-cli/request2.json", )?, })) @@ -75,7 +75,7 @@ fn menu_operation() -> Result { CommandMenuItem::ListRequestsLP => { OpSelection::Run(Box::from(Command::ListRequestsLP { lp_config_path: prompt::request_pathbuf( - "LP config (e.g. moat-cli/lp2.json)", + "LP config", "moat-cli/lp2.json", )?, })) @@ -83,7 +83,7 @@ fn menu_operation() -> Result { CommandMenuItem::IssueLicenseLP => { OpSelection::Run(Box::from(Command::IssueLicenseLP { lp_config_path: prompt::request_pathbuf( - "LP config (e.g. moat-cli/lp2.json)", + "LP config", "moat-cli/lp2.json", )?, request_hash: prompt::request_request_hash()?, @@ -92,7 +92,7 @@ fn menu_operation() -> Result { CommandMenuItem::ListLicenses => { OpSelection::Run(Box::from(Command::ListLicenses { request_path: prompt::request_pathbuf( - "request (e.g. moat-cli/request2.json)", + "request", "moat-cli/request2.json", )?, })) @@ -100,7 +100,7 @@ fn menu_operation() -> Result { CommandMenuItem::UseLicense => { OpSelection::Run(Box::from(Command::UseLicense { request_path: prompt::request_pathbuf( - "request (e.g. moat-cli/request2.json)", + "request", "moat-cli/request2.json", )?, license_hash: prompt::request_license_hash()?, @@ -123,6 +123,12 @@ fn menu_operation() -> Result { }) } +pub struct SetupHolder { + pub pp: PublicParameters, + pub prover: Prover, + pub verifier: Verifier, +} + pub struct Interactor { pub wallet_path: WalletPath, pub psw: Password, @@ -131,7 +137,7 @@ pub struct Interactor { pub gas_limit: u64, pub gas_price: u64, pub request_json: Option, - pub pp: Option, + pub setup_holder: Option, } impl Interactor { @@ -150,7 +156,7 @@ impl Interactor { self.gas_limit, self.gas_price, self.request_json.clone(), - &mut self.pp, + &mut self.setup_holder, ) .await; if result.is_err() { diff --git a/moat-cli/src/main.rs b/moat-cli/src/main.rs index 4ddfef8..b2bd627 100644 --- a/moat-cli/src/main.rs +++ b/moat-cli/src/main.rs @@ -60,7 +60,7 @@ async fn main() -> Result<(), CliError> { gas_limit, gas_price, request_json: Some(request_json), - pp: None, + setup_holder: None, }; interactor.run_loop().await?; From 9b1704558b7da833d942674500505f60091c19c6 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 7 Nov 2023 11:15:21 +0100 Subject: [PATCH 35/51] Refactored proving and using license into LicenseUser --- .../tests/citadel/int_test_user.rs | 116 +++--------------- moat-cli/src/command.rs | 3 +- .../src/citadel_licenses/license_user.rs | 87 +++++++++++++ moat-core/src/citadel_licenses/mod.rs | 9 ++ moat-core/src/lib.rs | 2 + 5 files changed, 114 insertions(+), 103 deletions(-) create mode 100644 moat-core/src/citadel_licenses/license_user.rs create mode 100644 moat-core/src/citadel_licenses/mod.rs diff --git a/integration-tests/tests/citadel/int_test_user.rs b/integration-tests/tests/citadel/int_test_user.rs index 2cecba6..fb06179 100644 --- a/integration-tests/tests/citadel/int_test_user.rs +++ b/integration-tests/tests/citadel/int_test_user.rs @@ -19,33 +19,28 @@ //! nullifier (or session id) in a collection which stops us from double //! usage of the license) -use bytecheck::CheckBytes; use bytes::Bytes; use dusk_bls12_381::BlsScalar; use dusk_bytes::DeserializableSlice; -use dusk_pki::{PublicSpendKey, SecretSpendKey}; +use dusk_pki::SecretSpendKey; use dusk_plonk::prelude::*; use dusk_wallet::{RuskHttpClient, WalletPath}; use license_provider::{LicenseIssuer, ReferenceLP}; use moat_core::Error::InvalidQueryResponse; use moat_core::{ BcInquirer, CitadelInquirer, Error, JsonLoader, LicenseCircuit, - LicenseSessionId, PayloadRetriever, PayloadSender, RequestCreator, - RequestJson, RequestSender, StreamAux, TxAwaiter, ARITY, DEPTH, - LICENSE_CONTRACT_ID, USE_LICENSE_METHOD_NAME, + LicenseSessionId, LicenseUser, PayloadRetriever, RequestCreator, + RequestJson, RequestSender, StreamAux, TxAwaiter, }; -use poseidon_merkle::Opening; use rand::rngs::StdRng; use rand::SeedableRng; -use rkyv::{check_archived_root, Archive, Deserialize, Infallible, Serialize}; +use rkyv::{check_archived_root, Deserialize, Infallible}; use std::path::PathBuf; use toml_base_config::BaseConfig; use tracing::{info, Level}; use wallet_accessor::BlockchainAccessConfig; use wallet_accessor::Password::PwdHash; -use zk_citadel::license::{ - CitadelProverParameters, License, Request, SessionCookie, -}; +use zk_citadel::license::{License, Request}; const WALLET_PATH: &str = concat!(env!("HOME"), "/.dusk/rusk-wallet"); const PWD_HASH: &str = @@ -56,34 +51,6 @@ const GAS_PRICE: u64 = 1; static LABEL: &[u8] = b"dusk-network"; const CAPACITY: usize = 17; // capacity required for the setup -/// Use License Argument. -#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)] -#[archive_attr(derive(CheckBytes))] -pub struct UseLicenseArg { - pub proof: Proof, - pub public_inputs: Vec, -} - -fn compute_citadel_parameters( - rng: &mut StdRng, - ssk: SecretSpendKey, - psk_lp: PublicSpendKey, - lic: &License, - merkle_proof: Opening<(), DEPTH, ARITY>, - challenge: &JubJubScalar, -) -> (CitadelProverParameters, SessionCookie) { - let (cpp, sc) = CitadelProverParameters::compute_parameters( - &ssk, - &lic, - &psk_lp, - &psk_lp, - challenge, - rng, - merkle_proof, - ); - (cpp, sc) -} - /// Calls license contract's issue license method. /// Awaits for confirmation of the contract-calling transaction. async fn issue_license( @@ -107,65 +74,6 @@ async fn issue_license( Ok(tx_id) } -/// Calculates and verified proof, sends proof along with public parameters -/// as arguments to the license contract's use_license method. -/// Awaits for confirmation of the contract-calling transaction. -async fn prove_and_send_use_license( - client: &RuskHttpClient, - blockchain_config: &BlockchainAccessConfig, - wallet_path: &WalletPath, - reference_lp: &ReferenceLP, - ssk_user: SecretSpendKey, - prover: &Prover, - verifier: &Verifier, - license: &License, - opening: Opening<(), DEPTH, ARITY>, - rng: &mut StdRng, - challenge: &JubJubScalar, -) -> Result { - let (cpp, sc) = compute_citadel_parameters( - rng, - ssk_user, - reference_lp.psk_lp, - license, - opening, - &challenge, - ); - let circuit = LicenseCircuit::new(&cpp, &sc); - - info!("calculating proof"); - let (proof, public_inputs) = - prover.prove(rng, &circuit).expect("Proving should succeed"); - - assert!(!public_inputs.is_empty()); - let session_id = public_inputs[0]; - - verifier - .verify(&proof, &public_inputs) - .expect("Verifying the circuit should succeed"); - info!("proof validated locally"); - - let use_license_arg = UseLicenseArg { - proof, - public_inputs, - }; - - info!("calling license contract's use_license"); - let tx_id = PayloadSender::execute_contract_method( - use_license_arg, - &blockchain_config, - &wallet_path, - &PwdHash(PWD_HASH.to_string()), - GAS_LIMIT, - GAS_PRICE, - LICENSE_CONTRACT_ID, - USE_LICENSE_METHOD_NAME, - ) - .await?; - TxAwaiter::wait_for(&client, tx_id).await?; - Ok(session_id) -} - /// Deserializes license, panics if deserialization fails. fn deserialise_license(v: &Vec) -> License { let response_data = check_archived_root::(v.as_slice()) @@ -351,21 +259,25 @@ async fn user_round_trip() -> Result<(), Error> { // so that it is different every time we run the test let (_, _, num_sessions) = CitadelInquirer::get_info(&client).await?; let challenge = JubJubScalar::from(num_sessions as u64 + 1); - info!("calling use_license (as a user)"); - let session_id = prove_and_send_use_license( - &client, + info!("proving license and calling use_license (as a user)"); + let (session_id, tx_id) = LicenseUser::prove_and_use_license( &blockchain_config, &wallet_path, - &reference_lp, - ssk_user, + &PwdHash(PWD_HASH.to_string()), + &ssk_user, + &reference_lp.psk_lp, &prover, &verifier, &license, opening.unwrap(), &mut rng, &challenge, + GAS_LIMIT, + GAS_PRICE, ) .await?; + TxAwaiter::wait_for(&client, tx_id).await?; + show_state(&client, "after use_license").await?; let session_id = LicenseSessionId { id: session_id }; diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index ccb81d8..f2c16d5 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -548,7 +548,8 @@ impl Command { assert!(!public_inputs.is_empty()); let session_id = public_inputs[0]; - setup_holder.verifier + setup_holder + .verifier .verify(&proof, &public_inputs) .expect("Verifying the circuit should succeed"); println!("proof validated locally"); diff --git a/moat-core/src/citadel_licenses/license_user.rs b/moat-core/src/citadel_licenses/license_user.rs new file mode 100644 index 0000000..e35bd9a --- /dev/null +++ b/moat-core/src/citadel_licenses/license_user.rs @@ -0,0 +1,87 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) DUSK NETWORK. All rights reserved. + +use crate::{ + Error, LicenseCircuit, PayloadSender, LICENSE_CONTRACT_ID, + USE_LICENSE_METHOD_NAME, +}; +use crate::{ARITY, DEPTH}; +use bytecheck::CheckBytes; +use dusk_bls12_381::BlsScalar; +use dusk_jubjub::JubJubScalar; +use dusk_pki::{PublicSpendKey, SecretSpendKey}; +use dusk_plonk::prelude::{Proof, Prover, Verifier}; +use dusk_wallet::WalletPath; +use poseidon_merkle::Opening; +use rand::rngs::StdRng; +use rkyv::{Archive, Deserialize, Serialize}; +use wallet_accessor::{BlockchainAccessConfig, Password}; +use zk_citadel::license::{CitadelProverParameters, License}; + +/// Use License Argument. +#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)] +#[archive_attr(derive(CheckBytes))] +pub struct UseLicenseArg { + pub proof: Proof, + pub public_inputs: Vec, +} + +pub struct LicenseUser; + +impl LicenseUser { + #[allow(clippy::too_many_arguments)] + /// Calculates and verified proof, sends proof along with public parameters + /// as arguments to the license contract's use_license method. + /// Awaits for confirmation of the contract-calling transaction. + pub async fn prove_and_use_license( + blockchain_config: &BlockchainAccessConfig, + wallet_path: &WalletPath, + password: &Password, + ssk_user: &SecretSpendKey, + psk_lp: &PublicSpendKey, + prover: &Prover, + verifier: &Verifier, + license: &License, + opening: Opening<(), DEPTH, ARITY>, + rng: &mut StdRng, + challenge: &JubJubScalar, + gas_limit: u64, + gas_price: u64, + ) -> Result<(BlsScalar, BlsScalar), Error> { + let (cpp, sc) = CitadelProverParameters::compute_parameters( + ssk_user, license, psk_lp, psk_lp, challenge, rng, opening, + ); + let circuit = LicenseCircuit::new(&cpp, &sc); + + let (proof, public_inputs) = + prover.prove(rng, &circuit).expect("Proving should succeed"); + + assert!(!public_inputs.is_empty()); + let session_id = public_inputs[0]; + + verifier + .verify(&proof, &public_inputs) + .expect("Verifying the circuit should succeed"); + + let use_license_arg = UseLicenseArg { + proof, + public_inputs, + }; + + let tx_id = PayloadSender::execute_contract_method( + use_license_arg, + blockchain_config, + wallet_path, + password, + gas_limit, + gas_price, + LICENSE_CONTRACT_ID, + USE_LICENSE_METHOD_NAME, + ) + .await?; + Ok((session_id, tx_id)) + } +} diff --git a/moat-core/src/citadel_licenses/mod.rs b/moat-core/src/citadel_licenses/mod.rs new file mode 100644 index 0000000..c3d6485 --- /dev/null +++ b/moat-core/src/citadel_licenses/mod.rs @@ -0,0 +1,9 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) DUSK NETWORK. All rights reserved. + +mod license_user; + +pub use license_user::LicenseUser; diff --git a/moat-core/src/lib.rs b/moat-core/src/lib.rs index 1d94737..a22abe8 100644 --- a/moat-core/src/lib.rs +++ b/moat-core/src/lib.rs @@ -15,6 +15,7 @@ mod bc_types; mod blockchain_payloads; mod blockchain_queries; mod circuit; +mod citadel_licenses; mod citadel_queries; mod citadel_requests; mod citadel_types; @@ -28,6 +29,7 @@ pub use blockchain_payloads::{ }; pub use blockchain_queries::{BcInquirer, TxAwaiter, TxInquirer}; pub use circuit::*; +pub use citadel_licenses::LicenseUser; pub use citadel_queries::{ CitadelInquirer, CitadelInquirerWs, LicenseSession, LicenseSessionId, }; From 01608c3b9b26e3d2c31bebc46df30919a3ce3a4a Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 7 Nov 2023 11:39:23 +0100 Subject: [PATCH 36/51] Reused proving license and sending use licensed from core in cli command --- .../tests/citadel/int_test_user.rs | 6 +- moat-cli/src/command.rs | 61 ++++++++----------- .../src/citadel_licenses/license_user.rs | 9 ++- 3 files changed, 32 insertions(+), 44 deletions(-) diff --git a/integration-tests/tests/citadel/int_test_user.rs b/integration-tests/tests/citadel/int_test_user.rs index fb06179..ff55517 100644 --- a/integration-tests/tests/citadel/int_test_user.rs +++ b/integration-tests/tests/citadel/int_test_user.rs @@ -260,7 +260,7 @@ async fn user_round_trip() -> Result<(), Error> { let (_, _, num_sessions) = CitadelInquirer::get_info(&client).await?; let challenge = JubJubScalar::from(num_sessions as u64 + 1); info!("proving license and calling use_license (as a user)"); - let (session_id, tx_id) = LicenseUser::prove_and_use_license( + let (tx_id, session_cookie) = LicenseUser::prove_and_use_license( &blockchain_config, &wallet_path, &PwdHash(PWD_HASH.to_string()), @@ -279,7 +279,9 @@ async fn user_round_trip() -> Result<(), Error> { TxAwaiter::wait_for(&client, tx_id).await?; show_state(&client, "after use_license").await?; - let session_id = LicenseSessionId { id: session_id }; + let session_id = LicenseSessionId { + id: session_cookie.session_id, + }; // as an SP, call get_session info!("calling get_session (as an SP)"); diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index f2c16d5..93ac8e5 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -17,9 +17,8 @@ use license_provider::{LicenseIssuer, ReferenceLP}; use moat_core::Error::InvalidQueryResponse; use moat_core::{ BcInquirer, CitadelInquirer, Error, JsonLoader, LicenseCircuit, - LicenseSessionId, PayloadSender, RequestCreator, RequestJson, - RequestScanner, RequestSender, StreamAux, TxAwaiter, LICENSE_CONTRACT_ID, - USE_LICENSE_METHOD_NAME, + LicenseSessionId, LicenseUser, RequestCreator, RequestJson, RequestScanner, + RequestSender, StreamAux, TxAwaiter, }; use rand::rngs::StdRng; use rkyv::ser::serializers::AllocSerializer; @@ -27,7 +26,7 @@ use rkyv::{check_archived_root, Archive, Deserialize, Infallible, Serialize}; use sha3::{Digest, Sha3_256}; use std::path::{Path, PathBuf}; use wallet_accessor::{BlockchainAccessConfig, Password, WalletAccessor}; -use zk_citadel::license::{CitadelProverParameters, License}; +use zk_citadel::license::License; /// Commands that can be run against the Moat #[derive(PartialEq, Eq, Hash, Clone, Debug)] @@ -534,41 +533,23 @@ impl Command { .await? .expect("Opening obtained successfully"); - let (cpp, sc) = CitadelProverParameters::compute_parameters( - &ssk_user, license, &psk_lp, &psk_lp, &challenge, &mut rng, opening, + println!( + "calculating proof and calling license contract's use_license" ); - let circuit = LicenseCircuit::new(&cpp, &sc); - - println!("calculating proof"); - let (proof, public_inputs) = setup_holder - .prover - .prove(&mut rng, &circuit) - .expect("Proving should succeed"); - - assert!(!public_inputs.is_empty()); - let session_id = public_inputs[0]; - - setup_holder - .verifier - .verify(&proof, &public_inputs) - .expect("Verifying the circuit should succeed"); - println!("proof validated locally"); - - let use_license_arg = UseLicenseArg { - proof, - public_inputs, - }; - - println!("calling license contract's use_license"); - let tx_id = PayloadSender::execute_contract_method( - use_license_arg, + let (tx_id, session_cookie) = LicenseUser::prove_and_use_license( blockchain_access_config, wallet_path, psw, + &ssk_user, + &psk_lp, + &setup_holder.prover, + &setup_holder.verifier, + license, + opening, + &mut rng, + &challenge, gas_limit, gas_price, - LICENSE_CONTRACT_ID, - USE_LICENSE_METHOD_NAME, ) .await?; TxAwaiter::wait_for(&client, tx_id).await?; @@ -579,11 +560,17 @@ impl Command { println!(); println!("license {} used", Self::to_hash_hex(license),); println!(); - println!("session cookie: {}", Self::to_blob_hex(&sc)); + println!("session cookie: {}", Self::to_blob_hex(&session_cookie)); println!(); - println!("user attributes: {}", hex::encode(sc.attr.to_bytes())); - println!("session id: {}", hex::encode(sc.session_id.to_bytes())); - Ok(session_id) + println!( + "user attributes: {}", + hex::encode(session_cookie.attr.to_bytes()) + ); + println!( + "session id: {}", + hex::encode(session_cookie.session_id.to_bytes()) + ); + Ok(session_cookie.session_id) } fn to_hash_hex(object: &T) -> String diff --git a/moat-core/src/citadel_licenses/license_user.rs b/moat-core/src/citadel_licenses/license_user.rs index e35bd9a..1e3ebb9 100644 --- a/moat-core/src/citadel_licenses/license_user.rs +++ b/moat-core/src/citadel_licenses/license_user.rs @@ -19,7 +19,7 @@ use poseidon_merkle::Opening; use rand::rngs::StdRng; use rkyv::{Archive, Deserialize, Serialize}; use wallet_accessor::{BlockchainAccessConfig, Password}; -use zk_citadel::license::{CitadelProverParameters, License}; +use zk_citadel::license::{CitadelProverParameters, License, SessionCookie}; /// Use License Argument. #[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)] @@ -35,7 +35,7 @@ impl LicenseUser { #[allow(clippy::too_many_arguments)] /// Calculates and verified proof, sends proof along with public parameters /// as arguments to the license contract's use_license method. - /// Awaits for confirmation of the contract-calling transaction. + /// Returns transaction id and a session cookie. pub async fn prove_and_use_license( blockchain_config: &BlockchainAccessConfig, wallet_path: &WalletPath, @@ -50,7 +50,7 @@ impl LicenseUser { challenge: &JubJubScalar, gas_limit: u64, gas_price: u64, - ) -> Result<(BlsScalar, BlsScalar), Error> { + ) -> Result<(BlsScalar, SessionCookie), Error> { let (cpp, sc) = CitadelProverParameters::compute_parameters( ssk_user, license, psk_lp, psk_lp, challenge, rng, opening, ); @@ -60,7 +60,6 @@ impl LicenseUser { prover.prove(rng, &circuit).expect("Proving should succeed"); assert!(!public_inputs.is_empty()); - let session_id = public_inputs[0]; verifier .verify(&proof, &public_inputs) @@ -82,6 +81,6 @@ impl LicenseUser { USE_LICENSE_METHOD_NAME, ) .await?; - Ok((session_id, tx_id)) + Ok((tx_id, sc)) } } From dde8cf0d2d2e8d002ae53ac2b82ae20d2b5c04d9 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 7 Nov 2023 12:24:15 +0100 Subject: [PATCH 37/51] Refactored commands submit-request and list-requests --- moat-cli/src/command.rs | 180 +++++++++++++++++++++---------------- moat-cli/src/interactor.rs | 4 +- 2 files changed, 102 insertions(+), 82 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 93ac8e5..4e5969e 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -34,7 +34,7 @@ pub(crate) enum Command { /// Submit request (User) SubmitRequest { request_path: Option }, /// List requests (User) - ListRequestsUser { dummy: bool }, + ListRequestsUser, /// List requests (LP) ListRequestsLP { lp_config_path: Option }, /// Issue license (LP) @@ -149,84 +149,10 @@ impl Command { setup_holder: &mut Option, ) -> Result<(), Error> { match self { - Command::SubmitRequest { request_path } => { - let request_json = match request_path { - Some(request_path) => RequestJson::from_file(request_path)?, - _ => request_json.expect("request should be provided"), - }; - let rng = &mut StdRng::from_entropy(); // seed_from_u64(0xcafe); - let request = RequestCreator::create_from_hex_args( - request_json.user_ssk, - request_json.provider_psk.clone(), - rng, - )?; - let request_hash_hex = Self::to_hash_hex(&request); - println!( - "submitting request to provider psk: {}", - request_json.provider_psk - ); - let tx_id = RequestSender::send_request( - request, - blockchain_access_config, - wallet_path, - psw, - gas_limit, - gas_price, - ) - .await?; - let client = RuskHttpClient::new( - blockchain_access_config.rusk_address.clone(), - ); - TxAwaiter::wait_for(&client, tx_id).await?; - println!( - "request submitting transaction {} confirmed", - hex::encode(tx_id.to_bytes()) - ); - println!("request submitted: {}", request_hash_hex); - println!(); - } - Command::ListRequestsUser { dummy: true } => { - let wallet_accessor = - WalletAccessor::new(wallet_path.clone(), psw.clone()); - let note_hashes: Vec = wallet_accessor - .get_notes(blockchain_access_config) - .await? - .iter() - .flat_map(|n| n.nullified_by) - .collect(); - // println!("current address has {} notes", note_hashes.len()); - - let mut found_requests = vec![]; - let mut height = 0; - let mut total_requests = 0usize; - loop { - let height_end = height + 10000; - let (requests, top, total) = - RequestScanner::scan_related_to_notes_in_block_range( - height, - height_end, - blockchain_access_config, - ¬e_hashes, - ) - .await?; - found_requests.extend(requests); - total_requests += total; - if top <= height_end { - height = top; - break; - } - height = height_end; - } - let owned_requests = found_requests.len(); - println!( - "scanned {} blocks, found {} requests, {} owned requests:", - height, total_requests, owned_requests, - ); - for request in found_requests.iter() { - println!("request: {}", Self::to_hash_hex(request)); - } - println!(); - } + Command::SubmitRequest { request_path } => + Self::submit_request(wallet_path, psw, blockchain_access_config, gas_limit, gas_price, request_json, request_path).await?, + Command::ListRequestsUser => + Self::list_requests(wallet_path, psw, blockchain_access_config).await?, Command::ListRequestsLP { lp_config_path } => { let lp_config_path = match lp_config_path { Some(lp_config_path) => lp_config_path, @@ -402,6 +328,102 @@ impl Command { Ok(()) } + /// Command: Submit Request + async fn submit_request( + wallet_path: &WalletPath, + psw: &Password, + blockchain_access_config: &BlockchainAccessConfig, + gas_limit: u64, + gas_price: u64, + request_json: Option, + request_path: Option, + ) -> Result<(), Error> { + let request_json = match request_path { + Some(request_path) => RequestJson::from_file(request_path)?, + _ => request_json.expect("request should be provided"), + }; + let rng = &mut StdRng::from_entropy(); // seed_from_u64(0xcafe); + let request = RequestCreator::create_from_hex_args( + request_json.user_ssk, + request_json.provider_psk.clone(), + rng, + )?; + let request_hash_hex = Self::to_hash_hex(&request); + println!( + "submitting request to provider psk: {}", + request_json.provider_psk + ); + let tx_id = RequestSender::send_request( + request, + blockchain_access_config, + wallet_path, + psw, + gas_limit, + gas_price, + ) + .await?; + let client = RuskHttpClient::new( + blockchain_access_config.rusk_address.clone(), + ); + TxAwaiter::wait_for(&client, tx_id).await?; + println!( + "request submitting transaction {} confirmed", + hex::encode(tx_id.to_bytes()) + ); + println!("request submitted: {}", request_hash_hex); + println!(); + Ok(()) + } + + /// Command: List Requests + async fn list_requests( + wallet_path: &WalletPath, + psw: &Password, + blockchain_access_config: &BlockchainAccessConfig, + ) -> Result<(), Error>{ + let wallet_accessor = + WalletAccessor::new(wallet_path.clone(), psw.clone()); + let note_hashes: Vec = wallet_accessor + .get_notes(blockchain_access_config) + .await? + .iter() + .flat_map(|n| n.nullified_by) + .collect(); + // println!("current address has {} notes", note_hashes.len()); + + let mut found_requests = vec![]; + let mut height = 0; + let mut total_requests = 0usize; + loop { + let height_end = height + 10000; + let (requests, top, total) = + RequestScanner::scan_related_to_notes_in_block_range( + height, + height_end, + blockchain_access_config, + ¬e_hashes, + ) + .await?; + found_requests.extend(requests); + total_requests += total; + if top <= height_end { + height = top; + break; + } + height = height_end; + } + let owned_requests = found_requests.len(); + println!( + "scanned {} blocks, found {} requests, {} owned requests:", + height, total_requests, owned_requests, + ); + for request in found_requests.iter() { + println!("request: {}", Self::to_hash_hex(request)); + } + println!(); + Ok(()) + } + async fn list_licenses( blockchain_access_config: &BlockchainAccessConfig, request_json: Option<&RequestJson>, diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index 42b3c0b..f3a7e12 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -68,9 +68,7 @@ fn menu_operation() -> Result { })) } CommandMenuItem::ListRequestsUser => { - OpSelection::Run(Box::from(Command::ListRequestsUser { - dummy: true, - })) + OpSelection::Run(Box::from(Command::ListRequestsUser)) } CommandMenuItem::ListRequestsLP => { OpSelection::Run(Box::from(Command::ListRequestsLP { From bc2d353cad52802138b0be2d75e2fc5ed0180586 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 7 Nov 2023 12:38:42 +0100 Subject: [PATCH 38/51] Refactored list requests lp command --- moat-cli/src/command.rs | 81 +++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 27 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 4e5969e..cbe4502 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -149,29 +149,29 @@ impl Command { setup_holder: &mut Option, ) -> Result<(), Error> { match self { - Command::SubmitRequest { request_path } => - Self::submit_request(wallet_path, psw, blockchain_access_config, gas_limit, gas_price, request_json, request_path).await?, - Command::ListRequestsUser => - Self::list_requests(wallet_path, psw, blockchain_access_config).await?, + Command::SubmitRequest { request_path } => { + Self::submit_request( + wallet_path, + psw, + blockchain_access_config, + gas_limit, + gas_price, + request_json, + request_path, + ) + .await? + } + Command::ListRequestsUser => { + Self::list_requests(wallet_path, psw, blockchain_access_config) + .await? + } Command::ListRequestsLP { lp_config_path } => { - let lp_config_path = match lp_config_path { - Some(lp_config_path) => lp_config_path, - _ => PathBuf::from(lp_config), - }; - let mut reference_lp = ReferenceLP::create(lp_config_path)?; - let (total_count, this_lp_count) = - reference_lp.scan(blockchain_access_config).await?; - println!( - "found {} requests total, {} requests for this LP:", - total_count, this_lp_count - ); - for request in reference_lp.requests_to_process.iter() { - println!( - "request to process by LP: {}", - Self::to_hash_hex(request) - ); - } - println!(); + Self::list_requests_lp( + blockchain_access_config, + lp_config, + lp_config_path, + ) + .await? } Command::IssueLicenseLP { lp_config_path, @@ -362,9 +362,8 @@ impl Command { gas_price, ) .await?; - let client = RuskHttpClient::new( - blockchain_access_config.rusk_address.clone(), - ); + let client = + RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); TxAwaiter::wait_for(&client, tx_id).await?; println!( "request submitting transaction {} confirmed", @@ -380,7 +379,7 @@ impl Command { wallet_path: &WalletPath, psw: &Password, blockchain_access_config: &BlockchainAccessConfig, - ) -> Result<(), Error>{ + ) -> Result<(), Error> { let wallet_accessor = WalletAccessor::new(wallet_path.clone(), psw.clone()); let note_hashes: Vec = wallet_accessor @@ -403,7 +402,7 @@ impl Command { blockchain_access_config, ¬e_hashes, ) - .await?; + .await?; found_requests.extend(requests); total_requests += total; if top <= height_end { @@ -424,6 +423,34 @@ impl Command { Ok(()) } + /// Command: List Requests LP + async fn list_requests_lp( + blockchain_access_config: &BlockchainAccessConfig, + lp_config: &Path, + lp_config_path: Option, + ) -> Result<(), Error> { + let lp_config_path = match lp_config_path { + Some(lp_config_path) => lp_config_path, + _ => PathBuf::from(lp_config), + }; + println!("lpcp={:?}", lp_config_path); + let mut reference_lp = ReferenceLP::create(lp_config_path)?; + let (total_count, this_lp_count) = + reference_lp.scan(blockchain_access_config).await?; + println!( + "found {} requests total, {} requests for this LP:", + total_count, this_lp_count + ); + for request in reference_lp.requests_to_process.iter() { + println!( + "request to process by LP: {}", + Self::to_hash_hex(request) + ); + } + println!(); + Ok(()) + } + async fn list_licenses( blockchain_access_config: &BlockchainAccessConfig, request_json: Option<&RequestJson>, From e0da72632b586a2d7ef3adebf96ade4f7180ef21 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 7 Nov 2023 12:47:43 +0100 Subject: [PATCH 39/51] Refactored issue license lp command --- moat-cli/src/command.rs | 115 ++++++++++++++++++++++++---------------- 1 file changed, 69 insertions(+), 46 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index cbe4502..dde0f5d 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -177,52 +177,17 @@ impl Command { lp_config_path, request_hash, } => { - let mut rng = StdRng::from_entropy(); // seed_from_u64(0xbeef); - let lp_config_path = match lp_config_path { - Some(lp_config_path) => lp_config_path, - _ => PathBuf::from(lp_config), - }; - let mut reference_lp = ReferenceLP::create(lp_config_path)?; - let (_total_count, _this_lp_count) = - reference_lp.scan(blockchain_access_config).await?; - - let request = reference_lp.get_request(&request_hash); - match request { - Some(request) => { - let license_issuer = LicenseIssuer::new( - blockchain_access_config.clone(), - wallet_path.clone(), - psw.clone(), - gas_limit, - gas_price, - ); - - println!( - "issuing license for request: {}", - Self::to_hash_hex(&request) - ); - let (tx_id, license_blob) = license_issuer - .issue_license( - &mut rng, - &request, - &reference_lp.ssk_lp, - ) - .await?; - println!( - "license issuing transaction {} confirmed", - hex::encode(tx_id.to_bytes()) - ); - println!( - "issued license: {}", - Self::blob_to_hash_hex(license_blob.as_slice()) - ); - } - _ => { - println!("Request not found"); - } - } - - println!(); + Self::issue_license_lp( + wallet_path, + psw, + blockchain_access_config, + lp_config, + gas_limit, + gas_price, + lp_config_path, + request_hash, + ) + .await? } Command::ListLicenses { request_path } => { let request_json = match request_path { @@ -451,6 +416,64 @@ impl Command { Ok(()) } + #[allow(clippy::too_many_arguments)] + /// Command: Issue License LP + async fn issue_license_lp( + wallet_path: &WalletPath, + psw: &Password, + blockchain_access_config: &BlockchainAccessConfig, + lp_config: &Path, + gas_limit: u64, + gas_price: u64, + lp_config_path: Option, + request_hash: String, + ) -> Result<(), Error> { + let mut rng = StdRng::from_entropy(); // seed_from_u64(0xbeef); + let lp_config_path = match lp_config_path { + Some(lp_config_path) => lp_config_path, + _ => PathBuf::from(lp_config), + }; + let mut reference_lp = ReferenceLP::create(lp_config_path)?; + let (_total_count, _this_lp_count) = + reference_lp.scan(blockchain_access_config).await?; + + let request = reference_lp.get_request(&request_hash); + match request { + Some(request) => { + let license_issuer = LicenseIssuer::new( + blockchain_access_config.clone(), + wallet_path.clone(), + psw.clone(), + gas_limit, + gas_price, + ); + + println!( + "issuing license for request: {}", + Self::to_hash_hex(&request) + ); + let (tx_id, license_blob) = license_issuer + .issue_license(&mut rng, &request, &reference_lp.ssk_lp) + .await?; + println!( + "license issuing transaction {} confirmed", + hex::encode(tx_id.to_bytes()) + ); + println!( + "issued license: {}", + Self::blob_to_hash_hex(license_blob.as_slice()) + ); + } + _ => { + println!("Request not found"); + } + } + + println!(); + + Ok(()) + } + async fn list_licenses( blockchain_access_config: &BlockchainAccessConfig, request_json: Option<&RequestJson>, From e5ddf97b0bfec9d67842216129bfdfaa0e87fccb Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 7 Nov 2023 12:54:17 +0100 Subject: [PATCH 40/51] Refactored list licenses --- moat-cli/src/command.rs | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index dde0f5d..30a8534 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -190,16 +190,12 @@ impl Command { .await? } Command::ListLicenses { request_path } => { - let request_json = match request_path { - Some(request_path) => RequestJson::from_file(request_path)?, - _ => request_json.expect("request should be provided"), - }; Self::list_licenses( blockchain_access_config, - Some(&request_json), + request_json, + request_path, ) - .await?; - println!(); + .await? } Command::UseLicense { request_path, @@ -474,10 +470,17 @@ impl Command { Ok(()) } + /// Command: List Licenses async fn list_licenses( blockchain_access_config: &BlockchainAccessConfig, - request_json: Option<&RequestJson>, + request_json: Option, + request_path: Option, ) -> Result<(), Error> { + let request_json = match request_path { + Some(request_path) => RequestJson::from_file(request_path)?, + _ => request_json.expect("request should be provided"), + }; + let client = RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); let end_height = BcInquirer::block_height(&client).await?; @@ -491,23 +494,9 @@ impl Command { CitadelInquirer::get_licenses(&client, block_heights).await?; let ssk_user = SecretSpendKey::from_slice( - hex::decode( - request_json - .expect("request should be provided") - .user_ssk - .clone(), - )? - .as_slice(), + hex::decode(request_json.user_ssk.clone())?.as_slice(), )?; - // let owned_pairs = find_owned_licenses(ssk_user, &mut - // licenses_stream)?; if owned_pairs.is_empty() { - // println!("licenses not found"); - // } else { - // for (_pos, license) in owned_pairs.iter() { - // println!("license: {}", Self::to_hash_hex(license)) - // } - // }; let pairs = find_all_licenses(&mut licenses_stream)?; if pairs.is_empty() { println!("licenses not found"); @@ -522,6 +511,7 @@ impl Command { ) } }; + println!(); Ok(()) } From 51a8547420888cf68cecb571f9fddca1c216432c Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 7 Nov 2023 13:07:25 +0100 Subject: [PATCH 41/51] Refactored use license command --- moat-cli/src/command.rs | 105 ++++++++++++++++++++++++---------------- 1 file changed, 64 insertions(+), 41 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 30a8534..f53e5a8 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -201,49 +201,18 @@ impl Command { request_path, license_hash, } => { - let request_json = match request_path { - Some(request_path) => RequestJson::from_file(request_path)?, - _ => request_json.expect("request should be provided"), - }; - let pos_license = Self::get_license_to_use( + Self::use_license( + wallet_path, + psw, blockchain_access_config, - Some(&request_json), - license_hash.clone(), + gas_limit, + gas_price, + request_json, + setup_holder, + request_path, + license_hash, ) - .await?; - match pos_license { - Some((pos, license)) => { - println!( - "using license: {}", - Self::to_hash_hex(&license) - ); - // println!("user_ssk={}", request_json.user_ssk); - // println!("lp_psk={}", request_json.provider_psk); - let ssk_user = SecretSpendKey::from_slice( - hex::decode(request_json.user_ssk)?.as_slice(), - )?; - let psk_lp = PublicSpendKey::from_slice( - hex::decode(request_json.provider_psk)?.as_slice(), - )?; - let _session_id = Self::prove_and_send_use_license( - blockchain_access_config, - wallet_path, - psw, - psk_lp, - ssk_user, - &license, - pos, - gas_limit, - gas_price, - setup_holder, - ) - .await?; - } - _ => { - println!("Please obtain a license"); - } - } - println!(); + .await? } Command::RequestService { session_cookie: _ } => { println!("Off-chain request service to be placed here"); @@ -515,6 +484,60 @@ impl Command { Ok(()) } + #[allow(clippy::too_many_arguments)] + /// Command: Use License + async fn use_license( + wallet_path: &WalletPath, + psw: &Password, + blockchain_access_config: &BlockchainAccessConfig, + gas_limit: u64, + gas_price: u64, + request_json: Option, + setup_holder: &mut Option, + request_path: Option, + license_hash: String, + ) -> Result<(), Error> { + let request_json = match request_path { + Some(request_path) => RequestJson::from_file(request_path)?, + _ => request_json.expect("request should be provided"), + }; + let pos_license = Self::get_license_to_use( + blockchain_access_config, + Some(&request_json), + license_hash.clone(), + ) + .await?; + match pos_license { + Some((pos, license)) => { + println!("using license: {}", Self::to_hash_hex(&license)); + let ssk_user = SecretSpendKey::from_slice( + hex::decode(request_json.user_ssk)?.as_slice(), + )?; + let psk_lp = PublicSpendKey::from_slice( + hex::decode(request_json.provider_psk)?.as_slice(), + )?; + let _session_id = Self::prove_and_send_use_license( + blockchain_access_config, + wallet_path, + psw, + psk_lp, + ssk_user, + &license, + pos, + gas_limit, + gas_price, + setup_holder, + ) + .await?; + } + _ => { + println!("Please obtain a license"); + } + } + println!(); + Ok(()) + } + async fn get_license_to_use( blockchain_access_config: &BlockchainAccessConfig, request_json: Option<&RequestJson>, From ff3c201076fec44c02516c359980cb0649bacced Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 7 Nov 2023 13:22:17 +0100 Subject: [PATCH 42/51] Refactored get session and show state commands --- moat-cli/src/command.rs | 82 ++++++++++++++++++++++---------------- moat-cli/src/interactor.rs | 2 +- 2 files changed, 49 insertions(+), 35 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index f53e5a8..d3721d8 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -54,7 +54,7 @@ pub(crate) enum Command { /// Get session (SP) GetSession { session_id: String }, /// Show state - ShowState { dummy: bool }, + ShowState, } // todo: move this function somewhere else @@ -219,41 +219,11 @@ impl Command { println!(); } Command::GetSession { session_id } => { - let client = RuskHttpClient::new( - blockchain_access_config.rusk_address.clone(), - ); - let id = LicenseSessionId { - id: BlsScalar::from_slice( - hex::decode(session_id.clone())?.as_slice(), - )?, - }; - match CitadelInquirer::get_session(&client, id).await? { - Some(session) => { - println!("obtained session with id={}:", session_id); - println!(); - for s in session.public_inputs.iter() { - println!("{}", hex::encode(s.to_bytes())); - } - } - _ => { - println!("session not found"); - } - } - println!(); + Self::get_session(blockchain_access_config, session_id).await? } - Command::ShowState { dummy: true } => { - let client = RuskHttpClient::new( - blockchain_access_config.rusk_address.clone(), - ); - let (num_licenses, _, num_sessions) = - CitadelInquirer::get_info(&client).await?; - println!( - "license contract state - licenses: {}, sessions: {}", - num_licenses, num_sessions - ); - println!(); + Command::ShowState => { + Self::show_state(blockchain_access_config).await? } - _ => (), } Ok(()) } @@ -538,6 +508,50 @@ impl Command { Ok(()) } + /// Command: Get Session + async fn get_session( + blockchain_access_config: &BlockchainAccessConfig, + session_id: String, + ) -> Result<(), Error> { + let client = + RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); + let id = LicenseSessionId { + id: BlsScalar::from_slice( + hex::decode(session_id.clone())?.as_slice(), + )?, + }; + match CitadelInquirer::get_session(&client, id).await? { + Some(session) => { + println!("obtained session with id={}:", session_id); + println!(); + for s in session.public_inputs.iter() { + println!("{}", hex::encode(s.to_bytes())); + } + } + _ => { + println!("session not found"); + } + } + println!(); + Ok(()) + } + + /// Command: Show State + async fn show_state( + blockchain_access_config: &BlockchainAccessConfig, + ) -> Result<(), Error> { + let client = + RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); + let (num_licenses, _, num_sessions) = + CitadelInquirer::get_info(&client).await?; + println!( + "license contract state - licenses: {}, sessions: {}", + num_licenses, num_sessions + ); + println!(); + Ok(()) + } + async fn get_license_to_use( blockchain_access_config: &BlockchainAccessConfig, request_json: Option<&RequestJson>, diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index f3a7e12..5c103c3 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -115,7 +115,7 @@ fn menu_operation() -> Result { })) } CommandMenuItem::ShowState => { - OpSelection::Run(Box::from(Command::ShowState { dummy: true })) + OpSelection::Run(Box::from(Command::ShowState)) } CommandMenuItem::Exit => OpSelection::Exit, }) From 332c483573c2cb1392e65e6f91fbf7a9d975a5c5 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 7 Nov 2023 15:48:33 +0100 Subject: [PATCH 43/51] Introduced run result implementing Display --- moat-cli/src/command.rs | 132 ++++++++++++------------------------- moat-cli/src/interactor.rs | 10 +-- moat-cli/src/main.rs | 1 + moat-cli/src/run_result.rs | 72 ++++++++++++++++++++ 4 files changed, 122 insertions(+), 93 deletions(-) create mode 100644 moat-cli/src/run_result.rs diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index d3721d8..0353567 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -5,6 +5,7 @@ // Copyright (c) DUSK NETWORK. All rights reserved. use crate::interactor::SetupHolder; +use crate::run_result::{RequestsSummary, RunResult}; use crate::SeedableRng; use bytecheck::CheckBytes; use bytes::Bytes; @@ -21,9 +22,7 @@ use moat_core::{ RequestSender, StreamAux, TxAwaiter, }; use rand::rngs::StdRng; -use rkyv::ser::serializers::AllocSerializer; use rkyv::{check_archived_root, Archive, Deserialize, Infallible, Serialize}; -use sha3::{Digest, Sha3_256}; use std::path::{Path, PathBuf}; use wallet_accessor::{BlockchainAccessConfig, Password, WalletAccessor}; use zk_citadel::license::License; @@ -122,15 +121,6 @@ fn find_all_licenses( Ok(pairs) } -// todo: move this struct to its proper place -/// Use License Argument. -#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)] -#[archive_attr(derive(CheckBytes))] -pub struct UseLicenseArg { - pub proof: Proof, - pub public_inputs: Vec, -} - // todo: move these consts to their proper place static LABEL: &[u8] = b"dusk-network"; const CAPACITY: usize = 17; // capacity required for the setup @@ -147,8 +137,8 @@ impl Command { gas_price: u64, request_json: Option, setup_holder: &mut Option, - ) -> Result<(), Error> { - match self { + ) -> Result { + let run_result = match self { Command::SubmitRequest { request_path } => { Self::submit_request( wallet_path, @@ -216,7 +206,7 @@ impl Command { } Command::RequestService { session_cookie: _ } => { println!("Off-chain request service to be placed here"); - println!(); + RunResult::Empty } Command::GetSession { session_id } => { Self::get_session(blockchain_access_config, session_id).await? @@ -224,8 +214,8 @@ impl Command { Command::ShowState => { Self::show_state(blockchain_access_config).await? } - } - Ok(()) + }; + Ok(run_result) } /// Command: Submit Request @@ -237,7 +227,7 @@ impl Command { gas_price: u64, request_json: Option, request_path: Option, - ) -> Result<(), Error> { + ) -> Result { let request_json = match request_path { Some(request_path) => RequestJson::from_file(request_path)?, _ => request_json.expect("request should be provided"), @@ -248,7 +238,7 @@ impl Command { request_json.provider_psk.clone(), rng, )?; - let request_hash_hex = Self::to_hash_hex(&request); + let request_hash_hex = RunResult::to_hash_hex(&request); println!( "submitting request to provider psk: {}", request_json.provider_psk @@ -270,8 +260,7 @@ impl Command { hex::encode(tx_id.to_bytes()) ); println!("request submitted: {}", request_hash_hex); - println!(); - Ok(()) + Ok(RunResult::Empty) } /// Command: List Requests @@ -279,7 +268,7 @@ impl Command { wallet_path: &WalletPath, psw: &Password, blockchain_access_config: &BlockchainAccessConfig, - ) -> Result<(), Error> { + ) -> Result { let wallet_accessor = WalletAccessor::new(wallet_path.clone(), psw.clone()); let note_hashes: Vec = wallet_accessor @@ -288,11 +277,10 @@ impl Command { .iter() .flat_map(|n| n.nullified_by) .collect(); - // println!("current address has {} notes", note_hashes.len()); let mut found_requests = vec![]; let mut height = 0; - let mut total_requests = 0usize; + let mut found_total = 0usize; loop { let height_end = height + 10000; let (requests, top, total) = @@ -304,23 +292,21 @@ impl Command { ) .await?; found_requests.extend(requests); - total_requests += total; + found_total += total; if top <= height_end { height = top; break; } height = height_end; } - let owned_requests = found_requests.len(); - println!( - "scanned {} blocks, found {} requests, {} owned requests:", - height, total_requests, owned_requests, - ); - for request in found_requests.iter() { - println!("request: {}", Self::to_hash_hex(request)); - } - println!(); - Ok(()) + let found_owned = found_requests.len(); + let summary = RequestsSummary { + height, + found_total, + found_owned, + }; + let run_result = RunResult::Requests(summary, found_requests); + Ok(run_result) } /// Command: List Requests LP @@ -328,7 +314,7 @@ impl Command { blockchain_access_config: &BlockchainAccessConfig, lp_config: &Path, lp_config_path: Option, - ) -> Result<(), Error> { + ) -> Result { let lp_config_path = match lp_config_path { Some(lp_config_path) => lp_config_path, _ => PathBuf::from(lp_config), @@ -344,11 +330,10 @@ impl Command { for request in reference_lp.requests_to_process.iter() { println!( "request to process by LP: {}", - Self::to_hash_hex(request) + RunResult::to_hash_hex(request) ); } - println!(); - Ok(()) + Ok(RunResult::Empty) } #[allow(clippy::too_many_arguments)] @@ -362,7 +347,7 @@ impl Command { gas_price: u64, lp_config_path: Option, request_hash: String, - ) -> Result<(), Error> { + ) -> Result { let mut rng = StdRng::from_entropy(); // seed_from_u64(0xbeef); let lp_config_path = match lp_config_path { Some(lp_config_path) => lp_config_path, @@ -385,7 +370,7 @@ impl Command { println!( "issuing license for request: {}", - Self::to_hash_hex(&request) + RunResult::to_hash_hex(&request) ); let (tx_id, license_blob) = license_issuer .issue_license(&mut rng, &request, &reference_lp.ssk_lp) @@ -396,17 +381,14 @@ impl Command { ); println!( "issued license: {}", - Self::blob_to_hash_hex(license_blob.as_slice()) + RunResult::blob_to_hash_hex(license_blob.as_slice()) ); } _ => { println!("Request not found"); } } - - println!(); - - Ok(()) + Ok(RunResult::Empty) } /// Command: List Licenses @@ -414,7 +396,7 @@ impl Command { blockchain_access_config: &BlockchainAccessConfig, request_json: Option, request_path: Option, - ) -> Result<(), Error> { + ) -> Result { let request_json = match request_path { Some(request_path) => RequestJson::from_file(request_path)?, _ => request_json.expect("request should be provided"), @@ -445,13 +427,12 @@ impl Command { let is_owned = vk.owns(&license.lsa); println!( "license: {} {}", - Self::to_hash_hex(license), + RunResult::to_hash_hex(license), if is_owned { "owned" } else { "" } ) } }; - println!(); - Ok(()) + Ok(RunResult::Empty) } #[allow(clippy::too_many_arguments)] @@ -466,7 +447,7 @@ impl Command { setup_holder: &mut Option, request_path: Option, license_hash: String, - ) -> Result<(), Error> { + ) -> Result { let request_json = match request_path { Some(request_path) => RequestJson::from_file(request_path)?, _ => request_json.expect("request should be provided"), @@ -479,7 +460,7 @@ impl Command { .await?; match pos_license { Some((pos, license)) => { - println!("using license: {}", Self::to_hash_hex(&license)); + println!("using license: {}", RunResult::to_hash_hex(&license)); let ssk_user = SecretSpendKey::from_slice( hex::decode(request_json.user_ssk)?.as_slice(), )?; @@ -504,15 +485,14 @@ impl Command { println!("Please obtain a license"); } } - println!(); - Ok(()) + Ok(RunResult::Empty) } /// Command: Get Session async fn get_session( blockchain_access_config: &BlockchainAccessConfig, session_id: String, - ) -> Result<(), Error> { + ) -> Result { let client = RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); let id = LicenseSessionId { @@ -532,14 +512,13 @@ impl Command { println!("session not found"); } } - println!(); - Ok(()) + Ok(RunResult::Empty) } /// Command: Show State async fn show_state( blockchain_access_config: &BlockchainAccessConfig, - ) -> Result<(), Error> { + ) -> Result { let client = RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); let (num_licenses, _, num_sessions) = @@ -548,8 +527,7 @@ impl Command { "license contract state - licenses: {}, sessions: {}", num_licenses, num_sessions ); - println!(); - Ok(()) + Ok(RunResult::Empty) } async fn get_license_to_use( @@ -580,7 +558,7 @@ impl Command { None } else { for (pos, license) in pairs.iter() { - if license_hash == Self::to_hash_hex(license) { + if license_hash == RunResult::to_hash_hex(license) { return Ok(Some((*pos, license.clone()))); } } @@ -657,9 +635,12 @@ impl Command { hex::encode(tx_id.to_bytes()) ); println!(); - println!("license {} used", Self::to_hash_hex(license),); + println!("license {} used", RunResult::to_hash_hex(license),); println!(); - println!("session cookie: {}", Self::to_blob_hex(&session_cookie)); + println!( + "session cookie: {}", + RunResult::to_blob_hex(&session_cookie) + ); println!(); println!( "user attributes: {}", @@ -671,31 +652,4 @@ impl Command { ); Ok(session_cookie.session_id) } - - fn to_hash_hex(object: &T) -> String - where - T: rkyv::Serialize>, - { - let blob = rkyv::to_bytes::<_, 16386>(object) - .expect("type should serialize correctly") - .to_vec(); - Self::blob_to_hash_hex(blob.as_slice()) - } - - fn blob_to_hash_hex(blob: &[u8]) -> String { - let mut hasher = Sha3_256::new(); - hasher.update(blob); - let result = hasher.finalize(); - hex::encode(result) - } - - fn to_blob_hex(object: &T) -> String - where - T: rkyv::Serialize>, - { - let blob = rkyv::to_bytes::<_, 16386>(object) - .expect("type should serialize correctly") - .to_vec(); - hex::encode(blob) - } } diff --git a/moat-cli/src/interactor.rs b/moat-cli/src/interactor.rs index 5c103c3..11536b7 100644 --- a/moat-cli/src/interactor.rs +++ b/moat-cli/src/interactor.rs @@ -157,9 +157,11 @@ impl Interactor { &mut self.setup_holder, ) .await; - if result.is_err() { - let error = result.unwrap_err(); - match error { + match result { + Ok(run_result) => { + println!("{}", run_result); + } + Err(error) => match error { Error::IO(arc) => { println!("{}", arc.as_ref().to_string()); } @@ -169,7 +171,7 @@ impl Interactor { _ => { println!("{:?}", error); } - } + }, } continue; } diff --git a/moat-cli/src/main.rs b/moat-cli/src/main.rs index b2bd627..f710ec9 100644 --- a/moat-cli/src/main.rs +++ b/moat-cli/src/main.rs @@ -12,6 +12,7 @@ mod error; mod interactor; mod menu; mod prompt; +mod run_result; use crate::args::Args; use crate::command::Command; diff --git a/moat-cli/src/run_result.rs b/moat-cli/src/run_result.rs new file mode 100644 index 0000000..27b8efe --- /dev/null +++ b/moat-cli/src/run_result.rs @@ -0,0 +1,72 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) DUSK NETWORK. All rights reserved. + +use rkyv::ser::serializers::AllocSerializer; +use std::fmt; +use zk_citadel::license::Request; +// use rkyv::{check_archived_root, Archive, Deserialize, Infallible, Serialize}; +use sha3::{Digest, Sha3_256}; + +pub struct RequestsSummary { + pub height: u64, + pub found_total: usize, + pub found_owned: usize, +} + +/// Possible results of running a command in interactive mode +pub enum RunResult { + Requests(RequestsSummary, Vec), + Empty, +} + +impl fmt::Display for RunResult { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use RunResult::*; + match self { + Requests(summary, requests) => { + writeln!( + f, + "scanned {} blocks, found {} requests, {} owned requests:", + summary.height, summary.found_total, summary.found_owned, + )?; + for request in requests.iter() { + writeln!(f, "request: {}", Self::to_hash_hex(request))?; + } + Ok(()) + } + Empty => Ok(()), + } + } +} + +impl RunResult { + pub fn to_hash_hex(object: &T) -> String + where + T: rkyv::Serialize>, + { + let blob = rkyv::to_bytes::<_, 16386>(object) + .expect("type should serialize correctly") + .to_vec(); + Self::blob_to_hash_hex(blob.as_slice()) + } + + pub fn blob_to_hash_hex(blob: &[u8]) -> String { + let mut hasher = Sha3_256::new(); + hasher.update(blob); + let result = hasher.finalize(); + hex::encode(result) + } + + pub fn to_blob_hex(object: &T) -> String + where + T: rkyv::Serialize>, + { + let blob = rkyv::to_bytes::<_, 16386>(object) + .expect("type should serialize correctly") + .to_vec(); + hex::encode(blob) + } +} From 4b14ccaeaecc6d08d8a1dfc190a82caecc226ecd Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 7 Nov 2023 16:15:20 +0100 Subject: [PATCH 44/51] Run result based display for submit request and list requests lp --- moat-cli/src/command.rs | 47 ++++++++++++++++---------------------- moat-cli/src/run_result.rs | 42 ++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 27 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 0353567..45903cc 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -5,9 +5,10 @@ // Copyright (c) DUSK NETWORK. All rights reserved. use crate::interactor::SetupHolder; -use crate::run_result::{RequestsSummary, RunResult}; +use crate::run_result::{ + RequestsLPSummary, RequestsSummary, RunResult, SubmitRequestSummary, +}; use crate::SeedableRng; -use bytecheck::CheckBytes; use bytes::Bytes; use dusk_bls12_381::BlsScalar; use dusk_bytes::DeserializableSlice; @@ -22,7 +23,7 @@ use moat_core::{ RequestSender, StreamAux, TxAwaiter, }; use rand::rngs::StdRng; -use rkyv::{check_archived_root, Archive, Deserialize, Infallible, Serialize}; +use rkyv::{check_archived_root, Deserialize, Infallible}; use std::path::{Path, PathBuf}; use wallet_accessor::{BlockchainAccessConfig, Password, WalletAccessor}; use zk_citadel::license::License; @@ -238,11 +239,7 @@ impl Command { request_json.provider_psk.clone(), rng, )?; - let request_hash_hex = RunResult::to_hash_hex(&request); - println!( - "submitting request to provider psk: {}", - request_json.provider_psk - ); + let request_hash = RunResult::to_hash_hex(&request); let tx_id = RequestSender::send_request( request, blockchain_access_config, @@ -255,12 +252,12 @@ impl Command { let client = RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); TxAwaiter::wait_for(&client, tx_id).await?; - println!( - "request submitting transaction {} confirmed", - hex::encode(tx_id.to_bytes()) - ); - println!("request submitted: {}", request_hash_hex); - Ok(RunResult::Empty) + let summary = SubmitRequestSummary { + psk_lp: request_json.provider_psk, + tx_id: hex::encode(tx_id.to_bytes()), + request_hash, + }; + Ok(RunResult::SubmitRequest(summary)) } /// Command: List Requests @@ -319,21 +316,17 @@ impl Command { Some(lp_config_path) => lp_config_path, _ => PathBuf::from(lp_config), }; - println!("lpcp={:?}", lp_config_path); let mut reference_lp = ReferenceLP::create(lp_config_path)?; - let (total_count, this_lp_count) = + let (found_total, found_owned) = reference_lp.scan(blockchain_access_config).await?; - println!( - "found {} requests total, {} requests for this LP:", - total_count, this_lp_count - ); - for request in reference_lp.requests_to_process.iter() { - println!( - "request to process by LP: {}", - RunResult::to_hash_hex(request) - ); - } - Ok(RunResult::Empty) + let summary = RequestsLPSummary { + found_total, + found_owned, + }; + Ok(RunResult::RequestsLP( + summary, + reference_lp.requests_to_process, + )) } #[allow(clippy::too_many_arguments)] diff --git a/moat-cli/src/run_result.rs b/moat-cli/src/run_result.rs index 27b8efe..9cf6f21 100644 --- a/moat-cli/src/run_result.rs +++ b/moat-cli/src/run_result.rs @@ -10,15 +10,28 @@ use zk_citadel::license::Request; // use rkyv::{check_archived_root, Archive, Deserialize, Infallible, Serialize}; use sha3::{Digest, Sha3_256}; +pub struct SubmitRequestSummary { + pub psk_lp: String, + pub tx_id: String, + pub request_hash: String, +} + pub struct RequestsSummary { pub height: u64, pub found_total: usize, pub found_owned: usize, } +pub struct RequestsLPSummary { + pub found_total: usize, + pub found_owned: usize, +} + /// Possible results of running a command in interactive mode pub enum RunResult { + SubmitRequest(SubmitRequestSummary), Requests(RequestsSummary, Vec), + RequestsLP(RequestsLPSummary, Vec), Empty, } @@ -26,6 +39,20 @@ impl fmt::Display for RunResult { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use RunResult::*; match self { + SubmitRequest(summary) => { + writeln!( + f, + "submitting request to provider psk: {}", + summary.psk_lp + )?; + writeln!( + f, + "request submitting transaction {} confirmed", + summary.tx_id + )?; + writeln!(f, "request submitted: {}", summary.request_hash)?; + Ok(()) + } Requests(summary, requests) => { writeln!( f, @@ -37,6 +64,21 @@ impl fmt::Display for RunResult { } Ok(()) } + RequestsLP(summary, requests) => { + writeln!( + f, + "found {} requests total, {} requests for this LP:", + summary.found_total, summary.found_owned + )?; + for request in requests.iter() { + writeln!( + f, + "request to process by LP: {}", + RunResult::to_hash_hex(request) + )?; + } + Ok(()) + } Empty => Ok(()), } } From 05d54c3a8525b6553f40830eedd194fddd541afd Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 7 Nov 2023 16:33:11 +0100 Subject: [PATCH 45/51] Run result based display for issue license --- moat-cli/src/command.rs | 31 +++++++++++-------------------- moat-cli/src/run_result.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 45903cc..7539f0c 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -6,7 +6,8 @@ use crate::interactor::SetupHolder; use crate::run_result::{ - RequestsLPSummary, RequestsSummary, RunResult, SubmitRequestSummary, + IssueLicenseSummary, RequestsLPSummary, RequestsSummary, RunResult, + SubmitRequestSummary, }; use crate::SeedableRng; use bytes::Bytes; @@ -351,7 +352,7 @@ impl Command { reference_lp.scan(blockchain_access_config).await?; let request = reference_lp.get_request(&request_hash); - match request { + Ok(match request { Some(request) => { let license_issuer = LicenseIssuer::new( blockchain_access_config.clone(), @@ -360,28 +361,18 @@ impl Command { gas_limit, gas_price, ); - - println!( - "issuing license for request: {}", - RunResult::to_hash_hex(&request) - ); let (tx_id, license_blob) = license_issuer .issue_license(&mut rng, &request, &reference_lp.ssk_lp) .await?; - println!( - "license issuing transaction {} confirmed", - hex::encode(tx_id.to_bytes()) - ); - println!( - "issued license: {}", - RunResult::blob_to_hash_hex(license_blob.as_slice()) - ); - } - _ => { - println!("Request not found"); + let summary = IssueLicenseSummary { + request, + tx_id: hex::encode(tx_id.to_bytes()), + license_blob, + }; + RunResult::IssueLicense(Some(summary)) } - } - Ok(RunResult::Empty) + _ => RunResult::IssueLicense(None), + }) } /// Command: List Licenses diff --git a/moat-cli/src/run_result.rs b/moat-cli/src/run_result.rs index 9cf6f21..fc4d8a9 100644 --- a/moat-cli/src/run_result.rs +++ b/moat-cli/src/run_result.rs @@ -27,11 +27,19 @@ pub struct RequestsLPSummary { pub found_owned: usize, } +pub struct IssueLicenseSummary { + pub request: Request, + pub tx_id: String, + pub license_blob: Vec, +} + +#[allow(clippy::large_enum_variant)] /// Possible results of running a command in interactive mode pub enum RunResult { SubmitRequest(SubmitRequestSummary), Requests(RequestsSummary, Vec), RequestsLP(RequestsLPSummary, Vec), + IssueLicense(Option), Empty, } @@ -79,6 +87,32 @@ impl fmt::Display for RunResult { } Ok(()) } + IssueLicense(summary) => match summary { + Some(summary) => { + writeln!( + f, + "issuing license for request: {}", + RunResult::to_hash_hex(&summary.request) + )?; + writeln!( + f, + "license issuing transaction {} confirmed", + summary.tx_id + )?; + writeln!( + f, + "issued license: {}", + RunResult::blob_to_hash_hex( + summary.license_blob.as_slice() + ) + )?; + Ok(()) + } + _ => { + writeln!(f, "Request not found")?; + Ok(()) + } + }, Empty => Ok(()), } } From 8f1f1af49e5bdd918a3aab7a0e0c68675b53c7d2 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 7 Nov 2023 16:58:00 +0100 Subject: [PATCH 46/51] Run result based display for list licenses --- moat-cli/src/command.rs | 29 +++++++++-------------------- moat-cli/src/run_result.rs | 24 +++++++++++++++++++++++- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 7539f0c..2c3017d 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -389,34 +389,23 @@ impl Command { let client = RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); let end_height = BcInquirer::block_height(&client).await?; - let block_heights = 0..(end_height + 1); + let block_range = 0..(end_height + 1); - println!( - "getting licenses within the block height range {:?}:", - block_heights - ); let mut licenses_stream = - CitadelInquirer::get_licenses(&client, block_heights).await?; + CitadelInquirer::get_licenses(&client, block_range.clone()).await?; let ssk_user = SecretSpendKey::from_slice( hex::decode(request_json.user_ssk.clone())?.as_slice(), )?; let pairs = find_all_licenses(&mut licenses_stream)?; - if pairs.is_empty() { - println!("licenses not found"); - } else { - let vk = ssk_user.view_key(); - for (_pos, license) in pairs.iter() { - let is_owned = vk.owns(&license.lsa); - println!( - "license: {} {}", - RunResult::to_hash_hex(license), - if is_owned { "owned" } else { "" } - ) - } - }; - Ok(RunResult::Empty) + let vk = ssk_user.view_key(); + let mut licenses = vec![]; + for (_pos, license) in pairs.into_iter() { + let is_owned = vk.owns(&license.lsa); + licenses.push((license, is_owned)); + } + Ok(RunResult::ListLicenses(block_range, licenses)) } #[allow(clippy::too_many_arguments)] diff --git a/moat-cli/src/run_result.rs b/moat-cli/src/run_result.rs index fc4d8a9..c14d854 100644 --- a/moat-cli/src/run_result.rs +++ b/moat-cli/src/run_result.rs @@ -6,7 +6,8 @@ use rkyv::ser::serializers::AllocSerializer; use std::fmt; -use zk_citadel::license::Request; +use std::ops::Range; +use zk_citadel::license::{License, Request}; // use rkyv::{check_archived_root, Archive, Deserialize, Infallible, Serialize}; use sha3::{Digest, Sha3_256}; @@ -40,6 +41,7 @@ pub enum RunResult { Requests(RequestsSummary, Vec), RequestsLP(RequestsLPSummary, Vec), IssueLicense(Option), + ListLicenses(Range, Vec<(License, bool)>), Empty, } @@ -113,6 +115,26 @@ impl fmt::Display for RunResult { Ok(()) } }, + ListLicenses(block_range, licenses) => { + writeln!( + f, + "getting licenses within the block height range {:?}:", + block_range + )?; + if licenses.is_empty() { + writeln!(f, "licenses not found")?; + } else { + for (license, is_owned) in licenses.iter() { + writeln!( + f, + "license: {} {}", + RunResult::to_hash_hex(license), + if *is_owned { "owned" } else { "" } + )?; + } + } + Ok(()) + } Empty => Ok(()), } } From 70e06918c6d6a52f1b93349b56f2b244cfbf2548 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 7 Nov 2023 17:19:15 +0100 Subject: [PATCH 47/51] Run result based display for get session and show state commands --- moat-cli/src/command.rs | 32 ++++++++++++++++---------------- moat-cli/src/run_result.rs | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 16 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 2c3017d..61665b7 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -6,8 +6,8 @@ use crate::interactor::SetupHolder; use crate::run_result::{ - IssueLicenseSummary, RequestsLPSummary, RequestsSummary, RunResult, - SubmitRequestSummary, + IssueLicenseSummary, LicenseContractSummary, RequestsLPSummary, + RequestsSummary, RunResult, SessionSummary, SubmitRequestSummary, }; use crate::SeedableRng; use bytes::Bytes; @@ -473,19 +473,19 @@ impl Command { hex::decode(session_id.clone())?.as_slice(), )?, }; - match CitadelInquirer::get_session(&client, id).await? { + Ok(match CitadelInquirer::get_session(&client, id).await? { Some(session) => { - println!("obtained session with id={}:", session_id); - println!(); + let mut summary = SessionSummary { + session_id, + session: vec![], + }; for s in session.public_inputs.iter() { - println!("{}", hex::encode(s.to_bytes())); + summary.session.push(hex::encode(s.to_bytes())); } + RunResult::GetSession(Some(summary)) } - _ => { - println!("session not found"); - } - } - Ok(RunResult::Empty) + _ => RunResult::GetSession(None), + }) } /// Command: Show State @@ -496,11 +496,11 @@ impl Command { RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); let (num_licenses, _, num_sessions) = CitadelInquirer::get_info(&client).await?; - println!( - "license contract state - licenses: {}, sessions: {}", - num_licenses, num_sessions - ); - Ok(RunResult::Empty) + let summary = LicenseContractSummary { + num_licenses, + num_sessions, + }; + Ok(RunResult::ShowState(summary)) } async fn get_license_to_use( diff --git a/moat-cli/src/run_result.rs b/moat-cli/src/run_result.rs index c14d854..1d94f83 100644 --- a/moat-cli/src/run_result.rs +++ b/moat-cli/src/run_result.rs @@ -34,6 +34,16 @@ pub struct IssueLicenseSummary { pub license_blob: Vec, } +pub struct SessionSummary { + pub session_id: String, + pub session: Vec, +} + +pub struct LicenseContractSummary { + pub num_licenses: u32, + pub num_sessions: u32, +} + #[allow(clippy::large_enum_variant)] /// Possible results of running a command in interactive mode pub enum RunResult { @@ -42,6 +52,8 @@ pub enum RunResult { RequestsLP(RequestsLPSummary, Vec), IssueLicense(Option), ListLicenses(Range, Vec<(License, bool)>), + GetSession(Option), + ShowState(LicenseContractSummary), Empty, } @@ -135,6 +147,32 @@ impl fmt::Display for RunResult { } Ok(()) } + GetSession(summary) => { + match summary { + Some(summary) => { + writeln!( + f, + "obtained session with id={}:", + summary.session_id + )?; + for s in summary.session.iter() { + writeln!(f, "{}", s)?; + } + } + _ => { + writeln!(f, "session not found")?; + } + } + Ok(()) + } + ShowState(summary) => { + writeln!( + f, + "license contract state - licenses: {}, sessions: {}", + summary.num_licenses, summary.num_sessions + )?; + Ok(()) + } Empty => Ok(()), } } From b3f856139024c6f198a7d9fcc046c6372a785f6c Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 7 Nov 2023 17:55:50 +0100 Subject: [PATCH 48/51] Run result based display for the use license command --- moat-cli/src/command.rs | 48 +++++++++++------------------- moat-cli/src/run_result.rs | 61 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 76 insertions(+), 33 deletions(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 61665b7..12ebb7d 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -8,6 +8,7 @@ use crate::interactor::SetupHolder; use crate::run_result::{ IssueLicenseSummary, LicenseContractSummary, RequestsLPSummary, RequestsSummary, RunResult, SessionSummary, SubmitRequestSummary, + UseLicenseSummary, }; use crate::SeedableRng; use bytes::Bytes; @@ -27,7 +28,7 @@ use rand::rngs::StdRng; use rkyv::{check_archived_root, Deserialize, Infallible}; use std::path::{Path, PathBuf}; use wallet_accessor::{BlockchainAccessConfig, Password, WalletAccessor}; -use zk_citadel::license::License; +use zk_citadel::license::{License, SessionCookie}; /// Commands that can be run against the Moat #[derive(PartialEq, Eq, Hash, Clone, Debug)] @@ -431,7 +432,7 @@ impl Command { license_hash.clone(), ) .await?; - match pos_license { + Ok(match pos_license { Some((pos, license)) => { println!("using license: {}", RunResult::to_hash_hex(&license)); let ssk_user = SecretSpendKey::from_slice( @@ -440,7 +441,7 @@ impl Command { let psk_lp = PublicSpendKey::from_slice( hex::decode(request_json.provider_psk)?.as_slice(), )?; - let _session_id = Self::prove_and_send_use_license( + let (tx_id, session_cookie) = Self::prove_and_send_use_license( blockchain_access_config, wallet_path, psw, @@ -453,12 +454,19 @@ impl Command { setup_holder, ) .await?; + let summary = UseLicenseSummary { + license_blob: RunResult::to_blob(&license), + tx_id: hex::encode(tx_id.to_bytes()), + user_attr: hex::encode(session_cookie.attr.to_bytes()), + session_id: hex::encode( + session_cookie.session_id.to_bytes(), + ), + session_cookie: RunResult::to_blob_hex(&session_cookie), + }; + RunResult::UseLicense(Some(summary)) } - _ => { - println!("Please obtain a license"); - } - } - Ok(RunResult::Empty) + _ => RunResult::UseLicense(None), + }) } /// Command: Get Session @@ -551,7 +559,7 @@ impl Command { gas_limit: u64, gas_price: u64, sh_opt: &mut Option, - ) -> Result { + ) -> Result<(BlsScalar, SessionCookie), Error> { let client = RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); // let (_, _, num_sessions) = CitadelInquirer::get_info(&client).await?; @@ -603,26 +611,6 @@ impl Command { ) .await?; TxAwaiter::wait_for(&client, tx_id).await?; - println!( - "use license executing transaction {} confirmed", - hex::encode(tx_id.to_bytes()) - ); - println!(); - println!("license {} used", RunResult::to_hash_hex(license),); - println!(); - println!( - "session cookie: {}", - RunResult::to_blob_hex(&session_cookie) - ); - println!(); - println!( - "user attributes: {}", - hex::encode(session_cookie.attr.to_bytes()) - ); - println!( - "session id: {}", - hex::encode(session_cookie.session_id.to_bytes()) - ); - Ok(session_cookie.session_id) + Ok((tx_id, session_cookie)) } } diff --git a/moat-cli/src/run_result.rs b/moat-cli/src/run_result.rs index 1d94f83..3a90e74 100644 --- a/moat-cli/src/run_result.rs +++ b/moat-cli/src/run_result.rs @@ -34,6 +34,14 @@ pub struct IssueLicenseSummary { pub license_blob: Vec, } +pub struct UseLicenseSummary { + pub license_blob: Vec, + pub tx_id: String, + pub session_cookie: String, + pub user_attr: String, + pub session_id: String, +} + pub struct SessionSummary { pub session_id: String, pub session: Vec, @@ -52,6 +60,7 @@ pub enum RunResult { RequestsLP(RequestsLPSummary, Vec), IssueLicense(Option), ListLicenses(Range, Vec<(License, bool)>), + UseLicense(Option), GetSession(Option), ShowState(LicenseContractSummary), Empty, @@ -147,6 +156,45 @@ impl fmt::Display for RunResult { } Ok(()) } + UseLicense(summary) => { + match summary { + Some(summary) => { + writeln!( + f, + "using license: {}", + Self::blob_to_hash_hex( + summary.license_blob.as_slice() + ) + )?; + writeln!( + f, + "use license executing transaction {} confirmed", + summary.tx_id + )?; + writeln!(f)?; + writeln!( + f, + "license {} used", + Self::blob_to_hash_hex( + summary.license_blob.as_slice() + ), + )?; + writeln!(f)?; + writeln!( + f, + "session cookie: {}", + summary.session_cookie + )?; + writeln!(f)?; + writeln!(f, "user attributes: {}", summary.user_attr)?; + writeln!(f, "session id: {}", summary.session_id)?; + } + _ => { + writeln!(f, "Please obtain a license")?; + } + } + Ok(()) + } GetSession(summary) => { match summary { Some(summary) => { @@ -200,9 +248,16 @@ impl RunResult { where T: rkyv::Serialize>, { - let blob = rkyv::to_bytes::<_, 16386>(object) - .expect("type should serialize correctly") - .to_vec(); + let blob = Self::to_blob(object); hex::encode(blob) } + + pub fn to_blob(object: &T) -> Vec + where + T: rkyv::Serialize>, + { + rkyv::to_bytes::<_, 16386>(object) + .expect("type should serialize correctly") + .to_vec() + } } From 8cd61b16659c7a005acddaadc871f16d30290cd6 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 7 Nov 2023 23:28:45 +0100 Subject: [PATCH 49/51] Pushed find owner licenses code from int test and cli to the core lib --- .../tests/citadel/int_test_user.rs | 43 ++--------- moat-cli/src/command.rs | 77 ++----------------- .../src/citadel_queries/citadel_inquirer.rs | 66 +++++++++++++++- 3 files changed, 76 insertions(+), 110 deletions(-) diff --git a/integration-tests/tests/citadel/int_test_user.rs b/integration-tests/tests/citadel/int_test_user.rs index ff55517..046c06d 100644 --- a/integration-tests/tests/citadel/int_test_user.rs +++ b/integration-tests/tests/citadel/int_test_user.rs @@ -19,28 +19,25 @@ //! nullifier (or session id) in a collection which stops us from double //! usage of the license) -use bytes::Bytes; use dusk_bls12_381::BlsScalar; use dusk_bytes::DeserializableSlice; use dusk_pki::SecretSpendKey; use dusk_plonk::prelude::*; use dusk_wallet::{RuskHttpClient, WalletPath}; use license_provider::{LicenseIssuer, ReferenceLP}; -use moat_core::Error::InvalidQueryResponse; use moat_core::{ BcInquirer, CitadelInquirer, Error, JsonLoader, LicenseCircuit, LicenseSessionId, LicenseUser, PayloadRetriever, RequestCreator, - RequestJson, RequestSender, StreamAux, TxAwaiter, + RequestJson, RequestSender, TxAwaiter, }; use rand::rngs::StdRng; use rand::SeedableRng; -use rkyv::{check_archived_root, Deserialize, Infallible}; use std::path::PathBuf; use toml_base_config::BaseConfig; use tracing::{info, Level}; use wallet_accessor::BlockchainAccessConfig; use wallet_accessor::Password::PwdHash; -use zk_citadel::license::{License, Request}; +use zk_citadel::license::Request; const WALLET_PATH: &str = concat!(env!("HOME"), "/.dusk/rusk-wallet"); const PWD_HASH: &str = @@ -74,19 +71,6 @@ async fn issue_license( Ok(tx_id) } -/// Deserializes license, panics if deserialization fails. -fn deserialise_license(v: &Vec) -> License { - let response_data = check_archived_root::(v.as_slice()) - .map_err(|_| { - InvalidQueryResponse(Box::from("rkyv deserialization error")) - }) - .expect("License should deserialize correctly"); - let license: License = response_data - .deserialize(&mut Infallible) - .expect("Infallible"); - license -} - /// Displays license contract current state summary. async fn show_state( client: &RuskHttpClient, @@ -104,24 +88,6 @@ async fn show_state( Ok(()) } -/// Finds owned license in a stream of licenses. -/// It searches in a reverse order to return a newest license. -fn find_owned_license( - ssk_user: SecretSpendKey, - stream: &mut (impl futures_core::Stream> - + std::marker::Unpin), -) -> Result<(u64, License), Error> { - const ITEM_LEN: usize = CitadelInquirer::GET_LICENSES_ITEM_LEN; - let (pos, lic_ser) = StreamAux::find_item::<(u64, Vec), ITEM_LEN>( - |(_, lic_vec)| { - let license = deserialise_license(lic_vec); - Ok(ssk_user.view_key().owns(&license.lsa)) - }, - stream, - )?; - Ok((pos, deserialise_license(&lic_ser))) -} - /// /// test user_round_trip realizes the following scenario: /// - creates request (User) @@ -244,8 +210,9 @@ async fn user_round_trip() -> Result<(), Error> { let mut licenses_stream = CitadelInquirer::get_licenses(&client, block_heights).await?; - let (pos, license) = find_owned_license(ssk_user, &mut licenses_stream) - .expect("owned license found"); + let owned_licenses = + CitadelInquirer::find_owned_licenses(ssk_user, &mut licenses_stream)?; + let (pos, license) = owned_licenses.last().expect("owned license found"); // as a User, call get_merkle_opening, obtain opening info!("calling get_merkle_opening (as a user)"); diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 12ebb7d..2edd361 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -11,21 +11,18 @@ use crate::run_result::{ UseLicenseSummary, }; use crate::SeedableRng; -use bytes::Bytes; use dusk_bls12_381::BlsScalar; use dusk_bytes::DeserializableSlice; use dusk_pki::{PublicSpendKey, SecretSpendKey}; use dusk_plonk::prelude::*; use dusk_wallet::{RuskHttpClient, WalletPath}; use license_provider::{LicenseIssuer, ReferenceLP}; -use moat_core::Error::InvalidQueryResponse; use moat_core::{ BcInquirer, CitadelInquirer, Error, JsonLoader, LicenseCircuit, LicenseSessionId, LicenseUser, RequestCreator, RequestJson, RequestScanner, - RequestSender, StreamAux, TxAwaiter, + RequestSender, TxAwaiter, }; use rand::rngs::StdRng; -use rkyv::{check_archived_root, Deserialize, Infallible}; use std::path::{Path, PathBuf}; use wallet_accessor::{BlockchainAccessConfig, Password, WalletAccessor}; use zk_citadel::license::{License, SessionCookie}; @@ -59,71 +56,6 @@ pub(crate) enum Command { ShowState, } -// todo: move this function somewhere else -/// Deserializes license, panics if deserialization fails. -fn deserialise_license(v: &Vec) -> License { - let response_data = check_archived_root::(v.as_slice()) - .map_err(|_| { - InvalidQueryResponse(Box::from("rkyv deserialization error")) - }) - .expect("License should deserialize correctly"); - let license: License = response_data - .deserialize(&mut Infallible) - .expect("Infallible"); - license -} - -// todo: move this function somewhere else -/// Finds owned license in a stream of licenses. -/// It searches in a reverse order to return a newest license. -fn find_owned_licenses( - ssk_user: SecretSpendKey, - stream: &mut (impl futures_core::Stream> - + std::marker::Unpin), -) -> Result, Error> { - const ITEM_LEN: usize = CitadelInquirer::GET_LICENSES_ITEM_LEN; - let mut pairs = vec![]; - loop { - let r = StreamAux::find_item::<(u64, Vec), ITEM_LEN>( - |(_, lic_vec)| { - let license = deserialise_license(lic_vec); - Ok(ssk_user.view_key().owns(&license.lsa)) - }, - stream, - ); - if r.is_err() { - break; - } - let (pos, lic_ser) = r?; - pairs.push((pos, deserialise_license(&lic_ser))) - } - Ok(pairs) -} - -// todo: move this function somewhere else and possibly merge with -// find_owned_licenses -/// Finds owned license in a stream of licenses. -/// It searches in a reverse order to return a newest license. -fn find_all_licenses( - stream: &mut (impl futures_core::Stream> - + std::marker::Unpin), -) -> Result, Error> { - const ITEM_LEN: usize = CitadelInquirer::GET_LICENSES_ITEM_LEN; - let mut pairs = vec![]; - loop { - let r = StreamAux::find_item::<(u64, Vec), ITEM_LEN>( - |_| Ok(true), - stream, - ); - if r.is_err() { - break; - } - let (pos, lic_ser) = r?; - pairs.push((pos, deserialise_license(&lic_ser))) - } - Ok(pairs) -} - // todo: move these consts to their proper place static LABEL: &[u8] = b"dusk-network"; const CAPACITY: usize = 17; // capacity required for the setup @@ -399,7 +331,7 @@ impl Command { hex::decode(request_json.user_ssk.clone())?.as_slice(), )?; - let pairs = find_all_licenses(&mut licenses_stream)?; + let pairs = CitadelInquirer::find_all_licenses(&mut licenses_stream)?; let vk = ssk_user.view_key(); let mut licenses = vec![]; for (_pos, license) in pairs.into_iter() { @@ -534,7 +466,10 @@ impl Command { .as_slice(), )?; - let pairs = find_owned_licenses(ssk_user, &mut licenses_stream)?; + let pairs = CitadelInquirer::find_owned_licenses( + ssk_user, + &mut licenses_stream, + )?; Ok(if pairs.is_empty() { None } else { diff --git a/moat-core/src/citadel_queries/citadel_inquirer.rs b/moat-core/src/citadel_queries/citadel_inquirer.rs index 7175a7c..5b29443 100644 --- a/moat-core/src/citadel_queries/citadel_inquirer.rs +++ b/moat-core/src/citadel_queries/citadel_inquirer.rs @@ -5,7 +5,8 @@ // Copyright (c) DUSK NETWORK. All rights reserved. use crate::error::Error; -use crate::BlockInPlace; +use crate::Error::InvalidQueryResponse; +use crate::{BlockInPlace, StreamAux}; use crate::{ ContractInquirer, LicenseSession, LicenseSessionId, ARITY, DEPTH, GET_INFO_METHOD_NAME, GET_LICENSES_METHOD_NAME, @@ -13,8 +14,10 @@ use crate::{ LICENSE_CONTRACT_ID, }; use bytes::Bytes; +use dusk_pki::SecretSpendKey; use dusk_wallet::RuskHttpClient; use poseidon_merkle::Opening; +use rkyv::{check_archived_root, Deserialize, Infallible}; use std::ops::Range; use zk_citadel::license::License; @@ -80,4 +83,65 @@ impl CitadelInquirer { ) .await } + + /// Deserializes license, panics if deserialization fails. + fn deserialise_license(v: &Vec) -> License { + let response_data = check_archived_root::(v.as_slice()) + .map_err(|_| { + InvalidQueryResponse(Box::from("rkyv deserialization error")) + }) + .expect("License should deserialize correctly"); + let license: License = response_data + .deserialize(&mut Infallible) + .expect("Infallible"); + license + } + + /// Finds owned license in a stream of licenses. + /// It searches in a reverse order to return a newest license. + pub fn find_owned_licenses( + ssk_user: SecretSpendKey, + stream: &mut (impl futures_core::Stream> + + std::marker::Unpin), + ) -> Result, Error> { + const ITEM_LEN: usize = CitadelInquirer::GET_LICENSES_ITEM_LEN; + let mut pairs = vec![]; + loop { + let r = StreamAux::find_item::<(u64, Vec), ITEM_LEN>( + |(_, lic_vec)| { + let license = Self::deserialise_license(lic_vec); + Ok(ssk_user.view_key().owns(&license.lsa)) + }, + stream, + ); + if r.is_err() { + break; + } + let (pos, lic_ser) = r?; + pairs.push((pos, Self::deserialise_license(&lic_ser))) + } + Ok(pairs) + } + + /// Finds owned license in a stream of licenses. + /// It searches in a reverse order to return a newest license. + pub fn find_all_licenses( + stream: &mut (impl futures_core::Stream> + + std::marker::Unpin), + ) -> Result, Error> { + const ITEM_LEN: usize = CitadelInquirer::GET_LICENSES_ITEM_LEN; + let mut pairs = vec![]; + loop { + let r = StreamAux::find_item::<(u64, Vec), ITEM_LEN>( + |_| Ok(true), + stream, + ); + if r.is_err() { + break; + } + let (pos, lic_ser) = r?; + pairs.push((pos, Self::deserialise_license(&lic_ser))) + } + Ok(pairs) + } } From 80a05f4c5a0b0c192d4cdb67d0f99b41bc3cf661 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Tue, 7 Nov 2023 23:32:04 +0100 Subject: [PATCH 50/51] Cosmetic - removed todo --- moat-cli/src/command.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index 2edd361..eea8ed4 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -56,7 +56,6 @@ pub(crate) enum Command { ShowState, } -// todo: move these consts to their proper place static LABEL: &[u8] = b"dusk-network"; const CAPACITY: usize = 17; // capacity required for the setup From 923f07cbcca86707e853faef681fb4b2c3b5f295 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Wed, 8 Nov 2023 11:56:43 +0100 Subject: [PATCH 51/51] Adjusted to zk-citadel 0.5.1 --- license-provider/src/license_issuer.rs | 4 ++-- moat-cli/src/command.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/license-provider/src/license_issuer.rs b/license-provider/src/license_issuer.rs index b73408a..85a9c4e 100644 --- a/license-provider/src/license_issuer.rs +++ b/license-provider/src/license_issuer.rs @@ -26,7 +26,7 @@ pub struct LicenseIssuer { gas_price: u64, } -const USER_ATTRIBUTES: u64 = 1 << 17; +const ATTRIBUTE_DATA: u64 = 1 << 17; impl LicenseIssuer { pub fn new( @@ -51,7 +51,7 @@ impl LicenseIssuer { request: &Request, ssk_lp: &SecretSpendKey, ) -> Result<(BlsScalar, Vec), Error> { - let attr = JubJubScalar::from(USER_ATTRIBUTES); + let attr = JubJubScalar::from(ATTRIBUTE_DATA); let license = License::new(&attr, ssk_lp, request, rng); let license_blob = rkyv::to_bytes::<_, MAX_LICENSE_SIZE>(&license) .expect("License should serialize correctly") diff --git a/moat-cli/src/command.rs b/moat-cli/src/command.rs index eea8ed4..9c1f8b4 100644 --- a/moat-cli/src/command.rs +++ b/moat-cli/src/command.rs @@ -388,7 +388,7 @@ impl Command { let summary = UseLicenseSummary { license_blob: RunResult::to_blob(&license), tx_id: hex::encode(tx_id.to_bytes()), - user_attr: hex::encode(session_cookie.attr.to_bytes()), + user_attr: hex::encode(session_cookie.attr_data.to_bytes()), session_id: hex::encode( session_cookie.session_id.to_bytes(), ),