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

Add a general subintent tx type & make owner key changes reserved #129

Merged
merged 5 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -392,6 +392,7 @@ impl From<CoreReservedInstruction> for ReservedInstruction {

#[derive(Clone, Debug, Enum)]
pub enum ManifestClass {
GeneralSubintent,
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::GeneralSubintent => Self::GeneralSubintent,
CoreManifestClass::General => Self::General,
CoreManifestClass::Transfer => Self::Transfer,
CoreManifestClass::PoolContribution => Self::PoolContribution,
Expand Down
46 changes: 35 additions & 11 deletions crates/radix-engine-toolkit/src/transaction_types/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
// specific language governing permissions and limitations
// under the License.

// TODO: Refactor the functions in here into a single function perhaps through
// some form of parsing modes, but we need to deduplicate the logic.

//! Functions that expose the transaction types functionality without exposing
//! any of the implementation details of how the module finds and determines
//! the transaction types.
Expand Down Expand Up @@ -44,6 +47,8 @@ pub fn statically_analyze<M: ReadableManifest + ?Sized>(
StaticAccountResourceMovementsDetector::default();

let mut general_transaction_detector = GeneralDetector::default();
let mut general_subintent_transaction_detector =
GeneralSubintentDetector::default();
let mut transfer_transaction_detector = TransferDetector::default();
let mut pool_contribution_detector = PoolContributionDetector::default();
let mut pool_redemption_detector = PoolRedemptionDetector::default();
Expand All @@ -62,6 +67,7 @@ pub fn statically_analyze<M: ReadableManifest + ?Sized>(
&mut reserved_instructions_detector,
&mut account_resource_movements_detector,
&mut general_transaction_detector,
&mut general_subintent_transaction_detector,
&mut transfer_transaction_detector,
&mut pool_contribution_detector,
&mut pool_redemption_detector,
Expand All @@ -82,6 +88,10 @@ pub fn statically_analyze<M: ReadableManifest + ?Sized>(
let (account_withdraws, account_deposits) =
account_resource_movements_detector.output();
let classification = [
(
ManifestClass::GeneralSubintent,
general_subintent_transaction_detector.is_valid(),
),
(
ManifestClass::General,
general_transaction_detector.is_valid(),
Expand Down Expand Up @@ -146,6 +156,8 @@ pub fn statically_analyze_and_validate<M: ReadableManifest + ?Sized>(
StaticAccountResourceMovementsDetector::default();

let mut general_transaction_detector = GeneralDetector::default();
let mut general_subintent_transaction_detector =
GeneralSubintentDetector::default();
let mut transfer_transaction_detector = TransferDetector::default();
let mut pool_contribution_detector = PoolContributionDetector::default();
let mut pool_redemption_detector = PoolRedemptionDetector::default();
Expand All @@ -164,6 +176,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_subintent_transaction_detector,
&mut transfer_transaction_detector,
&mut pool_contribution_detector,
&mut pool_redemption_detector,
Expand All @@ -184,6 +197,10 @@ pub fn statically_analyze_and_validate<M: ReadableManifest + ?Sized>(
let (account_withdraws, account_deposits) =
account_resource_movements_detector.output();
let classification = [
(
ManifestClass::GeneralSubintent,
general_subintent_transaction_detector.is_valid(),
),
(
ManifestClass::General,
general_transaction_detector.is_valid(),
Expand Down Expand Up @@ -262,6 +279,8 @@ pub fn classify_manifest<M: ReadableManifest + ?Sized>(
StaticAccountResourceMovementsDetector::default();

let mut general_transaction_detector = GeneralDetector::default();
let mut general_subintent_transaction_detector =
GeneralSubintentDetector::default();
let mut transfer_transaction_detector = TransferDetector::default();
let mut pool_contribution_detector = PoolContributionDetector::default();
let mut pool_redemption_detector = PoolRedemptionDetector::default();
Expand All @@ -280,6 +299,7 @@ pub fn classify_manifest<M: ReadableManifest + ?Sized>(
&mut reserved_instructions_detector,
&mut account_resource_movements_detector,
&mut general_transaction_detector,
&mut general_subintent_transaction_detector,
&mut transfer_transaction_detector,
&mut pool_contribution_detector,
&mut pool_redemption_detector,
Expand All @@ -293,6 +313,10 @@ pub fn classify_manifest<M: ReadableManifest + ?Sized>(

// Extracting the data out of the detectors and into the ManifestSummary
[
(
ManifestClass::GeneralSubintent,
general_subintent_transaction_detector.is_valid(),
),
(
ManifestClass::General,
general_transaction_detector.is_valid(),
Expand Down Expand Up @@ -352,6 +376,8 @@ pub fn dynamically_analyze<M: ReadableManifest>(
let newly_created_non_fungibles = receipt.new_non_fungibles();

let mut general_transaction_detector = GeneralDetector::default();
let mut general_subintent_transaction_detector =
GeneralSubintentDetector::default();
let mut transfer_transaction_detector = TransferDetector::default();
let mut pool_contribution_detector = PoolContributionDetector::default();
let mut pool_redemption_detector = PoolRedemptionDetector::default();
Expand All @@ -370,6 +396,7 @@ pub fn dynamically_analyze<M: ReadableManifest>(
&mut reserved_instructions_detector,
&mut account_resource_movements_detector,
&mut general_transaction_detector,
&mut general_subintent_transaction_detector,
&mut transfer_transaction_detector,
&mut pool_contribution_detector,
&mut pool_redemption_detector,
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
@@ -0,0 +1,183 @@
// 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 GeneralSubintentDetector {
is_valid: bool,
is_yield_to_parent_present: bool,
}

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

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

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

fn on_instruction(&mut self, instruction: &InstructionV2, _: usize) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERY MINOR / FOR FUTURE: In general, we can use AnyInstruction here instead of InstructionV2 (it's just an alias for the latest version, which would mean less code needs changing here if we add new instructions in future).

// 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,
};

if let InstructionV2::YieldToParent(..) = instruction {
self.is_yield_to_parent_present = true;
}
}
}

impl DynamicAnalysisCallback for GeneralSubintentDetector {}

impl GeneralSubintentDetector {
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
| EntityType::GlobalAccessController
| EntityType::GlobalOneResourcePool
| EntityType::GlobalTwoResourcePool
| EntityType::GlobalMultiResourcePool => {
FnRules::all_disallowed()
}
}
})
.unwrap_or(FnRules::all_disallowed())
}
}
}
}

impl Default for GeneralSubintentDetector {
fn default() -> Self {
Self {
is_valid: true,
is_yield_to_parent_present: false,
}
}
}
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_subintent;
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_subintent::*;
pub use pool_contribution::*;
pub use pool_redemption::*;
pub use transfer::*;
Expand Down
5 changes: 5 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,11 @@ pub struct DynamicAnalysis {
/// are the classes that the Radix Engine Toolkit supports.
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum ManifestClass {
/// A subintent manifest which satisfies the general rules allowed for in
/// general transactions and that includes a [`YieldToParent`] instruction.
///
/// [`YieldToParent`]: radix_transactions::manifest::YieldToParent
GeneralSubintent,
/// 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