Skip to content

Commit

Permalink
Added support for manifest expresions
Browse files Browse the repository at this point in the history
  • Loading branch information
mstrug-rdx committed Jan 30, 2024
1 parent 3fc3b34 commit c63e7a8
Show file tree
Hide file tree
Showing 2 changed files with 215 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,53 @@ impl TrustedWorktop {
ret
}

fn merge_same_resources(
resources: &[ResourceSpecifier],
) -> Vec<ResourceSpecifier> {
let mut set: IndexMap<ResourceAddress, Vec<&ResourceSpecifier>> =
IndexMap::new();

resources.iter().for_each(|resource| {
if let Some((_, key, item)) =
set.get_full_mut(&resource.resource_address())
{
assert_eq!(
resource.resource_address().is_fungible(),
key.is_fungible()
);
item.push(resource);
} else {
set.insert(resource.resource_address(), vec![resource]);
}
});

let mut ret: Vec<ResourceSpecifier> = Vec::new();
for (k, v) in set.iter() {
if !v.is_empty() {
ret.push(match v[0] {
ResourceSpecifier::Amount(_, _) => {
let mut amount = dec!(0);
for resource in v {
amount = amount
.checked_add(*resource.amount().unwrap())
.unwrap();
}
ResourceSpecifier::Amount(*k, amount)
}
ResourceSpecifier::Ids(_, _) => {
let mut new_ids: IndexSet<NonFungibleLocalId> =
IndexSet::new();
for resource in v {
new_ids.extend(resource.ids().unwrap().clone());
}
ResourceSpecifier::Ids(*k, new_ids)
}
})
}
}
ret
}

