Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

My/pay as bid #3

Merged
merged 23 commits into from
Aug 24, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
NODE_URL=
NODE_PORT=
WORKER_URL=
TRUSTED_WORKER_PORT=
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@
venv/**

# user data
my_keystore/**
my_keystore/**

# ignore the .env file
.env
74 changes: 74 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,77 @@ python run_integritee_cli.py
```
rustup target add --toolchain nightly wasm32-unknown-unknown
```

## Using Environment Variables

Please follow these steps to set up and use environment variables:

1. Copy the `.env.example` file and rename it to `.env`:

```bash
$ cp .env.example .env
```

2. Open the `.env` file and provide values for the environment variables.
3. Install the necessary dependencies by running:

```bash
$ pip install -r requirements.txt
```

## Run the Client

The `integritee-cli-py` is now configured for the following commands:

- Get help:
```bash
$ python3 run_integritee_cli.py --help

# output
usage: run_integritee_cli.py [-h] [--command {new_account_cmd,new_trusted_account_cmd,pay_as_bid_cmd,get_market_results_cmd,pay_as_bid_proof_cmd,verify_proof_cmd}] [--params PARAMS [PARAMS ...]]

Run Rust CLI with specific commands

options:
-h, --help show this help message and exit
--command {new_account_cmd,new_trusted_account_cmd,pay_as_bid_cmd,get_market_results_cmd,pay_as_bid_proof_cmd,verify_proof_cmd}
Please specify the command to run
--params PARAMS [PARAMS ...]
Parameters for the command
```

- Create a new account: `$ python3 run_integritee_cli.py --command new_account_cmd`

- Create a new trusted account: `$ python3 run_integritee_cli.py --command new_trusted_account_cmd --params <MRENCLAVE>`

- Pay As Bid:
```bash
$ python3 run_integritee_cli.py --command pay_as_bid_cmd --params <MRENCLAVE> <ACCOUNT> <ORDERS_STRING>

# Sample command
$ python3 run_integritee_cli.py --command pay_as_bid_cmd --params 9PPeGELLdD9Uw1mVJbUGTeRpGzPBGb1bdEk6TCL4pPCE 5Dsni69ozXZZwpxyCGjLq8KQnBpGrtPnbykepgst2Tbh7NuY "[{\"id\":0,\"order_type\":\"ask\",\"time_slot\":\"2022-10-04T05:06:07+00:00\",\"actor_id\":\"actor_0\",\"cluster_index\":0,\"energy_kwh\":5,\"price_euro_per_kwh\":0.19},{\"id\":1,\"order_type\":\"bid\",\"time_slot\":\"2022-10-04T05:06:07+00:00\",\"actor_id\":\"actor_1\",\"cluster_index\":0,\"energy_kwh\":8.8,\"price_euro_per_kwh\":0.23}]"
```

- Get Market Results:
```bash
$ python3 run_integritee_cli.py --command get_market_results_cmd --params <MRENCLAVE> <ACCOUNT> <TIMESTAMP>

# Sample command
$ python3 run_integritee_cli.py --command get_market_results_cmd --params 9PPeGELLdD9Uw1mVJbUGTeRpGzPBGb1bdEk6TCL4pPCE 5Dsni69ozXZZwpxyCGjLq8KQnBpGrtPnbykepgst2Tbh7NuY 2022-10-04T05:06:07+00:00
```

- Get Bid Proof:
```bash
$ python3 run_integritee_cli.py --command pay_as_bid_proof_cmd --params <MRENCLAVE> <ACCOUNT> <TIMESTAMP> <ACTOR_ID>

# Sample command
$ python3 run_integritee_cli.py --command pay_as_bid_proof_cmd --params 9PPeGELLdD9Uw1mVJbUGTeRpGzPBGb1bdEk6TCL4pPCE 5Dsni69ozXZZwpxyCGjLq8KQnBpGrtPnbykepgst2Tbh7NuY 2022-10-04T05:06:07+00:00 actor_0
```

- Verify Proof:
```bash
$ python3 run_integritee_cli.py --command verify_proof_cmd --params <MRENCLAVE> <ACCOUNT> <MERKLE_PROOF_JSON>

# Sample command
python3 run_integritee_cli.py --command verify_proof_cmd --params 9PPeGELLdD9Uw1mVJbUGTeRpGzPBGb1bdEk6TCL4pPCE 5Dsni69ozXZZwpxyCGjLq8KQnBpGrtPnbykepgst2Tbh7NuY "{\"root\":\"0xeae9131721b25db95622605c99a62f56f2e3b47e7f54f9b0653055b11b8d37b8\",\"proof\":[\"0xf147000d21d56a303b688da5bf1294d865518a8fb889af48ca21d12af5a6d823\"],\"number_of_leaves\":2,\"leaf_index\":0,\"leaf\":[0,0,0,0,0,0,0,0,1,100,50,48,50,50,45,49,48,45,48,52,84,48,53,58,48,54,58,48,55,43,48,48,58,48,48,28,97,99,116,111,114,95,48,1,0,0,0,0,0,0,0,0,0,0,20,64,82,184,30,133,235,81,200,63]}"
```
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
python-dotenv
argparse
82 changes: 76 additions & 6 deletions run_integritee_cli.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,81 @@
import os
from dotenv import load_dotenv
import argparse
import sys
import integritee_cli_py

node_url = "ws://127.0.0.1"
node_port = "9944"
worker_url = "wss://127.0.0.1"
trusted_worker_port = "2000"

# Load environment variables from .env file
load_dotenv()

# Access environment variables
NODE_URL = os.getenv("NODE_URL")
NODE_PORT = os.getenv("NODE_PORT")
WORKER_URL = os.getenv("WORKER_URL")
TRUSTED_WORKER_PORT = os.getenv("TRUSTED_WORKER_PORT")

# Mapping commands to their required parameter names
COMMAND_PARAMETER_INFO = {
"new_account_cmd": ([], 0),
"new_trusted_account_cmd": (
[
"mrenclave",
],
1,
),
"pay_as_bid_cmd": (["mrenclave", "account", "orders_string"], 3),
"get_market_results_cmd": (["mrenclave", "account", "timestamp"], 3),
"pay_as_bid_proof_cmd": (["mrenclave", "account", "timestamp", "actor_id"], 4),
"verify_proof_cmd": (["mrenclave", "account", "merkle_proof_json"], 3),
}


def validate_parameters(command, params):
required_params, required_count = COMMAND_PARAMETER_INFO.get(command, ([], 0))
if len(params) != required_count:
missing_params = required_count - len(params)
param_names = ", ".join(required_params)
raise argparse.ArgumentError(
None,
f"{command} requires {missing_params} more parameter(s): {param_names}",
)


if __name__ == "__main__":
integritee_cli_py.run_cli(node_url, node_port, worker_url, trusted_worker_port, "balanced")
print("TERMINATE")
parser = argparse.ArgumentParser(description="Run Rust CLI with specific commands")
parser.add_argument(
"--command",
type=str,
choices=COMMAND_PARAMETER_INFO.keys(),
help="Please specify the command to run",
)

parser.add_argument(
"--params",
nargs="+",
default=[],
help="Parameters for the command",
)

args = parser.parse_args()

if not args.command:
parser.print_help()
sys.exit(1)

try:
validate_parameters(args.command, args.params)

except argparse.ArgumentError as e:
print(str(e))
parser.print_help()
sys.exit(1)

try:
command_name = args.command
params = args.params
integritee_cli_py.run_cli(
NODE_URL, NODE_PORT, WORKER_URL, TRUSTED_WORKER_PORT, command_name, params
)
except Exception as e:
print("Encountered an error:", e)
125 changes: 109 additions & 16 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,56 @@ use pyo3::wrap_pyfunction;

// Import the RPC client
// use clap::Parser;
use integritee_cli::{commands, Cli, trusted_cli::TrustedCli};
use integritee_cli::commands::{BaseCommand, Commands};
use integritee_cli::trusted_cli::{PayAsBidCommand, TrustedBaseCommand, TrustedCommand};
use integritee_cli::trusted_cli::{
GetMarketResultsCommand, PayAsBidCommand, PayAsBidProofCommand, TrustedBaseCommand,
TrustedCommand, VerifyMerkleProofCommand,
};
use integritee_cli::{commands, trusted_cli::TrustedCli, Cli};

#[pymodule]
fn integritee_cli_py(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(run_cli, m)?)?;
Ok(())
}

#[pyfunction]
fn run_cli(node_url: String, node_port: String, worker_url: String, trusted_worker_port: String, _command: String) -> PyResult<()> {
println!("Run Cli");
fn find_command(command_name: &str, params: &[String]) -> Commands {
match command_name {
"new_account_cmd" => new_account_cmd(),
"new_trusted_account_cmd" => new_trusted_account_cmd(&params),
"pay_as_bid_cmd" => pay_as_bid_cmd(&params),
"get_market_results_cmd" => get_market_results_cmd(&params),
"pay_as_bid_proof_cmd" => pay_as_bid_proof_cmd(&params),
"verify_proof_cmd" => verify_proof_cmd(&params),
_ => panic!("Invalid command name"),
}
}

#[pyfunction]
fn run_cli(
node_url: String,
node_port: String,
worker_url: String,
trusted_worker_port: String,
command_name: String,
params: Vec<String>,
) -> PyResult<()> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should return value e.g. the created account string (which could be put also inside a dictionary) or the matches as Python Dict/List:
Could be similar to the following example for returning a python List of dictionaries:

    // Convert MarketOutput to Python List of Dict representing matches
    let pyMatches = PyList::new(py,
        matches.matches.into_iter().map(|mtch| {
            let dict = PyDict::new(py);
            dict.set_item("time", mtch.energy_kwh);
            dict.set_item("bid_id", mtch.bid_id);
            dict.set_item("ask_id", mtch.ask_id);
            dict.set_item("bid_actor", "");
            dict.set_item("ask_actor", "");
            dict.set_item("bid_cluster", 0);
            dict.set_item("ask_cluster", 0);
            dict.set_item("energy", mtch.energy_kwh);
            dict.set_item("price", mtch.price_euro_per_kwh);
            dict.set_item("included_grid_fee", 0);
            dict
        })
    );

As both types are different the account string or the match list could be it self returned within a dictionary with a specific key, i.e. {"account": account_string} or {"matches": pyMatches}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with the adapted algorithm, I might add some information to the matches returned by simplyr-lib both for pay as bid as well as the cluster-based matching

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created issue #5 can be changed in subsequent PR

let cli = Cli {
node_url,
node_port,
worker_url,
trusted_worker_port,
command: new_account_cmd(),
// command: pay_as_bid_cmd(),
command: find_command(&command_name, &params),
};

match command_name.as_str() {
"new_account_cmd" => new_account_cmd(),
"new_trusted_account_cmd" => new_trusted_account_cmd(&params),
"pay_as_bid_cmd" => pay_as_bid_cmd(&params),
"get_market_results_cmd" => get_market_results_cmd(&params),
"pay_as_bid_proof_cmd" => pay_as_bid_proof_cmd(&params),
"verify_proof_cmd" => verify_proof_cmd(&params),
_ => panic!("Invalid command name"),
};

commands::match_command(&cli).unwrap();
Expand All @@ -36,10 +65,11 @@ fn new_account_cmd() -> Commands {
}

/// Create a new trusted account in the enclave.
fn new_trusted_account_cmd() -> Commands {
Commands::Trusted(TrustedCli{
fn new_trusted_account_cmd(params: &[String]) -> Commands {
let mrenclave = &params[0];
Commands::Trusted(TrustedCli {
// random mrenclave, has to be replaced with one that has been fetched from the chain.
mrenclave: "4GMb72Acyg8hnnnGEJ89jZK5zxNC4LvSe2ME96wLRV6J".to_string(),
mrenclave: mrenclave.to_string(),
shard: None,
// signers and accounts starting with `//` will be recognized as dev-seeds and can
// always be used without first creating them in the keystore.
Expand All @@ -51,19 +81,82 @@ fn new_trusted_account_cmd() -> Commands {

// just a skeleton to see if the cli understands it. It will never return a successful result.
// We need to fill in some actual meaningful values.
fn pay_as_bid_cmd() -> Commands {
Commands::Trusted(TrustedCli{
fn pay_as_bid_cmd(params: &[String]) -> Commands {
let mrenclave = &params[0];
let account = &params[1];
let orders_string = &params[2];
Commands::Trusted(TrustedCli {
// random mrenclave, has to be replaced with one that has been fetched from the chain.
mrenclave: "4GMb72Acyg8hnnnGEJ89jZK5zxNC4LvSe2ME96wLRV6J".to_string(),
mrenclave: mrenclave.to_string(),
shard: None,
// signers and accounts starting with `//` will be recognized as dev-seeds and can
// always be used without first creating them in the keystore.
xt_signer: "//Alice".to_string(),
xt_signer: account.to_string(),
direct: true,
command: TrustedCommand::BaseTrusted(TrustedBaseCommand::PayAsBid(PayAsBidCommand {
account: "//Alice".to_string(),
orders_string: "".to_string(),
account: account.to_string(),
orders_string: orders_string.to_string(),
})),
})
}

fn get_market_results_cmd(params: &[String]) -> Commands {
let mrenclave = &params[0];
let account = &params[1];
let timestamp = &params[2];
Commands::Trusted(TrustedCli {
// random mrenclave, has to be replaced with one that has been fetched from the chain.
mrenclave: mrenclave.to_string(),
shard: None,
// signers and accounts starting with `//` will be recognized as dev-seeds and can
// always be used without first creating them in the keystore.
xt_signer: account.to_string(),
direct: true,
command: TrustedCommand::BaseTrusted(TrustedBaseCommand::GetMarketResults(
GetMarketResultsCommand {
account: account.to_string(),
timestamp: timestamp.to_string(),
},
)),
})
}

fn pay_as_bid_proof_cmd(params: &[String]) -> Commands {
let mrenclave = &params[0];
let account = &params[1];
let timestamp = &params[2];
let actor_id = &params[3];
Commands::Trusted(TrustedCli {
// random mrenclave, has to be replaced with one that has been fetched from the chain.
mrenclave: mrenclave.to_string(),
shard: None,
// signers and accounts starting with `//` will be recognized as dev-seeds and can
// always be used without first creating them in the keystore.
xt_signer: account.to_string(),
direct: true,
command: TrustedCommand::BaseTrusted(TrustedBaseCommand::PayAsBidProof(
PayAsBidProofCommand {
account: account.to_string(),
timestamp: timestamp.to_string(),
actor_id: actor_id.to_string(),
},
)),
})
}

fn verify_proof_cmd(params: &[String]) -> Commands {
let mrenclave = &params[0];
let account = &params[1];
let merkle_proof_json = &params[2];
Commands::Trusted(TrustedCli {
mrenclave: mrenclave.to_string(),
shard: None,
xt_signer: account.to_string(),
direct: true,
command: TrustedCommand::BaseTrusted(TrustedBaseCommand::VerifyProof(
VerifyMerkleProofCommand {
merkle_proof_json: merkle_proof_json.to_string(),
},
)),
})
}