diff --git a/cli/src/torii/tests.rs b/cli/src/torii/tests.rs index d2d7b89c0af..cbb07b04ba6 100644 --- a/cli/src/torii/tests.rs +++ b/cli/src/torii/tests.rs @@ -258,10 +258,13 @@ fn register_account(name: &str) -> Instruction { } fn register_asset_definition(name: &str) -> Instruction { - RegisterBox::new(AssetDefinition::new_quantity(AssetDefinitionId::new( - name.parse().expect("Valid"), - DOMAIN.parse().expect("Valid"), - ))) + RegisterBox::new( + AssetDefinition::quantity(AssetDefinitionId::new( + name.parse().expect("Valid"), + DOMAIN.parse().expect("Valid"), + )) + .build(), + ) .into() } diff --git a/client/benches/torii.rs b/client/benches/torii.rs index 15b04f96f80..a829a1e6f92 100644 --- a/client/benches/torii.rs +++ b/client/benches/torii.rs @@ -59,7 +59,8 @@ fn query_requests(criterion: &mut Criterion) { .public_key], )); let asset_definition_id = AssetDefinitionId::new("xor".parse().expect("Valid"), domain_id); - let create_asset = RegisterBox::new(AssetDefinition::new_quantity(asset_definition_id.clone())); + let create_asset = + RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).build()); let quantity: u32 = 200; let mint_asset = MintBox::new( Value::U32(quantity), diff --git a/client/examples/million_accounts_genesis.rs b/client/examples/million_accounts_genesis.rs index cbf088707fd..e7b7ce34a81 100644 --- a/client/examples/million_accounts_genesis.rs +++ b/client/examples/million_accounts_genesis.rs @@ -20,9 +20,12 @@ fn main() { PublicKey::default(), ) .with_asset( - format!("xor-{}", i).parse().expect("Valid"), - AssetValueType::Quantity, - false, + AssetDefinition::quantity( + format!("xor-{}", i) + .parse::<::Id>() + .expect("Valid"), + ) + .build(), ) .finish_domain(); } diff --git a/client/tests/integration/add_asset.rs b/client/tests/integration/add_asset.rs index 7c67b442247..f006d7c84c4 100644 --- a/client/tests/integration/add_asset.rs +++ b/client/tests/integration/add_asset.rs @@ -17,7 +17,8 @@ fn client_add_asset_quantity_to_existing_asset_should_increase_asset_amount() -> // Given let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::new_quantity(asset_definition_id.clone())); + let create_asset = + RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).build()); let metadata = iroha_data_model::metadata::UnlimitedMetadata::default(); //When let quantity: u32 = 200; @@ -48,9 +49,8 @@ fn client_add_big_asset_quantity_to_existing_asset_should_increase_asset_amount( // Given let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::new_big_quantity( - asset_definition_id.clone(), - )); + let create_asset = + RegisterBox::new(AssetDefinition::big_quantity(asset_definition_id.clone()).build()); let metadata = iroha_data_model::metadata::UnlimitedMetadata::default(); //When let quantity: u128 = 2_u128.pow(65); @@ -80,7 +80,7 @@ fn client_add_asset_with_decimal_should_increase_asset_amount() -> Result<()> { // Given let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); - let identifiable_box = AssetDefinition::new_fixed_precision(asset_definition_id.clone()); + let identifiable_box = AssetDefinition::fixed(asset_definition_id.clone()).build(); let create_asset = RegisterBox::new(identifiable_box); let metadata = iroha_data_model::metadata::UnlimitedMetadata::default(); @@ -132,18 +132,16 @@ fn client_add_asset_with_name_length_more_than_limit_should_not_commit_transacti // Given let normal_asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::new_quantity( - normal_asset_definition_id.clone(), - )); + let create_asset = + RegisterBox::new(AssetDefinition::quantity(normal_asset_definition_id.clone()).build()); test_client.submit(create_asset)?; iroha_logger::info!("Creating asset"); let too_long_asset_name = "0".repeat(2_usize.pow(14)); let incorrect_asset_definition_id = AssetDefinitionId::from_str(&(too_long_asset_name + "#wonderland")).expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::new_quantity( - incorrect_asset_definition_id.clone(), - )); + let create_asset = + RegisterBox::new(AssetDefinition::quantity(incorrect_asset_definition_id.clone()).build()); test_client.submit(create_asset)?; iroha_logger::info!("Creating another asset"); diff --git a/client/tests/integration/asset_propagation.rs b/client/tests/integration/asset_propagation.rs index 3b7c3f3fa41..a3944bed10d 100644 --- a/client/tests/integration/asset_propagation.rs +++ b/client/tests/integration/asset_propagation.rs @@ -25,7 +25,8 @@ fn client_add_asset_quantity_to_existing_asset_should_increase_asset_amount_on_a [KeyPair::generate()?.public_key], )); let asset_definition_id = AssetDefinitionId::from_str("xor#domain")?; - let create_asset = RegisterBox::new(AssetDefinition::new_quantity(asset_definition_id.clone())); + let create_asset = + RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).build()); iroha_client.submit_all(vec![ create_domain.into(), create_account.into(), diff --git a/client/tests/integration/multiple_blocks_created.rs b/client/tests/integration/multiple_blocks_created.rs index 641b35bb207..092e4ab7a65 100644 --- a/client/tests/integration/multiple_blocks_created.rs +++ b/client/tests/integration/multiple_blocks_created.rs @@ -28,7 +28,8 @@ fn long_multiple_blocks_created() { .public_key], )); let asset_definition_id: AssetDefinitionId = "xor#domain".parse().expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::new_quantity(asset_definition_id.clone())); + let create_asset = + RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).build()); iroha_client .submit_all(vec![ diff --git a/client/tests/integration/multisignature_account.rs b/client/tests/integration/multisignature_account.rs index 9f206de2fad..914939244c4 100644 --- a/client/tests/integration/multisignature_account.rs +++ b/client/tests/integration/multisignature_account.rs @@ -19,7 +19,8 @@ fn transaction_signed_by_new_signatory_of_account_should_pass() -> Result<()> { // Given let account_id: AccountId = "alice@wonderland".parse().expect("Valid"); let asset_definition_id: AssetDefinitionId = "xor#wonderland".parse().expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::new_quantity(asset_definition_id.clone())); + let create_asset = + RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).build()); let key_pair = KeyPair::generate()?; let add_signatory = MintBox::new( key_pair.public_key.clone(), diff --git a/client/tests/integration/multisignature_transaction.rs b/client/tests/integration/multisignature_transaction.rs index 18392aa831f..09f26e31139 100644 --- a/client/tests/integration/multisignature_transaction.rs +++ b/client/tests/integration/multisignature_transaction.rs @@ -28,7 +28,8 @@ fn multisignature_transactions_should_wait_for_all_signatures() { [key_pair_1.public_key.clone()], )); let asset_definition_id = AssetDefinitionId::from_str("xor#domain").expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::new_quantity(asset_definition_id.clone())); + let create_asset = + RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).build()); let set_signature_condition = MintBox::new( SignatureCheckCondition( ContainsAll::new( diff --git a/client/tests/integration/non_mintable.rs b/client/tests/integration/non_mintable.rs index 8cfbed17d89..a4596b2f685 100644 --- a/client/tests/integration/non_mintable.rs +++ b/client/tests/integration/non_mintable.rs @@ -15,9 +15,11 @@ fn non_mintable_asset_can_be_minted_once_but_not_twice() -> Result<()> { // Given let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); - let create_asset = RegisterBox::new(IdentifiableBox::from( - AssetDefinition::new_quantity_token(asset_definition_id.clone()), - )); + let create_asset = RegisterBox::new( + AssetDefinition::quantity(asset_definition_id.clone()) + .mintable_once() + .build(), + ); let metadata = UnlimitedMetadata::default(); @@ -29,7 +31,7 @@ fn non_mintable_asset_can_be_minted_once_but_not_twice() -> Result<()> { )), ); - let instructions: Vec = vec![create_asset.into(), mint.clone().into()]; + let instructions: [Instruction; 2] = [create_asset.into(), mint.clone().into()]; let tx = test_client.build_transaction(instructions.into(), metadata)?; // We can register and mint the non-mintable token @@ -42,7 +44,7 @@ fn non_mintable_asset_can_be_minted_once_but_not_twice() -> Result<()> { })?; // We can submit the request to mint again. - test_client.submit_all(vec![mint.into()])?; + test_client.submit_all([mint.into()])?; // However, this will fail assert!(test_client diff --git a/client/tests/integration/pagination.rs b/client/tests/integration/pagination.rs index 0476f72ac90..3802a08a41c 100644 --- a/client/tests/integration/pagination.rs +++ b/client/tests/integration/pagination.rs @@ -17,9 +17,11 @@ fn client_add_asset_quantity_to_existing_asset_should_increase_asset_amount() { let register: Vec = ('a'..'z') .map(|c| c.to_string()) .map(|name| (name + "#wonderland").parse().expect("Valid")) - .map(AssetDefinition::new_quantity) - .map(RegisterBox::new) - .map(Instruction::Register) + .map(|asset_definition_id| { + Instruction::Register(RegisterBox::new( + AssetDefinition::quantity(asset_definition_id).build(), + )) + }) .collect(); iroha_client .submit_all(register) diff --git a/client/tests/integration/permissions.rs b/client/tests/integration/permissions.rs index 416b89d9d11..6f5e36abcd7 100644 --- a/client/tests/integration/permissions.rs +++ b/client/tests/integration/permissions.rs @@ -41,7 +41,8 @@ fn permissions_disallow_asset_transfer() { let alice_id = AccountId::from_str("alice@wonderland").expect("Valid"); let bob_id = AccountId::from_str("bob@wonderland").expect("Valid"); let asset_definition_id: AssetDefinitionId = "xor#wonderland".parse().expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::new_quantity(asset_definition_id.clone())); + let create_asset = + RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).build()); let register_bob = RegisterBox::new(Account::new(bob_id.clone(), [])); let alice_start_assets = get_assets(&mut iroha_client, &alice_id); @@ -100,7 +101,8 @@ fn permissions_disallow_asset_burn() { let alice_id = "alice@wonderland".parse().expect("Valid"); let bob_id: AccountId = "bob@wonderland".parse().expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::new_quantity(asset_definition_id.clone())); + let create_asset = + RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).build()); let register_bob = RegisterBox::new(Account::new(bob_id.clone(), [])); let alice_start_assets = get_assets(&mut iroha_client, &alice_id); diff --git a/client/tests/integration/restart_peer.rs b/client/tests/integration/restart_peer.rs index 48008dfe354..43cc179ce95 100644 --- a/client/tests/integration/restart_peer.rs +++ b/client/tests/integration/restart_peer.rs @@ -30,7 +30,8 @@ fn restarted_peer_should_have_the_same_asset_amount() -> Result<()> { let account_id = AccountId::from_str("alice@wonderland").unwrap(); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").unwrap(); - let create_asset = RegisterBox::new(AssetDefinition::new_quantity(asset_definition_id.clone())); + let create_asset = + RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).build()); iroha_client.submit(create_asset)?; thread::sleep(pipeline_time * 2); //When diff --git a/client/tests/integration/roles.rs b/client/tests/integration/roles.rs index 657fc41e37e..8fbd54d9a3c 100644 --- a/client/tests/integration/roles.rs +++ b/client/tests/integration/roles.rs @@ -1,6 +1,6 @@ #![allow(clippy::restriction)] -use std::{str::FromStr as _, time::Duration}; +use std::{collections::BTreeMap, str::FromStr as _, time::Duration}; use eyre::{eyre, Result}; use iroha_client::client::{self, Client}; @@ -9,8 +9,6 @@ use iroha_data_model::{permissions::Permissions, prelude::*}; use iroha_permissions_validators::public_blockchain::transfer; use test_network::{Peer as TestPeer, *}; use tokio::runtime::Runtime; -use std::collections::BTreeMap; - #[test] fn add_role_to_limit_transfer_count() -> Result<()> { @@ -97,24 +95,20 @@ fn get_asset_value(client: &mut Client, asset_id: AssetId) -> Result { Ok(*TryAsRef::::try_as_ref(asset.value())?) } - #[test] fn register_empty_role() -> Result<()> { let (_rt, _peer, mut test_client) = ::start_test_with_runtime(); wait_for_genesis_committed(&vec![test_client.clone()], 0); let role_id = iroha_data_model::role::Id::new("root".parse::().expect("Valid")); - let register_role = RegisterBox::new(IdentifiableBox::from(Role::new( - role_id, - Permissions::new(), - ))); + let register_role = RegisterBox::new(Role::new(role_id, Permissions::new())); test_client.submit(register_role)?; Ok(()) } #[test] -fn register_role_with_empty_token() -> Result<()> { +fn register_role_with_empty_token_params() -> Result<()> { let (_rt, _peer, mut test_client) = ::start_test_with_runtime(); wait_for_genesis_committed(&vec![test_client.clone()], 0); @@ -124,7 +118,7 @@ fn register_role_with_empty_token() -> Result<()> { name: "token".parse().expect("Valid"), params: BTreeMap::new(), }); - let register_role = RegisterBox::new(IdentifiableBox::from(Role::new(role_id, permissions))); + let register_role = RegisterBox::new(Role::new(role_id, permissions)); test_client.submit(register_role)?; Ok(()) diff --git a/client/tests/integration/transfer_asset.rs b/client/tests/integration/transfer_asset.rs index 1634454f09c..f3f4db463ad 100644 --- a/client/tests/integration/transfer_asset.rs +++ b/client/tests/integration/transfer_asset.rs @@ -32,7 +32,8 @@ fn client_can_transfer_asset_to_another_account() { )); let asset_definition_id: AssetDefinitionId = "xor#domain".parse().expect("Valid"); let quantity: u32 = 200; - let create_asset = RegisterBox::new(AssetDefinition::new_quantity(asset_definition_id.clone())); + let create_asset = + RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).build()); let mint_asset = MintBox::new( Value::U32(quantity), IdBox::AssetId(AssetId::new( diff --git a/client/tests/integration/triggers/event_trigger.rs b/client/tests/integration/triggers/event_trigger.rs index 711bdca9604..94b170b56de 100644 --- a/client/tests/integration/triggers/event_trigger.rs +++ b/client/tests/integration/triggers/event_trigger.rs @@ -36,7 +36,7 @@ fn test_mint_asset_when_new_asset_definition_created() -> Result<()> { let tea_definition_id = "tea#wonderland".parse()?; let register_tea_definition = - RegisterBox::new(AssetDefinition::new_quantity(tea_definition_id)); + RegisterBox::new(AssetDefinition::quantity(tea_definition_id).build()); test_client.submit_blocking(register_tea_definition)?; let new_value = get_asset_value(&mut test_client, asset_id)?; diff --git a/client/tests/integration/tx_history.rs b/client/tests/integration/tx_history.rs index 965d4dd1a0a..ab8af770b38 100644 --- a/client/tests/integration/tx_history.rs +++ b/client/tests/integration/tx_history.rs @@ -18,7 +18,8 @@ fn client_has_rejected_and_acepted_txs_should_return_tx_history() { // Given let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::new_quantity(asset_definition_id.clone())); + let create_asset = + RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).build()); iroha_client .submit(create_asset) .expect("Failed to prepare state."); diff --git a/client/tests/integration/tx_rollback.rs b/client/tests/integration/tx_rollback.rs index bcdd7c9a1e4..7db6e8a82ef 100644 --- a/client/tests/integration/tx_rollback.rs +++ b/client/tests/integration/tx_rollback.rs @@ -19,7 +19,7 @@ fn client_sends_transaction_with_invalid_instruction_should_not_see_any_changes( let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); let wrong_asset_definition_id = AssetDefinitionId::from_str("ksor#wonderland").expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::new_quantity(asset_definition_id)); + let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id).build()); let quantity: u32 = 200; let mint_asset = MintBox::new( Value::U32(quantity), diff --git a/client/tests/integration/unregister_peer.rs b/client/tests/integration/unregister_peer.rs index 7dfb16614f0..7288cf0f838 100644 --- a/client/tests/integration/unregister_peer.rs +++ b/client/tests/integration/unregister_peer.rs @@ -107,7 +107,8 @@ fn init() -> Result<( [KeyPair::generate()?.public_key], )); let asset_definition_id: AssetDefinitionId = "xor#domain".parse().expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::new_quantity(asset_definition_id.clone())); + let create_asset = + RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).build()); client.submit_all(vec![ create_domain.into(), create_account.into(), diff --git a/client_cli/src/main.rs b/client_cli/src/main.rs index ca0bc725d27..f73ca055e86 100644 --- a/client_cli/src/main.rs +++ b/client_cli/src/main.rs @@ -413,6 +413,7 @@ mod account { mod asset { use iroha_client::client::{self, asset, Client}; + use iroha_data_model::asset::definition_builder::NewAssetDefinition; use super::*; @@ -466,7 +467,7 @@ mod asset { metadata: Metadata(metadata), } = self; submit( - RegisterBox::new(AssetDefinition::new(id, value_type, !unmintable)), + RegisterBox::new(NewAssetDefinition::new(id, value_type, !unmintable).build()), cfg, metadata, ) diff --git a/core/benches/validation.rs b/core/benches/validation.rs index 9c5b33141c5..4b60884dbba 100644 --- a/core/benches/validation.rs +++ b/core/benches/validation.rs @@ -39,11 +39,7 @@ fn build_test_transaction(keys: KeyPair) -> Transaction { "xor".parse().expect("Valid"), domain_name.parse().expect("Valid"), ); - let create_asset = RegisterBox::new(AssetDefinition::new( - asset_definition_id, - AssetValueType::Quantity, - true, - )); + let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id).build()); let instructions: Vec = vec![ create_domain.into(), create_account.into(), diff --git a/core/src/block.rs b/core/src/block.rs index 5e8f4df1e04..fbec7f30214 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -649,7 +649,7 @@ impl From<&ValidBlock> for Vec { block .transactions .iter() - .map(|transaction| { + .map(|transaction| -> Event { PipelineEvent::new( PipelineEntityKind::Transaction, PipelineStatus::Validating, diff --git a/core/src/genesis.rs b/core/src/genesis.rs index 7fad2e1e6c9..e61b863e61a 100644 --- a/core/src/genesis.rs +++ b/core/src/genesis.rs @@ -7,7 +7,7 @@ use std::{collections::HashSet, fmt::Debug, fs::File, io::BufReader, ops::Deref, use eyre::{eyre, Result, WrapErr}; use iroha_actor::Addr; use iroha_crypto::{KeyPair, PublicKey}; -use iroha_data_model::prelude::*; +use iroha_data_model::{asset::AssetDefinition, prelude::*}; use iroha_schema::prelude::*; use serde::{Deserialize, Serialize}; use small::SmallVec; @@ -418,6 +418,7 @@ impl RawGenesisDomainBuilder { transaction: self.transaction, } } + /// Add an account to this domain without a public key. /// Should only be used for testing. #[must_use] @@ -427,6 +428,7 @@ impl RawGenesisDomainBuilder { .push(RegisterBox::new(AccountId::new(account_name, self.domain_id.clone())).into()); self } + /// Add an account to this domain #[must_use] pub fn with_account(mut self, account_name: Name, public_key: PublicKey) -> Self { @@ -439,22 +441,13 @@ impl RawGenesisDomainBuilder { ); self } - /// Add an asset to this domain. + + /// Add [`AssetDefinition`] to current domain. #[must_use] - pub fn with_asset( - mut self, - asset_name: Name, - asset_value_type: AssetValueType, - asset_mintable: bool, - ) -> Self { - self.transaction.isi.push( - RegisterBox::new(AssetDefinition::new( - AssetDefinitionId::new(asset_name, self.domain_id.clone()), - asset_value_type, - asset_mintable, - )) - .into(), - ); + pub fn with_asset(mut self, definition: AssetDefinition) -> Self { + self.transaction + .isi + .push(RegisterBox::new(definition).into()); self } } @@ -499,7 +492,7 @@ mod tests { .finish_domain() .domain("meadow".parse().unwrap()) .with_account("Mad_Hatter".parse().unwrap(), public_key.parse().unwrap()) - .with_asset("hats".parse().unwrap(), AssetValueType::BigQuantity, true) + .with_asset(AssetDefinition::big_quantity("hats#meadow".parse().unwrap()).build()) .finish_domain(); let finished_genesis_block = genesis_builder.build(); @@ -539,18 +532,16 @@ mod tests { assert_eq!( finished_genesis_block.transactions[0].isi[6], RegisterBox::new(Account::new( - AccountId::new("Mad_Hatter".parse().unwrap(), domain_id.clone()), + AccountId::new("Mad_Hatter".parse().unwrap(), domain_id), [public_key.parse().unwrap()], )) .into() ); assert_eq!( finished_genesis_block.transactions[0].isi[7], - RegisterBox::new(AssetDefinition::new( - AssetDefinitionId::new("hats".parse().unwrap(), domain_id), - AssetValueType::BigQuantity, - true, - )) + RegisterBox::new( + AssetDefinition::big_quantity("hats#meadow".parse().unwrap()).build() + ) .into() ); } diff --git a/core/src/smartcontracts/isi/asset.rs b/core/src/smartcontracts/isi/asset.rs index 44362506a3c..fff5d2b5072 100644 --- a/core/src/smartcontracts/isi/asset.rs +++ b/core/src/smartcontracts/isi/asset.rs @@ -11,7 +11,7 @@ use super::prelude::*; /// - update metadata /// - transfer, etc. pub mod isi { - use iroha_data_model::asset::Mintable; + use iroha_data_model::{asset::Mintable, MintabilityError}; use iroha_logger::prelude::*; use super::*; @@ -44,10 +44,10 @@ pub mod isi { let definition = assert_asset_type(definition_id, wsv, expected_value_type)?; match definition.mintable() { Mintable::Infinitely => Ok(()), - Mintable::Not => Err(Error::Mintability(MintabilityError::MintUnmintableError)), + Mintable::Not => Err(Error::Mintability(MintabilityError::MintUnmintable)), Mintable::Once => { wsv.modify_asset_definition_entry(definition_id, |entry| { - entry.forbid_minting(); + entry.forbid_minting()?; Ok(AssetDefinitionEvent::MintabilityChanged( definition_id.clone(), )) diff --git a/core/src/smartcontracts/isi/mod.rs b/core/src/smartcontracts/isi/mod.rs index f2a4e92ec41..6a8c4f2c7fa 100644 --- a/core/src/smartcontracts/isi/mod.rs +++ b/core/src/smartcontracts/isi/mod.rs @@ -35,7 +35,9 @@ pub mod error { }; use iroha_crypto::HashOf; - use iroha_data_model::{fixed::FixedPointOperationError, metadata, prelude::*}; + use iroha_data_model::{ + fixed::FixedPointOperationError, metadata, prelude::*, MintabilityError, + }; use iroha_schema::IntoSchema; use parity_scale_codec::{Decode, Encode}; use thiserror::Error; @@ -53,7 +55,7 @@ pub mod error { Type(#[source] TypeError), /// Failed to assert mintability #[error("Mintability violation. {0}")] - Mintability(#[source] MintabilityError), + Mintability(#[from] MintabilityError), /// Failed due to math exception #[error("Math error. {0}")] Math(#[source] MathError), @@ -171,14 +173,6 @@ pub mod error { Role(RoleId), } - /// Mintability logic error - #[derive(Debug, Clone, Error, Copy, PartialEq, Eq)] - pub enum MintabilityError { - /// Tried to mint an Un-mintable asset. - #[error("Minting of this asset is forbidden")] - MintUnmintableError, - } - /// Type assertion error #[derive(Debug, Clone, Error, Copy, PartialEq, Eq)] pub enum TypeError { @@ -648,7 +642,10 @@ mod tests { assert!(domain.add_account(account).is_none()); let asset_definition_id = AssetDefinitionId::from_str("rose#wonderland")?; assert!(domain - .add_asset_definition(AssetDefinition::new_store(asset_definition_id), account_id) + .add_asset_definition( + AssetDefinition::store(asset_definition_id).build(), + account_id + ) .is_none()); Ok(World::with([domain], PeersIds::new())) } diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index ebe26621d74..a30ce55e2e5 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -236,7 +236,7 @@ mod tests { let asset_definition_id = AssetDefinitionId::from_str("rose#wonderland").expect("Valid"); assert!(domain .add_asset_definition( - AssetDefinition::new(asset_definition_id, AssetValueType::Quantity, true), + AssetDefinition::quantity(asset_definition_id).build(), ALICE_ID.clone(), ) .is_none()); @@ -249,7 +249,7 @@ mod tests { let mut account = Account::new(ALICE_ID.clone(), [ALICE_KEYS.public_key.clone()]).build(); assert!(domain .add_asset_definition( - AssetDefinition::new(asset_definition_id.clone(), AssetValueType::Quantity, true), + AssetDefinition::quantity(asset_definition_id.clone()).build(), ALICE_ID.clone(), ) .is_none()); @@ -286,7 +286,7 @@ mod tests { let asset_definition_id = AssetDefinitionId::from_str("rose#wonderland").expect("Valid"); assert!(domain .add_asset_definition( - AssetDefinition::new(asset_definition_id, AssetValueType::Quantity, true), + AssetDefinition::quantity(asset_definition_id).build(), ALICE_ID.clone(), ) .is_none()); @@ -382,7 +382,7 @@ mod tests { let asset_definition_id = AssetDefinitionId::from_str("rose#wonderland")?; assert!(domain .add_asset_definition( - AssetDefinition::new(asset_definition_id, AssetValueType::Quantity, true), + AssetDefinition::quantity(asset_definition_id).build(), ALICE_ID.clone(), ) .is_none()); diff --git a/core/test_network/src/lib.rs b/core/test_network/src/lib.rs index 6ea2b901c2f..a338b8dbed0 100644 --- a/core/test_network/src/lib.rs +++ b/core/test_network/src/lib.rs @@ -133,15 +133,21 @@ impl TestGenesis for G { get_key_pair().public_key, ); genesis.transactions[0].isi.push( - RegisterBox::new(AssetDefinition::new_quantity( - AssetDefinitionId::from_str("rose#wonderland").expect("valid names"), - )) + RegisterBox::new( + AssetDefinition::quantity( + AssetDefinitionId::from_str("rose#wonderland").expect("valid names"), + ) + .build(), + ) .into(), ); genesis.transactions[0].isi.push( - RegisterBox::new(AssetDefinition::new_quantity( - AssetDefinitionId::from_str("tulip#wonderland").expect("valid names"), - )) + RegisterBox::new( + AssetDefinition::quantity( + AssetDefinitionId::from_str("tulip#wonderland").expect("valid names"), + ) + .build(), + ) .into(), ); genesis.transactions[0].isi.push( @@ -650,9 +656,6 @@ pub trait TestClient: Sized { fn test_with_key(api_url: &str, telemetry_url: &str, keys: KeyPair) -> Self; /// Creates test client from api url, keypair, and account id - /// - /// # Errors - /// If predicate is not satisfied, after maximum retries. fn test_with_account( api_url: &str, telemetry_url: &str, diff --git a/data_model/src/asset.rs b/data_model/src/asset.rs index 69eaa463f7b..ae478020726 100644 --- a/data_model/src/asset.rs +++ b/data_model/src/asset.rs @@ -17,6 +17,7 @@ use iroha_schema::IntoSchema; use parity_scale_codec::{Decode, Encode}; use serde::{Deserialize, Serialize}; +use self::definition_builder::NewAssetDefinition; use crate::{ account::prelude::*, domain::prelude::*, fixed, fixed::Fixed, metadata::Metadata, Identifiable, Name, ParseError, TryAsMut, TryAsRef, Value, @@ -81,8 +82,11 @@ impl AssetDefinitionEntry { } /// Turn off minting for this asset. + /// + /// # Errors + /// If the asset was declared as `Mintable::Infinitely` #[cfg(feature = "mutable_api")] - pub fn forbid_minting(&mut self) { + pub fn forbid_minting(&mut self) -> Result<(), super::MintabilityError> { self.definition.forbid_minting() } } @@ -117,6 +121,9 @@ pub struct AssetDefinition { metadata: Metadata, } +/// An assets mintability scheme. `Infinitely` means elastic +/// supply. `Once` is what you want to use. Don't use `Not` explicitly +/// outside of smartcontracts. #[derive( Debug, Clone, @@ -131,7 +138,6 @@ pub struct AssetDefinition { Serialize, IntoSchema, )] -/// An assets mintability scheme. `Infinitely` means elastic supply. `Once` is what you want to use. Don't use `Not` explicitly outside of smartcontracts. pub enum Mintable { /// Regular asset with elastic supply. Can be minted and burned. Infinitely, @@ -343,105 +349,144 @@ pub struct Id { pub account_id: ::Id, } -impl AssetDefinition { - /// Construct [`AssetDefinition`]. - pub fn new( - id: ::Id, - value_type: AssetValueType, - mintable: bool, - ) -> ::RegisteredWith { - Self { - id, - metadata: Metadata::new(), - mintable: if mintable { - Mintable::Infinitely - } else { - Mintable::Once - }, - value_type, - } +pub mod definition_builder { + //! Builder for [`AssetDefinition`]. + use super::{AssetDefinition, AssetValueType, Mintable}; + use crate::{metadata::Metadata, Identifiable}; + + type Id = ::Id; + + /// Builder with all mandatory fields. + pub struct NewAssetDefinition { + pub(crate) id: Id, + pub(crate) value_type: AssetValueType, + pub(crate) mintable: Mintable, + pub(crate) metadata: Metadata, } - #[inline] - #[cfg(feature = "mutable_api")] - pub fn forbid_minting(&mut self) { - if let Mintable::Once = self.mintable { - self.mintable = Mintable::Not - } else { - panic!("You shouldn't forbid minting on assets that are not Mintable::Once.") + impl NewAssetDefinition { + /// Make the builder create a [`Mintable::Once`] instance of [`AssetDefinition`] + #[must_use] + #[inline] + pub fn mintable_once(mut self) -> Self { + self.mintable = Mintable::Once; + self } - } - /// Add [`Metadata`] to the asset definition replacing previously defined - #[inline] - #[must_use] - pub fn with_metadata(mut self, metadata: Metadata) -> Self { - self.metadata = metadata; - self - } + /// Most general constructor for the case where + /// [`AssetValueType`], and mintability are known ahead of + /// time. Don't forget to build the resulting [`Self`]. + pub fn new( + id: ::Id, + value_type: AssetValueType, + mintable: bool, + ) -> Self { + Self { + id, + value_type, + mintable: if mintable { + Mintable::Infinitely + } else { + Mintable::Once + }, + metadata: Metadata::new(), + } + } - /// Asset definition with quantity asset value type. - #[inline] - pub fn new_quantity( - id: ::Id, - ) -> ::RegisteredWith { - AssetDefinition::new(id, AssetValueType::Quantity, true) - } + /// Change mintability in-place + #[inline] + pub fn mintable(&mut self, mintable: bool) { + self.mintable = if mintable { + Mintable::Infinitely + } else { + Mintable::Once + }; + } - /// Token definition with quantity asset value type. - #[inline] - pub fn new_quantity_token( - id: ::Id, - ) -> ::RegisteredWith { - AssetDefinition::new(id, AssetValueType::Quantity, false) - } + /// Add metadata to builder + #[must_use] + #[inline] + pub fn with_metadata(mut self, metadata: Metadata) -> Self { + self.metadata = metadata; + self + } - /// Asset definition with big quantity asset value type. - #[inline] - pub fn new_big_quantity( - id: ::Id, - ) -> ::RegisteredWith { - AssetDefinition::new(id, AssetValueType::BigQuantity, true) + /// Build [`AssetDefinition`] + #[must_use] + #[inline] + pub fn build(self) -> ::RegisteredWith { + let Self { + id, + value_type, + mintable, + metadata, + } = self; + AssetDefinition { + id, + value_type, + mintable, + metadata, + } + } } +} - /// Token definition with big quantity asset value type. +impl AssetDefinition { + /// Construct [`AssetDefinition`]. + #[must_use] #[inline] - pub fn new_big_quantity_token( - id: ::Id, - ) -> ::RegisteredWith { - AssetDefinition::new(id, AssetValueType::BigQuantity, false) + pub fn quantity(id: ::Id) -> NewAssetDefinition { + NewAssetDefinition { + id, + value_type: AssetValueType::Quantity, + mintable: Mintable::Infinitely, + metadata: Metadata::default(), + } } - /// Asset definition with decimal quantity asset value type. + /// Construct [`AssetDefinition`]. + #[must_use] #[inline] - pub fn new_fixed_precision( - id: ::Id, - ) -> ::RegisteredWith { - AssetDefinition::new(id, AssetValueType::Fixed, true) + pub fn big_quantity(id: ::Id) -> NewAssetDefinition { + NewAssetDefinition { + value_type: AssetValueType::BigQuantity, + ..Self::quantity(id) + } } - /// Token definition with decimal quantity asset value type. + /// Construct [`AssetDefinition`]. + #[must_use] #[inline] - pub fn with_precision_token( - id: ::Id, - ) -> ::RegisteredWith { - AssetDefinition::new(id, AssetValueType::Fixed, false) + pub fn fixed(id: ::Id) -> NewAssetDefinition { + NewAssetDefinition { + value_type: AssetValueType::Fixed, + ..Self::quantity(id) + } } - /// Asset definition with store asset value type. + /// Construct [`AssetDefinition`]. + #[must_use] #[inline] - pub fn new_store( - id: ::Id, - ) -> ::RegisteredWith { - AssetDefinition::new(id, AssetValueType::Store, true) + pub fn store(id: ::Id) -> NewAssetDefinition { + NewAssetDefinition { + value_type: AssetValueType::Store, + ..Self::quantity(id) + } } - /// Token definition with store asset value type. + /// Stop minting on the [`AssetDefinition`] globally. + /// + /// # Errors + /// If the [`AssetDefinition`] is not `Mintable::Once`. #[inline] - pub fn new_store_token( - id: ::Id, - ) -> ::RegisteredWith { - AssetDefinition::new(id, AssetValueType::Store, false) + #[cfg(feature = "mutable_api")] + pub fn forbid_minting(&mut self) -> Result<(), super::MintabilityError> { + if self.mintable == Mintable::Once { + self.mintable = Mintable::Not; + Ok(()) + } else { + Err(super::MintabilityError::ForbidMintOnMintable) + } } } diff --git a/data_model/src/events/data/events.rs b/data_model/src/events/data/events.rs index 5cc4539fd94..1910a097ee1 100644 --- a/data_model/src/events/data/events.rs +++ b/data_model/src/events/data/events.rs @@ -51,6 +51,9 @@ mod asset { MetadataInserted(AssetDefinitionId), MetadataRemoved(AssetDefinitionId), } + // NOTE: Whenever you add a new event here, please also update the + // AssetDefinitionEventFilter enum and its `impl Filter for + // AssetDefinitionEventFilter`. impl IdTrait for AssetDefinitionEvent { type Id = AssetDefinitionId; diff --git a/data_model/src/events/data/filters.rs b/data_model/src/events/data/filters.rs index d6da292684a..f3920adca05 100644 --- a/data_model/src/events/data/filters.rs +++ b/data_model/src/events/data/filters.rs @@ -276,6 +276,7 @@ mod asset { pub enum AssetDefinitionEventFilter { ByCreated, ByDeleted, + ByMintabilityChanged, ByMetadataInserted, ByMetadataRemoved, } @@ -296,6 +297,10 @@ mod asset { Self::ByMetadataRemoved, AssetDefinitionEvent::MetadataRemoved(_) ) + | ( + Self::ByMintabilityChanged, + AssetDefinitionEvent::MintabilityChanged(_) + ) ) } } diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index 2dfa112c8d7..00976a93aa2 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -42,6 +42,32 @@ pub mod transaction; pub mod trigger; pub mod uri; +/// Mintability logic error +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum MintabilityError { + /// Tried to mint an Un-mintable asset. + MintUnmintable, + /// Tried to forbid minting on assets that should be mintable. + ForbidMintOnMintable, +} + +impl fmt::Display for MintabilityError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let message = match self { + MintabilityError::MintUnmintable => { + "This asset cannot be minted more than once and it was already minted." + } + MintabilityError::ForbidMintOnMintable => { + "This asset was set as infinitely mintable. You cannot forbid its minting." + } + }; + write!(f, "{}", message) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for MintabilityError {} + /// Error which occurs when parsing string into a data model entity #[derive(Debug, Display, Clone, Copy)] pub struct ParseError { diff --git a/data_model/tests/data_model.rs b/data_model/tests/data_model.rs index 3669fa77761..1acfdb494ad 100644 --- a/data_model/tests/data_model.rs +++ b/data_model/tests/data_model.rs @@ -8,7 +8,7 @@ use iroha_core::{ genesis::{GenesisNetwork, GenesisNetworkTrait, RawGenesisBlock}, prelude::*, }; -use iroha_data_model::prelude::*; +use iroha_data_model::{prelude::*, ParseError}; use small::SmallStr; use test_network::{Peer as TestPeer, TestRuntime}; use tokio::runtime::Runtime; @@ -133,10 +133,13 @@ mod register { } pub fn asset_definition(asset_name: &str, domain_name: &str) -> RegisterBox { - RegisterBox::new(AssetDefinition::new_quantity(AssetDefinitionId::new( - asset_name.parse().expect("Valid"), - domain_name.parse().expect("Valid"), - ))) + RegisterBox::new( + AssetDefinition::quantity(AssetDefinitionId::new( + asset_name.parse().expect("Valid"), + domain_name.parse().expect("Valid"), + )) + .build(), + ) } } @@ -270,11 +273,8 @@ fn find_rate_and_make_exchange_isi_should_succeed() { } #[test] -#[should_panic] -fn cannot_forbid_minting_on_asset_mintable_infinitely() { - if let Ok(id) = "test".parse() { - let mut definition = AssetDefinition::new_quantity(id); - definition.forbid_minting(); - } - // We should fail the test if it returns an error. +fn cannot_forbid_minting_on_asset_mintable_infinitely() -> Result<(), ParseError> { + let mut definition = AssetDefinition::quantity("test#hello".parse()?).build(); + assert!(definition.forbid_minting().is_err()); + Ok(()) } diff --git a/permissions_validators/src/public_blockchain/mod.rs b/permissions_validators/src/public_blockchain/mod.rs index 29a3de32e4f..ee65657f60f 100644 --- a/permissions_validators/src/public_blockchain/mod.rs +++ b/permissions_validators/src/public_blockchain/mod.rs @@ -178,7 +178,7 @@ mod tests { use super::*; fn new_xor_definition(xor_id: &AssetDefinitionId) -> AssetDefinition { - AssetDefinition::new_quantity(xor_id.clone()) + AssetDefinition::quantity(xor_id.clone()).build() } #[test]