radix_transactions/manifest/
manifest_traits.rs

1use crate::internal_prelude::*;
2
3pub trait BuildableManifest:
4    TypedReadableManifest
5    + Into<AnyManifest>
6    + TryFrom<AnyManifest, Error = ()>
7    + ManifestEncode
8    + Default
9    + Eq
10    + Debug
11{
12    fn builder() -> ManifestBuilder<Self> {
13        ManifestBuilder::<Self>::new_typed()
14    }
15
16    fn add_instruction(&mut self, instruction: Self::Instruction);
17    fn add_blob(&mut self, hash: Hash, content: Vec<u8>);
18    fn set_names(&mut self, names: KnownManifestObjectNames);
19    fn set_names_if_known(&mut self, names: impl Into<ManifestObjectNames>) {
20        match names.into() {
21            ManifestObjectNames::Unknown => {}
22            ManifestObjectNames::Known(known_names) => self.set_names(known_names),
23        };
24    }
25    fn add_child_subintent(&mut self, _hash: SubintentHash) -> Result<(), ManifestBuildError> {
26        Err(ManifestBuildError::ChildSubintentsUnsupportedByManifestType)
27    }
28    fn add_preallocated_address(
29        &mut self,
30        _preallocated: PreAllocatedAddress,
31    ) -> Result<(), ManifestBuildError> {
32        Err(ManifestBuildError::PreallocatedAddressesUnsupportedByManifestType)
33    }
34    fn preallocation_count(&self) -> usize {
35        0
36    }
37
38    fn default_test_execution_config_type(&self) -> DefaultTestExecutionConfigType;
39    fn into_executable_with_proofs(
40        self,
41        nonce: u32,
42        initial_proofs: BTreeSet<NonFungibleGlobalId>,
43        validator: &TransactionValidator,
44    ) -> Result<ExecutableTransaction, String>;
45
46    fn to_raw(self) -> Result<RawManifest, EncodeError> {
47        let any_manifest: AnyManifest = self.into();
48        any_manifest.to_raw()
49    }
50
51    fn from_raw(raw: &RawManifest) -> Result<Self, String> {
52        let any_manifest = AnyManifest::from_raw(raw)
53            .map_err(|err| format!("Could not decode as `AnyManifest`: {err:?}"))?;
54        Self::try_from(any_manifest)
55            .map_err(|()| format!("Encoded manifest was not of the correct type"))
56    }
57
58    fn decode_arbitrary(bytes: impl AsRef<[u8]>) -> Result<Self, String> {
59        let any_manifest = AnyManifest::attempt_decode_from_arbitrary_payload(bytes.as_ref())?;
60        Self::try_from(any_manifest)
61            .map_err(|()| format!("Encoded manifest was not of the correct type"))
62    }
63}
64
65#[derive(Debug, Copy, Clone, PartialEq, Eq)]
66pub enum DefaultTestExecutionConfigType {
67    Notarized,
68    System,
69    Test,
70}
71
72#[derive(Debug, Copy, Clone, PartialEq, Eq)]
73pub enum ManifestBuildError {
74    DuplicateChildSubintentHash,
75    ChildSubintentsUnsupportedByManifestType,
76    PreallocatedAddressesUnsupportedByManifestType,
77}
78
79/// A trait indicating the manifest supports children.
80/// In that case, it's expected `add_child_subintent` does not error.
81pub trait BuildableManifestSupportingChildren: BuildableManifest {}
82
83/// A trait indicating the manifest supports children.
84/// In that case, it's expected `add_preallocated_address` should not error.
85pub trait BuildableManifestSupportingPreallocatedAddresses: BuildableManifest {}
86
87/// A trait indicating the manifest has a parent
88pub trait BuildableManifestWithParent: BuildableManifest {}
89
90pub trait TypedReadableManifest: ReadableManifestBase {
91    type Instruction: ManifestInstructionSet;
92    fn get_typed_instructions(&self) -> &[Self::Instruction];
93}
94
95pub trait ReadableManifestBase {
96    fn is_subintent(&self) -> bool;
97    fn get_blobs<'a>(&'a self) -> impl Iterator<Item = (&'a Hash, &'a Vec<u8>)>;
98    fn get_preallocated_addresses(&self) -> &[PreAllocatedAddress] {
99        &NO_PREALLOCATED_ADDRESSES
100    }
101    fn get_child_subintent_hashes<'a>(
102        &'a self,
103    ) -> impl ExactSizeIterator<Item = &'a ChildSubintentSpecifier> {
104        NO_CHILD_SUBINTENTS.iter()
105    }
106    fn get_known_object_names_ref(&self) -> ManifestObjectNamesRef;
107}
108
109/// An object-safe version of ReadableManifest
110pub trait ReadableManifest: ReadableManifestBase {
111    fn iter_instruction_effects(&self) -> impl Iterator<Item = ManifestInstructionEffect>;
112    fn iter_cloned_instructions(&self) -> impl Iterator<Item = AnyInstruction>;
113    fn instruction_count(&self) -> usize;
114    /// Panics if index is out of bounds
115    fn instruction_effect(&self, index: usize) -> ManifestInstructionEffect;
116
117    fn validate(&self, ruleset: ValidationRuleset) -> Result<(), ManifestValidationError> {
118        StaticManifestInterpreter::new(ruleset, self).validate()
119    }
120}
121
122impl<T: TypedReadableManifest + ?Sized> ReadableManifest for T {
123    fn iter_instruction_effects(&self) -> impl Iterator<Item = ManifestInstructionEffect> {
124        self.get_typed_instructions().iter().map(|i| i.effect())
125    }
126
127    fn iter_cloned_instructions(&self) -> impl Iterator<Item = AnyInstruction> {
128        self.get_typed_instructions()
129            .iter()
130            .map(|i| i.clone().into())
131    }
132
133    fn instruction_count(&self) -> usize {
134        self.get_typed_instructions().len()
135    }
136
137    fn instruction_effect(&self, index: usize) -> ManifestInstructionEffect {
138        self.get_typed_instructions()[index].effect()
139    }
140}
141
142static NO_PREALLOCATED_ADDRESSES: [PreAllocatedAddress; 0] = [];
143static NO_CHILD_SUBINTENTS: [ChildSubintentSpecifier; 0] = [];
144
145pub struct EphemeralManifest<'a, I: ManifestInstructionSet> {
146    pub is_subintent: bool,
147    pub instructions: &'a [I],
148    pub blobs: &'a IndexMap<Hash, Vec<u8>>,
149    pub child_subintent_specifiers: Option<&'a IndexSet<ChildSubintentSpecifier>>,
150    pub known_object_names_ref: ManifestObjectNamesRef<'a>,
151}
152
153impl<'a, I: ManifestInstructionSet> EphemeralManifest<'a, I> {
154    pub fn new_childless_transaction_manifest(
155        instructions: &'a [I],
156        blobs: &'a IndexMap<Hash, Vec<u8>>,
157    ) -> Self {
158        Self {
159            is_subintent: false,
160            instructions,
161            blobs,
162            child_subintent_specifiers: None,
163            known_object_names_ref: ManifestObjectNamesRef::Unknown,
164        }
165    }
166
167    pub fn new(
168        instructions: &'a [I],
169        blobs: &'a IndexMap<Hash, Vec<u8>>,
170        child_subintent_specifiers: &'a IndexSet<ChildSubintentSpecifier>,
171        is_subintent: bool,
172    ) -> Self {
173        Self {
174            is_subintent,
175            instructions,
176            blobs,
177            child_subintent_specifiers: Some(child_subintent_specifiers),
178            known_object_names_ref: ManifestObjectNamesRef::Unknown,
179        }
180    }
181}
182
183impl<'a, I: ManifestInstructionSet> ReadableManifestBase for EphemeralManifest<'a, I> {
184    fn is_subintent(&self) -> bool {
185        self.is_subintent
186    }
187
188    fn get_blobs<'b>(&'b self) -> impl Iterator<Item = (&'b Hash, &'b Vec<u8>)> {
189        self.blobs.iter()
190    }
191
192    fn get_known_object_names_ref(&self) -> ManifestObjectNamesRef {
193        self.known_object_names_ref
194    }
195
196    fn get_child_subintent_hashes<'b>(
197        &'b self,
198    ) -> impl ExactSizeIterator<Item = &'b ChildSubintentSpecifier> {
199        let iterator: Box<dyn ExactSizeIterator<Item = &'b ChildSubintentSpecifier>> =
200            match self.child_subintent_specifiers {
201                Some(specifiers) => Box::new(specifiers.iter()),
202                None => Box::new(NO_CHILD_SUBINTENTS.iter()),
203            };
204        iterator
205    }
206}
207
208impl<'a, I: ManifestInstructionSet> TypedReadableManifest for EphemeralManifest<'a, I> {
209    type Instruction = I;
210
211    fn get_typed_instructions(&self) -> &[I] {
212        self.instructions
213    }
214}