Skip to content

Commit

Permalink
[feature] #3871: Register<AssetDefinition> permissions
Browse files Browse the repository at this point in the history
Signed-off-by: Ilia Churin <[email protected]>
Signed-off-by: Marin Veršić <[email protected]>
  • Loading branch information
ilchu authored and mversic committed Jan 15, 2024
1 parent ce4538f commit 9c2d71c
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 3 deletions.
63 changes: 60 additions & 3 deletions client/tests/integration/domain_owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,66 @@ use test_network::*;

#[test]
fn domain_owner_domain_permissions() -> Result<()> {
let chain_id = ChainId::new("0");

let (_rt, _peer, test_client) = <PeerBuilder>::new().with_port(11_080).start_with_runtime();
wait_for_genesis_committed(&[test_client.clone()], 0);

let kingdom_id: DomainId = "kingdom".parse()?;
let bob_id: AccountId = "bob@kingdom".parse()?;
let coin_id: AssetDefinitionId = "coin#kingdom".parse()?;
let coin = AssetDefinition::quantity(coin_id.clone());

// "alice@wonderland" is owner of "kingdom" domain
let kingdom = Domain::new(kingdom_id.clone());
test_client.submit_blocking(Register::domain(kingdom))?;

let bob_keypair = KeyPair::generate()?;
let bob = Account::new(bob_id.clone(), [bob_keypair.public_key().clone()]);
test_client.submit_blocking(Register::account(bob))?;

// Asset definitions can't be registered by "bob@kingdom" by default
let transaction = TransactionBuilder::new(chain_id.clone(), bob_id.clone())
.with_instructions([Register::asset_definition(coin.clone())])
.sign(bob_keypair.clone())?;
let err = test_client
.submit_transaction_blocking(&transaction)
.expect_err("Tx should fail due to permissions");

let rejection_reason = err
.downcast_ref::<PipelineRejectionReason>()
.unwrap_or_else(|| panic!("Error {err} is not PipelineRejectionReason"));

assert!(matches!(
rejection_reason,
&PipelineRejectionReason::Transaction(TransactionRejectionReason::Validation(
ValidationFail::NotPermitted(_)
))
));

// "alice@wonderland" owns the domain and can register AssetDefinitions by default as domain owner
test_client.submit_blocking(Register::asset_definition(coin.clone()))?;
test_client.submit_blocking(Unregister::asset_definition(coin_id))?;

// Granting a respective token also allows "bob@kingdom" to do so
let token = PermissionToken::new(
"CanRegisterAssetDefinitionInDomain".parse().unwrap(),
&json!({ "domain_id": kingdom_id }),
);
test_client.submit_blocking(Grant::permission_token(token.clone(), bob_id.clone()))?;
let transaction = TransactionBuilder::new(chain_id, bob_id.clone())
.with_instructions([Register::asset_definition(coin)])
.sign(bob_keypair)?;
test_client.submit_transaction_blocking(&transaction)?;
test_client.submit_blocking(Revoke::permission_token(token, bob_id.clone()))?;

// check that "alice@wonderland" as owner of domain can edit metadata in her domain
let key: Name = "key".parse()?;
let value: Name = "value".parse()?;
test_client.submit_blocking(SetKeyValue::domain(kingdom_id.clone(), key.clone(), value))?;
test_client.submit_blocking(RemoveKeyValue::domain(kingdom_id.clone(), key))?;

// check that "alice@wonderland" as owner of domain can grant and revoke domain related permission tokens
let bob_id: AccountId = "bob@wonderland".parse()?;
let token = PermissionToken::new(
"CanUnregisterDomain".parse().unwrap(),
&json!({ "domain_id": kingdom_id }),
Expand Down Expand Up @@ -111,7 +154,7 @@ fn domain_owner_asset_definition_permissions() -> Result<()> {
let coin_id: AssetDefinitionId = "coin#kingdom".parse()?;

// "alice@wonderland" is owner of "kingdom" domain
let kingdom = Domain::new(kingdom_id);
let kingdom = Domain::new(kingdom_id.clone());
test_client.submit_blocking(Register::domain(kingdom))?;

let bob_keypair = KeyPair::generate()?;
Expand All @@ -121,6 +164,13 @@ fn domain_owner_asset_definition_permissions() -> Result<()> {
let rabbit = Account::new(rabbit_id.clone(), []);
test_client.submit_blocking(Register::account(rabbit))?;

// Grant permission to register asset definitions to "bob@kingdom"
let token = PermissionToken::new(
"CanRegisterAssetDefinitionInDomain".parse().unwrap(),
&json!({ "domain_id": kingdom_id }),
);
test_client.submit_blocking(Grant::permission_token(token, bob_id.clone()))?;

// register asset definitions by "bob@kingdom" so he is owner of it
let coin = AssetDefinition::quantity(coin_id.clone());
let transaction = TransactionBuilder::new(chain_id, bob_id.clone())
Expand Down Expand Up @@ -174,13 +224,20 @@ fn domain_owner_asset_permissions() -> Result<()> {
let store_id: AssetDefinitionId = "store#kingdom".parse()?;

// "alice@wonderland" is owner of "kingdom" domain
let kingdom = Domain::new(kingdom_id);
let kingdom = Domain::new(kingdom_id.clone());
test_client.submit_blocking(Register::domain(kingdom))?;

let bob_keypair = KeyPair::generate()?;
let bob = Account::new(bob_id.clone(), [bob_keypair.public_key().clone()]);
test_client.submit_blocking(Register::account(bob))?;

// Grant permission to register asset definitions to "bob@kingdom"
let token = PermissionToken::new(
"CanRegisterAssetDefinitionInDomain".parse().unwrap(),
&json!({ "domain_id": kingdom_id }),
);
test_client.submit_blocking(Grant::permission_token(token, bob_id.clone()))?;

// register asset definitions by "bob@kingdom" so he is owner of it
let coin = AssetDefinition::quantity(coin_id.clone());
let store = AssetDefinition::store(store_id.clone());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,18 @@ fn main(_owner: AccountId, _event: Event) {

let limits = MetadataLimits::new(256, 256);

let bad_domain_ids: [DomainId; 2] = [
"genesis".parse().dbg_unwrap(),
"garden_of_live_flowers".parse().dbg_unwrap(),
];

for account in accounts_cursor {
let account = account.dbg_unwrap();

if bad_domain_ids.contains(account.id().domain_id()) {
continue;
}

let mut metadata = Metadata::new();
let name = format!(
"nft_for_{}_in_{}",
Expand Down
Binary file modified configs/peer/executor.wasm
Binary file not shown.
5 changes: 5 additions & 0 deletions core/test_network/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ impl TestGenesis for GenesisNetwork {
);
let upgrade_executor_permission =
PermissionToken::new("CanUpgradeExecutor".parse().unwrap(), &json!(null));
let register_asset_definitions_permission = PermissionToken::new(
"CanRegisterAssetDefinitionInDomain".parse().unwrap(),
&json!({ "domain_id": DomainId::from_str("wonderland").unwrap() } ),
);

let first_transaction = genesis
.first_transaction_mut()
Expand All @@ -122,6 +126,7 @@ impl TestGenesis for GenesisNetwork {
unregister_any_role_permission,
unregister_wonderland_domain,
upgrade_executor_permission,
register_asset_definitions_permission,
] {
first_transaction
.append_instruction(Grant::permission_token(permission, alice_id.clone()).into());
Expand Down
1 change: 1 addition & 0 deletions smart_contract/executor/derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ pub fn derive_token(input: TokenStream) -> Result<TokenStream> {
/// - `asset_definition::Owner` - checks if the authority is the asset definition owner;
/// - `asset::Owner` - checks if the authority is the asset owner;
/// - `account::Owner` - checks if the authority is the account owner.
/// - `domain::Owner` - checks if the authority is the domain owner.
/// - `AlwaysPass` - checks nothing and always passes.
/// - `OnlyGenesis` - checks that block height is 0.
///
Expand Down
5 changes: 5 additions & 0 deletions smart_contract/executor/src/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ pub fn default_permission_token_schema() -> PermissionTokenSchema {
schema
}

// NOTE: If any new `visit_..` functions are introduced in this module, one should
// not forget to update the default executor boilerplate too, specifically the
// `iroha_executor::derive::default::impl_derive_visit` function
// signature list.

/// Default validation for [`SignedTransaction`].
///
/// # Warning
Expand Down
9 changes: 9 additions & 0 deletions smart_contract/executor/src/default/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ declare_tokens! {
crate::default::tokens::domain::{CanUnregisterDomain},
crate::default::tokens::domain::{CanSetKeyValueInDomain},
crate::default::tokens::domain::{CanRemoveKeyValueInDomain},
crate::default::tokens::domain::{CanRegisterAssetDefinitionInDomain},

crate::default::tokens::account::{CanUnregisterAccount},
crate::default::tokens::account::{CanMintUserPublicKeys},
Expand Down Expand Up @@ -146,6 +147,14 @@ pub mod domain {
pub domain_id: DomainId,
}
}

token! {
#[derive(ValidateGrantRevoke, permission::derive_conversions::domain::Owner)]
#[validate(permission::domain::Owner)]
pub struct CanRegisterAssetDefinitionInDomain {
pub domain_id: DomainId,
}
}
}

pub mod account {
Expand Down

0 comments on commit 9c2d71c

Please sign in to comment.