Skip to content

Commit

Permalink
Update RET's transaction analysis
Browse files Browse the repository at this point in the history
  • Loading branch information
0xOmarA committed Dec 12, 2024
1 parent 2b73796 commit 13ee650
Show file tree
Hide file tree
Showing 9 changed files with 880 additions and 702 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ impl From<CoreReservedInstruction> for ReservedInstruction {

#[derive(Clone, Debug, Enum)]
pub enum ManifestClass {
GeneralNonEnclosed,
General,
Transfer,
PoolContribution,
Expand All @@ -405,6 +406,7 @@ pub enum ManifestClass {
impl From<CoreManifestClass> for ManifestClass {
fn from(value: CoreManifestClass) -> Self {
match value {
CoreManifestClass::GeneralNonEnclosed => Self::GeneralNonEnclosed,
CoreManifestClass::General => Self::General,
CoreManifestClass::Transfer => Self::Transfer,
CoreManifestClass::PoolContribution => Self::PoolContribution,
Expand Down
1 change: 1 addition & 0 deletions crates/radix-engine-toolkit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ cargo_toml = { version = "0.15.3" }

[dev-dependencies]
scrypto-test = { workspace = true }
radix-transactions = { workspace = true }

[features]
default = []
Expand Down
52 changes: 38 additions & 14 deletions crates/radix-engine-toolkit/src/transaction_types/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ pub fn statically_analyze<M: ReadableManifest + ?Sized>(
let mut account_resource_movements_detector =
StaticAccountResourceMovementsDetector::default();

let mut general_non_enclosed_transaction_detector =
GeneralNonEnclosedDetector::default();
let mut general_transaction_detector = GeneralDetector::default();
let mut transfer_transaction_detector = TransferDetector::default();
let mut pool_contribution_detector = PoolContributionDetector::default();
Expand All @@ -62,6 +64,7 @@ pub fn statically_analyze<M: ReadableManifest + ?Sized>(
&mut reserved_instructions_detector,
&mut account_resource_movements_detector,
&mut general_transaction_detector,
&mut general_non_enclosed_transaction_detector,
&mut transfer_transaction_detector,
&mut pool_contribution_detector,
&mut pool_redemption_detector,
Expand All @@ -82,9 +85,15 @@ pub fn statically_analyze<M: ReadableManifest + ?Sized>(
let (account_withdraws, account_deposits) =
account_resource_movements_detector.output();
let classification = [
(
ManifestClass::GeneralNonEnclosed,
general_non_enclosed_transaction_detector.is_valid()
&& !general_transaction_detector.is_valid(),
),
(
ManifestClass::General,
general_transaction_detector.is_valid(),
general_transaction_detector.is_valid()
&& !general_non_enclosed_transaction_detector.is_valid(),
),
(
ManifestClass::Transfer,
Expand Down Expand Up @@ -145,6 +154,8 @@ pub fn statically_analyze_and_validate<M: ReadableManifest + ?Sized>(
let mut account_resource_movements_detector =
StaticAccountResourceMovementsDetector::default();

let mut general_non_enclosed_transaction_detector =
GeneralNonEnclosedDetector::default();
let mut general_transaction_detector = GeneralDetector::default();
let mut transfer_transaction_detector = TransferDetector::default();
let mut pool_contribution_detector = PoolContributionDetector::default();
Expand All @@ -164,6 +175,7 @@ pub fn statically_analyze_and_validate<M: ReadableManifest + ?Sized>(
&mut reserved_instructions_detector,
&mut account_resource_movements_detector,
&mut general_transaction_detector,
&mut general_non_enclosed_transaction_detector,
&mut transfer_transaction_detector,
&mut pool_contribution_detector,
&mut pool_redemption_detector,
Expand All @@ -184,9 +196,15 @@ pub fn statically_analyze_and_validate<M: ReadableManifest + ?Sized>(
let (account_withdraws, account_deposits) =
account_resource_movements_detector.output();
let classification = [
(
ManifestClass::GeneralNonEnclosed,
general_non_enclosed_transaction_detector.is_valid()
&& !general_transaction_detector.is_valid(),
),
(
ManifestClass::General,
general_transaction_detector.is_valid(),
general_transaction_detector.is_valid()
&& !general_non_enclosed_transaction_detector.is_valid(),
),
(
ManifestClass::Transfer,
Expand Down Expand Up @@ -261,6 +279,8 @@ pub fn classify_manifest<M: ReadableManifest + ?Sized>(
let mut account_resource_movements_detector =
StaticAccountResourceMovementsDetector::default();

let mut general_non_enclosed_transaction_detector =
GeneralNonEnclosedDetector::default();
let mut general_transaction_detector = GeneralDetector::default();
let mut transfer_transaction_detector = TransferDetector::default();
let mut pool_contribution_detector = PoolContributionDetector::default();
Expand All @@ -279,6 +299,7 @@ pub fn classify_manifest<M: ReadableManifest + ?Sized>(
&mut requiring_auth_detector,
&mut reserved_instructions_detector,
&mut account_resource_movements_detector,
&mut general_non_enclosed_transaction_detector,
&mut general_transaction_detector,
&mut transfer_transaction_detector,
&mut pool_contribution_detector,
Expand All @@ -293,9 +314,15 @@ pub fn classify_manifest<M: ReadableManifest + ?Sized>(

// Extracting the data out of the detectors and into the ManifestSummary
[
(
ManifestClass::GeneralNonEnclosed,
general_non_enclosed_transaction_detector.is_valid()
&& !general_transaction_detector.is_valid(),
),
(
ManifestClass::General,
general_transaction_detector.is_valid(),
general_transaction_detector.is_valid()
&& !general_non_enclosed_transaction_detector.is_valid(),
),
(
ManifestClass::Transfer,
Expand Down Expand Up @@ -486,17 +513,14 @@ pub fn dynamically_analyze<M: ReadableManifest>(
k,
v.into_iter()
.map(|(badge, operation)| {
(
badge,
match operation {
Update::Set(()) => {
Operation::Added
}
Update::Remove => {
Operation::Removed
}
},
)
(badge, match operation {
Update::Set(()) => {
Operation::Added
}
Update::Remove => {
Operation::Removed
}
})
})
.collect(),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ impl GeneralDetector {
| EntityType::InternalNonFungibleVault
| EntityType::InternalKeyValueStore
| EntityType::GlobalTransactionTracker
// TODO: Will be a problem once we do MFA and we
// need to allow for creation of proofs from the
// access controller.
| EntityType::GlobalAccessController
| EntityType::GlobalOneResourcePool
| EntityType::GlobalTwoResourcePool
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

use radix_transactions::manifest::*;
use radix_transactions::prelude::*;
use scrypto::prelude::*;

use radix_engine_interface::blueprints::account::*;

use crate::transaction_types::*;

pub struct GeneralNonEnclosedDetector {
is_valid: bool,
}

impl GeneralNonEnclosedDetector {
pub fn is_valid(&self) -> bool {
self.is_valid
}

pub fn output(self) -> Option<()> {
if self.is_valid() { Some(()) } else { None }
}
}

impl StaticAnalysisCallback for GeneralNonEnclosedDetector {
fn on_finish(&mut self, instructions_count: usize) {
if instructions_count == 0 {
self.is_valid = false
}
}

fn on_instruction(&mut self, instruction: &InstructionV2, _: usize) {
// Control whether or not this is allowed or not based on:
// 1. Whether the instruction is allowed.
// 2. Whether the instruction contents are allowed.
self.is_valid &= match instruction {
/* Maybe Permitted - Need more info */
InstructionV2::CallMethod(CallMethod {
address,
method_name,
..
}) => {
Self::construct_fn_rules(address).is_fn_permitted(method_name)
}
/* Permitted */
InstructionV2::TakeFromWorktop(..)
| InstructionV2::TakeNonFungiblesFromWorktop(..)
| InstructionV2::TakeAllFromWorktop(..)
| InstructionV2::ReturnToWorktop(..)
| InstructionV2::AssertWorktopContainsAny(..)
| InstructionV2::AssertWorktopContains(..)
| InstructionV2::AssertWorktopContainsNonFungibles(..)
| InstructionV2::AssertWorktopResourcesOnly(..)
| InstructionV2::AssertWorktopResourcesInclude(..)
| InstructionV2::AssertNextCallReturnsOnly(..)
| InstructionV2::AssertNextCallReturnsInclude(..)
| InstructionV2::AssertBucketContents(..)
| InstructionV2::PopFromAuthZone(..)
| InstructionV2::PushToAuthZone(..)
| InstructionV2::CreateProofFromAuthZoneOfAmount(..)
| InstructionV2::CreateProofFromAuthZoneOfNonFungibles(..)
| InstructionV2::CreateProofFromAuthZoneOfAll(..)
| InstructionV2::DropAuthZoneProofs(..)
| InstructionV2::DropAuthZoneRegularProofs(..)
| InstructionV2::DropAuthZoneSignatureProofs(..)
| InstructionV2::CreateProofFromBucketOfAmount(..)
| InstructionV2::CreateProofFromBucketOfNonFungibles(..)
| InstructionV2::CreateProofFromBucketOfAll(..)
| InstructionV2::CloneProof(..)
| InstructionV2::DropProof(..)
| InstructionV2::DropNamedProofs(..)
| InstructionV2::DropAllProofs(..)
| InstructionV2::CallFunction(..)
| InstructionV2::YieldToParent(_)
| InstructionV2::YieldToChild(_)
| InstructionV2::VerifyParent(_) => true,
/* Not Permitted */
InstructionV2::BurnResource(..)
| InstructionV2::CallRoyaltyMethod(..)
| InstructionV2::CallMetadataMethod(..)
| InstructionV2::CallRoleAssignmentMethod(..)
| InstructionV2::CallDirectVaultMethod(..)
| InstructionV2::AllocateGlobalAddress(..) => false,
}
}
}

impl DynamicAnalysisCallback for GeneralNonEnclosedDetector {}

impl GeneralNonEnclosedDetector {
fn construct_fn_rules(address: &DynamicGlobalAddress) -> FnRules {
match address {
DynamicGlobalAddress::Named(..) => FnRules::all_disallowed(),
DynamicGlobalAddress::Static(address) => {
address
.as_node_id()
.entity_type()
.map(|entity_type| {
match entity_type {
EntityType::GlobalAccount
| EntityType::GlobalPreallocatedSecp256k1Account
| EntityType::GlobalPreallocatedEd25519Account => {
FnRules {
allowed: &[
/* All withdraw methods */
ACCOUNT_WITHDRAW_IDENT,
ACCOUNT_WITHDRAW_NON_FUNGIBLES_IDENT,
/* All deposit methods */
ACCOUNT_DEPOSIT_IDENT,
ACCOUNT_DEPOSIT_BATCH_IDENT,
ACCOUNT_TRY_DEPOSIT_OR_ABORT_IDENT,
ACCOUNT_TRY_DEPOSIT_BATCH_OR_ABORT_IDENT,
/* All proof creation methods */
ACCOUNT_CREATE_PROOF_OF_AMOUNT_IDENT,
ACCOUNT_CREATE_PROOF_OF_NON_FUNGIBLES_IDENT,
/* Locking of fees */
ACCOUNT_LOCK_FEE_IDENT,
ACCOUNT_LOCK_CONTINGENT_FEE_IDENT,
ACCOUNT_LOCK_FEE_AND_WITHDRAW_IDENT,
ACCOUNT_LOCK_FEE_AND_WITHDRAW_NON_FUNGIBLES_IDENT,
],
disallowed: &[],
default: FnRule::Disallowed,
}
}
EntityType::GlobalGenericComponent
| EntityType::GlobalIdentity
| EntityType::GlobalPreallocatedSecp256k1Identity
| EntityType::GlobalPreallocatedEd25519Identity
| EntityType::InternalGenericComponent
| EntityType::GlobalAccountLocker => FnRules::all_allowed(),
/* Disallowed */
EntityType::GlobalPackage
| EntityType::GlobalValidator
| EntityType::GlobalFungibleResourceManager
| EntityType::GlobalNonFungibleResourceManager
| EntityType::GlobalConsensusManager
| EntityType::InternalFungibleVault
| EntityType::InternalNonFungibleVault
| EntityType::InternalKeyValueStore
| EntityType::GlobalTransactionTracker
// TODO: Will be a problem once we do MFA and we
// need to allow for creation of proofs from the
// access controller.
| EntityType::GlobalAccessController
| EntityType::GlobalOneResourcePool
| EntityType::GlobalTwoResourcePool
| EntityType::GlobalMultiResourcePool => {
FnRules::all_disallowed()
}
}
})
.unwrap_or(FnRules::all_disallowed())
}
}
}
}

impl Default for GeneralNonEnclosedDetector {
fn default() -> Self {
Self { is_valid: true }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
mod account_resource_movements;
mod account_settings;
mod general;
mod general_non_enclosed;
mod pool_contribution;
mod pool_redemption;
mod transfer;
Expand All @@ -28,6 +29,7 @@ mod validator_unstake;
pub use account_resource_movements::*;
pub use account_settings::*;
pub use general::*;
pub use general_non_enclosed::*;
pub use pool_contribution::*;
pub use pool_redemption::*;
pub use transfer::*;
Expand Down
3 changes: 3 additions & 0 deletions crates/radix-engine-toolkit/src/transaction_types/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ pub struct DynamicAnalysis {
/// are the classes that the Radix Engine Toolkit supports.
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum ManifestClass {
/// A general manifest that is not enclosed which means that it belongs to
/// a subintent.
GeneralNonEnclosed,
/// A general manifest that involves any amount of arbitrary components
/// and packages where nothing more concrete can be said about the manifest
/// and its nature.
Expand Down
Loading

0 comments on commit 13ee650

Please sign in to comment.