Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the static analyzer to understand that some resources are not returned in invocations #2063

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1089,12 +1089,48 @@ fn static_analysis_on_account_add_authorized_depositor_with_named_address_succee
assert!(rtn.is_ok());
}

#[test]
fn static_analyzer_understands_when_non_of_the_input_resources_will_be_returned() {
// Arrange
let account = account_address(0);
let validator = validator_address(1);
let manifest = ManifestBuilder::new()
.withdraw_from_account(account, XRD, 100)
.take_from_worktop(XRD, 50, "bucket")
.stake_validator(validator, "bucket")
.take_all_from_worktop(XRD, "xrd")
.try_deposit_or_abort(account, None, "xrd")
.try_deposit_entire_worktop_or_abort(account, None)
.build();

// Act
let (deposits, ..) = statically_analyze(&manifest).unwrap();

// Assert
let account_deposits = deposits.get(&account).unwrap();
let first_deposit = account_deposits.first().unwrap();
assert_eq!(
first_deposit.unspecified_resources(),
UnspecifiedResources::none()
);
assert_eq!(
first_deposit.specified_resources().get(&XRD),
Some(&SimpleResourceBounds::Fungible(
SimpleFungibleResourceBounds::Exact(50.into())
))
);
}

fn account_address(id: u64) -> ComponentAddress {
unsafe {
ComponentAddress::new_unchecked(node_id(EntityType::GlobalPreallocatedEd25519Account, id).0)
}
}

fn validator_address(id: u64) -> ComponentAddress {
unsafe { ComponentAddress::new_unchecked(node_id(EntityType::GlobalValidator, id).0) }
}

fn component_address(id: u64) -> ComponentAddress {
unsafe { ComponentAddress::new_unchecked(node_id(EntityType::GlobalGenericComponent, id).0) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,23 +56,55 @@ macro_rules! no_output_static_invocation_resources_output_impl {
};
}

macro_rules! handle_single_unknown_output_static_invocation_resources_output_impl {
($input_ty: ty) => {
impl StaticInvocationResourcesOutput for $input_ty {
fn output(
&self,
details: InvocationDetails,
) -> Result<TrackedResources, StaticResourceMovementsError> {
Ok(
TrackedResources::new_with_possible_balance_of_unspecified_resources([
details.source
]),
)
}
}
};
(no_resource_inputs_returned: $input_ty: ty) => {
impl StaticInvocationResourcesOutput for $input_ty {
fn output(
&self,
details: InvocationDetails,
) -> Result<TrackedResources, StaticResourceMovementsError> {
let mut tracked_resources =
TrackedResources::new_with_possible_balance_of_unspecified_resources([
details.source
]);
for resource_address in details.sent_resources.specified_resources().keys() {
tracked_resources.handle_resource_assertion(
*resource_address,
ResourceBounds::zero(),
details.source,
)?;
}

Ok(tracked_resources)
}
}
};
}

macro_rules! unknown_output_static_invocation_resources_output_impl {
(
$(
$output_ident: ident
$([$modifier: ident]:)? $input_ty: ident
),* $(,)?
) => {
$(
impl StaticInvocationResourcesOutput for $output_ident {
fn output(
&self,
details: InvocationDetails
) -> Result<TrackedResources, StaticResourceMovementsError> {
Ok(TrackedResources::new_with_possible_balance_of_unspecified_resources([
details.source
]))
}
}
handle_single_unknown_output_static_invocation_resources_output_impl!(
$($modifier:)? $input_ty
);
)*
};
}
Expand Down Expand Up @@ -232,33 +264,33 @@ unknown_output_static_invocation_resources_output_impl![
AccessControllerMintRecoveryBadgesManifestInput,
// The validator stake unit resource is unknown at static validation time
/* Validator */
ValidatorStakeAsOwnerManifestInput,
[no_resource_inputs_returned]: ValidatorStakeAsOwnerManifestInput,
// The validator stake unit resource is unknown at static validation time
ValidatorStakeManifestInput,
[no_resource_inputs_returned]: ValidatorStakeManifestInput,
// The validator unstake receipt is unknown at static validation time
ValidatorUnstakeManifestInput,
[no_resource_inputs_returned]: ValidatorUnstakeManifestInput,
// This can return validator stake units which are an unknown resource at static validation time
ValidatorFinishUnlockOwnerStakeUnitsManifestInput,
[no_resource_inputs_returned]: ValidatorFinishUnlockOwnerStakeUnitsManifestInput,
// This generates and returns a new badge resource, which is unknowable at static time
/* AccountLocker */
AccountLockerInstantiateSimpleManifestInput,
/* OneResourcePool */
// This returns pool units of an unknown resource address and an unknown amount.
OneResourcePoolContributeManifestInput,
[no_resource_inputs_returned]: OneResourcePoolContributeManifestInput,
// This returns unknown resources of an unknown amount from the redemption.
OneResourcePoolRedeemManifestInput,
[no_resource_inputs_returned]: OneResourcePoolRedeemManifestInput,
// This returns an unknown resource but a known amount which we can't do much with.
OneResourcePoolProtectedWithdrawManifestInput,
/* TwoResourcePool */
// This returns pool units of an unknown resource address and an unknown amount.
TwoResourcePoolContributeManifestInput,
// This returns unknown resources of an unknown amount from the redemption.
TwoResourcePoolRedeemManifestInput,
[no_resource_inputs_returned]: TwoResourcePoolRedeemManifestInput,
/* MultiResourcePool */
// This returns pool units of an unknown resource address and an unknown amount.
MultiResourcePoolContributeManifestInput,
// This returns unknown resources of an unknown amount from the redemption.
MultiResourcePoolRedeemManifestInput,
[no_resource_inputs_returned]: MultiResourcePoolRedeemManifestInput,
/* FungibleResourceManager */
// This returns this resource so we know the amount but we don't know the resource address
// so we can't do much with that.
Expand Down
Loading