Skip to content

Commit

Permalink
[fix] hyperledger-iroha#160: Register and Query Account
Browse files Browse the repository at this point in the history
Signed-off-by: Sam H. Smith <sam.henning.smith@protonmail.com>
  • Loading branch information
SamHSmith committed Jan 29, 2024
1 parent d2b1837 commit 4a9b430
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 31 deletions.
50 changes: 50 additions & 0 deletions docs-recipes/4.register-account.py
Original file line number Diff line number Diff line change
@@ -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,)
55 changes: 40 additions & 15 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -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.
Expand All @@ -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<Vec<String>> {
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<Vec<String>> {
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)
}
Expand Down
31 changes: 19 additions & 12 deletions src/data_model/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<Self> {
serde_json::from_str::<KeyPair>(json_str).map(|k| k.into()).map_err(|error| {
PyErr::new::<PyValueError, _>(format!("Error: Failed to deserialize keypair: {}", error))
}).into()
serde_json::from_str::<KeyPair>(json_str)
.map(|k| k.into())
.map_err(|error| {
PyErr::new::<PyValueError, _>(format!(
"Error: Failed to deserialize keypair: {}",
error
))
})
.into()
}

#[getter]
Expand Down Expand Up @@ -121,18 +127,20 @@ impl PyKeyGenConfiguration {
}

fn use_seed_hex(&self, hex_str: &str) -> PyResult<Self> {
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<Self> {
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<PyKeyPair> {
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))
}

Expand All @@ -141,7 +149,6 @@ impl PyKeyGenConfiguration {
}
}


pub fn register_items(_py: Python<'_>, module: &PyModule) -> PyResult<()> {
module.add_class::<PyPrivateKey>()?;
module.add_class::<PyPublicKey>()?;
Expand Down
29 changes: 25 additions & 4 deletions src/isi.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
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::*};

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)]
Expand Down Expand Up @@ -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<PyInstruction> {
Expand All @@ -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<PyPublicKey>,
) -> PyResult<PyInstruction> {
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]
Expand Down

0 comments on commit 4a9b430

Please sign in to comment.