Skip to content

Commit

Permalink
feat(engine): implement recall
Browse files Browse the repository at this point in the history
  • Loading branch information
sdbondi committed Nov 17, 2023
1 parent 9d06a84 commit 51078d3
Show file tree
Hide file tree
Showing 38 changed files with 961 additions and 308 deletions.
7 changes: 0 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion applications/tari_dan_app_utilities/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ anyhow = "1.0.53"
bytes = "1"
chrono = "0.4.22"
futures = { version = "^0.3.1" }
lazy_static = "1.4.0"
log = { version = "0.4.8", features = ["std"] }
mini-moka = "0.10.0"
dashmap = "5.5.0"
Expand Down
2 changes: 0 additions & 2 deletions applications/tari_indexer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ tari_indexer_client = { path = "../../clients/tari_indexer_client" }
tari_indexer_lib = { path = "../../dan_layer/indexer_lib" }
tari_template_lib = { path = "../../dan_layer/template_lib" }
tari_transaction = { path = "../../dan_layer/transaction" }
tari_validator_node_client = { path = "../../clients/validator_node_client" }
tari_validator_node_rpc = { path = "../../dan_layer/validator_node_rpc" }
tari_dan_p2p = { path = "../../dan_layer/p2p" }

Expand Down Expand Up @@ -60,7 +59,6 @@ log4rs = { version = "1.1.1", features = [
"fixed_window_roller",
] }
prost = "0.9"
rand = "0.8"
reqwest = "0.11.11"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
Expand Down
11 changes: 5 additions & 6 deletions applications/tari_indexer/src/json_rpc/json_encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,7 @@ fn fix_invalid_object_keys(value: &CborValue) -> CborValue {

#[cfg(test)]
mod tests {
use tari_common_types::types::PublicKey;
use tari_crypto::commitment::HomomorphicCommitment;
use tari_common_types::types::Commitment;
use tari_engine_types::{confidential::ConfidentialOutput, resource_container::ResourceContainer, vault::Vault};
use tari_template_lib::{
models::{Amount, ResourceAddress, VaultId},
Expand All @@ -183,14 +182,14 @@ mod tests {
fn it_encodes_confidential_vaults() {
let address = ResourceAddress::new(Hash::default());

let public_key = PublicKey::default();
let commitment = Commitment::default();
let confidential_output = ConfidentialOutput {
commitment: HomomorphicCommitment::from_public_key(&public_key),
stealth_public_nonce: public_key.clone(),
commitment: commitment.clone(),
stealth_public_nonce: commitment.as_public_key().clone(),
encrypted_data: Default::default(),
minimum_value_promise: 0,
};
let commitment = Some((public_key, confidential_output));
let commitment = Some((commitment, confidential_output));

let revealed_amount = Amount::zero();
let container = ResourceContainer::confidential(address, commitment, revealed_amount);
Expand Down
53 changes: 42 additions & 11 deletions dan_layer/engine/src/runtime/impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ use tari_template_lib::{
PayFeeArg,
ProofAction,
ProofRef,
RecallResourceArg,
ResourceAction,
ResourceGetNonFungibleArg,
ResourceRef,
Expand Down Expand Up @@ -562,6 +563,39 @@ impl<TTemplateProvider: TemplateProvider<Template = LoadedTemplate>> RuntimeInte
Ok(InvokeResult::encode(&bucket)?)
})
},
ResourceAction::Recall => {
let resource_address =
resource_ref
.as_resource_address()
.ok_or_else(|| RuntimeError::InvalidArgument {
argument: "resource_ref",
reason: "Recall resource action requires a resource address".to_string(),
})?;
let arg: RecallResourceArg = args.assert_one_arg()?;

self.tracker.write_with(|state| {
let resource_lock =
state.lock_substate(&SubstateAddress::Resource(resource_address), LockFlag::Write)?;

state
.authorization()
.check_resource_access_rules(ResourceAuthAction::Recall, &resource_lock)?;

let vault_lock = state.lock_substate(&arg.vault_id.into(), LockFlag::Write)?;

let resource = state.recall_resource_from_vault(&vault_lock, arg.resource)?;

let bucket_id = self.tracker.id_provider().new_bucket_id();
state.new_bucket(bucket_id, resource)?;

state.unlock_substate(vault_lock)?;
state.unlock_substate(resource_lock)?;

Ok(InvokeResult::encode(&tari_template_lib::models::Bucket::from_id(
bucket_id,
))?)
})
},
ResourceAction::GetNonFungible => {
let resource_address =
resource_ref
Expand Down Expand Up @@ -785,8 +819,8 @@ impl<TTemplateProvider: TemplateProvider<Template = LoadedTemplate>> RuntimeInte
let bucket_id = self.tracker.id_provider().new_bucket_id();
state.new_bucket(bucket_id, resource_container)?;

state.unlock_substate(resource_lock)?;
state.unlock_substate(vault_lock)?;
state.unlock_substate(resource_lock)?;

let bucket = tari_template_lib::models::Bucket::from_id(bucket_id);
Ok(InvokeResult::encode(&bucket)?)
Expand Down Expand Up @@ -1500,15 +1534,12 @@ impl<TTemplateProvider: TemplateProvider<Template = LoadedTemplate>> RuntimeInte
// 4. Create the confidential resource
let mut resource = ResourceContainer::confidential(
CONFIDENTIAL_TARI_RESOURCE_ADDRESS,
Some((
unclaimed_output.commitment.as_public_key().clone(),
ConfidentialOutput {
commitment: unclaimed_output.commitment,
stealth_public_nonce: diffie_hellman_public_key,
encrypted_data: unclaimed_output.encrypted_data,
minimum_value_promise: 0,
},
)),
Some((unclaimed_output.commitment.clone(), ConfidentialOutput {
commitment: unclaimed_output.commitment,
stealth_public_nonce: diffie_hellman_public_key,
encrypted_data: unclaimed_output.encrypted_data,
minimum_value_promise: 0,
})),
Amount::zero(),
);

Expand Down Expand Up @@ -1548,7 +1579,7 @@ impl<TTemplateProvider: TemplateProvider<Template = LoadedTemplate>> RuntimeInte
) -> Result<BucketId, RuntimeError> {
let resource = ResourceContainer::confidential(
CONFIDENTIAL_TARI_RESOURCE_ADDRESS,
output.map(|o| (o.commitment.as_public_key().clone(), o)),
output.map(|o| (o.commitment.clone(), o)),
revealed_amount,
);

Expand Down
97 changes: 94 additions & 3 deletions dan_layer/engine/src/runtime/working_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use tari_engine_types::{
TemplateAddress,
};
use tari_template_lib::{
args::MintArg,
args::{MintArg, ResourceDiscriminator},
constants::CONFIDENTIAL_TARI_RESOURCE_ADDRESS,
models::{
Amount,
Expand Down Expand Up @@ -498,10 +498,11 @@ impl WorkingState {
token_id: nft_address.id().clone(),
});
}
self.new_substate(addr.clone(), NonFungibleContainer::new(data, mut_data))?;
if !token_ids.insert(id.clone()) {
// Can't happen
return Err(RuntimeError::DuplicateNonFungibleId { token_id: id });
}
self.new_substate(addr.clone(), NonFungibleContainer::new(data, mut_data))?;

// for each new nft we also create an index to be allow resource scanning
let index_address = NonFungibleIndexAddress::new(resource_address, index);
Expand Down Expand Up @@ -530,6 +531,96 @@ impl WorkingState {
Ok(resource_container)
}

pub fn recall_resource_from_vault(
&mut self,
vault_lock: &LockedSubstate,
resource_discriminator: ResourceDiscriminator,
) -> Result<ResourceContainer, RuntimeError> {
let vault_id = vault_lock
.address()
.as_vault_id()
.ok_or_else(|| RuntimeError::InvariantError {
function: "recall_resource_from_vault",
details: "LockedSubstate address is not a VaultId".to_string(),
})?;

let vault_mut = self.get_vault_mut(vault_lock)?;
let resource_address = *vault_mut.resource_address();

let resource_container = match resource_discriminator {
ResourceDiscriminator::Everything => vault_mut.recall_all()?,
ResourceDiscriminator::Fungible { amount } => {
if amount.is_negative() {
return Err(RuntimeError::InvalidAmount {
amount,
reason: "Amount must be positive".to_string(),
});
}

if !vault_mut.resource_type().is_fungible() {
return Err(RuntimeError::InvalidArgument {
argument: "resource",
reason: format!(
"Vault {} contains a {} resource but a fungible was requested",
vault_id,
vault_mut.resource_type()
),
});
}

debug!(
target: LOG_TARGET,
"Recalling {} fungible tokens on resource: {}", amount, resource_address
);
vault_mut.withdraw(amount)?
},
ResourceDiscriminator::NonFungible { tokens } => {
debug!(
target: LOG_TARGET,
"Recalling {} NFT token(s) on vault: {}",
tokens.len(),
vault_id
);

if !vault_mut.resource_type().is_non_fungible() {
return Err(RuntimeError::InvalidArgument {
argument: "resource",
reason: format!(
"Vault {} contains a {} resource but a non-fungible was requested",
vault_id,
vault_mut.resource_type()
),
});
}

vault_mut.withdraw_non_fungibles(&tokens)?
},
ResourceDiscriminator::Confidential {
commitments,
revealed_amount,
} => {
debug!(
target: LOG_TARGET,
"Recalling confidential tokens on vault: {}", vault_id
);

if !vault_mut.resource_type().is_confidential() {
return Err(RuntimeError::InvalidArgument {
argument: "resource",
reason: format!(
"Vault contains a {} resource but a confidential was requested",
vault_mut.resource_type()
),
});
}

vault_mut.recall_confidential(commitments, revealed_amount)?
},
};

Ok(resource_container)
}

pub fn new_bucket(&mut self, bucket_id: BucketId, resource: ResourceContainer) -> Result<(), RuntimeError> {
debug!(
target: LOG_TARGET,
Expand Down Expand Up @@ -711,7 +802,7 @@ impl WorkingState {
.expect("invariant: vault that made fee payment not in changeset")
.as_vault_mut()
.expect("invariant: substate address for fee refund is not a vault");
vault_mut.resource_container_mut().deposit(resx.withdraw_all()?)?;
vault_mut.resource_container_mut().deposit(resx.recall_all()?)?;
}

Ok(TransactionReceipt {
Expand Down
Loading

0 comments on commit 51078d3

Please sign in to comment.