From 2fc7963ac408d44a38521aa9411f7b7531dd397c Mon Sep 17 00:00:00 2001 From: "Sam H. Smith" Date: Mon, 29 Jan 2024 21:20:31 +0100 Subject: [PATCH] [fix] #160: Register and Query Account Signed-off-by: Sam H. Smith --- docs-recipes/4.register-account.py | 50 +++++++++++++++++++++++++++ src/client.rs | 55 ++++++++++++++++++++++-------- src/data_model/crypto.rs | 31 ++++++++++------- src/isi.rs | 29 +++++++++++++--- 4 files changed, 134 insertions(+), 31 deletions(-) create mode 100644 docs-recipes/4.register-account.py diff --git a/docs-recipes/4.register-account.py b/docs-recipes/4.register-account.py new file mode 100644 index 00000000..ed50b74a --- /dev/null +++ b/docs-recipes/4.register-account.py @@ -0,0 +1,50 @@ +import iroha + +key_pair = iroha.KeyPair.from_json(""" +{ + "public_key": "ed01207233BFC89DCBD68C19FDE6CE6158225298EC1131B6A130D1AEB454C1AB5183C0", + "private_key": { + "digest_function": "ed25519", + "payload": "9ac47abf59b356e0bd7dcbbbb4dec080e302156a48ca907e47cb6aea1d32719e7233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0" + } +} +""") + +account_id = "alice@wonderland" +web_login = "mad_hatter" +password = "ilovetea" +api_url = "http://127.0.0.1:8080/" +telemetry_url = "http://127.0.0.1:8180/" + +client = iroha.Client.create( + key_pair, + account_id, + web_login, + password, + api_url) + +new_account_key_pair = iroha.KeyGenConfiguration.default().use_seed_hex("abcd1122").generate() +new_account_id = "white_rabbit@wonderland" + +accounts = client.query_all_accounts_in_domain("wonderland") + +print("Listing all accounts in wonderland...") +for a in accounts: + print(" - ", a,) + +if new_account_id in accounts: + print("'white_rabbit@wonderland' domain already exists.") + +register = iroha.Instruction.register_account(new_account_id, [new_account_key_pair.public_key]) + +client.submit_executable([register]) + +while True: + accounts = client.query_all_accounts_in_domain("wonderland") + + if new_account_id in accounts: + break + +print("Listing all accounts in wonderland...") +for a in accounts: + print(" - ", a,) \ No newline at end of file diff --git a/src/client.rs b/src/client.rs index b5121d5f..274a936c 100644 --- a/src/client.rs +++ b/src/client.rs @@ -7,14 +7,15 @@ use pyo3::{ use iroha_client::client::Client as IrohaClient; use iroha_config::client::*; -use std::str::FromStr; use std::num::NonZeroU64; +use std::str::FromStr; use crate::data_model::asset::{PyAsset, PyAssetDefinition, PyAssetDefinitionId, PyAssetId}; use crate::data_model::crypto::*; -use iroha_data_model::account::AccountId; use crate::data_model::PyMirror; use crate::{data_model::account::PyAccountId, isi::PyInstruction}; +use iroha_data_model::account::AccountId; +use iroha_data_model::prelude::DomainId; #[allow(unsafe_code)] const DEFAULT_TRANSACTION_TIME_TO_LIVE_MS: NonZeroU64 = @@ -40,12 +41,15 @@ impl Client { let config = Configuration { public_key: key_pair.0.public_key().clone(), private_key: key_pair.0.private_key().clone(), - account_id: AccountId::from_str(account_id).map_err(|e| PyValueError::new_err(e.to_string()))?, + account_id: AccountId::from_str(account_id) + .map_err(|e| PyValueError::new_err(e.to_string()))?, basic_auth: Some(BasicAuth { - web_login: WebLogin::from_str(web_login).map_err(|e| PyValueError::new_err(e.to_string()))?, + web_login: WebLogin::from_str(web_login) + .map_err(|e| PyValueError::new_err(e.to_string()))?, password: iroha_primitives::small::SmallStr::from_str(password), }), - torii_api_url: url::Url::parse(api_url).map_err(|e| PyValueError::new_err(e.to_string()))?, + torii_api_url: url::Url::parse(api_url) + .map_err(|e| PyValueError::new_err(e.to_string()))?, transaction_time_to_live_ms: Some(DEFAULT_TRANSACTION_TIME_TO_LIVE_MS), transaction_status_timeout_ms: DEFAULT_TRANSACTION_STATUS_TIMEOUT_MS, // deprecated, does nothing. @@ -69,22 +73,43 @@ impl Client { .map(|hash| hash.to_string()) .map_err(|e| PyRuntimeError::new_err(format!("Error submitting instruction: {}", e))) } - + fn query_all_domains(&self) -> PyResult> { let query = iroha_data_model::query::prelude::FindAllDomains {}; - - let val = self.client.request(query) + + let val = self + .client + .request(query) + .map_err(|e| PyRuntimeError::new_err(format!("{e:?}")))?; + + let mut items = Vec::new(); + for item in val { + items.push( + item.map(|d| d.id.to_string()) + .map_err(|e| PyRuntimeError::new_err(format!("{e:?}")))?, + ); + } + Ok(items) + } + + fn query_all_accounts_in_domain(&self, domain_id: &str) -> PyResult> { + let query = iroha_data_model::query::prelude::FindAccountsByDomainId { + domain_id: DomainId::from_str(domain_id) + .map_err(|e| PyValueError::new_err(e.to_string()))? + .into(), + }; + + let val = self + .client + .request(query) .map_err(|e| PyRuntimeError::new_err(format!("{e:?}")))?; - + let mut items = Vec::new(); for item in val { items.push( - item - .map(|d| d.id.to_string()) - .map_err(|e| - PyRuntimeError::new_err(format!("{e:?}")) - )? - ); + item.map(|d| d.id.to_string()) + .map_err(|e| PyRuntimeError::new_err(format!("{e:?}")))?, + ); } Ok(items) } diff --git a/src/data_model/crypto.rs b/src/data_model/crypto.rs index 797e9720..417c6a9e 100644 --- a/src/data_model/crypto.rs +++ b/src/data_model/crypto.rs @@ -3,7 +3,7 @@ use pyo3::{ prelude::*, }; -use iroha_crypto::{Algorithm, KeyPair, PrivateKey, PublicKey, KeyGenConfiguration}; +use iroha_crypto::{Algorithm, KeyGenConfiguration, KeyPair, PrivateKey, PublicKey}; use super::PyMirror; @@ -78,12 +78,18 @@ impl PyKeyPair { .map_err(|e| PyRuntimeError::new_err(format!("Failed to generate keypair: {e}")))?; Ok(PyKeyPair(kp)) } - + #[staticmethod] fn from_json(json_str: &str) -> PyResult { - serde_json::from_str::(json_str).map(|k| k.into()).map_err(|error| { - PyErr::new::(format!("Error: Failed to deserialize keypair: {}", error)) - }).into() + serde_json::from_str::(json_str) + .map(|k| k.into()) + .map_err(|error| { + PyErr::new::(format!( + "Error: Failed to deserialize keypair: {}", + error + )) + }) + .into() } #[getter] @@ -121,18 +127,20 @@ impl PyKeyGenConfiguration { } fn use_seed_hex(&self, hex_str: &str) -> PyResult { - let seed = hex::decode(hex_str).map_err(|e| PyValueError::new_err(format!("Invalid hex string: {e}")))?; - let copy : KeyGenConfiguration = self.clone().into(); + let seed = hex::decode(hex_str) + .map_err(|e| PyValueError::new_err(format!("Invalid hex string: {e}")))?; + let copy: KeyGenConfiguration = self.clone().into(); Ok(copy.use_seed(seed).into()) } - + fn use_private_key(&self, private_key: PyPrivateKey) -> PyResult { - let copy : KeyGenConfiguration = self.clone().into(); + let copy: KeyGenConfiguration = self.clone().into(); Ok(copy.use_private_key(private_key.into()).into()) } - + fn generate(&self) -> PyResult { - let kp = KeyPair::generate_with_configuration(self.0.clone()).map_err(|e| PyRuntimeError::new_err(format!("Failed to generate keypair: {e}")))?; + let kp = KeyPair::generate_with_configuration(self.0.clone()) + .map_err(|e| PyRuntimeError::new_err(format!("Failed to generate keypair: {e}")))?; Ok(PyKeyPair(kp)) } @@ -141,7 +149,6 @@ impl PyKeyGenConfiguration { } } - pub fn register_items(_py: Python<'_>, module: &PyModule) -> PyResult<()> { module.add_class::()?; module.add_class::()?; diff --git a/src/isi.rs b/src/isi.rs index b2f94c35..01313a3b 100644 --- a/src/isi.rs +++ b/src/isi.rs @@ -1,8 +1,9 @@ +use iroha_data_model::account::NewAccount; +use iroha_data_model::domain::NewDomain; use iroha_data_model::isi::{ InstructionExpr, MintExpr, RegisterExpr, TransferExpr, UnregisterExpr, }; -use iroha_data_model::domain::NewDomain; -use iroha_data_model::prelude::DomainId; +use iroha_data_model::prelude::*; use iroha_data_model::NumericValue; use pyo3::{exceptions::PyValueError, prelude::*}; @@ -10,6 +11,7 @@ use std::str::FromStr; use crate::data_model::account::{PyAccountId, PyNewAccount}; use crate::data_model::asset::{PyAssetDefinitionId, PyAssetId, PyNewAssetDefinition}; +use crate::data_model::crypto::*; use crate::data_model::domain::{PyDomainId, PyNewDomain}; #[derive(Debug, Clone)] @@ -44,7 +46,7 @@ impl PyInstruction { "Only registration of accounts, asset definitions and domains is supported", )) } - + #[staticmethod] /// Create an instruction for registering a new domain. fn register_domain(domain_id: &str) -> PyResult { @@ -53,7 +55,26 @@ impl PyInstruction { logo: None, metadata: Default::default(), }; - return Ok(PyInstruction(InstructionExpr::Register(RegisterExpr::new(new_domain_object)))); + return Ok(PyInstruction(InstructionExpr::Register(RegisterExpr::new( + new_domain_object, + )))); + } + + #[staticmethod] + /// Create an instruction for registering a new domain. + fn register_account( + account_id: &str, + public_keys: Vec, + ) -> PyResult { + let new_account_object = NewAccount { + id: AccountId::from_str(account_id) + .map_err(|e| PyValueError::new_err(e.to_string()))?, + signatories: public_keys.into_iter().map(|x| x.into()).collect(), + metadata: Metadata::default(), + }; + return Ok(PyInstruction(InstructionExpr::Register(RegisterExpr::new( + new_account_object, + )))); } #[staticmethod]