fn handle_account_methods(
&mut self,
method_name: &String,
Expand Down Expand Up @@ -300,7 +347,7 @@ impl TrustedWorktop {
// setting untracked buckets mode as we are not supporting handling vectors of buckets
self.untrack_buckets = true;
}
_ => (),
_ => self.add_new_instruction(false, None),
}
} else {
assert_eq!(input_args.buckets().len(), 1);
Expand All @@ -321,12 +368,52 @@ impl TrustedWorktop {
| ACCOUNT_TRY_DEPOSIT_BATCH_OR_ABORT_IDENT => {
if !self.untrack_buckets {
let input_args = IndexedManifestValue::from_typed(args);
for bucket_id in input_args.buckets() {
self.bucket_consumed(bucket_id)
.expect("Bucket not found");

if input_args.expressions().len() > 0 {
match input_args
.expressions()
.first()
.expect("Expected expresion")
{
ManifestExpression::EntireWorktop => {
if !self.untrack_worktop_content {
let resources =
self.take_all_from_worktop();
self.add_new_instruction_with_many_resources(true, resources);
} else {
self.add_new_instruction(false, None);
}
}
_ => self.add_new_instruction(false, None),
}
} else {
let mut found_all_resources = true;
let mut resources =
Vec::with_capacity(input_args.buckets().len());
for bucket_id in input_args.buckets() {
if let Some(res) = self
.bucket_consumed(bucket_id)
.expect("Bucket not found")
{
resources.push(res);
} else {
// bucket with unknown resource -> untrusted instruction,
// iterate to consume rest of the buckets
found_all_resources = false;
}
}
if found_all_resources {
self.add_new_instruction_with_many_resources(
true,
Self::merge_same_resources(&resources),
);
} else {
self.add_new_instruction(false, None);
}
}
} else {
self.add_new_instruction(false, None);
}
self.add_new_instruction(false, None);
}
ACCOUNT_TRY_DEPOSIT_OR_REFUND_IDENT
| ACCOUNT_TRY_DEPOSIT_BATCH_OR_REFUND_IDENT => {
Expand Down Expand Up @@ -701,7 +788,6 @@ impl ManifestSummaryCallback for TrustedWorktop {
instruction: &InstructionV1,
instruction_index: usize,
) {
println!(" ==> TW: {}: {:?}", instruction_index, instruction);
match instruction {
InstructionV1::TakeAllFromWorktop { resource_address } => {
if !self.untrack_worktop_content {
Expand Down
166 changes: 123 additions & 43 deletions crates/radix-engine-toolkit/tests/worktop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,51 +34,58 @@ fn validate(
assert_eq!(
manifest_summary.trusted_worktop_instructions[instruction].trusted,
trusted,
"Instruction: {}",
"Instruction: {} (wrong trusted state)",
instruction
);
if resources.is_none() {
assert!(
manifest_summary.trusted_worktop_instructions[instruction]
.resources
.is_empty(),
"Instruction: {}",
"Instruction: {} (resoruce address not found)",
instruction
);
} else {
match resources.unwrap() {
ResourceSpecifier::Amount(address, amount) => {
assert_eq!(
assert!(
manifest_summary.trusted_worktop_instructions[instruction]
.resources
.first()
.unwrap()
.resource_address(),
address,
"Instruction: {}",
.iter()
.find(|item| item.resource_address() == address)
.is_some(),
"Instruction: {} (resource address not found)",
instruction
);
assert_eq!(
*manifest_summary.trusted_worktop_instructions[instruction]
assert!(
manifest_summary.trusted_worktop_instructions[instruction]
.resources
.first()
.unwrap()
.amount()
.unwrap(),
amount,
"Instruction: {}",
.iter()
.find(|item| item.resource_address() == address
&& *item.amount().unwrap() == amount)
.is_some(),
"Instruction: {} (amount not equal)",
instruction
);
}
ResourceSpecifier::Ids(address, _ids) => {
assert_eq!(
ResourceSpecifier::Ids(address, ids) => {
assert!(
manifest_summary.trusted_worktop_instructions[instruction]
.resources
.first()
.unwrap()
.resource_address(),
address,
"Instruction: {}",
.iter()
.find(|item| item.resource_address() == address)
.is_some(),
"Instruction: {} (resource address not found)",
instruction
);
assert!(
manifest_summary.trusted_worktop_instructions[instruction]
.resources
.iter()
.find(|item| item.resource_address() == address
&& ids.difference(item.ids().unwrap()).count() == 0)
.is_some(),
"Instruction: {} (ids not equal)",
instruction
);
}
Expand All @@ -91,19 +98,20 @@ fn validate_amount(
manifest_summary: &ManifestSummary,
instruction: usize,
trusted: bool,
resource_address: ResourceAddress,
amount: Decimal,
resource: &[(ResourceAddress, Decimal)],
) {
validate(
manifest_summary,
instruction,
trusted,
Some(ResourceSpecifier::Amount(resource_address, amount)),
);
resource.iter().for_each(|(resource_address, amount)| {
validate(
manifest_summary,
instruction,
trusted,
Some(ResourceSpecifier::Amount(*resource_address, *amount)),
)
});
}

#[test]
fn worktop_simple() {
fn trusted_worktop_deposit_from_bucket() {
// Arrange
let mut test_runner = TestRunnerBuilder::new().without_trace().build();
let (_, _, account) = test_runner.new_allocated_account();
Expand All @@ -122,13 +130,13 @@ fn worktop_simple() {
// Assert
assert_eq!(manifest_summary.trusted_worktop_instructions.len(), 4);
validate(&manifest_summary, 0, true, None);
validate_amount(&manifest_summary, 1, true, address, dec!(10));
validate_amount(&manifest_summary, 2, true, address, dec!(10));
validate_amount(&manifest_summary, 3, true, address, dec!(10));
validate_amount(&manifest_summary, 1, true, &[(address, dec!(10))]);
validate_amount(&manifest_summary, 2, true, &[(address, dec!(10))]);
validate_amount(&manifest_summary, 3, true, &[(address, dec!(10))]);
}

#[test]
fn worktop_simple2() {
fn trusted_worktop_burn_all() {
// Arrange
let mut test_runner = TestRunnerBuilder::new().without_trace().build();
let (_, _, account) = test_runner.new_allocated_account();
Expand All @@ -151,13 +159,13 @@ fn worktop_simple2() {
// Assert
assert_eq!(manifest_summary.trusted_worktop_instructions.len(), 4);
validate(&manifest_summary, 0, true, None);
validate_amount(&manifest_summary, 1, true, address, dec!(10));
validate_amount(&manifest_summary, 2, true, address, dec!(10)); // inserted instruction TakeAllFromWorktop by test framework
validate_amount(&manifest_summary, 1, true, &[(address, dec!(10))]);
validate_amount(&manifest_summary, 2, true, &[(address, dec!(10))]); // inserted instruction TakeAllFromWorktop by test framework
validate(&manifest_summary, 3, true, None);
}

#[test]
fn worktop_simple3() {
fn trusted_worktop_deposit_entire_worktop() {
// Arrange
let mut test_runner = TestRunnerBuilder::new().without_trace().build();
let (_, _, account) = test_runner.new_allocated_account();
Expand All @@ -182,8 +190,80 @@ fn worktop_simple3() {
// Assert
assert_eq!(manifest_summary.trusted_worktop_instructions.len(), 5);
validate(&manifest_summary, 0, true, None);
validate_amount(&manifest_summary, 1, true, address, dec!(10));
validate_amount(&manifest_summary, 2, true, address, dec!(6));
validate_amount(&manifest_summary, 3, true, address, dec!(6));
validate(&manifest_summary, 4, false, None);
validate_amount(&manifest_summary, 1, true, &[(address, dec!(10))]);
validate_amount(&manifest_summary, 2, true, &[(address, dec!(6))]);
validate_amount(&manifest_summary, 3, true, &[(address, dec!(6))]);
validate_amount(&manifest_summary, 4, true, &[(address, dec!(10))]);
}

#[test]
fn trusted_worktop_deposit_account_and_deposit_entire_worktop() {
// Arrange
let mut test_runner = TestRunnerBuilder::new().without_trace().build();
let (_, _, account) = test_runner.new_allocated_account();
let address = test_runner
.create_freely_mintable_and_burnable_fungible_resource(
OwnerRole::None,
Some(dec!(100)),
0,
account,
);

//Act
let manifest = ManifestBuilder::new()
.lock_fee_from_faucet()
.withdraw_from_account(account, address, 10)
.take_from_worktop(address, 6, "bucket_1")
.deposit(account, "bucket_1")
.try_deposit_entire_worktop_or_abort(account, None)
.build();
let (manifest_summary, _) = test_runner.summarize(manifest);

// Assert
assert_eq!(manifest_summary.trusted_worktop_instructions.len(), 5);
validate(&manifest_summary, 0, true, None);
validate_amount(&manifest_summary, 1, true, &[(address, dec!(10))]);
validate_amount(&manifest_summary, 2, true, &[(address, dec!(6))]);
validate_amount(&manifest_summary, 3, true, &[(address, dec!(6))]);
validate_amount(&manifest_summary, 4, true, &[(address, dec!(4))]);
}

#[test]
fn trusted_worktop_deposit_batch_and_deposit_entire_worktop() {
// Arrange
let mut test_runner = TestRunnerBuilder::new().without_trace().build();
let (_, _, account) = test_runner.new_allocated_account();
let address = test_runner
.create_freely_mintable_and_burnable_fungible_resource(
OwnerRole::None,
Some(dec!(100)),
0,
account,
);

//Act
let manifest = ManifestBuilder::new()
.get_free_xrd_from_faucet()
.take_from_worktop(XRD, dec!(1000), "bucket_1")
.take_from_worktop(XRD, dec!(2000), "bucket_2")
.withdraw_from_account(account, address, 10)
.take_from_worktop(address, 6, "bucket_3")
.try_deposit_batch_or_abort(
account,
["bucket_1", "bucket_2", "bucket_3"],
None,
)
.try_deposit_entire_worktop_or_abort(account, None)
.build();
let (ms, _) = test_runner.summarize(manifest);

// Assert
assert_eq!(ms.trusted_worktop_instructions.len(), 7);
validate_amount(&ms, 0, true, &[(XRD, dec!(10000))]);
validate_amount(&ms, 1, true, &[(XRD, dec!(1000))]);
validate_amount(&ms, 2, true, &[(XRD, dec!(2000))]);
validate_amount(&ms, 3, true, &[(address, dec!(10))]);
validate_amount(&ms, 4, true, &[(address, dec!(6))]);
validate_amount(&ms, 5, true, &[(XRD, dec!(3000)), (address, dec!(6))]);
validate_amount(&ms, 6, true, &[(XRD, dec!(7000)), (address, dec!(4))]);
}

0 comments on commit c63e7a8

Please sign in to comment.