From e4e773ee7ad3e7df0dea932f1935b7063270d934 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 29 Jul 2024 15:03:13 +0200 Subject: [PATCH 01/21] validation: validate (& compute contract state) all operations in order --- src/contract/seal.rs | 4 + src/stl.rs | 2 +- src/validation/{anchor.rs => commitments.rs} | 0 src/validation/consignment.rs | 20 +- src/validation/logic.rs | 27 +- src/validation/mod.rs | 6 +- src/validation/state.rs | 2 + src/validation/status.rs | 29 +- src/validation/validator.rs | 273 +++++++++---------- src/vm/contract.rs | 38 ++- src/vm/isa.rs | 16 +- src/vm/mod.rs | 2 +- src/vm/op_contract.rs | 63 +++-- 13 files changed, 264 insertions(+), 218 deletions(-) rename src/validation/{anchor.rs => commitments.rs} (100%) diff --git a/src/contract/seal.rs b/src/contract/seal.rs index cbdc1c0b..d8bc5e4e 100644 --- a/src/contract/seal.rs +++ b/src/contract/seal.rs @@ -187,6 +187,8 @@ impl XChain { serde(crate = "serde_crate", rename_all = "camelCase") )] #[display("{height}@{timestamp}")] +// TODO: Rename into `TxPos` +// TODO: Move into validation::Logic or vm::Contract pub struct WitnessPos { height: u32, timestamp: i64, @@ -221,6 +223,8 @@ impl Ord for WitnessPos { derive(Serialize, Deserialize), serde(crate = "serde_crate", rename_all = "camelCase", untagged) )] +// TODO: Rename into `TxOrd` +// TODO: Move into validation::Logic or vm::Contract pub enum WitnessOrd { #[from] #[display(inner)] diff --git a/src/stl.rs b/src/stl.rs index cbd3551e..bfb737af 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -40,7 +40,7 @@ pub const LIB_ID_RGB_COMMIT: &str = "stl:tjFc6jD7-fe78CxG-WdJlH!l-uXlFfW0-XwG1!qV-MNdtNGE#orbit-airport-voice"; /// Strict types id for the library providing data types for RGB consensus. pub const LIB_ID_RGB_LOGIC: &str = - "stl:htYXb5WT-hbjOSBy-XWFng1B-6HCQUkx-5oCOB2H-P4KgVV8#target-locate-justin"; + "stl:BUSyF3Du-Fd$ARpR-oIQ2Wzx-vZ1iJQ8-PViDtnv-sj16HQo#clara-star-battery"; fn _rgb_commit_stl() -> Result { LibBuilder::new(libname!(LIB_NAME_RGB_COMMIT), tiny_bset! { diff --git a/src/validation/anchor.rs b/src/validation/commitments.rs similarity index 100% rename from src/validation/anchor.rs rename to src/validation/commitments.rs diff --git a/src/validation/consignment.rs b/src/validation/consignment.rs index 87af173a..a661fc27 100644 --- a/src/validation/consignment.rs +++ b/src/validation/consignment.rs @@ -31,10 +31,7 @@ use amplify::confinement::Confined; use strict_types::TypeSystem; use super::EAnchor; -use crate::{ - BundleId, Genesis, OpId, OpRef, Operation, Schema, SecretSeal, TransitionBundle, XChain, - XWitnessId, -}; +use crate::{BundleId, Genesis, OpId, OpRef, Operation, Schema, TransitionBundle, XWitnessId}; pub const CONSIGNMENT_MAX_LIBS: usize = 1024; @@ -59,10 +56,6 @@ impl<'consignment, C: ConsignmentApi> ConsignmentApi for CheckedConsignment<'con fn genesis(&self) -> &Genesis { self.0.genesis() } - fn terminals<'iter>(&self) -> impl Iterator)> + 'iter { - self.0.terminals() - } - fn bundle_ids<'iter>(&self) -> impl Iterator + 'iter { self.0.bundle_ids() } fn bundle(&self, bundle_id: BundleId) -> Option<&TransitionBundle> { @@ -103,17 +96,6 @@ pub trait ConsignmentApi { /// Contract genesis. fn genesis(&self) -> &Genesis; - /// The final state ("endpoints") provided by this consignment. - /// - /// There are two reasons for having endpoints: - /// - navigation towards genesis from the final state is more - /// computationally efficient, since state transition/extension graph is - /// directed towards genesis (like bitcoin transaction graph) - /// - if the consignment contains concealed state (known by the receiver), - /// it will be computationally inefficient to understand which of the - /// state transitions represent the final state - fn terminals<'iter>(&self) -> impl Iterator)> + 'iter; - /// Returns iterator over all bundle ids present in the consignment. fn bundle_ids<'iter>(&self) -> impl Iterator + 'iter; diff --git a/src/validation/logic.rs b/src/validation/logic.rs index 4cac5294..bccae583 100644 --- a/src/validation/logic.rs +++ b/src/validation/logic.rs @@ -20,7 +20,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::cell::RefCell; use std::collections::BTreeSet; +use std::rc::Rc; use aluvm::data::Number; use aluvm::isa::Instr; @@ -32,7 +34,7 @@ use strict_types::TypeSystem; use crate::schema::{AssignmentsSchema, GlobalSchema, ValencySchema}; use crate::validation::{CheckedConsignment, ConsignmentApi}; -use crate::vm::RgbIsa; +use crate::vm::{ContractState, RgbIsa}; use crate::{ validation, AssetTags, Assignments, AssignmentsRef, ContractId, ExposedSeal, Extension, GlobalState, GlobalStateSchema, GlobalValues, GraphSeal, Inputs, MetaSchema, Metadata, @@ -41,10 +43,12 @@ use crate::{ }; impl Schema { - pub fn validate_state<'validator, C: ConsignmentApi>( + // TODO: Instead of returning status fail immediately + pub fn validate_state<'validator, C: ConsignmentApi, S: ContractState>( &'validator self, consignment: &'validator CheckedConsignment<'_, C>, op: OpRef, + contract_state: Rc>, ) -> validation::Status { let opid = op.id(); let mut status = validation::Status::new(); @@ -194,17 +198,21 @@ impl Schema { &redeemed, &genesis.asset_tags, ); + let context = VmContext { + op_info, + contract_state, + }; // We need to run scripts as the very last step, since before that // we need to make sure that the operation data match the schema, so // scripts are not required to validate the structure of the state if let Some(validator) = validator { let scripts = consignment.scripts(); - let mut vm = Vm::>::new(); + let mut vm = Vm::>>::new(); if let Some(ty) = ty { vm.registers.set_n(RegA::A16, Reg32::Reg0, ty); } - if !vm.exec(validator, |id| scripts.get(&id), &op_info) { + if !vm.exec(validator, |id| scripts.get(&id), &context) { let error_code: Option = vm.registers.get_n(RegA::A8, Reg32::Reg0).into(); status.add_failure(validation::Failure::ScriptFailure( opid, @@ -212,6 +220,8 @@ impl Schema { None, )); } + let contract_state = context.contract_state; + contract_state.borrow_mut().evolve_state(op); } status } @@ -470,10 +480,19 @@ impl Schema { } } +// TODO: Move to VM module +pub struct VmContext<'op, S: ContractState> { + pub op_info: OpInfo<'op>, + pub contract_state: Rc>, +} + +// TODO: Move to VM module pub struct OpInfo<'op> { + // TODO: Move to VmContext pub contract_id: ContractId, pub id: OpId, pub ty: OpFullType, + // TODO: Move to VmContext pub asset_tags: &'op AssetTags, pub metadata: &'op Metadata, pub prev_state: &'op Assignments, diff --git a/src/validation/mod.rs b/src/validation/mod.rs index cea9bd58..e7d62586 100644 --- a/src/validation/mod.rs +++ b/src/validation/mod.rs @@ -26,10 +26,10 @@ mod state; mod validator; mod consignment; mod status; -mod anchor; +mod commitments; -pub use anchor::{DbcError, DbcProof, EAnchor}; +pub use commitments::{DbcError, DbcProof, EAnchor}; pub use consignment::{CheckedConsignment, ConsignmentApi, Scripts, CONSIGNMENT_MAX_LIBS}; -pub(crate) use logic::OpInfo; +pub(crate) use logic::VmContext; pub use status::{Failure, Info, Status, Validity, Warning}; pub use validator::{ResolveWitness, Validator, WitnessResolverError}; diff --git a/src/validation/state.rs b/src/validation/state.rs index 89cb2768..563dc535 100644 --- a/src/validation/state.rs +++ b/src/validation/state.rs @@ -20,6 +20,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// TODO: Move into `logic` mod + use strict_types::TypeSystem; use crate::schema::AssignmentType; diff --git a/src/validation/status.rs b/src/validation/status.rs index be3d37aa..deda9554 100644 --- a/src/validation/status.rs +++ b/src/validation/status.rs @@ -31,8 +31,8 @@ use crate::contract::Opout; use crate::schema::{self, SchemaId}; use crate::validation::WitnessResolverError; use crate::{ - AssignmentType, BundleId, ContractId, Layer1, OccurrencesMismatch, OpFullType, OpId, OpType, - SecretSeal, StateType, Vin, XChain, XGraphSeal, XOutputSeal, XWitnessId, + BundleId, ContractId, Layer1, OccurrencesMismatch, OpFullType, OpId, StateType, Vin, + XGraphSeal, XOutputSeal, XWitnessId, }; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Display)] @@ -239,21 +239,16 @@ pub enum Failure { CyclicGraph(OpId), /// operation {0} is absent from the consignment. OperationAbsent(OpId), - /// {ty} data doesn't match operation id {expected} (actual id is {actual}). - OperationIdMismatch { - ty: OpType, - expected: OpId, - actual: OpId, - }, - /// transition bundle {0} referenced in consignment terminals is absent from - /// the consignment. - TerminalBundleAbsent(BundleId), /// transition bundle {0} is absent in the consignment. BundleAbsent(BundleId), /// anchor for transitio bundle {0} is absent in the consignment. AnchorAbsent(BundleId), /// witness id for transition bundle {0} is absent in the consignment. WitnessIdAbsent(BundleId), + /// bundle {0} public witness {1} is not known to the resolver; validation + /// stopped since operations can't be consensus-ordered. The resolver + /// responded with error {2} + WitnessUnresolved(BundleId, XWitnessId, WitnessResolverError), /// operation {0} is under a different contract {1}. ContractMismatch(OpId, ContractId), @@ -271,9 +266,9 @@ pub enum Failure { // Errors checking asset tags /// asset type provided in genesis references unknown fungible state of type /// {0}. - AssetTagNoState(AssignmentType), + AssetTagNoState(schema::AssignmentType), /// fungible state {0} has no asset tag defined. - FungibleStateNoTag(AssignmentType), + FungibleStateNoTag(schema::AssignmentType), // Errors checking seal closing /// transition {opid} references state type {state_type} absent in the @@ -288,8 +283,9 @@ pub enum Failure { /// seal defined in the history as a part of operation output {0} is /// confidential and can't be validated. ConfidentialSeal(Opout), - /// public witness {0} is not known to the resolver. - SealNoPubWitness(XWitnessId, WitnessResolverError), + /// bundle {0} public witness {1} is not known to the resolver. Resolver + /// reported error {2} + SealNoPubWitness(BundleId, XWitnessId, WitnessResolverError), /// witness layer 1 {anchor} doesn't match seal definition {seal}. SealWitnessLayer1Mismatch { seal: Layer1, anchor: Layer1 }, /// seal {1} is defined on {0} which is not in the set of layers allowed @@ -370,9 +366,6 @@ pub enum Failure { )] #[display(doc_comments)] pub enum Warning { - /// terminal seal {1:?} referencing operation {0} is not present in - /// operation assignments. - TerminalSealAbsent(OpId, XChain), /// operation {0} contains state in assignment {1} which is confidential and /// thus was not validated. UncheckableConfidentialState(OpId, schema::AssignmentType), diff --git a/src/validation/validator.rs b/src/validation/validator.rs index 17d8ed79..d75b6692 100644 --- a/src/validation/validator.rs +++ b/src/validation/validator.rs @@ -21,7 +21,8 @@ // limitations under the License. use std::cell::RefCell; -use std::collections::{BTreeMap, BTreeSet, VecDeque}; +use std::collections::{BTreeMap, BTreeSet}; +use std::rc::Rc; use bp::dbc::Anchor; use bp::seals::txout::{CloseMethod, TxoSeal, Witness}; @@ -29,11 +30,12 @@ use bp::{dbc, Outpoint}; use commit_verify::mpc; use single_use_seals::SealWitness; -use super::status::{Failure, Warning}; +use super::status::Failure; use super::{CheckedConsignment, ConsignmentApi, DbcProof, EAnchor, Status, Validity}; +use crate::vm::{ContractState, OpOrd, WitnessAnchor}; use crate::{ - AltLayer1, BundleId, ContractId, Layer1, OpId, OpRef, OpType, Operation, Opout, Schema, - SchemaId, TransitionBundle, TypedAssigns, XChain, XOutpoint, XOutputSeal, XWitnessId, + validation, AltLayer1, BundleId, ContractId, Layer1, OpId, OpRef, OpType, Operation, Opout, + Schema, SchemaId, TransitionBundle, WitnessOrd, XChain, XOutpoint, XOutputSeal, XWitnessId, XWitnessTx, }; @@ -62,6 +64,13 @@ pub trait ResolveWitness { &self, witness_id: XWitnessId, ) -> Result; + + // TODO: Remove ResolveWitnessHeight trait from RGB stdlib and use this method + // instead + fn resolve_pub_witness_ord( + &self, + witness_id: XWitnessId, + ) -> Result; } impl ResolveWitness for &T { @@ -71,6 +80,13 @@ impl ResolveWitness for &T { ) -> Result { ResolveWitness::resolve_pub_witness(*self, witness_id) } + + fn resolve_pub_witness_ord( + &self, + witness_id: XWitnessId, + ) -> Result { + ResolveWitness::resolve_pub_witness_ord(*self, witness_id) + } } struct CheckedWitnessResolver { @@ -96,9 +112,23 @@ impl ResolveWitness for CheckedWitnessResolver { } Ok(witness) } + + #[inline] + fn resolve_pub_witness_ord( + &self, + witness_id: XWitnessId, + ) -> Result { + self.inner.resolve_pub_witness_ord(witness_id) + } } -pub struct Validator<'consignment, 'resolver, C: ConsignmentApi, R: ResolveWitness> { +pub struct Validator< + 'consignment, + 'resolver, + C: ConsignmentApi, + R: ResolveWitness, + S: ContractState, +> { consignment: CheckedConsignment<'consignment, C>, status: RefCell, @@ -108,19 +138,20 @@ pub struct Validator<'consignment, 'resolver, C: ConsignmentApi, R: ResolveWitne contract_id: ContractId, layers1: BTreeSet, + contract_state: Rc>, validated_op_seals: RefCell>, validated_op_state: RefCell>, resolver: CheckedWitnessResolver<&'resolver R>, } -impl<'consignment, 'resolver, C: ConsignmentApi, R: ResolveWitness> - Validator<'consignment, 'resolver, C, R> +impl<'consignment, 'resolver, C: ConsignmentApi, R: ResolveWitness, S: ContractState> + Validator<'consignment, 'resolver, C, R, S> { fn init(consignment: &'consignment C, resolver: &'resolver R) -> Self { // We use validation status object to store all detected failures and // warnings - let mut status = Status::default(); + let status = Status::default(); let consignment = CheckedConsignment::new(consignment); // Frequently used computation-heavy data @@ -129,30 +160,6 @@ impl<'consignment, 'resolver, C: ConsignmentApi, R: ResolveWitness> let contract_id = genesis.contract_id(); let schema_id = genesis.schema_id; - // Collect all endpoint transitions. - // This is pretty simple operation; it takes a lot of code because we would like - // to detect any potential issues with the consignment structure and notify user - // about them (in form of generated warnings) - for (bundle_id, seal_endpoint) in consignment.terminals() { - let Some(bundle) = consignment.bundle(bundle_id) else { - status.add_failure(Failure::TerminalBundleAbsent(bundle_id)); - continue; - }; - for (opid, transition) in &bundle.known_transitions { - // Checking for endpoint definition duplicates - if !transition - .assignments - .values() - .flat_map(TypedAssigns::to_confidential_seals) - .any(|seal| seal == seal_endpoint) - { - // We generate just a warning here because it's up to a user to decide whether - // to accept consignment with wrong endpoint list - status.add_warning(Warning::TerminalSealAbsent(*opid, seal_endpoint)); - } - } - } - // Validation index is used to check that all transitions presented in the // consignment were validated. Also, we use it to avoid double schema // validations for transitions. @@ -172,6 +179,7 @@ impl<'consignment, 'resolver, C: ConsignmentApi, R: ResolveWitness> validated_op_state, validated_op_seals, resolver: CheckedWitnessResolver::from(resolver), + contract_state: Rc::new(RefCell::new(empty!())), } } @@ -185,7 +193,7 @@ impl<'consignment, 'resolver, C: ConsignmentApi, R: ResolveWitness> /// rest of the consignment data. This can help to debug and detect all /// problems with the consignment. pub fn validate(consignment: &'consignment C, resolver: &'resolver R, testnet: bool) -> Status { - let mut validator = Validator::init(consignment, resolver); + let mut validator = Self::init(consignment, resolver); // If the network mismatches there is no point in validating the contract since // all witness transactions will be missed. if testnet != validator.consignment.genesis().testnet { @@ -241,124 +249,113 @@ impl<'consignment, 'resolver, C: ConsignmentApi, R: ResolveWitness> } // [VALIDATION]: Validate genesis - *self.status.borrow_mut() += - schema.validate_state(&self.consignment, OpRef::Genesis(self.consignment.genesis())); + *self.status.borrow_mut() += schema.validate_state( + &self.consignment, + OpRef::Genesis(self.consignment.genesis()), + self.contract_state.clone(), + ); self.validated_op_state.borrow_mut().insert(self.genesis_id); - // [VALIDATION]: Iterating over each endpoint, reconstructing operation - // graph up to genesis for each one of them. - // NB: We are not aiming to validate the consignment as a whole, but instead - // treat it as a superposition of subgraphs, one for each endpoint; and validate - // them independently. - for (bundle_id, _) in self.consignment.terminals() { - let Some(bundle) = self.consignment.bundle(bundle_id) else { - // We already checked and errored here during the terminal validation, so just - // skipping. - continue; - }; - for opid in bundle.known_transitions.keys() { - self.validate_logic_on_route(*opid); + // [VALIDATION]: Iterating over all consignment operations, ordering them according to the + // consensus ordering rules. + let mut ops = BTreeMap::::new(); + for bundle_id in self.consignment.bundle_ids() { + let bundle = self + .consignment + .bundle(bundle_id) + .expect("invalid checked consignment"); + let (witness_id, _) = self + .consignment + .anchor(bundle_id) + .expect("invalid checked consignment"); + let witness_ord = + match self.resolver.resolve_pub_witness_ord(witness_id) { + Ok(witness_ord) => witness_ord, + Err(err) => { + self.status.borrow_mut().add_failure( + validation::Failure::WitnessUnresolved(bundle_id, witness_id, err), + ); + // We need to stop validation there since we can't order operations + return; + } + }; + for (opid, op) in &bundle.known_transitions { + ops.insert( + OpOrd { + witness_ord: WitnessAnchor { + witness_ord, + witness_id, + }, + opid: *opid, + }, + OpRef::Transition(op), + ); } } + // TODO: Check that we include all terminal transitions + for op in ops.into_values() { + self.validate_operation(op); + } } - fn validate_logic_on_route(&self, opid: OpId) { + fn validate_operation(&self, operation: OpRef<'consignment>) { let schema = self.consignment.schema(); - let Some(OpRef::Transition(transition)) = self.consignment.operation(opid) else { + let opid = operation.id(); + + if operation.contract_id() != self.contract_id { self.status .borrow_mut() - .add_failure(Failure::OperationAbsent(opid)); - return; - }; - - let mut queue: VecDeque<(OpId, OpRef)> = VecDeque::new(); - - // Instead of constructing complex graph structures or using a recursions we - // utilize queue to keep the track of the upstream (ancestor) nodes and make - // sure that ve have validated each one of them up to genesis. The graph is - // valid when each of its nodes and each of its edges is valid, i.e. when all - // individual nodes have passed validation against the schema (we track - // that fact with `validation_index`) and each of the operation ancestor state - // change to a given operation is valid against the schema + committed - // into bitcoin transaction graph with proper anchor. That is what we are - // checking in the code below: - queue.push_back((opid, OpRef::Transition(transition))); - while let Some((opid, operation)) = queue.pop_front() { - let actual_opid = operation.id(); - if opid != actual_opid { - self.status - .borrow_mut() - .add_failure(Failure::OperationIdMismatch { - ty: operation.op_type(), - expected: opid, - actual: actual_opid, - }); - } + .add_failure(Failure::ContractMismatch(opid, operation.contract_id())); + } - if operation.contract_id() != self.contract_id { - self.status - .borrow_mut() - .add_failure(Failure::ContractMismatch(opid, operation.contract_id())); - continue; - } + if !self.validated_op_seals.borrow().contains(&opid) && + operation.op_type() == OpType::StateTransition + { + self.status + .borrow_mut() + .add_failure(Failure::SealsUnvalidated(opid)); + } + // [VALIDATION]: Verify operation against the schema and scripts + if self.validated_op_state.borrow_mut().insert(opid) { + *self.status.borrow_mut() += + schema.validate_state(&self.consignment, operation, self.contract_state.clone()); + } - if !self.validated_op_seals.borrow().contains(&opid) && - operation.op_type() == OpType::StateTransition - { - self.status - .borrow_mut() - .add_failure(Failure::SealsUnvalidated(opid)); + match operation { + OpRef::Genesis(_) => { + unreachable!("genesis is not a part of the operation history") } - // [VALIDATION]: Verify operation against the schema and scripts - if self.validated_op_state.borrow_mut().insert(opid) { - *self.status.borrow_mut() += schema.validate_state(&self.consignment, operation); - } - - match operation { - OpRef::Genesis(_) => { - // nothing to add to the queue here - } - OpRef::Transition(transition) => { - // Now, we must collect all parent nodes and add them to the verification queue - let parent_nodes = transition.inputs.iter().filter_map(|input| { - self.consignment - .operation(input.prev_out.op) - .map(|op| (input.prev_out.op, op)) - .or_else(|| { - self.status - .borrow_mut() - .add_failure(Failure::OperationAbsent(input.prev_out.op)); - None - }) - }); - - queue.extend(parent_nodes); + OpRef::Transition(transition) => { + for input in &transition.inputs { + if self.consignment.operation(input.prev_out.op).is_none() { + self.status + .borrow_mut() + .add_failure(Failure::OperationAbsent(input.prev_out.op)); + } } - OpRef::Extension(extension) => { - for (valency, prev_id) in &extension.redeemed { - let Some(prev_op) = self.consignment.operation(*prev_id) else { - self.status - .borrow_mut() - .add_failure(Failure::ValencyNoParent { - opid, - prev_id: *prev_id, - valency: *valency, - }); - continue; - }; - - if !prev_op.valencies().contains(valency) { - self.status - .borrow_mut() - .add_failure(Failure::NoPrevValency { - opid, - prev_id: *prev_id, - valency: *valency, - }); - continue; - } + } + OpRef::Extension(extension) => { + for (valency, prev_id) in &extension.redeemed { + let Some(prev_op) = self.consignment.operation(*prev_id) else { + self.status + .borrow_mut() + .add_failure(Failure::ValencyNoParent { + opid, + prev_id: *prev_id, + valency: *valency, + }); + continue; + }; - queue.push_back((*prev_id, prev_op)); + if !prev_op.valencies().contains(valency) { + self.status + .borrow_mut() + .add_failure(Failure::NoPrevValency { + opid, + prev_id: *prev_id, + valency: *valency, + }); + continue; } } } @@ -464,7 +461,7 @@ impl<'consignment, 'resolver, C: ConsignmentApi, R: ResolveWitness> // failure!) self.status .borrow_mut() - .add_failure(Failure::SealNoPubWitness(witness_id, err)); + .add_failure(Failure::SealNoPubWitness(bundle_id, witness_id, err)); None } Ok(pub_witness) => { diff --git a/src/vm/contract.rs b/src/vm/contract.rs index fe2e8b37..d055cdf7 100644 --- a/src/vm/contract.rs +++ b/src/vm/contract.rs @@ -25,11 +25,12 @@ use std::cmp::Ordering; use std::fmt::Debug; use amplify::num::u24; +use amplify::Bytes32; use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; use crate::{ - AssignmentType, AttachState, DataState, FungibleState, GlobalStateType, WitnessOrd, XOutpoint, - XWitnessId, LIB_NAME_RGB_LOGIC, + AssignmentType, AttachState, DataState, FungibleState, GlobalStateType, OpId, OpRef, + WitnessOrd, XOutpoint, XWitnessId, LIB_NAME_RGB_LOGIC, }; #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display, From)] @@ -40,6 +41,7 @@ use crate::{ derive(Serialize, Deserialize), serde(crate = "serde_crate", rename_all = "camelCase", untagged) )] +// TODO: Rename into `OpWitnessId` pub enum AssignmentWitness { #[display("~")] #[strict_type(tag = 0, dumb)] @@ -87,6 +89,7 @@ impl AssignmentWitness { serde(crate = "serde_crate", rename_all = "camelCase") )] #[display("{witness_id}/{witness_ord}")] +// TODO: Rename into `WitnessOrd` pub struct WitnessAnchor { pub witness_ord: WitnessOrd, pub witness_id: XWitnessId, @@ -125,6 +128,21 @@ impl WitnessAnchor { } } +/// Consensus ordering of operations within a contract. +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_LOGIC)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +pub struct OpOrd { + pub witness_ord: WitnessAnchor, + pub opid: OpId, +} + +/// Consensus ordering of global state #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_LOGIC)] @@ -134,7 +152,10 @@ impl WitnessAnchor { serde(crate = "serde_crate", rename_all = "camelCase") )] pub struct GlobalOrd { + // Absent for state defined in genesis + // TODO: Change into `AssignmentWitness` pub witness_anchor: Option, + pub opid: OpId, pub idx: u16, } @@ -159,16 +180,18 @@ impl Ord for GlobalOrd { impl GlobalOrd { #[inline] - pub fn with_witness(witness_id: XWitnessId, ord: WitnessOrd, idx: u16) -> Self { + pub fn with_witness(opid: OpId, witness_id: XWitnessId, ord: WitnessOrd, idx: u16) -> Self { GlobalOrd { witness_anchor: Some(WitnessAnchor::with(witness_id, ord)), + opid, idx, } } #[inline] - pub fn genesis(idx: u16) -> Self { + pub fn genesis(opid: OpId, idx: u16) -> Self { GlobalOrd { witness_anchor: None, + opid, idx, } } @@ -210,7 +233,9 @@ impl GlobalContractState { #[inline] pub fn new(mut iter: I) -> Self { let last_ord = iter.prev().map(|(ord, _)| ord).unwrap_or(GlobalOrd { + // This is dumb object which must always have the lowest ordering. witness_anchor: None, + opid: Bytes32::zero().into(), idx: 0, }); iter.reset(u24::ZERO); @@ -280,7 +305,8 @@ impl Iterator for GlobalContractState { #[display("unknown global state type {0} requested from the contract")] pub struct UnknownGlobalStateType(pub GlobalStateType); -pub trait ContractState { +// TODO: Separate mutable and immutable parts of the trait +pub trait ContractState: Debug + Default { fn global( &self, ty: GlobalStateType, @@ -305,4 +331,6 @@ pub trait ContractState { outpoint: XOutpoint, ty: AssignmentType, ) -> impl DoubleEndedIterator>; + + fn evolve_state(&mut self, op: OpRef); } diff --git a/src/vm/isa.rs b/src/vm/isa.rs index 9f088f3c..de0e0ff9 100644 --- a/src/vm/isa.rs +++ b/src/vm/isa.rs @@ -28,15 +28,15 @@ use aluvm::isa::{Bytecode, BytecodeError, ExecStep, InstructionSet}; use aluvm::library::{CodeEofError, IsaSeg, LibSite, Read, Write}; use aluvm::reg::{CoreRegs, Reg}; -use super::{ContractOp, TimechainOp}; -use crate::validation::OpInfo; +use super::{ContractOp, ContractState, TimechainOp}; +use crate::validation::VmContext; use crate::vm::opcodes::{INSTR_RGBISA_FROM, INSTR_RGBISA_TO}; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] #[display(inner)] #[non_exhaustive] -pub enum RgbIsa { - Contract(ContractOp), +pub enum RgbIsa { + Contract(ContractOp), Timechain(TimechainOp), @@ -45,8 +45,8 @@ pub enum RgbIsa { Fail(u8), } -impl InstructionSet for RgbIsa { - type Context<'ctx> = OpInfo<'ctx>; +impl InstructionSet for RgbIsa { + type Context<'ctx> = VmContext<'ctx, S>; fn isa_ids() -> IsaSeg { IsaSeg::with("RGB") } @@ -86,7 +86,7 @@ impl InstructionSet for RgbIsa { } } -impl Bytecode for RgbIsa { +impl Bytecode for RgbIsa { fn instr_range() -> RangeInclusive { INSTR_RGBISA_FROM..=INSTR_RGBISA_TO } fn instr_byte(&self) -> u8 { @@ -113,7 +113,7 @@ impl Bytecode for RgbIsa { { let instr = reader.peek_u8()?; Ok(match instr { - instr if ContractOp::instr_range().contains(&instr) => { + instr if ContractOp::::instr_range().contains(&instr) => { RgbIsa::Contract(ContractOp::decode(reader)?) } instr if TimechainOp::instr_range().contains(&instr) => { diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 05440c56..d1299860 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -34,7 +34,7 @@ mod contract; pub use aluvm::aluasm_isa; pub use contract::{ - AssignmentWitness, ContractState, GlobalContractState, GlobalOrd, GlobalStateIter, + AssignmentWitness, ContractState, GlobalContractState, GlobalOrd, GlobalStateIter, OpOrd, UnknownGlobalStateType, WitnessAnchor, }; pub use isa::RgbIsa; diff --git a/src/vm/op_contract.rs b/src/vm/op_contract.rs index 83814daf..4948cdb7 100644 --- a/src/vm/op_contract.rs +++ b/src/vm/op_contract.rs @@ -23,6 +23,7 @@ #![allow(clippy::unusual_byte_groupings)] use std::collections::BTreeSet; +use std::marker::PhantomData; use std::ops::RangeInclusive; use aluvm::isa::{Bytecode, BytecodeError, ExecStep, InstructionSet}; @@ -33,14 +34,15 @@ use amplify::Wrapper; use commit_verify::CommitVerify; use super::opcodes::*; -use crate::validation::OpInfo; +use crate::validation::VmContext; +use crate::vm::ContractState; use crate::{ Assign, AssignmentType, BlindingFactor, GlobalStateType, MetaType, PedersenCommitment, RevealedValue, TypedAssigns, }; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] -pub enum ContractOp { +pub enum ContractOp { /// Counts number of inputs (previous state entries) of the provided type /// and puts the number to the destination `a16` register. #[display("cnp {0},a16{1}")] @@ -161,11 +163,11 @@ pub enum ContractOp { /// All other future unsupported operations, which must set `st0` to /// `false` and stop the execution. #[display("fail {0}")] - Fail(u8), + Fail(u8, PhantomData), } -impl InstructionSet for ContractOp { - type Context<'ctx> = OpInfo<'ctx>; +impl InstructionSet for ContractOp { + type Context<'ctx> = VmContext<'ctx, S>; fn isa_ids() -> IsaSeg { IsaSeg::with("RGB") } @@ -184,7 +186,7 @@ impl InstructionSet for ContractOp { ContractOp::LdM(_, _) => bset![], ContractOp::Pcvs(_) => bset![], ContractOp::Pcas(_) | ContractOp::Pcps(_) => bset![Reg::A(RegA::A64, Reg32::Reg0)], - ContractOp::Fail(_) => bset![], + ContractOp::Fail(_, _) => bset![], } } @@ -209,7 +211,7 @@ impl InstructionSet for ContractOp { ContractOp::Pcvs(_) | ContractOp::Pcas(_) | ContractOp::Pcps(_) => { bset![] } - ContractOp::Fail(_) => bset![], + ContractOp::Fail(_, _) => bset![], } } @@ -227,7 +229,7 @@ impl InstructionSet for ContractOp { ContractOp::LdM(_, _) => 6, ContractOp::Pcvs(_) => 1024, ContractOp::Pcas(_) | ContractOp::Pcps(_) => 512, - ContractOp::Fail(_) => u64::MAX, + ContractOp::Fail(_, _) => u64::MAX, } } @@ -240,7 +242,7 @@ impl InstructionSet for ContractOp { } macro_rules! load_inputs { ($state_type:ident) => {{ - let Some(prev_state) = context.prev_state.get($state_type) else { + let Some(prev_state) = context.op_info.prev_state.get($state_type) else { fail!() }; match prev_state { @@ -255,7 +257,7 @@ impl InstructionSet for ContractOp { } macro_rules! load_outputs { ($state_type:ident) => {{ - let Some(new_state) = context.owned_state.get(*$state_type) else { + let Some(new_state) = context.op_info.owned_state.get(*$state_type) else { fail!() }; match new_state { @@ -274,18 +276,30 @@ impl InstructionSet for ContractOp { regs.set_n( RegA::A16, *reg, - context.prev_state.get(state_type).map(|a| a.len_u16()), + context + .op_info + .prev_state + .get(state_type) + .map(|a| a.len_u16()), ); } ContractOp::CnS(state_type, reg) => { regs.set_n( RegA::A16, *reg, - context.owned_state.get(*state_type).map(|a| a.len_u16()), + context + .op_info + .owned_state + .get(*state_type) + .map(|a| a.len_u16()), ); } ContractOp::CnG(state_type, reg) => { - regs.set_n(RegA::A8, *reg, context.global.get(state_type).map(|a| a.len_u16())); + regs.set_n( + RegA::A8, + *reg, + context.op_info.global.get(state_type).map(|a| a.len_u16()), + ); } ContractOp::CnC(_state_type, _reg) => { // TODO: implement global contract state @@ -298,6 +312,7 @@ impl InstructionSet for ContractOp { let index: u16 = reg_32.into(); let Some(Ok(state)) = context + .op_info .prev_state .get(state_type) .map(|a| a.as_structured_state_at(index)) @@ -314,6 +329,7 @@ impl InstructionSet for ContractOp { let index: u16 = reg_32.into(); let Some(Ok(state)) = context + .op_info .owned_state .get(*state_type) .map(|a| a.into_structured_state_at(index)) @@ -330,6 +346,7 @@ impl InstructionSet for ContractOp { let index: u16 = reg_32.into(); let Some(Ok(state)) = context + .op_info .owned_state .get(*state_type) .map(|a| a.into_fungible_state_at(index)) @@ -345,6 +362,7 @@ impl InstructionSet for ContractOp { let index: u8 = reg_32.into(); let Some(state) = context + .op_info .global .get(state_type) .and_then(|a| a.get(index as usize)) @@ -359,7 +377,7 @@ impl InstructionSet for ContractOp { fail!() } ContractOp::LdM(type_id, reg) => { - let Some(meta) = context.metadata.get(type_id) else { + let Some(meta) = context.op_info.metadata.get(type_id) else { fail!() }; regs.set_s(*reg, Some(meta.to_inner())); @@ -383,7 +401,7 @@ impl InstructionSet for ContractOp { }; let sum = u64::from(sum); - let Some(tag) = context.asset_tags.get(owned_state) else { + let Some(tag) = context.op_info.asset_tags.get(owned_state) else { fail!() }; let sum = RevealedValue::with_blinding(sum, BlindingFactor::EMPTY, *tag); @@ -406,7 +424,7 @@ impl InstructionSet for ContractOp { }; let sum = u64::from(sum); - let Some(tag) = context.asset_tags.get(owned_state) else { + let Some(tag) = context.op_info.asset_tags.get(owned_state) else { fail!() }; let sum = RevealedValue::with_blinding(sum, BlindingFactor::EMPTY, *tag); @@ -429,7 +447,7 @@ impl InstructionSet for ContractOp { } } -impl Bytecode for ContractOp { +impl Bytecode for ContractOp { fn instr_range() -> RangeInclusive { INSTR_CONTRACT_FROM..=INSTR_CONTRACT_TO } fn instr_byte(&self) -> u8 { @@ -450,7 +468,7 @@ impl Bytecode for ContractOp { ContractOp::Pcas(_) => INSTR_PCAS, ContractOp::Pcps(_) => INSTR_PCPS, - ContractOp::Fail(other) => *other, + ContractOp::Fail(other, _) => *other, } } @@ -512,7 +530,7 @@ impl Bytecode for ContractOp { ContractOp::Pcas(owned_type) => writer.write_u16(*owned_type)?, ContractOp::Pcps(owned_type) => writer.write_u16(*owned_type)?, - ContractOp::Fail(_) => {} + ContractOp::Fail(_, _) => {} } Ok(()) } @@ -579,11 +597,13 @@ impl Bytecode for ContractOp { INSTR_PCAS => Self::Pcas(reader.read_u16()?.into()), INSTR_PCPS => Self::Pcps(reader.read_u16()?.into()), - x => Self::Fail(x), + x => Self::Fail(x, PhantomData), }) } } +// TODO: Re-enable once we will have a test ContractState object +/* #[cfg(test)] mod test { use aluvm::isa::Instr; @@ -614,6 +634,7 @@ mod test { .to_hex(), "0303414c55084250444947455354035247420300d0a00f000000" ); - assert_eq!(alu_lib.disassemble::>().unwrap(), code); + assert_eq!(alu_lib.disassemble::>>().unwrap(), code); } } +*/ From 44e2e5c36182290bf2a1bd25b6faf4c7ed8c6f63 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 29 Jul 2024 15:18:30 +0200 Subject: [PATCH 02/21] validation: move state into logic module --- src/validation/logic.rs | 102 +++++++++++++++++++++++++++++++- src/validation/mod.rs | 1 - src/validation/state.rs | 126 ---------------------------------------- 3 files changed, 99 insertions(+), 130 deletions(-) delete mode 100644 src/validation/state.rs diff --git a/src/validation/logic.rs b/src/validation/logic.rs index bccae583..7714f1ac 100644 --- a/src/validation/logic.rs +++ b/src/validation/logic.rs @@ -36,9 +36,10 @@ use crate::schema::{AssignmentsSchema, GlobalSchema, ValencySchema}; use crate::validation::{CheckedConsignment, ConsignmentApi}; use crate::vm::{ContractState, RgbIsa}; use crate::{ - validation, AssetTags, Assignments, AssignmentsRef, ContractId, ExposedSeal, Extension, - GlobalState, GlobalStateSchema, GlobalValues, GraphSeal, Inputs, MetaSchema, Metadata, - OpFullType, OpId, OpRef, Operation, Opout, OwnedStateSchema, Schema, StateType, Transition, + validation, AssetTags, Assign, AssignmentType, Assignments, AssignmentsRef, ConcealedState, + ConfidentialState, ContractId, ExposedSeal, ExposedState, Extension, GlobalState, + GlobalStateSchema, GlobalValues, GraphSeal, Inputs, MetaSchema, Metadata, OpFullType, OpId, + OpRef, Operation, Opout, OwnedStateSchema, RevealedState, Schema, StateType, Transition, TypedAssigns, Valencies, }; @@ -609,3 +610,98 @@ fn extract_prev_state( .expect("collections is assembled from another collection with the same size requirements") .into() } + +impl OwnedStateSchema { + pub fn validate( + &self, + opid: OpId, + state_type: AssignmentType, + data: &Assign, + type_system: &TypeSystem, + ) -> validation::Status { + let mut status = validation::Status::new(); + match data { + Assign::Confidential { state, .. } | Assign::ConfidentialState { state, .. } => { + match (self, state.state_commitment()) { + (OwnedStateSchema::Declarative, ConcealedState::Void) => {} + (OwnedStateSchema::Fungible(_), ConcealedState::Fungible(value)) => { + // [SECURITY-CRITICAL]: Bulletproofs validation + if let Err(err) = value.verify_range_proof() { + status.add_failure(validation::Failure::BulletproofsInvalid( + opid, + state_type, + err.to_string(), + )); + } + } + (OwnedStateSchema::Structured(_), ConcealedState::Structured(_)) => { + status.add_warning(validation::Warning::UncheckableConfidentialState( + opid, state_type, + )); + } + (OwnedStateSchema::Attachment(_), ConcealedState::Attachment(_)) => { + status.add_warning(validation::Warning::UncheckableConfidentialState( + opid, state_type, + )); + } + // all other options are mismatches + (state_schema, found) => { + status.add_failure(validation::Failure::StateTypeMismatch { + opid, + state_type, + expected: state_schema.state_type(), + found: found.state_type(), + }); + } + } + } + Assign::Revealed { state, .. } | Assign::ConfidentialSeal { state, .. } => { + match (self, state.state_data()) { + (OwnedStateSchema::Declarative, RevealedState::Void) => {} + ( + OwnedStateSchema::Attachment(media_type), + RevealedState::Attachment(attach), + ) if !attach.file.media_type.conforms(media_type) => { + status.add_failure(validation::Failure::MediaTypeMismatch { + opid, + state_type, + expected: *media_type, + found: attach.file.media_type, + }); + } + (OwnedStateSchema::Fungible(schema), RevealedState::Fungible(v)) + if v.value.fungible_type() != *schema => + { + status.add_failure(validation::Failure::FungibleTypeMismatch { + opid, + state_type, + expected: *schema, + found: v.value.fungible_type(), + }); + } + (OwnedStateSchema::Fungible(_), RevealedState::Fungible(_)) => {} + (OwnedStateSchema::Structured(sem_id), RevealedState::Structured(data)) => { + if type_system + .strict_deserialize_type(*sem_id, data.value.as_ref()) + .is_err() + { + status.add_failure(validation::Failure::SchemaInvalidOwnedValue( + opid, state_type, *sem_id, + )); + }; + } + // all other options are mismatches + (state_schema, found) => { + status.add_failure(validation::Failure::StateTypeMismatch { + opid, + state_type, + expected: state_schema.state_type(), + found: found.state_type(), + }); + } + } + } + } + status + } +} diff --git a/src/validation/mod.rs b/src/validation/mod.rs index e7d62586..4acc5faf 100644 --- a/src/validation/mod.rs +++ b/src/validation/mod.rs @@ -22,7 +22,6 @@ mod schema; mod logic; -mod state; mod validator; mod consignment; mod status; diff --git a/src/validation/state.rs b/src/validation/state.rs deleted file mode 100644 index 563dc535..00000000 --- a/src/validation/state.rs +++ /dev/null @@ -1,126 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed 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. - -// TODO: Move into `logic` mod - -use strict_types::TypeSystem; - -use crate::schema::AssignmentType; -use crate::{ - validation, Assign, ConcealedState, ConfidentialState, ExposedSeal, ExposedState, OpId, - OwnedStateSchema, RevealedState, -}; - -impl OwnedStateSchema { - pub fn validate( - &self, - opid: OpId, - state_type: AssignmentType, - data: &Assign, - type_system: &TypeSystem, - ) -> validation::Status { - let mut status = validation::Status::new(); - match data { - Assign::Confidential { state, .. } | Assign::ConfidentialState { state, .. } => { - match (self, state.state_commitment()) { - (OwnedStateSchema::Declarative, ConcealedState::Void) => {} - (OwnedStateSchema::Fungible(_), ConcealedState::Fungible(value)) => { - // [SECURITY-CRITICAL]: Bulletproofs validation - if let Err(err) = value.verify_range_proof() { - status.add_failure(validation::Failure::BulletproofsInvalid( - opid, - state_type, - err.to_string(), - )); - } - } - (OwnedStateSchema::Structured(_), ConcealedState::Structured(_)) => { - status.add_warning(validation::Warning::UncheckableConfidentialState( - opid, state_type, - )); - } - (OwnedStateSchema::Attachment(_), ConcealedState::Attachment(_)) => { - status.add_warning(validation::Warning::UncheckableConfidentialState( - opid, state_type, - )); - } - // all other options are mismatches - (state_schema, found) => { - status.add_failure(validation::Failure::StateTypeMismatch { - opid, - state_type, - expected: state_schema.state_type(), - found: found.state_type(), - }); - } - } - } - Assign::Revealed { state, .. } | Assign::ConfidentialSeal { state, .. } => { - match (self, state.state_data()) { - (OwnedStateSchema::Declarative, RevealedState::Void) => {} - ( - OwnedStateSchema::Attachment(media_type), - RevealedState::Attachment(attach), - ) if !attach.file.media_type.conforms(media_type) => { - status.add_failure(validation::Failure::MediaTypeMismatch { - opid, - state_type, - expected: *media_type, - found: attach.file.media_type, - }); - } - (OwnedStateSchema::Fungible(schema), RevealedState::Fungible(v)) - if v.value.fungible_type() != *schema => - { - status.add_failure(validation::Failure::FungibleTypeMismatch { - opid, - state_type, - expected: *schema, - found: v.value.fungible_type(), - }); - } - (OwnedStateSchema::Fungible(_), RevealedState::Fungible(_)) => {} - (OwnedStateSchema::Structured(sem_id), RevealedState::Structured(data)) => { - if type_system - .strict_deserialize_type(*sem_id, data.value.as_ref()) - .is_err() - { - status.add_failure(validation::Failure::SchemaInvalidOwnedValue( - opid, state_type, *sem_id, - )); - }; - } - // all other options are mismatches - (state_schema, found) => { - status.add_failure(validation::Failure::StateTypeMismatch { - opid, - state_type, - expected: state_schema.state_type(), - found: found.state_type(), - }); - } - } - } - } - status - } -} From 3a5892339b96ad7a971c407817abc5db2d62f8c4 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 29 Jul 2024 15:21:11 +0200 Subject: [PATCH 03/21] vm: move OpInfo and VmContext from validation module --- src/validation/logic.rs | 57 ++++------------------------------------- src/validation/mod.rs | 1 - src/vm/contract.rs | 51 ++++++++++++++++++++++++++++++++++-- src/vm/isa.rs | 3 +-- src/vm/mod.rs | 1 + src/vm/op_contract.rs | 2 +- 6 files changed, 57 insertions(+), 58 deletions(-) diff --git a/src/validation/logic.rs b/src/validation/logic.rs index 7714f1ac..c5d92c56 100644 --- a/src/validation/logic.rs +++ b/src/validation/logic.rs @@ -34,13 +34,12 @@ use strict_types::TypeSystem; use crate::schema::{AssignmentsSchema, GlobalSchema, ValencySchema}; use crate::validation::{CheckedConsignment, ConsignmentApi}; -use crate::vm::{ContractState, RgbIsa}; +use crate::vm::{ContractState, OpInfo, RgbIsa, VmContext}; use crate::{ - validation, AssetTags, Assign, AssignmentType, Assignments, AssignmentsRef, ConcealedState, - ConfidentialState, ContractId, ExposedSeal, ExposedState, Extension, GlobalState, - GlobalStateSchema, GlobalValues, GraphSeal, Inputs, MetaSchema, Metadata, OpFullType, OpId, - OpRef, Operation, Opout, OwnedStateSchema, RevealedState, Schema, StateType, Transition, - TypedAssigns, Valencies, + validation, Assign, AssignmentType, Assignments, AssignmentsRef, ConcealedState, + ConfidentialState, ExposedSeal, ExposedState, Extension, GlobalState, GlobalStateSchema, + GlobalValues, GraphSeal, Inputs, MetaSchema, Metadata, OpId, OpRef, Operation, Opout, + OwnedStateSchema, RevealedState, Schema, StateType, Transition, TypedAssigns, Valencies, }; impl Schema { @@ -481,52 +480,6 @@ impl Schema { } } -// TODO: Move to VM module -pub struct VmContext<'op, S: ContractState> { - pub op_info: OpInfo<'op>, - pub contract_state: Rc>, -} - -// TODO: Move to VM module -pub struct OpInfo<'op> { - // TODO: Move to VmContext - pub contract_id: ContractId, - pub id: OpId, - pub ty: OpFullType, - // TODO: Move to VmContext - pub asset_tags: &'op AssetTags, - pub metadata: &'op Metadata, - pub prev_state: &'op Assignments, - pub owned_state: AssignmentsRef<'op>, - pub redeemed: &'op Valencies, - pub valencies: &'op Valencies, - pub global: &'op GlobalState, -} - -impl<'op> OpInfo<'op> { - pub fn with( - contract_id: ContractId, - id: OpId, - op: &'op OpRef<'op>, - prev_state: &'op Assignments, - redeemed: &'op Valencies, - asset_tags: &'op AssetTags, - ) -> Self { - OpInfo { - id, - contract_id, - ty: op.full_type(), - asset_tags, - metadata: op.metadata(), - prev_state, - owned_state: op.assignments(), - redeemed, - valencies: op.valencies(), - global: op.globals(), - } - } -} - fn extract_prev_state( consignment: &C, opid: OpId, diff --git a/src/validation/mod.rs b/src/validation/mod.rs index 4acc5faf..6b8fa165 100644 --- a/src/validation/mod.rs +++ b/src/validation/mod.rs @@ -29,6 +29,5 @@ mod commitments; pub use commitments::{DbcError, DbcProof, EAnchor}; pub use consignment::{CheckedConsignment, ConsignmentApi, Scripts, CONSIGNMENT_MAX_LIBS}; -pub(crate) use logic::VmContext; pub use status::{Failure, Info, Status, Validity, Warning}; pub use validator::{ResolveWitness, Validator, WitnessResolverError}; diff --git a/src/vm/contract.rs b/src/vm/contract.rs index d055cdf7..577bb008 100644 --- a/src/vm/contract.rs +++ b/src/vm/contract.rs @@ -21,16 +21,19 @@ // limitations under the License. use std::borrow::Borrow; +use std::cell::RefCell; use std::cmp::Ordering; use std::fmt::Debug; +use std::rc::Rc; use amplify::num::u24; use amplify::Bytes32; use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; use crate::{ - AssignmentType, AttachState, DataState, FungibleState, GlobalStateType, OpId, OpRef, - WitnessOrd, XOutpoint, XWitnessId, LIB_NAME_RGB_LOGIC, + AssetTags, AssignmentType, Assignments, AssignmentsRef, AttachState, ContractId, DataState, + FungibleState, GlobalState, GlobalStateType, GraphSeal, Metadata, OpFullType, OpId, OpRef, + Operation, Valencies, WitnessOrd, XOutpoint, XWitnessId, LIB_NAME_RGB_LOGIC, }; #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display, From)] @@ -334,3 +337,47 @@ pub trait ContractState: Debug + Default { fn evolve_state(&mut self, op: OpRef); } + +pub struct VmContext<'op, S: ContractState> { + pub op_info: OpInfo<'op>, + pub contract_state: Rc>, +} + +pub struct OpInfo<'op> { + // TODO: Move to VmContext + pub contract_id: ContractId, + pub id: OpId, + pub ty: OpFullType, + // TODO: Move to VmContext + pub asset_tags: &'op AssetTags, + pub metadata: &'op Metadata, + pub prev_state: &'op Assignments, + pub owned_state: AssignmentsRef<'op>, + pub redeemed: &'op Valencies, + pub valencies: &'op Valencies, + pub global: &'op GlobalState, +} + +impl<'op> OpInfo<'op> { + pub fn with( + contract_id: ContractId, + id: OpId, + op: &'op OpRef<'op>, + prev_state: &'op Assignments, + redeemed: &'op Valencies, + asset_tags: &'op AssetTags, + ) -> Self { + OpInfo { + id, + contract_id, + ty: op.full_type(), + asset_tags, + metadata: op.metadata(), + prev_state, + owned_state: op.assignments(), + redeemed, + valencies: op.valencies(), + global: op.globals(), + } + } +} diff --git a/src/vm/isa.rs b/src/vm/isa.rs index de0e0ff9..8c3417ae 100644 --- a/src/vm/isa.rs +++ b/src/vm/isa.rs @@ -28,8 +28,7 @@ use aluvm::isa::{Bytecode, BytecodeError, ExecStep, InstructionSet}; use aluvm::library::{CodeEofError, IsaSeg, LibSite, Read, Write}; use aluvm::reg::{CoreRegs, Reg}; -use super::{ContractOp, ContractState, TimechainOp}; -use crate::validation::VmContext; +use super::{ContractOp, ContractState, TimechainOp, VmContext}; use crate::vm::opcodes::{INSTR_RGBISA_FROM, INSTR_RGBISA_TO}; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] diff --git a/src/vm/mod.rs b/src/vm/mod.rs index d1299860..dde4b865 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -37,6 +37,7 @@ pub use contract::{ AssignmentWitness, ContractState, GlobalContractState, GlobalOrd, GlobalStateIter, OpOrd, UnknownGlobalStateType, WitnessAnchor, }; +pub(crate) use contract::{OpInfo, VmContext}; pub use isa::RgbIsa; pub use op_contract::ContractOp; pub use op_timechain::TimechainOp; diff --git a/src/vm/op_contract.rs b/src/vm/op_contract.rs index 4948cdb7..da01b5a2 100644 --- a/src/vm/op_contract.rs +++ b/src/vm/op_contract.rs @@ -34,7 +34,7 @@ use amplify::Wrapper; use commit_verify::CommitVerify; use super::opcodes::*; -use crate::validation::VmContext; +use super::VmContext; use crate::vm::ContractState; use crate::{ Assign, AssignmentType, BlindingFactor, GlobalStateType, MetaType, PedersenCommitment, From 47a23487d0dc6ba19f82034024b2abb52f095d18 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 29 Jul 2024 15:22:44 +0200 Subject: [PATCH 04/21] contract: rename WitnessOrd/Pos into TxOrd/Pos --- src/contract/mod.rs | 2 +- src/contract/seal.rs | 20 ++- src/stl.rs | 2 +- src/validation/validator.rs | 8 +- src/vm/contract.rs | 10 +- stl/AnchoredBundle.vesper | 10 +- stl/RGBCommit@0.1.0.sta | 299 ++++++++++++++++++------------------ stl/RGBCommit@0.1.0.stl | Bin 16230 -> 16282 bytes stl/RGBCommit@0.1.0.sty | 15 +- stl/RGBLogic@0.1.0.sta | 31 ++-- stl/RGBLogic@0.1.0.stl | Bin 1236 -> 1333 bytes stl/RGBLogic@0.1.0.sty | 23 +-- stl/Schema.vesper | 2 +- stl/Transition.vesper | 10 +- 14 files changed, 220 insertions(+), 212 deletions(-) diff --git a/src/contract/mod.rs b/src/contract/mod.rs index d229a1d8..af9e7558 100644 --- a/src/contract/mod.rs +++ b/src/contract/mod.rs @@ -55,7 +55,7 @@ pub use operations::{ OpoutParseError, Redeemed, Transition, Valencies, }; pub use seal::{ - ExposedSeal, GenesisSeal, GraphSeal, OutputSeal, SecretSeal, TxoSeal, WitnessOrd, WitnessPos, + ExposedSeal, GenesisSeal, GraphSeal, OutputSeal, SecretSeal, TxOrd, TxPos, TxoSeal, XGenesisSeal, XGraphSeal, XOutputSeal, XWitnessId, XWitnessTx, }; pub use state::{ConcealedState, ConfidentialState, ExposedState, RevealedState, StateType}; diff --git a/src/contract/seal.rs b/src/contract/seal.rs index d8bc5e4e..13fe7ca3 100644 --- a/src/contract/seal.rs +++ b/src/contract/seal.rs @@ -187,29 +187,28 @@ impl XChain { serde(crate = "serde_crate", rename_all = "camelCase") )] #[display("{height}@{timestamp}")] -// TODO: Rename into `TxPos` // TODO: Move into validation::Logic or vm::Contract -pub struct WitnessPos { +pub struct TxPos { height: u32, timestamp: i64, } -impl WitnessPos { +impl TxPos { pub fn new(height: u32, timestamp: i64) -> Option { if height == 0 || timestamp < 1231006505 { return None; } - Some(WitnessPos { height, timestamp }) + Some(TxPos { height, timestamp }) } pub fn height(&self) -> NonZeroU32 { NonZeroU32::new(self.height).expect("invariant") } } -impl PartialOrd for WitnessPos { +impl PartialOrd for TxPos { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for WitnessPos { +impl Ord for TxPos { fn cmp(&self, other: &Self) -> Ordering { self.timestamp.cmp(&other.timestamp) } } @@ -223,12 +222,11 @@ impl Ord for WitnessPos { derive(Serialize, Deserialize), serde(crate = "serde_crate", rename_all = "camelCase", untagged) )] -// TODO: Rename into `TxOrd` // TODO: Move into validation::Logic or vm::Contract -pub enum WitnessOrd { +pub enum TxOrd { #[from] #[display(inner)] - OnChain(WitnessPos), + OnChain(TxPos), #[display("offchain@{priority}")] OffChain { priority: u32 }, @@ -238,9 +236,9 @@ pub enum WitnessOrd { Archived, } -impl WitnessOrd { +impl TxOrd { #[inline] - pub fn offchain(priority: u32) -> Self { WitnessOrd::OffChain { priority } } + pub fn offchain(priority: u32) -> Self { TxOrd::OffChain { priority } } } pub type XWitnessTx = XChain; diff --git a/src/stl.rs b/src/stl.rs index bfb737af..8d8e1675 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -40,7 +40,7 @@ pub const LIB_ID_RGB_COMMIT: &str = "stl:tjFc6jD7-fe78CxG-WdJlH!l-uXlFfW0-XwG1!qV-MNdtNGE#orbit-airport-voice"; /// Strict types id for the library providing data types for RGB consensus. pub const LIB_ID_RGB_LOGIC: &str = - "stl:BUSyF3Du-Fd$ARpR-oIQ2Wzx-vZ1iJQ8-PViDtnv-sj16HQo#clara-star-battery"; + "stl:lfwSIiCB-NMEafxB-$XKtmil-Ve95dNq-9Ni$L$Z-wbkqO2c#alarm-amanda-source"; fn _rgb_commit_stl() -> Result { LibBuilder::new(libname!(LIB_NAME_RGB_COMMIT), tiny_bset! { diff --git a/src/validation/validator.rs b/src/validation/validator.rs index d75b6692..4eb6363e 100644 --- a/src/validation/validator.rs +++ b/src/validation/validator.rs @@ -35,7 +35,7 @@ use super::{CheckedConsignment, ConsignmentApi, DbcProof, EAnchor, Status, Valid use crate::vm::{ContractState, OpOrd, WitnessAnchor}; use crate::{ validation, AltLayer1, BundleId, ContractId, Layer1, OpId, OpRef, OpType, Operation, Opout, - Schema, SchemaId, TransitionBundle, WitnessOrd, XChain, XOutpoint, XOutputSeal, XWitnessId, + Schema, SchemaId, TransitionBundle, TxOrd, XChain, XOutpoint, XOutputSeal, XWitnessId, XWitnessTx, }; @@ -70,7 +70,7 @@ pub trait ResolveWitness { fn resolve_pub_witness_ord( &self, witness_id: XWitnessId, - ) -> Result; + ) -> Result; } impl ResolveWitness for &T { @@ -84,7 +84,7 @@ impl ResolveWitness for &T { fn resolve_pub_witness_ord( &self, witness_id: XWitnessId, - ) -> Result { + ) -> Result { ResolveWitness::resolve_pub_witness_ord(*self, witness_id) } } @@ -117,7 +117,7 @@ impl ResolveWitness for CheckedWitnessResolver { fn resolve_pub_witness_ord( &self, witness_id: XWitnessId, - ) -> Result { + ) -> Result { self.inner.resolve_pub_witness_ord(witness_id) } } diff --git a/src/vm/contract.rs b/src/vm/contract.rs index 577bb008..17c862d6 100644 --- a/src/vm/contract.rs +++ b/src/vm/contract.rs @@ -33,7 +33,7 @@ use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; use crate::{ AssetTags, AssignmentType, Assignments, AssignmentsRef, AttachState, ContractId, DataState, FungibleState, GlobalState, GlobalStateType, GraphSeal, Metadata, OpFullType, OpId, OpRef, - Operation, Valencies, WitnessOrd, XOutpoint, XWitnessId, LIB_NAME_RGB_LOGIC, + Operation, TxOrd, Valencies, XOutpoint, XWitnessId, LIB_NAME_RGB_LOGIC, }; #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display, From)] @@ -94,7 +94,7 @@ impl AssignmentWitness { #[display("{witness_id}/{witness_ord}")] // TODO: Rename into `WitnessOrd` pub struct WitnessAnchor { - pub witness_ord: WitnessOrd, + pub witness_ord: TxOrd, pub witness_id: XWitnessId, } @@ -116,7 +116,7 @@ impl Ord for WitnessAnchor { } impl WitnessAnchor { - pub fn with(witness_id: XWitnessId, witness_ord: WitnessOrd) -> Self { + pub fn with(witness_id: XWitnessId, witness_ord: TxOrd) -> Self { WitnessAnchor { witness_id, witness_ord, @@ -125,7 +125,7 @@ impl WitnessAnchor { pub fn from_mempool(witness_id: XWitnessId, priority: u32) -> Self { WitnessAnchor { - witness_ord: WitnessOrd::OffChain { priority }, + witness_ord: TxOrd::OffChain { priority }, witness_id, } } @@ -183,7 +183,7 @@ impl Ord for GlobalOrd { impl GlobalOrd { #[inline] - pub fn with_witness(opid: OpId, witness_id: XWitnessId, ord: WitnessOrd, idx: u16) -> Self { + pub fn with_witness(opid: OpId, witness_id: XWitnessId, ord: TxOrd, idx: u16) -> Self { GlobalOrd { witness_anchor: Some(WitnessAnchor::with(witness_id, ord)), opid, diff --git a/stl/AnchoredBundle.vesper b/stl/AnchoredBundle.vesper index dcd00dfe..b7ea1295 100644 --- a/stl/AnchoredBundle.vesper +++ b/stl/AnchoredBundle.vesper @@ -244,8 +244,9 @@ TransitionBundle rec bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 liquid bytes len=32 wrapped aka=SecretSeal tag=1 state rec RevealedAttach - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 + file rec AttachState + id bytes len=32 aka=AttachId + mediaType enum MediaType any=255 salt is U64 lock bytes len=2 aka=ReservedBytes2 revealed rec tag=3 @@ -265,8 +266,9 @@ TransitionBundle rec vout is U32 aka=Vout blinding is U64 state rec RevealedAttach - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 + file rec AttachState + id bytes len=32 aka=AttachId + mediaType enum MediaType any=255 salt is U64 lock bytes len=2 aka=ReservedBytes2 valencies set len=0..MAX8 aka=Valencies diff --git a/stl/RGBCommit@0.1.0.sta b/stl/RGBCommit@0.1.0.sta index b7a90a52..65cfa7a6 100644 --- a/stl/RGBCommit@0.1.0.sta +++ b/stl/RGBCommit@0.1.0.sta @@ -1,5 +1,5 @@ -----BEGIN STRICT TYPE LIB----- -Id: stl:DjmgI8Aw-L0XQMsu-q9HS$Za-!D8BzVj-bvaq$yq-p56MdqY#jester-philips-prelude +Id: stl:tjFc6jD7-fe78CxG-WdJlH!l-uXlFfW0-XwG1!qV-MNdtNGE#orbit-airport-voice Name: RGBCommit Dependencies: StrictTypes#century-comrade-chess, @@ -8,7 +8,7 @@ Dependencies: Std#ralph-blue-lucky, CommitVerify#tennis-peace-olympic, Bitcoin#signal-color-cipher -Check-SHA256: b85826c8774d6d163e1206bd2460f08a710577e8c3009d6224576a31d0d964ce +Check-SHA256: 01bd46a72a4d496903d4a321d4f81dfe5d3faaa40ff499d1c0179208ade2ce71 2~tNwLvL+uX>Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI)Q*?4^V{}w`aAk91a5aA+<>R2X hQO_4{AcS-HH^7AVzASV8M4NYxyCjHL2PwaO>Z8S`G>t*&Lor=XWH@ulIpd#VR%e3()@~+=qs(Ia|S|C @@ -28,7 +28,7 @@ BNr;@ghiU?gEXK9KMDE{F?;HZBRuDVqlk6qmbeZmb;*F>vukd; =m`ygb@x#_>`RmOO$0)3Z)}yry~#}iVEJ)s5j^%uEnQ9{n2s|9Fa^ps+HG#`XS5DMY;b5{PIYZeZ)9O} Xt{%a=RmHK6WZ%EWRm@*ULd%lgGoFTxUTU 76^nC$%1sKzB<;EQA|)S-x88IWKN#S$#@T&w`gPtRC#b^PGN0jYXqYdo~D%m7H6OD0<^0n_2##VWXRdj -y=DB@qgYOj1yf~hNn}L;2|;XhOksItaxnt|25f0@b!lV)3_)ykOksItaxqh7bOiwb2?5A!f_n>Eea4Xl +y=DB@qgYOj1yf~hNn}O<2|;XhOksItaxnt|25f0@b!lV)3_)ykOksItaxqh7bOiwb2?5A!f_n>Eea4Xl By!~v3=AX`3Ri0000000000{{R3000000B0+O=X=iRyWp-s@Y-MCYbaY{3XhLjhZe&wsVQf@*P;_zx1ONLxBDo)YaDXjV8yEYGuo~Ej#9D^K)f#Cf|Xn@L3mU0Z2&n -dr?jcD1Ll0RaLKV{dL|X=G(?bZKF1Q)OXn00sjDb7f&{0o#gN8iEuMbtv-qj6g$b#7A9pc!|f`I$jaR -zSe2A1O;<+VRU5yXj3#G4BS)3O?Kk8E~;iP+B(^hzXq!*4!qFzdIL(#1Z;0(YXafX-5feW*SKg&%h~b$ +zSe2A1O;<+VRU5y=Ov5&mq(eSq^TM>JW4?*h+3X!X@fjr@d0IimUQ-Q1Z;0(YXafX-5feW*SKg&%h~b$ G{NN>LxBDo)YaDXjV8yEYGuo~Ej#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RaODa%Fa9VQgh&00sjD -b7f&{0gt=F=tr7PLxBDo)YaDXjV8yEYGuo~Ej#9D^K)f#Cf|Xn +b7f&{0gt=F=tr7PJW4?*h+3X! +X@fjr@d0IimUQ-Q1Z;0(YXafX-5feW*SKg&%h~b$G{NN>LxBDo)YaDXjV8yEYGuo~Ej#9D^K)f#Cf|Xn @L3mU0Z2&n-dr?jcD1Ll0RbUFb8~5DZc=4-WnpY(WI=RvVPj}QY-w&}Q)OXnRCsA*1OxyKV{dL|X=G(? bZKF100sjDb7f&{0o#gN8iEuMbtv-qj6g$b#7A9pc!|f`I$jaRzSe2A1O;<+VRU5y{4_<~U(XE-|Ev|H db$N7;9H9;8!%;3hl7uME$faw1Z;0(YXafX-5feW*SKg&%h~b$G{NN>LxBDo)YaDXjV8yEYGuo~Ej#9D @@ -49,10 +49,10 @@ db$N7;9H9;8!%;3hl7uME$faw1Z;0(YXafX-5feW*SKg&%h~b$G{NN>LxBDo)YaDXjV8yEYGuo~Ej#9D sJ>Egn0epQk*PX+nL>xOm%pK>soMo}bYXO50sJ&Y-CxfQ3;(PYq_>4e9YQ#rfba;u!+d5tm#=h2RwFCuo -bYXO50ccY+APn47#!YtOwl1n>FWNfUk-rA3DGt2Q_Id+K%mi$2V`~E8(cK(6LD#rwNz2*s{WQVl8bg5o +bYXO50p}%){+CCYqok=CI6O*0D2Q5~XK8~xVetWFewK9hZ3Jv@V`~E8(cK(6LD#rwNz2*s{WQVl8bg5o 8r0R+^o=IRl4@nkxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%B2y$h1WnpY(WB>*O1aoC!YypA{ -4XEgn0epQk*PX+nL>xOm%pK>soMo}bYXO50ccY+APn47#!YtOwl1n>FWNfUk-rA3DGt2Q -_Id+K%mi$2V`~E8(cK(6LD#rwNz2*s{WQVl8bg5o8r0R+^o=IRl4@nkxGg*8X!CPrawgw_sqk4BX8}k^ +4XEgn0epQk*PX+nL>xOm%pK>soMo}bYXO50p}%){+CCYqok=CI6O*0D2Q5~XK8~xVetWF +ewK9hZ3Jv@V`~E8(cK(6LD#rwNz2*s{WQVl8bg5o8r0R+^o=IRl4@nkxGg*8X!CPrawgw_sqk4BX8}k^ ^xj-FXm+)yumJ%eL349yXKqquc4c8~Wn@HQbYVhlX>MdwWnpYocu;h51OxyKV{dL|X=G(?bZKF100sjD b7f&{0o#gN8iEuMbtv-qj6g$b#7A9pc!|f`I$jaRzSe2A1O;<+VRU5ya1CV;vVwtcAGbZ_5@VACR|ut2 VXXq-)V^B9&!_4M1Z;0(YXafX-5feW*SKg&%h~b$G{NN>LxBDo)YaDXjV8yEYGuo~Ej#9D^K)f#Cf|Xn @@ -119,151 +119,152 @@ Nc7%ZG-!6Ur?3G50uWWZob97;JWdSa-rT!PdFhnqz;9Q#~ob0000000000{{R30000007(sJ$X=iS2Wo~qHLTqVnWK(5fY*ct@WCZ~L3IT`y;$>KfZ0H=m -hJ>?uVE25ED1b!Bn_;nCe3IziXCXi3Z2@%=Qx -4E?M+l67UG^w8*<_XZ#%uyqCt-#n(R;4&W&+>mb;*F>vukd;=m`ygb@x#_>`RmOO$uRbbWCA+ -WpZ;d0^!l!96CYQxM)es+421}!Q~o5fc_fP)zG60RRU806-uB4?}NmV`X7%Wn@8gbYWv?1pxpD002NB -01ZQLZewL(Y-MCbVRT^y0RRU806-uB5kqfoV`X7%Wn@NmZf9v?Y-I)l3S)0=ZE19EWo~oV=@3Ik?lb^+R(Q4?4eR(6nw`loIF_owDud_=c42H~ZewX>a{=9jW&m$t -WDykZj`7#3_zANbB(SO{shhGe=&H{tM@ -LxBDo)YaDXjV8yEYGuo~Ej#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0Raz1cywiMb7^mGQ)6glZD9rm +baDj&015$z{^Dg=h-~N_zJ`Red1EINWrM}GXaQb}6c#qIM2EQnd$KicKz74!90ND1i-DNy><~nFGwl#> +J&iiT&+eT*0000000000{{R30000007(sJ$X=iS2Wo~qHLTqVnWK(5fY*ct@WCZ~L3IT`y;$>KfZ0H=m +hJ>?uVc;Wd;HQX=DL}aSf9!PV~dK2uo>;u!nFdemP_$ +e?^hl+JkM;eY!XaZDnL>VN`i=WdTAkVTFju)TLxBDo)YaDXjV8yEYGsr6V0dsu5sjwLjgQcrOsaG1 +F{QvR+LMR3-^ZN{xOxb4V`yb~Wpi|4 +ZEyepNCs(hb9H5M0^!l!96CYQxM)es+421}!Q~o5fc_fP)zLxBDo)YaDXjV8yE +YGrM&t;O}HAO^^zqT0%g+nC0;-MWK<)&Ge4`aq}l(*_A)b8}^MRAFax0^!l!96CYQxM)es+421}!Q~o5 +fc_fP)zMd`Zf8beV{~tF1pxpD +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 +VRU6vV`ybC`}q*rYXqYd +o~D%m7H6OD0<^0n_2##VWXRdjy=DB@qgYOj2yJ0_Npxjxa{vGX4@YcoVqt7kbYXO5RC#b^1pxp60t`oN +Z(?C=R$**)Wpf1q00;pxo>ox?`Aroor<$W|05z3@o%ygg4E?M+l67UG^w8*<_XZ#%uyqCrG{{7b@t4MVjY>G@u4Q +3HlB(d+LiLJm-R=h;`?dxBvhE000000RImF0000000l{IaCLMB0taw%Wp+<>bODnPynwMZT8l5kSW@l} +O=!>^xB4~9n`Dx!RtcK)nwJQ2Wpib6c4cG&;nCe3IziXCXi3Z2@%=QxRw7=FYk8VVufK10Q-T=FR=Q=>S+XYD&lVN`i=Wd#8M00Ie3WprUyVQh6} +1pxpE002M$0000000030{{R3000008O=WapWMOn+1pxpG0d?d}_}|Wp0vpvv$c&#PW69R$ltr%da5t5w +^x+8!q5%{oJdRMsrjHBJ^EIe4enz&iEACnc`NWk%>en!wdoTb1000000093000000000Y5V`Fu4a%FB~ +Wpf4s18r$;00065ZDDu-00In8a6@lxZE19EWo~o^3Ik?lb^+R(Q4?4eR(6nw`9N|x?>fArE*KsLwol4Pgj!HjQmQ`GTOgji|WprU=VRT^v;nCe3IziXC +Xi3Z2@%=QxsZfv!yd427@;7veO2zMB=| +GX`mHaCLNZ0^!l!96CYQxM)es+421}!Q~o5fc_fP)zsZfv!yd427@; +7veO2zMB=|GYesJb7^O8ZDnqBa{}Sf-5feW*SKg&%h~b$G{NN>LxBDo)YaDXjV8yEYGpW{Lxv|61vo|< +S$`kJ6oIZx{|tq&1{dNqe!iO(;xhWpe`I(cK(6LD#rwNz2*s{WQVl8bg5o +8r0R+^o=IRl4@mbudT)PryvH%qoUf%jN6#Tx81sfg4O?s`uaep_R|IjcWHEPWpi@^;nCe3IziXCXi3Z2 +@%=QxClv)aMjKgwAH@`bu1x<7g|G$};xvA~n-$_S33g#@X=Gt^Z*l_R +(cK(6LD#rwNz2*s{WQVl8bg5o8r0R+^o=IRl4@mbudT)PryvH%qoUf%jN6#Tx81sfg4O?s`uaep_R|Ig +PjE?O1pxpD002NB00mEQZ*_DA0|IYw0hP$+dLDIRU(}XWLTZugenOC;Z(5k~zEJnJiX;;E#R7DB0f+wL +Wmt%8=p4R=gtK{LClh6Z#kObxUW*hKHnBv9xdLu)0006IPj_x*WK(oubY)XxXk~3-1OxyJWMyM)VRB(~ +X?A4*00039W_507X<}?;00jX7`Sh#^X0AbZX4L%*5q$))*;M@wXI>IJVg&1PPwC}G0t$0Lb#i57 +00jX8Me3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*rYXqYdo~D%m7H6OD0<^0n_2##VWXRdjy=DB@ +qgYOj0}5eubYWv?ZDnqB00jX7LNH;4h{)8d6ed8&{mBRDiWpZ<6ZbNTv +ZE19EWo~o@0RRU806-xC2vTKaWo2z;WCZ~L3IRs#=EDda{kY~=q$*tC#t4Le{2#tvcDZqMsmk?Ml$g}C@DyY!@{4YR*LMYs=? +Zg_*ktx|21^lzg9sBTBv19V|$0m+Y=slx_K8vXre8<)H){QgX6j~{c$E$eY_=V_ZFuLe_NXk~3-1`Pvd +W_AJEn^6;37FKqUhx?i3R+Mr!fY&(;2BFL(m@EZk_srD=W^7?+a{}Sf-5feW*SKg&%h~b$G{NN>LxBDo +)YaDXjV8yEYGsr6V0dsu5sjwLjgQcrOsaG1F{QvR+LMR3-^ZN{xOxO`VQpmsMe3tp+xFv-0Xp&G?S=|} +9rRaeU`~uMrbA>C`}q*rQx*t>6v={gsJ=SZlTl1iF5eQ8IAl(q%E@>So406W33O>~Wpi|4ZEyepNC{+R +c4cgDaAk4ioJ +pYH;+t0eX2w~A!Q+0eaZ{MVycPK^Kn000000093000000000YTY;R&=Y*cx0Wpe-u0oCr34oQf!Y4K`P +(FaQVwIle)QgI&pHa%8Z1>xis%K=jn%|ogzQLxC5#{z1Bs(ImjcZKu%4y_xMoB3q3{22fM0000000930 +00000000VacWz~5RC#b^a{vkfhyLPaScq)s9KMExvw34D6J>+NwrBxfixd_%u|$Wt0VPFrzQMU~Cv3(o +CX8r!*SiR9zOp;)>$$b(q=dpw@&Et;000000RI300000001S3vY-Mg^c~p6DWpe-t0Y>fS!w4MxxaL=+ +DqP^k2!wz9AHH68xp8!<%Jqp^&Hw-a000000RI300000000(DfZe??6a{(Ag)zidWvABmX&uCxQ{9vUA +sn@)h(<^=)@3p(i4Fw8icywiMb7^mGa{vkfWOW`wsTH9-LlJ`2|Ay5Z(?oEikl{+~pis;@Q*TJ#0Rw0P +%&6V>N}#h955#ht!=;R2Lj=uo+MI7C_W0!u+yDRo000000RI300000001I?-VQzD2bZKvHa{vkfG*S<) +6P6lYy(#<=BR_>s@(?%#f7ArN-=Rj?7Ns(10d}<;Xp5rzopjE#5h98`u~h0v`BV8NkLOrpFzp4z*Z=?k +000000RI300000000?qrb7gXNWn=>3(cK(6LD#rwNz2*s{WQVl8bg5o8r0R+^o=IRl4@oCf)+{Nc)mXT +m=OBn8@DNvJ^I(u7Ttc@lJ^C)`OzK-Q)6glZDC1d1pxpD002NB018xcVQzD2bZKvH1_}daW_AJEn^6;3 +7FKqUhx?i3R+Mr!fY&(;2BFL(m@EZk_srD_V{dMBa$#e1Nn`<^2rNlD$O59e#ogQsB77jPl+h5j^*S;RbaG*Cb7^#GZ*Ek1aAg5BQV*^ZmKt8YDf|&5KZQ>65I6*X)C9iYp+?yjr7~y;ZDn*}WMOn+ +0rh%KI9Y!AFx9LCk8@hQXE7w+qW3^C%eTEp@#^?_H3w&GZ(?C=a{=BXk!z-`g4hv-$6z_YxoLZ_neUP> +BpbEf7FA*KKfDHMZg6#Ua{;NMdRLRko603iZGCpt_aPM;fT16ofolpo#8?XuHZHx7d=!p7E)2#$3Lc42H~ZewX>a{=9jW&m$tWDykZj`7#3_zANbB(SO{ +shhGe=&H{tM@LxBDo)YaDXjV8yEYGuo~ +Ej#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0Ra$Ha$#@6CZbEf#WNc*y0}EqpZ*yf$Wprq7WCCv< +midRhTh1hu7-!n@1Cr{swqbZoGSd8tmgp<3rE@N~5GA>8Wft0d6dj=*oo`t>c$)o5X19O9`rXu=lIsX* +Zg6#UO<`~W6`5yb%eAXO2UPPRaj@((`=>9Tsh)f38uw_!yYu^q5NmF4cWzX2VQzD2bZKvHa{vkfmB{9L +9(7`0)Rt93YLV-HLXe?vTA1;^Q1`ZqBog<<0WvO>-_DBy8`Vb0jGrW9$=2qS +MXvL3HGEG0000000000{{R300000025D|^b#!w8 +3IT`y;$>KfZ0H=mhJ>?uVKfZ0H=mhJ>?uVa{vhe M(yUq2ps*m=2xUDT;RqCgn#@WzFu~@adfH5^@&-|0000000000{{R300000033g#@X=Gt^Z*l+x0ssVV Z*FA(00035b8l^B00jX8VsJHoA?4$swuZp1Wc+9AOf`(TIbyKWjTy4WkGaM+ZSSEb;k|42*wg~2q@ -3^Lq|9zft}OB~jx>)hO74Mli#Wo~n6Z*Ek1aAgGn00065MrL*e0RR934MuftXK7+=Wm9xvbY%nq2nJ$l -baOT|00jX600<05b#7;AVr*qpd2nR|0S$F-b7^O8Wn?xqLTPje2S;UYWpinB1`PvdW_AJEn^6;37FKqU -hx?i3R+Mr!fY&(;2BFL(m@EZk_srD@b7N>_ZDC1d0hChH+XJhss8OG%_CC-Q>(otsF+cqN0Qy}ddQ=3E -5CvvzVP|s!;nCe3IziXCXi3Z2@%=Qx~Wpi|4ZEyepNCs(hb9H5M0k-IXh8!q$B6|*YuiTY;OURW8#d%1{rxIXtTaY^?oCkDe -b98QHbOOpO9&dx0-7pM3Z=O*v*GCA9fL-<|HrZsA`NnJlR3~AEBGG%U@MZ$v=XJ?|;InIPy66cFfOYp# -JM2r7_Du?5Y;;Uvd1Z2QF##l3QrKmH@SMtOBR5nML?B>%qbz^!%<&Wu0B;HjDvSwXb8}^MRAFax0VyR8 -2Em!ld>cVuZ*8Se%j3y;5n>eohpw0DA7$}d%m{5|bYWy+bYTJYdQCW4e)%xftOSp9TD)g5B;KO;Krzd= -y+`rt_<1!4XKZg`VQg~&-XoD~rmTY45rxNKIl#GTd$5`Bk}o71wcZw0Vevn_3t@9}X=iS2Wo~qH0V?uE -LDn7E_h5K%L=laq&yA1J -oJ^{7>oKLkF4~iax8KK|47hp?M`dnhb7^x^V`ybVZDn*}WMOn+00{wgKfZ0H=mhJ>?uVa{vheM(yUq2ps*m=2xUDT;RqCgn#@WzFu~@ -adfH5^@&-|0000000000{{R300000033g#@X=Gt^Z*l+x0ssVVZ*FA(00035b8l^B00jX8VsJHoA?4$s -wuZp1Wc+9AOf`(TIbyKWjTy4WkGaM+ZSSEb;k|42*wg~2q@3^Lq|9zft}OB~jx>)hO73rB2kVqt7k -bYXO51pxpG0oCr34oQf!Y4K`P(FaQVwIle)QgI&pHa%8Z1>xis%K-|*_9BKowP1qopf1fvG|`fdOK000000093000000000q3Y;R&=Y*Tb$bY)XxXk~3-1_KCkWpib6c4cG&;nCe3IziXC -Xi3Z2@%=QxNn`>= -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 -j`7#3_zANbB(SO{shhGe=&H{tM@LxBDo -)YaDXjV8yEYGuo~Ej#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0Ra$Ha$#@6CZbEf#WNc*y0}Eqp -Z*yf$Wprq7WCCv8Wft0d6dj=*oo`t>c$)o5 -X19O9`rXu=lIsX*Zg6#UO<`~W6`5yb%eAXO2UPPRaj@((`=>9Tsh)f38uw_!yYu^q5NmF4cWzX2VQzD2 -bZKvHa{vkfmB{9L9(7`0)Rt93YLV-HLXe?vTA1;^Q1`ZqBog<<0piXs!(qZ;Lj-T~1#;7GmaeV$(NXMz -5-`m!kXibHi2(or000000RR600000001#AiVQzD2bZKvHQ)6glZD9rm2yJC_VPs)+VE_pMb>vO>-_DBy -8`Vb0jGrW9$=2qSMXvL3HGEG0000000000{{R30 -0000025D|^b#!w83IT`y;$>KfZ0H=mhJ>?uVKfZ0H=mhJ>?uVa{vheM(yUq2ps*m=2xUDT;RqCgn#@WzFu~@adfH5^@&-|0000000000{{R300000033g#@ -X=Gt^Z*l+x0ssVVZ*FA(00035b8l^B00jX8VsJHoA?4$swuZp1Wc+9AOf`(TIbyKWjTy4WkGaM+ZSSEb -;k|42*wg~2q@3^Lq|9zft}OB~jx>)hO74peesZgXjLX>V>+d2nR~0RR934pez?WkYXmZE19EWo~o? -0{{nSWo~72X>$Mt0Rb~)Sy27nfgB_8)3w|}PX0nR=3w=3IXvnu`4)OW{2u`dbaG*Cb7^#GZ*Bku0s)^0 -EJ-@Z0;0Ob-P{Wzd?2rs)M&&=&l*}G;Jw22Ix+z?QV*^ZmKt8YDf|&5KZQ>65I6*X)C9iYp+?yjr7~y& -31xV6Wo~n6Z*Bku0s)^0EJ-@Z0;0Ob-P{Wzd?2rs)M&&=&l*}G;Jw22Ix+!dbsj>g6`?#s5rWnKhSeO? -L~x^!;Y#eFP|P}0Z%E!6RC#b^WI=OtX=iS8LTqVnWK(5fY*ctqbaDg)01ISgV{Bn^VRUJBWdH>M00;p& -C-dJ*Ygad93@i9pCb+uV$agN<27ESr7(9FG*~&Hm0000000030{{R30000012xfI|XK7+=WdH>M00;rv -#pxZ$?Eb+fZ@!;9xB`-n7hgEflW({{JNKm>5MosT0000000030{{R30000023UhRFbz^jOa%E%y1pxpE -0f8RpmkyA>T}tj_kdvFcMGT4`fC%jFncQ)?C=$=&Q2+n{000000RR60000000RIYMbaY{3Xl-R~bN~eb -00;rzm4zh;p_e*BIH}G_uHL`vNz<~wu(~9K*$!EolXjf|0000000030{{R300000PRC#b^WI=OtX=iS8 -LTqVnWK(5fY*ct@WCR2N3uI+uY+-U?bZK^F00jX62mzD8lw1;)SBG%dXmxGxLL8mnw6u)Qc}1I}@VaR| -$Swc?00000009600000000039W_507X<}?;00jX62m$}nN9KoA`=lHP5CAeGSam&QM5L=EvI-ld!uoqo -p~3(F0000000960000000006Cb98cbV{~&5D -V!5;tB_sd<000000096000000000SAVQgh?V`*h`1pxpF0Y>fS!w4MxxaL=+DqP^k2!wz9AHH68xp8!< -%Jqp^&Hw-a000000RI300000001H-OY-Mg^c~p6DWd#8M00IeCZ)s#xbYXO51pxp602Ek5Xklq?LTqVn -WK(5fY*ctqbaDg&00&}ebYpL6ZU6-V0&gCc`G>t*&Lor=XWH@ulIpd#VR%e3()@~+=qs(Ib4DkqE>N`F -8f<{_M@^MEhcVy#omh=bI-rl&{j_4Y)d2=oOFWB>&L0&gCc`G>t*&Lor=XWH@ulIpd#VR%e3()@~+ -=qs(Ib4DkqE>N`F8f<{_M@^MEhcVy#omh=bI-rl&{j_4Y)e~4lXklq?LTqVnWK(5fY*ct@WCQ{L2V!Y- -V{d7000jX8ZyuKUhrL_QB$OCu+VTUE>b16EcuX?V{EC+7E3Kt-u*Pw&hI`xNV4B0;>oUbhHyi-Y#=22) -QEgSwgb16EcuX?V{EC+7E3Kt-u*Pw&hI`xNV4B0; ->oUbhHyi-Y#=22)QEgSwgbW>$vYy<)T2V!Y-V{d7000jX8ZyuKUhrL_QB$OCu -+VTUE>b16EcuX?V{EC+7E3Kt-Xc_Cg)w39@m$R6qOEzWQ+NTC@=;b16EcuX?V{EC+7E3Kt-Xc_Cg)w39@m$R6qOEzWQ+NTC@=;?<6X>I@o0Rr`G6JjIwIj2eqliWu}$@z+_xPw?-wb>Rw7=FYk8VaL=Li5Yl -(a@n1+Ku60FILp}Zw|!7cE!MGSxid=WmW+OY-w?IX=DHe0Rr`G6JjIwIj2eqliWu}$@z+_xPw?-wb>Rw -7=FYk8VaL=Li5Yl(a@n1+Ku60FILp}Zw|!7cE!MGSxid=WmW +3^Lq|9zft}OB~jx>)hO74peesZgXjLX>V>+d2nR~0RR934pez?WkYXmZE19EWo~o?0{{nSWo~72X>$Mt +0Rb~)Sy27nfgB_8)3w|}PX0nR=3w=3IXvnu`4)OW{2u`dbaG*Cb7^#GZ*Bku0s)^0EJ-@Z0;0Ob-P{Wz +d?2rs)M&&=&l*}G;Jw22Ix+z?QV*^ZmKt8YDf|&5KZQ>65I6*X)C9iYp+?yjr7~y&31xV6Wo~n6Z*Bku +0s)^0EJ-@Z0;0Ob-P{Wzd?2rs)M&&=&l*}G;Jw22Ix+!dbsj>g6`?#s5rWnKhSeO?L~x^!;Y#eFP|P}0 +Z%E!6RC#b^WI=OtX=iS8LTqVnWK(5fY*ctqbaDg)01ISgV{Bn^VRUJBWdH>M00;p&C-dJ*Ygad93@i9p +Cb+uV$agN<27ESr7(9FG*~&Hm0000000030{{R30000012xfI|XK7+=WdH>M00;rv#pxZ$?Eb+fZ@!;9 +xB`-n7hgEflW({{JNKm>5MosT0000000030{{R30000023UhRFbz^jOa%E%y1pxpE0f8RpmkyA>T}tj_ +kdvFcMGT4`fC%jFncQ)?C=$=&Q2+n{000000RR60000000RIYMbaY{3Xl-R~bN~eb00;rryfd-Ec2fx7 +@|$_F!~L1|Gb|wN=sA3IJojZB|09R9osd9G^&mV=@u*B|k@iff^?C=mvC@no9rx00000 +0096000000000SAVQgh?V`*h`1pxpF0Y>fS!w4MxxaL=+DqP^k2!wz9AHH68xp8!<%Jqp^&Hw-a00000 +0RI300000001H-OY-Mg^c~p6DWd#8M00IeCZ)s#xbYXO51pxp602Ek5Xklq?LTqVnWK(5fY*ctqbaDg& +00&}ebYpL6ZU6-V0&gCc`G>t*&Lor=XWH@ulIpd#VR%e3()@~+=qs(Ib4DkqE>N`F8f<{_M@^MEhcVy# +omh=bI-rl&{j_4Y)d2=oOFWB>&L0&gCc`G>t*&Lor=XWH@ulIpd#VR%e3()@~+=qs(Ib4DkqE>N`F +8f<{_M@^MEhcVy#omh=bI-rl&{j_4Y)e~4lXklq?LTqVnWK(5fY*ct@WCQ{L2V!Y-V{d7000jX8ZyuKU +hrL_QB$OCu+VTUE>b16EcuX?V{EC+7E3Kt-u*Pw&hI`xNV4B0;>oUbhHyi-Y#=22)QEgSwgb16EcuX?V{EC+7E3Kt-u*Pw&hI`xNV4B0;>oUbhHyi-Y#=22) +QEgSwgbW>$vYy<)T2V!Y-V{d7000jX8ZyuKUhrL_QB$OCu+VTUE>b16EcuX?V +{EC+7E3Kt-Xc_Cg)w39@m$R6qOEzWQ+NTC@=;b16EcuX?V{EC+7E3Kt-Xc_Cg)w39@m$R6qOEzWQ+NTC@=;?<6X>I@o0Rr`G6JjIwIj2eqliWu}$@z+_xPw?-wb>Rw7=FYk8VaL=Li5Yl(a@n1+Ku60FILp} +Zw|!7cE!MGSxid=WmW+OY-w?IX=DHe0Rr`G6JjIwIj2eqliWu}$@z+_xPw?-wb>Rw7=FYk8VaL=Li5Yl +(a@n1+Ku60FILp}Zw|!7cE!MGSxid=WmW -----END STRICT TYPE LIB----- diff --git a/stl/RGBCommit@0.1.0.stl b/stl/RGBCommit@0.1.0.stl index 3622997abb7c583a0cddc0c270ffe03818220b32..6fd344ddea80daf1802362c072f0eae4b3b1a392 100644 GIT binary patch delta 618 zcmaD>H>-X_9}A<~=6;r1CWYs!-T$V$&s@A@rIdw@m!n2U)V%b}W}C#1jHz|gO1|Yz z){}~y{EbJQ7=><=tpxZdr?U!9u9k3`yqmRYvc07GWLeG?#At3HMv>d*(_C`}6sk9w z<~o!e&XZv_U)9|>mkQ&z0{OPRR)@~Nn`<|@L)u>c0D~F+Yw!dY$)p z&A*K;COYK~jf~M7d>7n&$u#-9v=Se;V@XM3az=1TVo53+)8u4*|ILyzJ7PLRod4Y24Ele(k)HwfU(04;F%|Ccl?2+Z?RAor#foGq*-K zyE+p~T4qivBj>hyq5H41r*g5ze=OOvdRpXa^Zf^#948;Vux~|xtn`GRs>+8o<*lE8@vW7fGW%!B=0B2~os2k{6`a0JdVR;3#r7|Al)u3g z`MamzZn_+4&eyDS=-9PBj=oZ$8}?7uGTX0U{F%4B>)T$>|1rIcCOwrEYxk$L9(eS? zv9WdDl(0Fo6*hC4|6*3Sw#Rtm!LneE`=4f4Zan;V<~L&}t75nUD72m9E u&CI9}d?7c?X>CaKD|4Co9*xOHf}d6G-5VOE)V{o6E15FOd$XI30y6-*?GH=< delta 562 zcmbPL|Ez999}A=F=6;r1CWVY(69t|-!N+{d9&OWGm8O5o>gL4#Y^yc-_FVW@#q4!v zvYu4rZ zDdok96OQf5=i2U1oWFTny(-u4qkEO^FwaZrUiZ;&a)-3P!ZOnf>XYkoF66DdzQ11XWF*Z(6o_gX(rBMyAaf8sY4W%#+n+{5L<-FJMx*?;m^P z=XE7s&mIxO<}kZtlDt>)|z`SFP%QIb@P1FI!1*@=kyLI9!hX#$^XP!bUA<8y0zag2EJ($GB~R@ zA@Wya=Vn{;U(5>krnahbESzrTWU=y`=em3QUwdBOw12}cm6n@)k+Ub4&D|Vs&CIB9 r(rDN9igQb)_ZVlKuzMO8X!OZL{m#0>>#VjW?c5@$s ^ ..0xff TypedAssignsBlindSea @mnemonic(factor-hair-everest) data AttachId : [Byte ^ 32] +@mnemonic(harvard-burma-bicycle) +data AttachState : id AttachId, mediaType MediaType + @mnemonic(amadeus-sunday-casino) data BaseCommitment : flags CommitVerify.ReservedBytes1 , schemaId SchemaId @@ -266,10 +269,10 @@ data GenesisSchema : metadata {MetaType ^ ..0xff} @mnemonic(initial-malta-sierra) data GlobalState : {GlobalStateType -> ^ ..0xff GlobalValues} -@mnemonic(connect-ricardo-lava) +@mnemonic(silk-college-august) data GlobalStateSchema : reserved CommitVerify.ReservedBytes1 , semId StrictTypes.SemId - , maxItems U16 + , maxItems U24 @mnemonic(yoga-quick-jasmine) data GlobalStateType : U16 @@ -337,10 +340,8 @@ data PedersenCommitment : [Byte ^ 33] @mnemonic(anita-vega-pirate) data Redeemed : {ValencyType -> ^ ..0xff OpId} -@mnemonic(hammer-prism-twin) -data RevealedAttach : id AttachId - , mediaType MediaType - , salt U64 +@mnemonic(simple-bombay-salute) +data RevealedAttach : file AttachState, salt U64 @mnemonic(sleep-source-figure) data RevealedData : value DataState, salt U128 diff --git a/stl/RGBLogic@0.1.0.sta b/stl/RGBLogic@0.1.0.sta index dcae2973..d4aa7573 100644 --- a/stl/RGBLogic@0.1.0.sta +++ b/stl/RGBLogic@0.1.0.sta @@ -1,14 +1,14 @@ -----BEGIN STRICT TYPE LIB----- -Id: stl:J61WrKfv-HBO6mFZ-9bZzqau-j!wrLMA-9IgEJGM-hcaprmA#podium-colombo-buenos +Id: stl:lfwSIiCB-NMEafxB-$XKtmil-Ve95dNq-9Ni$L$Z-wbkqO2c#alarm-amanda-source Name: RGBLogic Dependencies: - RGBCommit#jester-philips-prelude, BPCore#garbo-radius-peru, + RGBCommit#orbit-airport-voice, Bitcoin#signal-color-cipher -Check-SHA256: 27edb1e36757ef5995caf499d793c4a4ea20560442c55610552b8a84fba54bbe +Check-SHA256: 9448f86bdc65f2a672ab3b24672ba862e00a4b3204667c14c32c2fd8ddfe16dd -2vSEvOmAmtV*?I3pd-LAFGbKY%c}Hrzh$q3@Ep~RyV|S#s;8cecBTnZM?ynyZEb0EZyuKUhrL_QB$OCu -+VTUE>b16EcuX?V{EC+7E3Kt-20~CnZ*pbzY!hN5_Bp3Y36tDMM#=e#tGI($UA5U3KNx<*C>ja}LTPkk +2vSEvOmAmtV*_s;CP(yEWWwtR~>M;9#?)(c8mUNj% +`dgQjSJu&d2G{D9FxPD~VF^-4LPKwDZE1A%Y!hN5_Bp3Y36tDMM#=e#tGI($UA5U3KNx<*C>ja}LTPkk Z)t7=20~CnZ*pY?00DdlT>wB!7L}MA7sFvK#<=RP4S#T1Vv-hhTICs&5fM~jaB^jIPH$voP+@X(Ze?;0 wjY>38tto&d&=eG4cRAF#( @@ -17,16 +17,17 @@ Wpq+$XJ~Xna$#;`Xh%-ZT+rxDK6vW;JU&?LxLM72H?wDC1Zo}=N}D)4mkLjCa%FT-a&K>D2SRCdV{d70 DJ{*3f84s>#k$1lf7uIEVQ@}wWMxQUb7)_z*=^-NPQ?`2v5jYd+6t@dEhY>7H!Y*UdZb-BpG^u(WnpGh V{&P5bfbbo^UK%K(4i9Ajp1M~R@C@!4#dQE#lUD;OiKi1Rs>XdX=JH|gm+V(X#23g?#G%T#8*SXRQUS6 KbYXtkv-?PH+Tw3ZggdGZeeUtYqm29sTjYuk_~RiSfnI}BSuP}NCm0qyW47Umu?kmdbZ%vHb5L({iECIT&Bl;lSX#$ms8AQN7m&qY38tto&d&=e@L7b8|s%V`y)300aU61a5C`WdHyG0R(ez -ZDjxj0RgHurJHC-KI9f(dtNbZ%vHb4g?Z4mqGBz%VaG&@#)a^mM;vuY>R$)s4H_tNf~`o{V;;iECIT&Bl;lSX#$m -s8AQN7m&qYL?_ +X=Ihi=6W7=VqesjRYGc!>wZFzp>JB4@xD;^wu&SY_r(NHa7kpd#2fCIclJV8?azCZf?DV8N)@@tC^qK9 +Y3*6^{&AQERCrHvWCH*QL}Fu5a&K>D1OfpDbYXCEWpn@q0RnFxmidRhTh1hu7-!n@1Cr{swqbZoGSd8t +mgp<3rE?FqADBNH?W>M^%H|xc>sh|Dn*!v8^Ea7rh?dzC2n+%RZ*X#DbN~eb0&gCc`G>t*&Lor=XWH@u +lIpd#VR%e3()@~+=qs(Ib4O0kT+rxDK6vW;JU&?LxLM72H?wDC1Zo}=N}D)4mkCE~Z(?C=PjX}i0}Xd+ +bZ%vHb3txnXm4@=1OfmAZf|a7000011aog~WdH>M0aM7zbNe|pT0D`h%@_Ts#lP_<=f%~pj)XbI<1wSp +*932HX=DPnFEi>Xk6pZ8Tw($mV(;bz)!CmQ_M(k?Vd!kfCo{nDM?) +_qK{868FUeX=Hc+00IqHX>@L7b8|s%V`y)31_BCqX>@L7b8}B}WCFG^T@L7b8|^#0=6++>M;9#?)(c8 +mUNj%`dgQjSJu&d2G{D9FxPD~VTo&4CC$c=UszhlV5m?Ru@{iVU*wrVdeH+Q@FPbX@c -----END STRICT TYPE LIB----- diff --git a/stl/RGBLogic@0.1.0.stl b/stl/RGBLogic@0.1.0.stl index 5eaecccf118f78b2a763da4deba2c8117f6a6033..ccfc49d8226f95e667b8a40613db9f2b8e920038 100644 GIT binary patch delta 462 zcmcb@xs{8HBgoy!CqF$inR&7|vw|U;Q-E`RQR+6sm{$hBYv29h7MxZx)BRWU^eN%j zF4nMJe>K(Mdag+#Cs3Djer|4N$;RjqCRG-OHY4W4!tv5ZXWCmeYEv{kw_mn@x=}s2 zXX)$(72nMrwy}m(Ouosa=P~ufvnsjLr1&e-LY=ZEzOHkcurNPr#>agD-?w$C2z@`w z;$PsIviXSgyBX!*oWkFpub$Er_57`u=*|-wX3q|1zK#6!uW$y)Fn#7tjLefCF{{)E zpEy$sUQgLF zPM}KX{M_8klF1vH71-IF0-W=UQa472FljL}@a^C6)*>lyN%Jm~&muoVN?(TEbT<{g zqb?z4lf3O==SHsZ%#ys+;^N6ynDjJ0bZ!!MWejEB!}W5#+kPpAhVJ(NdbiHcVtn7K z{_$8{6I`(u^Cm{7$$yzu6jqrnT{tJAjpNlO6(9X+$$vl2{yxFqByHjy6O(@_%DO6( w+gX(B3HgAKy`1F`M|!3(5i+VXJ3{sBu?g`JQO6Tj1c+}GpKvsO@@pm@08=xZxc~qF diff --git a/stl/RGBLogic@0.1.0.sty b/stl/RGBLogic@0.1.0.sty index 0e698fb3..0df92719 100644 --- a/stl/RGBLogic@0.1.0.sty +++ b/stl/RGBLogic@0.1.0.sty @@ -1,5 +1,5 @@ {- - Id: stl:J61WrKfv-HBO6mFZ-9bZzqau-j!wrLMA-9IgEJGM-hcaprmA#podium-colombo-buenos + Id: stl:lfwSIiCB-NMEafxB-$XKtmil-Ve95dNq-9Ni$L$Z-wbkqO2c#alarm-amanda-source Name: RGBLogic Version: 0.1.0 Description: Consensus logic layer for RGB smart contracts @@ -11,11 +11,6 @@ @context typelib RGBLogic -import RGBCommit#jester-philips-prelude - use WitnessPos#snow-local-tonight - use XChainTxid#liquid-river-absorb - use WitnessOrd#chief-digital-vitamin - import BPCore#garbo-radius-peru use TapretNodePartner#roger-member-educate use TapretProof#marco-border-sample @@ -23,6 +18,12 @@ import BPCore#garbo-radius-peru use TapretRightBranch#miracle-patriot-touch use OpretProof#good-village-flex +import RGBCommit#orbit-airport-voice + use TxPos#john-invest-weekend + use XChainTxid#liquid-river-absorb + use OpId#picnic-single-gloria + use TxOrd#brigade-sweet-script + import Bitcoin#signal-color-cipher use ScriptBytes#equator-cockpit-gong use TapNodeHash#paprika-amanda-hunter @@ -37,10 +38,12 @@ import Bitcoin#signal-color-cipher data DbcProof : tapret#1 BPCore.TapretProof | opret BPCore.OpretProof -@mnemonic(miguel-lava-extend) -data GlobalOrd : witnessAnchor WitnessAnchor?, idx U16 +@mnemonic(nice-corona-order) +data GlobalOrd : witnessAnchor WitnessAnchor? + , opid RGBCommit.OpId + , idx U16 -@mnemonic(scoop-scoop-cadet) -data WitnessAnchor : witnessOrd RGBCommit.WitnessOrd, witnessId RGBCommit.XChainTxid +@mnemonic(maze-grid-user) +data WitnessAnchor : witnessOrd RGBCommit.TxOrd, witnessId RGBCommit.XChainTxid diff --git a/stl/Schema.vesper b/stl/Schema.vesper index ad76aa75..21aae701 100644 --- a/stl/Schema.vesper +++ b/stl/Schema.vesper @@ -47,7 +47,7 @@ Schema rec value rec GlobalStateSchema reserved bytes len=1 aka=ReservedBytes1 semId bytes len=32 aka=SemId - maxItems is U16 + maxItems is U24 ownedTypes map len=0..MAX8 key is U16 aka=AssignmentType value union OwnedStateSchema diff --git a/stl/Transition.vesper b/stl/Transition.vesper index e1f2c2bf..ce5df9f0 100644 --- a/stl/Transition.vesper +++ b/stl/Transition.vesper @@ -254,8 +254,9 @@ Transition rec bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 liquid bytes len=32 wrapped aka=SecretSeal tag=1 state rec RevealedAttach - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 + file rec AttachState + id bytes len=32 aka=AttachId + mediaType enum MediaType any=255 salt is U64 lock bytes len=2 aka=ReservedBytes2 revealed rec tag=3 @@ -275,8 +276,9 @@ Transition rec vout is U32 aka=Vout blinding is U64 state rec RevealedAttach - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 + file rec AttachState + id bytes len=32 aka=AttachId + mediaType enum MediaType any=255 salt is U64 lock bytes len=2 aka=ReservedBytes2 valencies set len=0..MAX8 aka=Valencies From 63edc94474d9146de5f9cf296af4555996127858 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 29 Jul 2024 15:26:02 +0200 Subject: [PATCH 05/21] validation: move TxPos/Ord from contract modul --- src/contract/mod.rs | 4 +-- src/contract/seal.rs | 69 ++----------------------------------- src/stl.rs | 2 +- src/validation/logic.rs | 66 +++++++++++++++++++++++++++++++++++ src/validation/mod.rs | 1 + src/validation/validator.rs | 5 ++- src/vm/contract.rs | 3 +- 7 files changed, 76 insertions(+), 74 deletions(-) diff --git a/src/contract/mod.rs b/src/contract/mod.rs index af9e7558..625b1571 100644 --- a/src/contract/mod.rs +++ b/src/contract/mod.rs @@ -55,8 +55,8 @@ pub use operations::{ OpoutParseError, Redeemed, Transition, Valencies, }; pub use seal::{ - ExposedSeal, GenesisSeal, GraphSeal, OutputSeal, SecretSeal, TxOrd, TxPos, TxoSeal, - XGenesisSeal, XGraphSeal, XOutputSeal, XWitnessId, XWitnessTx, + ExposedSeal, GenesisSeal, GraphSeal, OutputSeal, SecretSeal, TxoSeal, XGenesisSeal, XGraphSeal, + XOutputSeal, XWitnessId, XWitnessTx, }; pub use state::{ConcealedState, ConfidentialState, ExposedState, RevealedState, StateType}; pub use xchain::{ diff --git a/src/contract/seal.rs b/src/contract/seal.rs index 13fe7ca3..b1e684e6 100644 --- a/src/contract/seal.rs +++ b/src/contract/seal.rs @@ -21,9 +21,7 @@ // limitations under the License. use core::fmt::Debug; -use std::cmp::Ordering; use std::hash::Hash; -use std::num::NonZeroU32; use bp::dbc::Method; pub use bp::seals::txout::blind::{ChainBlindSeal, ParseError, SingleBlindSeal}; @@ -33,10 +31,10 @@ pub use bp::seals::SecretSeal; use bp::{dbc, Outpoint, Tx, Txid, Vout}; use commit_verify::{mpc, Conceal}; use single_use_seals::SealWitness; -use strict_encoding::{StrictDecode, StrictDumb, StrictEncode, StrictType}; +use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; use crate::contract::xchain::Impossible; -use crate::{XChain, XOutpoint, LIB_NAME_RGB_COMMIT}; +use crate::{XChain, XOutpoint}; pub type GenesisSeal = SingleBlindSeal; pub type GraphSeal = ChainBlindSeal; @@ -178,69 +176,6 @@ impl XChain { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Display)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[display("{height}@{timestamp}")] -// TODO: Move into validation::Logic or vm::Contract -pub struct TxPos { - height: u32, - timestamp: i64, -} - -impl TxPos { - pub fn new(height: u32, timestamp: i64) -> Option { - if height == 0 || timestamp < 1231006505 { - return None; - } - Some(TxPos { height, timestamp }) - } - - pub fn height(&self) -> NonZeroU32 { NonZeroU32::new(self.height).expect("invariant") } -} - -impl PartialOrd for TxPos { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} - -impl Ord for TxPos { - fn cmp(&self, other: &Self) -> Ordering { self.timestamp.cmp(&other.timestamp) } -} - -/// RGB consensus information about the current mined height of a witness -/// transaction defining the ordering of the contract state data. -#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, Display, From)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT, tags = order)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase", untagged) -)] -// TODO: Move into validation::Logic or vm::Contract -pub enum TxOrd { - #[from] - #[display(inner)] - OnChain(TxPos), - - #[display("offchain@{priority}")] - OffChain { priority: u32 }, - - #[display("archived")] - #[strict_type(dumb)] - Archived, -} - -impl TxOrd { - #[inline] - pub fn offchain(priority: u32) -> Self { TxOrd::OffChain { priority } } -} - pub type XWitnessTx = XChain; impl XWitnessTx { diff --git a/src/stl.rs b/src/stl.rs index 8d8e1675..3bd6b25e 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -40,7 +40,7 @@ pub const LIB_ID_RGB_COMMIT: &str = "stl:tjFc6jD7-fe78CxG-WdJlH!l-uXlFfW0-XwG1!qV-MNdtNGE#orbit-airport-voice"; /// Strict types id for the library providing data types for RGB consensus. pub const LIB_ID_RGB_LOGIC: &str = - "stl:lfwSIiCB-NMEafxB-$XKtmil-Ve95dNq-9Ni$L$Z-wbkqO2c#alarm-amanda-source"; + "stl:laJnTnBl-aRfkNII-$JJME95-FUU2D6c-6gKwzuB-N5hJi08#shallow-heroic-patrol"; fn _rgb_commit_stl() -> Result { LibBuilder::new(libname!(LIB_NAME_RGB_COMMIT), tiny_bset! { diff --git a/src/validation/logic.rs b/src/validation/logic.rs index c5d92c56..c3b94f4f 100644 --- a/src/validation/logic.rs +++ b/src/validation/logic.rs @@ -21,7 +21,9 @@ // limitations under the License. use std::cell::RefCell; +use std::cmp::Ordering; use std::collections::BTreeSet; +use std::num::NonZeroU32; use std::rc::Rc; use aluvm::data::Number; @@ -40,8 +42,72 @@ use crate::{ ConfidentialState, ExposedSeal, ExposedState, Extension, GlobalState, GlobalStateSchema, GlobalValues, GraphSeal, Inputs, MetaSchema, Metadata, OpId, OpRef, Operation, Opout, OwnedStateSchema, RevealedState, Schema, StateType, Transition, TypedAssigns, Valencies, + LIB_NAME_RGB_LOGIC, }; +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Display)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_LOGIC)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +#[display("{height}@{timestamp}")] +// TODO: Move into validation::Logic or vm::Contract +pub struct TxPos { + height: u32, + timestamp: i64, +} + +impl TxPos { + pub fn new(height: u32, timestamp: i64) -> Option { + if height == 0 || timestamp < 1231006505 { + return None; + } + Some(TxPos { height, timestamp }) + } + + pub fn height(&self) -> NonZeroU32 { NonZeroU32::new(self.height).expect("invariant") } +} + +impl PartialOrd for TxPos { + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } +} + +impl Ord for TxPos { + fn cmp(&self, other: &Self) -> Ordering { self.timestamp.cmp(&other.timestamp) } +} + +/// RGB consensus information about the current mined height of a witness +/// transaction defining the ordering of the contract state data. +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, Display, From)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_LOGIC, tags = order)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase", untagged) +)] +// TODO: Move into validation::Logic or vm::Contract +pub enum TxOrd { + #[from] + #[display(inner)] + OnChain(TxPos), + + #[display("offchain@{priority}")] + OffChain { priority: u32 }, + + #[display("archived")] + #[strict_type(dumb)] + Archived, +} + +impl TxOrd { + #[inline] + pub fn offchain(priority: u32) -> Self { TxOrd::OffChain { priority } } +} + impl Schema { // TODO: Instead of returning status fail immediately pub fn validate_state<'validator, C: ConsignmentApi, S: ContractState>( diff --git a/src/validation/mod.rs b/src/validation/mod.rs index 6b8fa165..b0962b81 100644 --- a/src/validation/mod.rs +++ b/src/validation/mod.rs @@ -29,5 +29,6 @@ mod commitments; pub use commitments::{DbcError, DbcProof, EAnchor}; pub use consignment::{CheckedConsignment, ConsignmentApi, Scripts, CONSIGNMENT_MAX_LIBS}; +pub use logic::{TxOrd, TxPos}; pub use status::{Failure, Info, Status, Validity, Warning}; pub use validator::{ResolveWitness, Validator, WitnessResolverError}; diff --git a/src/validation/validator.rs b/src/validation/validator.rs index 4eb6363e..9c337b3c 100644 --- a/src/validation/validator.rs +++ b/src/validation/validator.rs @@ -31,12 +31,11 @@ use commit_verify::mpc; use single_use_seals::SealWitness; use super::status::Failure; -use super::{CheckedConsignment, ConsignmentApi, DbcProof, EAnchor, Status, Validity}; +use super::{CheckedConsignment, ConsignmentApi, DbcProof, EAnchor, Status, TxOrd, Validity}; use crate::vm::{ContractState, OpOrd, WitnessAnchor}; use crate::{ validation, AltLayer1, BundleId, ContractId, Layer1, OpId, OpRef, OpType, Operation, Opout, - Schema, SchemaId, TransitionBundle, TxOrd, XChain, XOutpoint, XOutputSeal, XWitnessId, - XWitnessTx, + Schema, SchemaId, TransitionBundle, XChain, XOutpoint, XOutputSeal, XWitnessId, XWitnessTx, }; #[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] diff --git a/src/vm/contract.rs b/src/vm/contract.rs index 17c862d6..2d1873ab 100644 --- a/src/vm/contract.rs +++ b/src/vm/contract.rs @@ -30,10 +30,11 @@ use amplify::num::u24; use amplify::Bytes32; use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; +use crate::validation::TxOrd; use crate::{ AssetTags, AssignmentType, Assignments, AssignmentsRef, AttachState, ContractId, DataState, FungibleState, GlobalState, GlobalStateType, GraphSeal, Metadata, OpFullType, OpId, OpRef, - Operation, TxOrd, Valencies, XOutpoint, XWitnessId, LIB_NAME_RGB_LOGIC, + Operation, Valencies, XOutpoint, XWitnessId, LIB_NAME_RGB_LOGIC, }; #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display, From)] From f72bfb75376c38ee3c3888840328b3cd1a113f41 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 29 Jul 2024 15:26:43 +0200 Subject: [PATCH 06/21] contract: rename into operation module --- src/lib.rs | 4 ++-- src/{contract => operation}/assignments.rs | 2 +- src/{contract => operation}/attachment.rs | 0 src/{contract => operation}/bundle.rs | 0 src/{contract => operation}/commit.rs | 0 src/{contract => operation}/data.rs | 0 src/{contract => operation}/fungible.rs | 0 src/{contract => operation}/global.rs | 0 src/{contract => operation}/meta.rs | 0 src/{contract => operation}/mod.rs | 0 src/{contract => operation}/operations.rs | 0 src/{contract => operation}/seal.rs | 2 +- src/{contract => operation}/state.rs | 0 src/{contract => operation}/xchain.rs | 0 src/validation/status.rs | 2 +- 15 files changed, 5 insertions(+), 5 deletions(-) rename src/{contract => operation}/assignments.rs (99%) rename src/{contract => operation}/attachment.rs (100%) rename src/{contract => operation}/bundle.rs (100%) rename src/{contract => operation}/commit.rs (100%) rename src/{contract => operation}/data.rs (100%) rename src/{contract => operation}/fungible.rs (100%) rename src/{contract => operation}/global.rs (100%) rename src/{contract => operation}/meta.rs (100%) rename src/{contract => operation}/mod.rs (100%) rename src/{contract => operation}/operations.rs (100%) rename src/{contract => operation}/seal.rs (99%) rename src/{contract => operation}/state.rs (100%) rename src/{contract => operation}/xchain.rs (100%) diff --git a/src/lib.rs b/src/lib.rs index d73a4515..7e65a85c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,7 +44,7 @@ extern crate commit_verify; extern crate serde_crate as serde; extern crate core; -mod contract; +mod operation; pub mod schema; pub mod validation; #[macro_use] @@ -54,7 +54,7 @@ pub mod stl; pub mod prelude { pub use commit_verify::ReservedBytes; - pub use contract::*; + pub use operation::*; pub use schema::*; #[cfg(feature = "stl")] diff --git a/src/contract/assignments.rs b/src/operation/assignments.rs similarity index 99% rename from src/contract/assignments.rs rename to src/operation/assignments.rs index e2bda5ef..9682e35b 100644 --- a/src/contract/assignments.rs +++ b/src/operation/assignments.rs @@ -30,7 +30,7 @@ use commit_verify::{Conceal, ReservedBytes}; use strict_encoding::{StrictDumb, StrictEncode}; use super::ExposedState; -use crate::contract::seal::GenesisSeal; +use crate::operation::seal::GenesisSeal; use crate::{ AssignmentType, ExposedSeal, GraphSeal, RevealedAttach, RevealedData, RevealedValue, SecretSeal, StateType, VoidState, XChain, LIB_NAME_RGB_COMMIT, diff --git a/src/contract/attachment.rs b/src/operation/attachment.rs similarity index 100% rename from src/contract/attachment.rs rename to src/operation/attachment.rs diff --git a/src/contract/bundle.rs b/src/operation/bundle.rs similarity index 100% rename from src/contract/bundle.rs rename to src/operation/bundle.rs diff --git a/src/contract/commit.rs b/src/operation/commit.rs similarity index 100% rename from src/contract/commit.rs rename to src/operation/commit.rs diff --git a/src/contract/data.rs b/src/operation/data.rs similarity index 100% rename from src/contract/data.rs rename to src/operation/data.rs diff --git a/src/contract/fungible.rs b/src/operation/fungible.rs similarity index 100% rename from src/contract/fungible.rs rename to src/operation/fungible.rs diff --git a/src/contract/global.rs b/src/operation/global.rs similarity index 100% rename from src/contract/global.rs rename to src/operation/global.rs diff --git a/src/contract/meta.rs b/src/operation/meta.rs similarity index 100% rename from src/contract/meta.rs rename to src/operation/meta.rs diff --git a/src/contract/mod.rs b/src/operation/mod.rs similarity index 100% rename from src/contract/mod.rs rename to src/operation/mod.rs diff --git a/src/contract/operations.rs b/src/operation/operations.rs similarity index 100% rename from src/contract/operations.rs rename to src/operation/operations.rs diff --git a/src/contract/seal.rs b/src/operation/seal.rs similarity index 99% rename from src/contract/seal.rs rename to src/operation/seal.rs index b1e684e6..7d9e4436 100644 --- a/src/contract/seal.rs +++ b/src/operation/seal.rs @@ -33,7 +33,7 @@ use commit_verify::{mpc, Conceal}; use single_use_seals::SealWitness; use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; -use crate::contract::xchain::Impossible; +use crate::operation::xchain::Impossible; use crate::{XChain, XOutpoint}; pub type GenesisSeal = SingleBlindSeal; diff --git a/src/contract/state.rs b/src/operation/state.rs similarity index 100% rename from src/contract/state.rs rename to src/operation/state.rs diff --git a/src/contract/xchain.rs b/src/operation/xchain.rs similarity index 100% rename from src/contract/xchain.rs rename to src/operation/xchain.rs diff --git a/src/validation/status.rs b/src/validation/status.rs index deda9554..0761cb58 100644 --- a/src/validation/status.rs +++ b/src/validation/status.rs @@ -27,7 +27,7 @@ use amplify::num::u24; use commit_verify::mpc::InvalidProof; use strict_types::SemId; -use crate::contract::Opout; +use crate::operation::Opout; use crate::schema::{self, SchemaId}; use crate::validation::WitnessResolverError; use crate::{ From c4672e8253ccfbc1fb64530b61e15d4e9346b51e Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 29 Jul 2024 15:28:31 +0200 Subject: [PATCH 07/21] vm: move TxOrd/Pos from validation module --- src/validation/logic.rs | 66 --------------------------------- src/validation/mod.rs | 1 - src/validation/validator.rs | 4 +- src/vm/contract.rs | 73 ++++++++++++++++++++++++++++++++++++- src/vm/mod.rs | 2 +- 5 files changed, 75 insertions(+), 71 deletions(-) diff --git a/src/validation/logic.rs b/src/validation/logic.rs index c3b94f4f..c5d92c56 100644 --- a/src/validation/logic.rs +++ b/src/validation/logic.rs @@ -21,9 +21,7 @@ // limitations under the License. use std::cell::RefCell; -use std::cmp::Ordering; use std::collections::BTreeSet; -use std::num::NonZeroU32; use std::rc::Rc; use aluvm::data::Number; @@ -42,72 +40,8 @@ use crate::{ ConfidentialState, ExposedSeal, ExposedState, Extension, GlobalState, GlobalStateSchema, GlobalValues, GraphSeal, Inputs, MetaSchema, Metadata, OpId, OpRef, Operation, Opout, OwnedStateSchema, RevealedState, Schema, StateType, Transition, TypedAssigns, Valencies, - LIB_NAME_RGB_LOGIC, }; -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Display)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_LOGIC)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[display("{height}@{timestamp}")] -// TODO: Move into validation::Logic or vm::Contract -pub struct TxPos { - height: u32, - timestamp: i64, -} - -impl TxPos { - pub fn new(height: u32, timestamp: i64) -> Option { - if height == 0 || timestamp < 1231006505 { - return None; - } - Some(TxPos { height, timestamp }) - } - - pub fn height(&self) -> NonZeroU32 { NonZeroU32::new(self.height).expect("invariant") } -} - -impl PartialOrd for TxPos { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} - -impl Ord for TxPos { - fn cmp(&self, other: &Self) -> Ordering { self.timestamp.cmp(&other.timestamp) } -} - -/// RGB consensus information about the current mined height of a witness -/// transaction defining the ordering of the contract state data. -#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, Display, From)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_LOGIC, tags = order)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase", untagged) -)] -// TODO: Move into validation::Logic or vm::Contract -pub enum TxOrd { - #[from] - #[display(inner)] - OnChain(TxPos), - - #[display("offchain@{priority}")] - OffChain { priority: u32 }, - - #[display("archived")] - #[strict_type(dumb)] - Archived, -} - -impl TxOrd { - #[inline] - pub fn offchain(priority: u32) -> Self { TxOrd::OffChain { priority } } -} - impl Schema { // TODO: Instead of returning status fail immediately pub fn validate_state<'validator, C: ConsignmentApi, S: ContractState>( diff --git a/src/validation/mod.rs b/src/validation/mod.rs index b0962b81..6b8fa165 100644 --- a/src/validation/mod.rs +++ b/src/validation/mod.rs @@ -29,6 +29,5 @@ mod commitments; pub use commitments::{DbcError, DbcProof, EAnchor}; pub use consignment::{CheckedConsignment, ConsignmentApi, Scripts, CONSIGNMENT_MAX_LIBS}; -pub use logic::{TxOrd, TxPos}; pub use status::{Failure, Info, Status, Validity, Warning}; pub use validator::{ResolveWitness, Validator, WitnessResolverError}; diff --git a/src/validation/validator.rs b/src/validation/validator.rs index 9c337b3c..600f0990 100644 --- a/src/validation/validator.rs +++ b/src/validation/validator.rs @@ -31,8 +31,8 @@ use commit_verify::mpc; use single_use_seals::SealWitness; use super::status::Failure; -use super::{CheckedConsignment, ConsignmentApi, DbcProof, EAnchor, Status, TxOrd, Validity}; -use crate::vm::{ContractState, OpOrd, WitnessAnchor}; +use super::{CheckedConsignment, ConsignmentApi, DbcProof, EAnchor, Status, Validity}; +use crate::vm::{ContractState, OpOrd, TxOrd, WitnessAnchor}; use crate::{ validation, AltLayer1, BundleId, ContractId, Layer1, OpId, OpRef, OpType, Operation, Opout, Schema, SchemaId, TransitionBundle, XChain, XOutpoint, XOutputSeal, XWitnessId, XWitnessTx, diff --git a/src/vm/contract.rs b/src/vm/contract.rs index 2d1873ab..3499cdde 100644 --- a/src/vm/contract.rs +++ b/src/vm/contract.rs @@ -24,19 +24,90 @@ use std::borrow::Borrow; use std::cell::RefCell; use std::cmp::Ordering; use std::fmt::Debug; +use std::num::NonZeroU32; use std::rc::Rc; use amplify::num::u24; use amplify::Bytes32; use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; -use crate::validation::TxOrd; use crate::{ AssetTags, AssignmentType, Assignments, AssignmentsRef, AttachState, ContractId, DataState, FungibleState, GlobalState, GlobalStateType, GraphSeal, Metadata, OpFullType, OpId, OpRef, Operation, Valencies, XOutpoint, XWitnessId, LIB_NAME_RGB_LOGIC, }; +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Display)] +#[derive( + StrictType, + strict_encoding::StrictDumb, + strict_encoding::StrictEncode, + strict_encoding::StrictDecode +)] +#[strict_type(lib = LIB_NAME_RGB_LOGIC)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +#[display("{height}@{timestamp}")] +pub struct TxPos { + height: u32, + timestamp: i64, +} + +impl TxPos { + pub fn new(height: u32, timestamp: i64) -> Option { + if height == 0 || timestamp < 1231006505 { + return None; + } + Some(TxPos { height, timestamp }) + } + + pub fn height(&self) -> NonZeroU32 { NonZeroU32::new(self.height).expect("invariant") } +} + +impl PartialOrd for TxPos { + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } +} + +impl Ord for TxPos { + fn cmp(&self, other: &Self) -> Ordering { self.timestamp.cmp(&other.timestamp) } +} + +/// RGB consensus information about the current mined height of a witness +/// transaction defining the ordering of the contract state data. +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, Display, From)] +#[derive( + StrictType, + strict_encoding::StrictDumb, + strict_encoding::StrictEncode, + strict_encoding::StrictDecode +)] +#[strict_type(lib = LIB_NAME_RGB_LOGIC, tags = order)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase", untagged) +)] +pub enum TxOrd { + #[from] + #[display(inner)] + OnChain(TxPos), + + #[display("offchain@{priority}")] + OffChain { priority: u32 }, + + #[display("archived")] + #[strict_type(dumb)] + Archived, +} + +impl TxOrd { + #[inline] + pub fn offchain(priority: u32) -> Self { TxOrd::OffChain { priority } } +} + #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display, From)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_LOGIC, tags = custom)] diff --git a/src/vm/mod.rs b/src/vm/mod.rs index dde4b865..05d40114 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -35,7 +35,7 @@ mod contract; pub use aluvm::aluasm_isa; pub use contract::{ AssignmentWitness, ContractState, GlobalContractState, GlobalOrd, GlobalStateIter, OpOrd, - UnknownGlobalStateType, WitnessAnchor, + TxOrd, TxPos, UnknownGlobalStateType, WitnessAnchor, }; pub(crate) use contract::{OpInfo, VmContext}; pub use isa::RgbIsa; From 7ca191515741e35246aa9ff7ba905bb1a5afce85 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 29 Jul 2024 15:29:30 +0200 Subject: [PATCH 08/21] vm: rename AssignmentWitness into OpWitnessId --- src/vm/contract.rs | 21 ++++++++++----------- src/vm/mod.rs | 4 ++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/vm/contract.rs b/src/vm/contract.rs index 3499cdde..2c9c522d 100644 --- a/src/vm/contract.rs +++ b/src/vm/contract.rs @@ -116,8 +116,7 @@ impl TxOrd { derive(Serialize, Deserialize), serde(crate = "serde_crate", rename_all = "camelCase", untagged) )] -// TODO: Rename into `OpWitnessId` -pub enum AssignmentWitness { +pub enum OpWitnessId { #[display("~")] #[strict_type(tag = 0, dumb)] Absent, @@ -129,27 +128,27 @@ pub enum AssignmentWitness { Present(XWitnessId), } -impl PartialEq for AssignmentWitness { +impl PartialEq for OpWitnessId { fn eq(&self, other: &XWitnessId) -> bool { self.witness_id() == Some(*other) } } -impl PartialEq for XWitnessId { - fn eq(&self, other: &AssignmentWitness) -> bool { other.witness_id() == Some(*self) } +impl PartialEq for XWitnessId { + fn eq(&self, other: &OpWitnessId) -> bool { other.witness_id() == Some(*self) } } -impl From> for AssignmentWitness { +impl From> for OpWitnessId { fn from(value: Option) -> Self { match value { - None => AssignmentWitness::Absent, - Some(id) => AssignmentWitness::Present(id), + None => OpWitnessId::Absent, + Some(id) => OpWitnessId::Present(id), } } } -impl AssignmentWitness { +impl OpWitnessId { pub fn witness_id(&self) -> Option { match self { - AssignmentWitness::Absent => None, - AssignmentWitness::Present(witness_id) => Some(*witness_id), + OpWitnessId::Absent => None, + OpWitnessId::Present(witness_id) => Some(*witness_id), } } } diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 05d40114..5a04f307 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -34,8 +34,8 @@ mod contract; pub use aluvm::aluasm_isa; pub use contract::{ - AssignmentWitness, ContractState, GlobalContractState, GlobalOrd, GlobalStateIter, OpOrd, - TxOrd, TxPos, UnknownGlobalStateType, WitnessAnchor, + ContractState, GlobalContractState, GlobalOrd, GlobalStateIter, OpOrd, OpWitnessId, TxOrd, + TxPos, UnknownGlobalStateType, WitnessAnchor, }; pub(crate) use contract::{OpInfo, VmContext}; pub use isa::RgbIsa; From c9904997cacf07120a5bf792326d686f552ba3eb Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 29 Jul 2024 15:30:09 +0200 Subject: [PATCH 09/21] vm: rename WitnessAnchor into WitnessOrd --- src/validation/validator.rs | 4 ++-- src/vm/contract.rs | 19 +++++++++---------- src/vm/mod.rs | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/validation/validator.rs b/src/validation/validator.rs index 600f0990..d1475a48 100644 --- a/src/validation/validator.rs +++ b/src/validation/validator.rs @@ -32,7 +32,7 @@ use single_use_seals::SealWitness; use super::status::Failure; use super::{CheckedConsignment, ConsignmentApi, DbcProof, EAnchor, Status, Validity}; -use crate::vm::{ContractState, OpOrd, TxOrd, WitnessAnchor}; +use crate::vm::{ContractState, OpOrd, TxOrd, WitnessOrd}; use crate::{ validation, AltLayer1, BundleId, ContractId, Layer1, OpId, OpRef, OpType, Operation, Opout, Schema, SchemaId, TransitionBundle, XChain, XOutpoint, XOutputSeal, XWitnessId, XWitnessTx, @@ -281,7 +281,7 @@ impl<'consignment, 'resolver, C: ConsignmentApi, R: ResolveWitness, S: ContractS for (opid, op) in &bundle.known_transitions { ops.insert( OpOrd { - witness_ord: WitnessAnchor { + witness_ord: WitnessOrd { witness_ord, witness_id, }, diff --git a/src/vm/contract.rs b/src/vm/contract.rs index 2c9c522d..ec34c7dc 100644 --- a/src/vm/contract.rs +++ b/src/vm/contract.rs @@ -163,17 +163,16 @@ impl OpWitnessId { serde(crate = "serde_crate", rename_all = "camelCase") )] #[display("{witness_id}/{witness_ord}")] -// TODO: Rename into `WitnessOrd` -pub struct WitnessAnchor { +pub struct WitnessOrd { pub witness_ord: TxOrd, pub witness_id: XWitnessId, } -impl PartialOrd for WitnessAnchor { +impl PartialOrd for WitnessOrd { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for WitnessAnchor { +impl Ord for WitnessOrd { fn cmp(&self, other: &Self) -> Ordering { if self == other { return Ordering::Equal; @@ -186,16 +185,16 @@ impl Ord for WitnessAnchor { } } -impl WitnessAnchor { +impl WitnessOrd { pub fn with(witness_id: XWitnessId, witness_ord: TxOrd) -> Self { - WitnessAnchor { + WitnessOrd { witness_id, witness_ord, } } pub fn from_mempool(witness_id: XWitnessId, priority: u32) -> Self { - WitnessAnchor { + WitnessOrd { witness_ord: TxOrd::OffChain { priority }, witness_id, } @@ -212,7 +211,7 @@ impl WitnessAnchor { serde(crate = "serde_crate", rename_all = "camelCase") )] pub struct OpOrd { - pub witness_ord: WitnessAnchor, + pub witness_ord: WitnessOrd, pub opid: OpId, } @@ -228,7 +227,7 @@ pub struct OpOrd { pub struct GlobalOrd { // Absent for state defined in genesis // TODO: Change into `AssignmentWitness` - pub witness_anchor: Option, + pub witness_anchor: Option, pub opid: OpId, pub idx: u16, } @@ -256,7 +255,7 @@ impl GlobalOrd { #[inline] pub fn with_witness(opid: OpId, witness_id: XWitnessId, ord: TxOrd, idx: u16) -> Self { GlobalOrd { - witness_anchor: Some(WitnessAnchor::with(witness_id, ord)), + witness_anchor: Some(WitnessOrd::with(witness_id, ord)), opid, idx, } diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 5a04f307..5a23e3d3 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -35,7 +35,7 @@ mod contract; pub use aluvm::aluasm_isa; pub use contract::{ ContractState, GlobalContractState, GlobalOrd, GlobalStateIter, OpOrd, OpWitnessId, TxOrd, - TxPos, UnknownGlobalStateType, WitnessAnchor, + TxPos, UnknownGlobalStateType, WitnessOrd, }; pub(crate) use contract::{OpInfo, VmContext}; pub use isa::RgbIsa; From a19447af9465eb9715a7d5f17237a4376ec248fa Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 29 Jul 2024 15:33:30 +0200 Subject: [PATCH 10/21] vm: rename field in TxOrg --- src/stl.rs | 2 +- src/validation/validator.rs | 6 +++--- src/vm/contract.rs | 24 ++++++++++++------------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/stl.rs b/src/stl.rs index 3bd6b25e..c66cf6e8 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -40,7 +40,7 @@ pub const LIB_ID_RGB_COMMIT: &str = "stl:tjFc6jD7-fe78CxG-WdJlH!l-uXlFfW0-XwG1!qV-MNdtNGE#orbit-airport-voice"; /// Strict types id for the library providing data types for RGB consensus. pub const LIB_ID_RGB_LOGIC: &str = - "stl:laJnTnBl-aRfkNII-$JJME95-FUU2D6c-6gKwzuB-N5hJi08#shallow-heroic-patrol"; + "stl:8kmQvIP0-D3E4nxl-MFgfuC6-rgXKJGD-nN1hhfy-L$8sqCQ#tropic-photo-analyze"; fn _rgb_commit_stl() -> Result { LibBuilder::new(libname!(LIB_NAME_RGB_COMMIT), tiny_bset! { diff --git a/src/validation/validator.rs b/src/validation/validator.rs index d1475a48..16e2ae26 100644 --- a/src/validation/validator.rs +++ b/src/validation/validator.rs @@ -267,9 +267,9 @@ impl<'consignment, 'resolver, C: ConsignmentApi, R: ResolveWitness, S: ContractS .consignment .anchor(bundle_id) .expect("invalid checked consignment"); - let witness_ord = + let pub_ord = match self.resolver.resolve_pub_witness_ord(witness_id) { - Ok(witness_ord) => witness_ord, + Ok(ord) => ord, Err(err) => { self.status.borrow_mut().add_failure( validation::Failure::WitnessUnresolved(bundle_id, witness_id, err), @@ -282,7 +282,7 @@ impl<'consignment, 'resolver, C: ConsignmentApi, R: ResolveWitness, S: ContractS ops.insert( OpOrd { witness_ord: WitnessOrd { - witness_ord, + pub_ord, witness_id, }, opid: *opid, diff --git a/src/vm/contract.rs b/src/vm/contract.rs index ec34c7dc..14a7321c 100644 --- a/src/vm/contract.rs +++ b/src/vm/contract.rs @@ -162,9 +162,9 @@ impl OpWitnessId { derive(Serialize, Deserialize), serde(crate = "serde_crate", rename_all = "camelCase") )] -#[display("{witness_id}/{witness_ord}")] +#[display("{witness_id}/{pub_ord}")] pub struct WitnessOrd { - pub witness_ord: TxOrd, + pub pub_ord: TxOrd, pub witness_id: XWitnessId, } @@ -177,7 +177,7 @@ impl Ord for WitnessOrd { if self == other { return Ordering::Equal; } - match self.witness_ord.cmp(&other.witness_ord) { + match self.pub_ord.cmp(&other.pub_ord) { Ordering::Less => Ordering::Less, Ordering::Greater => Ordering::Greater, Ordering::Equal => self.witness_id.cmp(&other.witness_id), @@ -186,16 +186,16 @@ impl Ord for WitnessOrd { } impl WitnessOrd { - pub fn with(witness_id: XWitnessId, witness_ord: TxOrd) -> Self { + pub fn with(witness_id: XWitnessId, pub_ord: TxOrd) -> Self { WitnessOrd { witness_id, - witness_ord, + pub_ord, } } pub fn from_mempool(witness_id: XWitnessId, priority: u32) -> Self { WitnessOrd { - witness_ord: TxOrd::OffChain { priority }, + pub_ord: TxOrd::OffChain { priority }, witness_id, } } @@ -227,7 +227,7 @@ pub struct OpOrd { pub struct GlobalOrd { // Absent for state defined in genesis // TODO: Change into `AssignmentWitness` - pub witness_anchor: Option, + pub witness_ord: Option, pub opid: OpId, pub idx: u16, } @@ -241,7 +241,7 @@ impl Ord for GlobalOrd { if self == other { return Ordering::Equal; } - match (self.witness_anchor, &other.witness_anchor) { + match (self.witness_ord, &other.witness_ord) { (None, None) => self.idx.cmp(&other.idx), (None, Some(_)) => Ordering::Less, (Some(_), None) => Ordering::Greater, @@ -255,7 +255,7 @@ impl GlobalOrd { #[inline] pub fn with_witness(opid: OpId, witness_id: XWitnessId, ord: TxOrd, idx: u16) -> Self { GlobalOrd { - witness_anchor: Some(WitnessOrd::with(witness_id, ord)), + witness_ord: Some(WitnessOrd::with(witness_id, ord)), opid, idx, } @@ -263,13 +263,13 @@ impl GlobalOrd { #[inline] pub fn genesis(opid: OpId, idx: u16) -> Self { GlobalOrd { - witness_anchor: None, + witness_ord: None, opid, idx, } } #[inline] - pub fn witness_id(&self) -> Option { self.witness_anchor.map(|a| a.witness_id) } + pub fn witness_id(&self) -> Option { self.witness_ord.map(|a| a.witness_id) } } pub trait GlobalStateIter { @@ -307,7 +307,7 @@ impl GlobalContractState { pub fn new(mut iter: I) -> Self { let last_ord = iter.prev().map(|(ord, _)| ord).unwrap_or(GlobalOrd { // This is dumb object which must always have the lowest ordering. - witness_anchor: None, + witness_ord: None, opid: Bytes32::zero().into(), idx: 0, }); From 0e778b2c4df6e7030833fbd85b9a50fcc6a88d44 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 29 Jul 2024 15:35:21 +0200 Subject: [PATCH 11/21] vm: improve imports --- src/vm/isa.rs | 2 +- src/vm/op_contract.rs | 3 +-- src/vm/op_timechain.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/vm/isa.rs b/src/vm/isa.rs index 8c3417ae..2dbeb0b0 100644 --- a/src/vm/isa.rs +++ b/src/vm/isa.rs @@ -28,8 +28,8 @@ use aluvm::isa::{Bytecode, BytecodeError, ExecStep, InstructionSet}; use aluvm::library::{CodeEofError, IsaSeg, LibSite, Read, Write}; use aluvm::reg::{CoreRegs, Reg}; +use super::opcodes::{INSTR_RGBISA_FROM, INSTR_RGBISA_TO}; use super::{ContractOp, ContractState, TimechainOp, VmContext}; -use crate::vm::opcodes::{INSTR_RGBISA_FROM, INSTR_RGBISA_TO}; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] #[display(inner)] diff --git a/src/vm/op_contract.rs b/src/vm/op_contract.rs index da01b5a2..defd1cf0 100644 --- a/src/vm/op_contract.rs +++ b/src/vm/op_contract.rs @@ -34,8 +34,7 @@ use amplify::Wrapper; use commit_verify::CommitVerify; use super::opcodes::*; -use super::VmContext; -use crate::vm::ContractState; +use super::{ContractState, VmContext}; use crate::{ Assign, AssignmentType, BlindingFactor, GlobalStateType, MetaType, PedersenCommitment, RevealedValue, TypedAssigns, diff --git a/src/vm/op_timechain.rs b/src/vm/op_timechain.rs index 92378bb6..d258f29d 100644 --- a/src/vm/op_timechain.rs +++ b/src/vm/op_timechain.rs @@ -27,7 +27,7 @@ use aluvm::isa::{Bytecode, BytecodeError, ExecStep, InstructionSet}; use aluvm::library::{CodeEofError, IsaSeg, LibSite, Read, Write}; use aluvm::reg::{CoreRegs, Reg}; -use crate::vm::opcodes::{INSTR_TIMECHAIN_FROM, INSTR_TIMECHAIN_TO}; +use super::opcodes::{INSTR_TIMECHAIN_FROM, INSTR_TIMECHAIN_TO}; // TODO: Implement bitcoin blockchain introspection From 20e606085086c449be12143de600427d71d198d0 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 29 Jul 2024 15:37:23 +0200 Subject: [PATCH 12/21] vm: redistribute fields of VmContext and OpInfo --- src/validation/logic.rs | 11 +++-------- src/vm/contract.rs | 10 ++-------- src/vm/op_contract.rs | 4 ++-- 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/validation/logic.rs b/src/validation/logic.rs index c5d92c56..7b5e14a3 100644 --- a/src/validation/logic.rs +++ b/src/validation/logic.rs @@ -190,15 +190,10 @@ impl Schema { status += self.validate_valencies(opid, op.valencies(), valency_schema); let genesis = consignment.genesis(); - let op_info = OpInfo::with( - genesis.contract_id(), - opid, - &op, - &prev_state, - &redeemed, - &genesis.asset_tags, - ); + let op_info = OpInfo::with(opid, &op, &prev_state, &redeemed); let context = VmContext { + contract_id: genesis.contract_id(), + asset_tags: &genesis.asset_tags, op_info, contract_state, }; diff --git a/src/vm/contract.rs b/src/vm/contract.rs index 14a7321c..8e811cb8 100644 --- a/src/vm/contract.rs +++ b/src/vm/contract.rs @@ -409,17 +409,15 @@ pub trait ContractState: Debug + Default { } pub struct VmContext<'op, S: ContractState> { + pub contract_id: ContractId, + pub asset_tags: &'op AssetTags, pub op_info: OpInfo<'op>, pub contract_state: Rc>, } pub struct OpInfo<'op> { - // TODO: Move to VmContext - pub contract_id: ContractId, pub id: OpId, pub ty: OpFullType, - // TODO: Move to VmContext - pub asset_tags: &'op AssetTags, pub metadata: &'op Metadata, pub prev_state: &'op Assignments, pub owned_state: AssignmentsRef<'op>, @@ -430,18 +428,14 @@ pub struct OpInfo<'op> { impl<'op> OpInfo<'op> { pub fn with( - contract_id: ContractId, id: OpId, op: &'op OpRef<'op>, prev_state: &'op Assignments, redeemed: &'op Valencies, - asset_tags: &'op AssetTags, ) -> Self { OpInfo { id, - contract_id, ty: op.full_type(), - asset_tags, metadata: op.metadata(), prev_state, owned_state: op.assignments(), diff --git a/src/vm/op_contract.rs b/src/vm/op_contract.rs index defd1cf0..ebedd912 100644 --- a/src/vm/op_contract.rs +++ b/src/vm/op_contract.rs @@ -400,7 +400,7 @@ impl InstructionSet for ContractOp { }; let sum = u64::from(sum); - let Some(tag) = context.op_info.asset_tags.get(owned_state) else { + let Some(tag) = context.asset_tags.get(owned_state) else { fail!() }; let sum = RevealedValue::with_blinding(sum, BlindingFactor::EMPTY, *tag); @@ -423,7 +423,7 @@ impl InstructionSet for ContractOp { }; let sum = u64::from(sum); - let Some(tag) = context.op_info.asset_tags.get(owned_state) else { + let Some(tag) = context.asset_tags.get(owned_state) else { fail!() }; let sum = RevealedValue::with_blinding(sum, BlindingFactor::EMPTY, *tag); From 8fd8d5ae7afda05acca43c92d0e32c21e13f4973 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 29 Jul 2024 15:44:30 +0200 Subject: [PATCH 13/21] vm: separate ContractState and ContractStateEvolve traits --- src/validation/logic.rs | 4 ++-- src/validation/validator.rs | 6 +++--- src/vm/contract.rs | 5 +++-- src/vm/mod.rs | 4 ++-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/validation/logic.rs b/src/validation/logic.rs index 7b5e14a3..7dc259e0 100644 --- a/src/validation/logic.rs +++ b/src/validation/logic.rs @@ -34,7 +34,7 @@ use strict_types::TypeSystem; use crate::schema::{AssignmentsSchema, GlobalSchema, ValencySchema}; use crate::validation::{CheckedConsignment, ConsignmentApi}; -use crate::vm::{ContractState, OpInfo, RgbIsa, VmContext}; +use crate::vm::{ContractStateEvolve, OpInfo, RgbIsa, VmContext}; use crate::{ validation, Assign, AssignmentType, Assignments, AssignmentsRef, ConcealedState, ConfidentialState, ExposedSeal, ExposedState, Extension, GlobalState, GlobalStateSchema, @@ -44,7 +44,7 @@ use crate::{ impl Schema { // TODO: Instead of returning status fail immediately - pub fn validate_state<'validator, C: ConsignmentApi, S: ContractState>( + pub fn validate_state<'validator, C: ConsignmentApi, S: ContractStateEvolve>( &'validator self, consignment: &'validator CheckedConsignment<'_, C>, op: OpRef, diff --git a/src/validation/validator.rs b/src/validation/validator.rs index 16e2ae26..26209105 100644 --- a/src/validation/validator.rs +++ b/src/validation/validator.rs @@ -32,7 +32,7 @@ use single_use_seals::SealWitness; use super::status::Failure; use super::{CheckedConsignment, ConsignmentApi, DbcProof, EAnchor, Status, Validity}; -use crate::vm::{ContractState, OpOrd, TxOrd, WitnessOrd}; +use crate::vm::{ContractStateEvolve, OpOrd, TxOrd, WitnessOrd}; use crate::{ validation, AltLayer1, BundleId, ContractId, Layer1, OpId, OpRef, OpType, Operation, Opout, Schema, SchemaId, TransitionBundle, XChain, XOutpoint, XOutputSeal, XWitnessId, XWitnessTx, @@ -126,7 +126,7 @@ pub struct Validator< 'resolver, C: ConsignmentApi, R: ResolveWitness, - S: ContractState, + S: ContractStateEvolve, > { consignment: CheckedConsignment<'consignment, C>, @@ -144,7 +144,7 @@ pub struct Validator< resolver: CheckedWitnessResolver<&'resolver R>, } -impl<'consignment, 'resolver, C: ConsignmentApi, R: ResolveWitness, S: ContractState> +impl<'consignment, 'resolver, C: ConsignmentApi, R: ResolveWitness, S: ContractStateEvolve> Validator<'consignment, 'resolver, C, R, S> { fn init(consignment: &'consignment C, resolver: &'resolver R) -> Self { diff --git a/src/vm/contract.rs b/src/vm/contract.rs index 8e811cb8..353b1f30 100644 --- a/src/vm/contract.rs +++ b/src/vm/contract.rs @@ -378,8 +378,7 @@ impl Iterator for GlobalContractState { #[display("unknown global state type {0} requested from the contract")] pub struct UnknownGlobalStateType(pub GlobalStateType); -// TODO: Separate mutable and immutable parts of the trait -pub trait ContractState: Debug + Default { +pub trait ContractState: Debug { fn global( &self, ty: GlobalStateType, @@ -404,7 +403,9 @@ pub trait ContractState: Debug + Default { outpoint: XOutpoint, ty: AssignmentType, ) -> impl DoubleEndedIterator>; +} +pub trait ContractStateEvolve: ContractState + Default { fn evolve_state(&mut self, op: OpRef); } diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 5a23e3d3..2769f7f1 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -34,8 +34,8 @@ mod contract; pub use aluvm::aluasm_isa; pub use contract::{ - ContractState, GlobalContractState, GlobalOrd, GlobalStateIter, OpOrd, OpWitnessId, TxOrd, - TxPos, UnknownGlobalStateType, WitnessOrd, + ContractState, ContractStateEvolve, GlobalContractState, GlobalOrd, GlobalStateIter, OpOrd, + OpWitnessId, TxOrd, TxPos, UnknownGlobalStateType, WitnessOrd, }; pub(crate) use contract::{OpInfo, VmContext}; pub use isa::RgbIsa; From 25cf921ff2130fd9a6c9f9acdac3087f79f7c4d3 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 29 Jul 2024 15:45:56 +0200 Subject: [PATCH 14/21] chore: fmt --- src/vm/contract.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/vm/contract.rs b/src/vm/contract.rs index 353b1f30..3518d4de 100644 --- a/src/vm/contract.rs +++ b/src/vm/contract.rs @@ -38,12 +38,7 @@ use crate::{ }; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Display)] -#[derive( - StrictType, - strict_encoding::StrictDumb, - strict_encoding::StrictEncode, - strict_encoding::StrictDecode -)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_LOGIC)] #[cfg_attr( feature = "serde", @@ -78,12 +73,7 @@ impl Ord for TxPos { /// RGB consensus information about the current mined height of a witness /// transaction defining the ordering of the contract state data. #[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, Display, From)] -#[derive( - StrictType, - strict_encoding::StrictDumb, - strict_encoding::StrictEncode, - strict_encoding::StrictDecode -)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_LOGIC, tags = order)] #[cfg_attr( feature = "serde", @@ -226,7 +216,6 @@ pub struct OpOrd { )] pub struct GlobalOrd { // Absent for state defined in genesis - // TODO: Change into `AssignmentWitness` pub witness_ord: Option, pub opid: OpId, pub idx: u16, From b5acf6bce3d0cfa906c793112571b0baf062fe7a Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 29 Jul 2024 15:49:12 +0200 Subject: [PATCH 15/21] vm: remove OpWitnessId type --- src/vm/contract.rs | 45 --------------------------------------------- src/vm/mod.rs | 2 +- 2 files changed, 1 insertion(+), 46 deletions(-) diff --git a/src/vm/contract.rs b/src/vm/contract.rs index 3518d4de..858b31ca 100644 --- a/src/vm/contract.rs +++ b/src/vm/contract.rs @@ -98,51 +98,6 @@ impl TxOrd { pub fn offchain(priority: u32) -> Self { TxOrd::OffChain { priority } } } -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display, From)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_LOGIC, tags = custom)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase", untagged) -)] -pub enum OpWitnessId { - #[display("~")] - #[strict_type(tag = 0, dumb)] - Absent, - - // TODO: Consider separating transition and extension witnesses - #[from] - #[display(inner)] - #[strict_type(tag = 1)] - Present(XWitnessId), -} - -impl PartialEq for OpWitnessId { - fn eq(&self, other: &XWitnessId) -> bool { self.witness_id() == Some(*other) } -} -impl PartialEq for XWitnessId { - fn eq(&self, other: &OpWitnessId) -> bool { other.witness_id() == Some(*self) } -} - -impl From> for OpWitnessId { - fn from(value: Option) -> Self { - match value { - None => OpWitnessId::Absent, - Some(id) => OpWitnessId::Present(id), - } - } -} - -impl OpWitnessId { - pub fn witness_id(&self) -> Option { - match self { - OpWitnessId::Absent => None, - OpWitnessId::Present(witness_id) => Some(*witness_id), - } - } -} - /// Txid and height information ordered according to the RGB consensus rules. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 2769f7f1..e7ae7480 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -35,7 +35,7 @@ mod contract; pub use aluvm::aluasm_isa; pub use contract::{ ContractState, ContractStateEvolve, GlobalContractState, GlobalOrd, GlobalStateIter, OpOrd, - OpWitnessId, TxOrd, TxPos, UnknownGlobalStateType, WitnessOrd, + TxOrd, TxPos, UnknownGlobalStateType, WitnessOrd, }; pub(crate) use contract::{OpInfo, VmContext}; pub use isa::RgbIsa; From dc1318565528cc9ffb1db266765a8e4347d8ecc5 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 30 Jul 2024 13:18:59 +0200 Subject: [PATCH 16/21] vm: ensure timestamp is always greater than 0 --- src/vm/contract.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vm/contract.rs b/src/vm/contract.rs index 0e9999c5..430e1969 100644 --- a/src/vm/contract.rs +++ b/src/vm/contract.rs @@ -67,7 +67,11 @@ impl PartialOrd for TxPos { } impl Ord for TxPos { - fn cmp(&self, other: &Self) -> Ordering { self.timestamp.cmp(&other.timestamp) } + fn cmp(&self, other: &Self) -> Ordering { + assert!(self.timestamp > 0); + assert!(other.timestamp > 0); + self.timestamp.cmp(&other.timestamp) + } } /// RGB consensus information about the current mined height of a witness From fded4523d4b67abee5fc5a2932182e6258e1dc71 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 30 Jul 2024 18:02:06 +0200 Subject: [PATCH 17/21] vm: further separate ContractStateAccess and ContractStateEvolve --- src/validation/logic.rs | 8 ++++++-- src/validation/validator.rs | 28 ++++++++++++++++++---------- src/vm/contract.rs | 8 +++++--- src/vm/isa.rs | 8 ++++---- src/vm/mod.rs | 4 ++-- src/vm/op_contract.rs | 8 ++++---- 6 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/validation/logic.rs b/src/validation/logic.rs index 7dc259e0..837e555f 100644 --- a/src/validation/logic.rs +++ b/src/validation/logic.rs @@ -34,7 +34,7 @@ use strict_types::TypeSystem; use crate::schema::{AssignmentsSchema, GlobalSchema, ValencySchema}; use crate::validation::{CheckedConsignment, ConsignmentApi}; -use crate::vm::{ContractStateEvolve, OpInfo, RgbIsa, VmContext}; +use crate::vm::{ContractStateAccess, ContractStateEvolve, OpInfo, RgbIsa, VmContext}; use crate::{ validation, Assign, AssignmentType, Assignments, AssignmentsRef, ConcealedState, ConfidentialState, ExposedSeal, ExposedState, Extension, GlobalState, GlobalStateSchema, @@ -44,7 +44,11 @@ use crate::{ impl Schema { // TODO: Instead of returning status fail immediately - pub fn validate_state<'validator, C: ConsignmentApi, S: ContractStateEvolve>( + pub fn validate_state< + 'validator, + C: ConsignmentApi, + S: ContractStateAccess + ContractStateEvolve, + >( &'validator self, consignment: &'validator CheckedConsignment<'_, C>, op: OpRef, diff --git a/src/validation/validator.rs b/src/validation/validator.rs index 26209105..521f8379 100644 --- a/src/validation/validator.rs +++ b/src/validation/validator.rs @@ -32,7 +32,7 @@ use single_use_seals::SealWitness; use super::status::Failure; use super::{CheckedConsignment, ConsignmentApi, DbcProof, EAnchor, Status, Validity}; -use crate::vm::{ContractStateEvolve, OpOrd, TxOrd, WitnessOrd}; +use crate::vm::{ContractStateAccess, ContractStateEvolve, OpOrd, TxOrd, WitnessOrd}; use crate::{ validation, AltLayer1, BundleId, ContractId, Layer1, OpId, OpRef, OpType, Operation, Opout, Schema, SchemaId, TransitionBundle, XChain, XOutpoint, XOutputSeal, XWitnessId, XWitnessTx, @@ -64,8 +64,6 @@ pub trait ResolveWitness { witness_id: XWitnessId, ) -> Result; - // TODO: Remove ResolveWitnessHeight trait from RGB stdlib and use this method - // instead fn resolve_pub_witness_ord( &self, witness_id: XWitnessId, @@ -124,9 +122,9 @@ impl ResolveWitness for CheckedWitnessResolver { pub struct Validator< 'consignment, 'resolver, + S: ContractStateAccess + ContractStateEvolve, C: ConsignmentApi, R: ResolveWitness, - S: ContractStateEvolve, > { consignment: CheckedConsignment<'consignment, C>, @@ -144,10 +142,15 @@ pub struct Validator< resolver: CheckedWitnessResolver<&'resolver R>, } -impl<'consignment, 'resolver, C: ConsignmentApi, R: ResolveWitness, S: ContractStateEvolve> - Validator<'consignment, 'resolver, C, R, S> +impl< + 'consignment, + 'resolver, + S: ContractStateAccess + ContractStateEvolve, + C: ConsignmentApi, + R: ResolveWitness, +> Validator<'consignment, 'resolver, S, C, R> { - fn init(consignment: &'consignment C, resolver: &'resolver R) -> Self { + fn init(consignment: &'consignment C, resolver: &'resolver R, context: S::Context<'_>) -> Self { // We use validation status object to store all detected failures and // warnings let status = Status::default(); @@ -178,7 +181,7 @@ impl<'consignment, 'resolver, C: ConsignmentApi, R: ResolveWitness, S: ContractS validated_op_state, validated_op_seals, resolver: CheckedWitnessResolver::from(resolver), - contract_state: Rc::new(RefCell::new(empty!())), + contract_state: Rc::new(RefCell::new(S::init(context))), } } @@ -191,8 +194,13 @@ impl<'consignment, 'resolver, C: ConsignmentApi, R: ResolveWitness, S: ContractS /// logged into the status object, but the validation continues for the /// rest of the consignment data. This can help to debug and detect all /// problems with the consignment. - pub fn validate(consignment: &'consignment C, resolver: &'resolver R, testnet: bool) -> Status { - let mut validator = Self::init(consignment, resolver); + pub fn validate( + consignment: &'consignment C, + resolver: &'resolver R, + testnet: bool, + context: S::Context<'_>, + ) -> Status { + let mut validator = Self::init(consignment, resolver, context); // If the network mismatches there is no point in validating the contract since // all witness transactions will be missed. if testnet != validator.consignment.genesis().testnet { diff --git a/src/vm/contract.rs b/src/vm/contract.rs index 430e1969..315a64ac 100644 --- a/src/vm/contract.rs +++ b/src/vm/contract.rs @@ -328,7 +328,7 @@ impl Iterator for GlobalContractState { #[display("unknown global state type {0} requested from the contract")] pub struct UnknownGlobalStateType(pub GlobalStateType); -pub trait ContractState: Debug { +pub trait ContractStateAccess: Debug { fn global( &self, ty: GlobalStateType, @@ -355,11 +355,13 @@ pub trait ContractState: Debug { ) -> impl DoubleEndedIterator>; } -pub trait ContractStateEvolve: ContractState + Default { +pub trait ContractStateEvolve { + type Context<'ctx>; + fn init(context: Self::Context<'_>) -> Self; fn evolve_state(&mut self, op: OpRef); } -pub struct VmContext<'op, S: ContractState> { +pub struct VmContext<'op, S: ContractStateAccess> { pub contract_id: ContractId, pub asset_tags: &'op AssetTags, pub op_info: OpInfo<'op>, diff --git a/src/vm/isa.rs b/src/vm/isa.rs index 2dbeb0b0..8148b5ef 100644 --- a/src/vm/isa.rs +++ b/src/vm/isa.rs @@ -29,12 +29,12 @@ use aluvm::library::{CodeEofError, IsaSeg, LibSite, Read, Write}; use aluvm::reg::{CoreRegs, Reg}; use super::opcodes::{INSTR_RGBISA_FROM, INSTR_RGBISA_TO}; -use super::{ContractOp, ContractState, TimechainOp, VmContext}; +use super::{ContractOp, ContractStateAccess, TimechainOp, VmContext}; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] #[display(inner)] #[non_exhaustive] -pub enum RgbIsa { +pub enum RgbIsa { Contract(ContractOp), Timechain(TimechainOp), @@ -44,7 +44,7 @@ pub enum RgbIsa { Fail(u8), } -impl InstructionSet for RgbIsa { +impl InstructionSet for RgbIsa { type Context<'ctx> = VmContext<'ctx, S>; fn isa_ids() -> IsaSeg { IsaSeg::with("RGB") } @@ -85,7 +85,7 @@ impl InstructionSet for RgbIsa { } } -impl Bytecode for RgbIsa { +impl Bytecode for RgbIsa { fn instr_range() -> RangeInclusive { INSTR_RGBISA_FROM..=INSTR_RGBISA_TO } fn instr_byte(&self) -> u8 { diff --git a/src/vm/mod.rs b/src/vm/mod.rs index e7ae7480..479ccf0c 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -34,8 +34,8 @@ mod contract; pub use aluvm::aluasm_isa; pub use contract::{ - ContractState, ContractStateEvolve, GlobalContractState, GlobalOrd, GlobalStateIter, OpOrd, - TxOrd, TxPos, UnknownGlobalStateType, WitnessOrd, + ContractStateAccess, ContractStateEvolve, GlobalContractState, GlobalOrd, GlobalStateIter, + OpOrd, TxOrd, TxPos, UnknownGlobalStateType, WitnessOrd, }; pub(crate) use contract::{OpInfo, VmContext}; pub use isa::RgbIsa; diff --git a/src/vm/op_contract.rs b/src/vm/op_contract.rs index ebedd912..a33b73b2 100644 --- a/src/vm/op_contract.rs +++ b/src/vm/op_contract.rs @@ -34,14 +34,14 @@ use amplify::Wrapper; use commit_verify::CommitVerify; use super::opcodes::*; -use super::{ContractState, VmContext}; +use super::{ContractStateAccess, VmContext}; use crate::{ Assign, AssignmentType, BlindingFactor, GlobalStateType, MetaType, PedersenCommitment, RevealedValue, TypedAssigns, }; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] -pub enum ContractOp { +pub enum ContractOp { /// Counts number of inputs (previous state entries) of the provided type /// and puts the number to the destination `a16` register. #[display("cnp {0},a16{1}")] @@ -165,7 +165,7 @@ pub enum ContractOp { Fail(u8, PhantomData), } -impl InstructionSet for ContractOp { +impl InstructionSet for ContractOp { type Context<'ctx> = VmContext<'ctx, S>; fn isa_ids() -> IsaSeg { IsaSeg::with("RGB") } @@ -446,7 +446,7 @@ impl InstructionSet for ContractOp { } } -impl Bytecode for ContractOp { +impl Bytecode for ContractOp { fn instr_range() -> RangeInclusive { INSTR_CONTRACT_FROM..=INSTR_CONTRACT_TO } fn instr_byte(&self) -> u8 { From 61c1c12c2fc4c2e81f454e7b8e5285faaaee9356 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 30 Jul 2024 18:36:21 +0200 Subject: [PATCH 18/21] vm: move OpRef to vm::Contracts module --- src/operation/mod.rs | 4 +- src/operation/operations.rs | 108 -------------------------------- src/operation/seal.rs | 2 + src/validation/consignment.rs | 3 +- src/validation/logic.rs | 4 +- src/validation/validator.rs | 6 +- src/vm/contract.rs | 113 +++++++++++++++++++++++++++++++++- src/vm/mod.rs | 2 +- 8 files changed, 123 insertions(+), 119 deletions(-) diff --git a/src/operation/mod.rs b/src/operation/mod.rs index 625b1571..304ae69f 100644 --- a/src/operation/mod.rs +++ b/src/operation/mod.rs @@ -51,8 +51,8 @@ pub use fungible::{ pub use global::{GlobalState, GlobalValues}; pub use meta::{MetaValue, Metadata, MetadataError}; pub use operations::{ - AssetTags, Extension, Genesis, Identity, Input, Inputs, OpRef, Operation, Opout, - OpoutParseError, Redeemed, Transition, Valencies, + AssetTags, Extension, Genesis, Identity, Input, Inputs, Operation, Opout, OpoutParseError, + Redeemed, Transition, Valencies, }; pub use seal::{ ExposedSeal, GenesisSeal, GraphSeal, OutputSeal, SecretSeal, TxoSeal, XGenesisSeal, XGraphSeal, diff --git a/src/operation/operations.rs b/src/operation/operations.rs index 55e4e5f0..63a4b02a 100644 --- a/src/operation/operations.rs +++ b/src/operation/operations.rs @@ -621,114 +621,6 @@ impl Operation for Transition { fn inputs(&self) -> Inputs { self.inputs.clone() } } -#[derive(Copy, Clone, PartialEq, Eq, Debug, From)] -pub enum OpRef<'op> { - #[from] - Genesis(&'op Genesis), - #[from] - Transition(&'op Transition), - #[from] - Extension(&'op Extension), -} - -impl<'op> Operation for OpRef<'op> { - fn op_type(&self) -> OpType { - match self { - OpRef::Genesis(op) => op.op_type(), - OpRef::Transition(op) => op.op_type(), - OpRef::Extension(op) => op.op_type(), - } - } - - fn full_type(&self) -> OpFullType { - match self { - OpRef::Genesis(op) => op.full_type(), - OpRef::Transition(op) => op.full_type(), - OpRef::Extension(op) => op.full_type(), - } - } - - fn id(&self) -> OpId { - match self { - OpRef::Genesis(op) => op.id(), - OpRef::Transition(op) => op.id(), - OpRef::Extension(op) => op.id(), - } - } - - fn contract_id(&self) -> ContractId { - match self { - OpRef::Genesis(op) => op.contract_id(), - OpRef::Transition(op) => op.contract_id(), - OpRef::Extension(op) => op.contract_id(), - } - } - - fn transition_type(&self) -> Option { - match self { - OpRef::Genesis(op) => op.transition_type(), - OpRef::Transition(op) => op.transition_type(), - OpRef::Extension(op) => op.transition_type(), - } - } - - fn extension_type(&self) -> Option { - match self { - OpRef::Genesis(op) => op.extension_type(), - OpRef::Transition(op) => op.extension_type(), - OpRef::Extension(op) => op.extension_type(), - } - } - - fn metadata(&self) -> &Metadata { - match self { - OpRef::Genesis(op) => op.metadata(), - OpRef::Transition(op) => op.metadata(), - OpRef::Extension(op) => op.metadata(), - } - } - - fn globals(&self) -> &GlobalState { - match self { - OpRef::Genesis(op) => op.globals(), - OpRef::Transition(op) => op.globals(), - OpRef::Extension(op) => op.globals(), - } - } - - fn valencies(&self) -> &Valencies { - match self { - OpRef::Genesis(op) => op.valencies(), - OpRef::Transition(op) => op.valencies(), - OpRef::Extension(op) => op.valencies(), - } - } - - fn assignments(&self) -> AssignmentsRef<'op> { - match self { - OpRef::Genesis(op) => (&op.assignments).into(), - OpRef::Transition(op) => (&op.assignments).into(), - OpRef::Extension(op) => (&op.assignments).into(), - } - } - - fn assignments_by_type(&self, t: AssignmentType) -> Option> { - match self { - OpRef::Genesis(op) => op.assignments_by_type(t), - OpRef::Transition(op) => op.assignments_by_type(t), - OpRef::Extension(op) => op.assignments_by_type(t), - } - } - - fn inputs(&self) -> Inputs { - match self { - OpRef::Genesis(op) => op.inputs(), - OpRef::Transition(op) => op.inputs(), - OpRef::Extension(op) => op.inputs(), - } - } -} - #[cfg(test)] mod test { use amplify::ByteArray; diff --git a/src/operation/seal.rs b/src/operation/seal.rs index 7d9e4436..14f2c25f 100644 --- a/src/operation/seal.rs +++ b/src/operation/seal.rs @@ -41,6 +41,7 @@ pub type GraphSeal = ChainBlindSeal; pub type OutputSeal = ExplicitSeal; +// TODO: Move to vm::Contract pub type XWitnessId = XChain; pub type XGenesisSeal = XChain; @@ -176,6 +177,7 @@ impl XChain { } } +// TODO: Move to vm::Contract pub type XWitnessTx = XChain; impl XWitnessTx { diff --git a/src/validation/consignment.rs b/src/validation/consignment.rs index a661fc27..77f83bff 100644 --- a/src/validation/consignment.rs +++ b/src/validation/consignment.rs @@ -31,7 +31,8 @@ use amplify::confinement::Confined; use strict_types::TypeSystem; use super::EAnchor; -use crate::{BundleId, Genesis, OpId, OpRef, Operation, Schema, TransitionBundle, XWitnessId}; +use crate::vm::OpRef; +use crate::{BundleId, Genesis, OpId, Operation, Schema, TransitionBundle, XWitnessId}; pub const CONSIGNMENT_MAX_LIBS: usize = 1024; diff --git a/src/validation/logic.rs b/src/validation/logic.rs index 837e555f..ca214121 100644 --- a/src/validation/logic.rs +++ b/src/validation/logic.rs @@ -34,11 +34,11 @@ use strict_types::TypeSystem; use crate::schema::{AssignmentsSchema, GlobalSchema, ValencySchema}; use crate::validation::{CheckedConsignment, ConsignmentApi}; -use crate::vm::{ContractStateAccess, ContractStateEvolve, OpInfo, RgbIsa, VmContext}; +use crate::vm::{ContractStateAccess, ContractStateEvolve, OpInfo, OpRef, RgbIsa, VmContext}; use crate::{ validation, Assign, AssignmentType, Assignments, AssignmentsRef, ConcealedState, ConfidentialState, ExposedSeal, ExposedState, Extension, GlobalState, GlobalStateSchema, - GlobalValues, GraphSeal, Inputs, MetaSchema, Metadata, OpId, OpRef, Operation, Opout, + GlobalValues, GraphSeal, Inputs, MetaSchema, Metadata, OpId, Operation, Opout, OwnedStateSchema, RevealedState, Schema, StateType, Transition, TypedAssigns, Valencies, }; diff --git a/src/validation/validator.rs b/src/validation/validator.rs index 521f8379..402b2ca8 100644 --- a/src/validation/validator.rs +++ b/src/validation/validator.rs @@ -32,10 +32,10 @@ use single_use_seals::SealWitness; use super::status::Failure; use super::{CheckedConsignment, ConsignmentApi, DbcProof, EAnchor, Status, Validity}; -use crate::vm::{ContractStateAccess, ContractStateEvolve, OpOrd, TxOrd, WitnessOrd}; +use crate::vm::{ContractStateAccess, ContractStateEvolve, OpOrd, OpRef, TxOrd, WitnessOrd}; use crate::{ - validation, AltLayer1, BundleId, ContractId, Layer1, OpId, OpRef, OpType, Operation, Opout, - Schema, SchemaId, TransitionBundle, XChain, XOutpoint, XOutputSeal, XWitnessId, XWitnessTx, + validation, AltLayer1, BundleId, ContractId, Layer1, OpId, OpType, Operation, Opout, Schema, + SchemaId, TransitionBundle, XChain, XOutpoint, XOutputSeal, XWitnessId, XWitnessTx, }; #[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] diff --git a/src/vm/contract.rs b/src/vm/contract.rs index 315a64ac..02f31fbf 100644 --- a/src/vm/contract.rs +++ b/src/vm/contract.rs @@ -33,10 +33,119 @@ use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; use crate::{ AssetTags, AssignmentType, Assignments, AssignmentsRef, AttachState, ContractId, DataState, - FungibleState, GlobalState, GlobalStateType, GraphSeal, Metadata, OpFullType, OpId, OpRef, - Operation, Valencies, XOutpoint, XWitnessId, LIB_NAME_RGB_LOGIC, + Extension, ExtensionType, FungibleState, Genesis, GlobalState, GlobalStateType, GraphSeal, + Inputs, Metadata, OpFullType, OpId, OpType, Operation, Transition, TransitionType, + TypedAssigns, Valencies, XOutpoint, XWitnessId, LIB_NAME_RGB_LOGIC, }; +#[derive(Copy, Clone, PartialEq, Eq, Debug, From)] +pub enum OpRef<'op> { + #[from] + Genesis(&'op Genesis), + #[from] + Transition(&'op Transition), + #[from] + Extension(&'op Extension), +} + +impl<'op> Operation for OpRef<'op> { + fn op_type(&self) -> OpType { + match self { + OpRef::Genesis(op) => op.op_type(), + OpRef::Transition(op) => op.op_type(), + OpRef::Extension(op) => op.op_type(), + } + } + + fn full_type(&self) -> OpFullType { + match self { + OpRef::Genesis(op) => op.full_type(), + OpRef::Transition(op) => op.full_type(), + OpRef::Extension(op) => op.full_type(), + } + } + + fn id(&self) -> OpId { + match self { + OpRef::Genesis(op) => op.id(), + OpRef::Transition(op) => op.id(), + OpRef::Extension(op) => op.id(), + } + } + + fn contract_id(&self) -> ContractId { + match self { + OpRef::Genesis(op) => op.contract_id(), + OpRef::Transition(op) => op.contract_id(), + OpRef::Extension(op) => op.contract_id(), + } + } + + fn transition_type(&self) -> Option { + match self { + OpRef::Genesis(op) => op.transition_type(), + OpRef::Transition(op) => op.transition_type(), + OpRef::Extension(op) => op.transition_type(), + } + } + + fn extension_type(&self) -> Option { + match self { + OpRef::Genesis(op) => op.extension_type(), + OpRef::Transition(op) => op.extension_type(), + OpRef::Extension(op) => op.extension_type(), + } + } + + fn metadata(&self) -> &Metadata { + match self { + OpRef::Genesis(op) => op.metadata(), + OpRef::Transition(op) => op.metadata(), + OpRef::Extension(op) => op.metadata(), + } + } + + fn globals(&self) -> &GlobalState { + match self { + OpRef::Genesis(op) => op.globals(), + OpRef::Transition(op) => op.globals(), + OpRef::Extension(op) => op.globals(), + } + } + + fn valencies(&self) -> &Valencies { + match self { + OpRef::Genesis(op) => op.valencies(), + OpRef::Transition(op) => op.valencies(), + OpRef::Extension(op) => op.valencies(), + } + } + + fn assignments(&self) -> AssignmentsRef<'op> { + match self { + OpRef::Genesis(op) => (&op.assignments).into(), + OpRef::Transition(op) => (&op.assignments).into(), + OpRef::Extension(op) => (&op.assignments).into(), + } + } + + fn assignments_by_type(&self, t: AssignmentType) -> Option> { + match self { + OpRef::Genesis(op) => op.assignments_by_type(t), + OpRef::Transition(op) => op.assignments_by_type(t), + OpRef::Extension(op) => op.assignments_by_type(t), + } + } + + fn inputs(&self) -> Inputs { + match self { + OpRef::Genesis(op) => op.inputs(), + OpRef::Transition(op) => op.inputs(), + OpRef::Extension(op) => op.inputs(), + } + } +} + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Display)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_LOGIC)] diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 479ccf0c..b3099a3f 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -35,7 +35,7 @@ mod contract; pub use aluvm::aluasm_isa; pub use contract::{ ContractStateAccess, ContractStateEvolve, GlobalContractState, GlobalOrd, GlobalStateIter, - OpOrd, TxOrd, TxPos, UnknownGlobalStateType, WitnessOrd, + OpOrd, OpRef, TxOrd, TxPos, UnknownGlobalStateType, WitnessOrd, }; pub(crate) use contract::{OpInfo, VmContext}; pub use isa::RgbIsa; From 7a09574424d3c0aa1783120e6120b23d363e9ad0 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 30 Jul 2024 18:43:50 +0200 Subject: [PATCH 19/21] vm: move witness-related types from operations module --- src/operation/mod.rs | 2 +- src/operation/seal.rs | 102 +-------------------------------- src/stl.rs | 4 +- src/validation/consignment.rs | 4 +- src/validation/status.rs | 6 +- src/validation/validator.rs | 7 ++- src/vm/contract.rs | 103 +++++++++++++++++++++++++++++++++- src/vm/mod.rs | 2 +- 8 files changed, 117 insertions(+), 113 deletions(-) diff --git a/src/operation/mod.rs b/src/operation/mod.rs index 304ae69f..c13450be 100644 --- a/src/operation/mod.rs +++ b/src/operation/mod.rs @@ -56,7 +56,7 @@ pub use operations::{ }; pub use seal::{ ExposedSeal, GenesisSeal, GraphSeal, OutputSeal, SecretSeal, TxoSeal, XGenesisSeal, XGraphSeal, - XOutputSeal, XWitnessId, XWitnessTx, + XOutputSeal, }; pub use state::{ConcealedState, ConfidentialState, ExposedState, RevealedState, StateType}; pub use xchain::{ diff --git a/src/operation/seal.rs b/src/operation/seal.rs index 14f2c25f..186af74c 100644 --- a/src/operation/seal.rs +++ b/src/operation/seal.rs @@ -26,14 +26,12 @@ use std::hash::Hash; use bp::dbc::Method; pub use bp::seals::txout::blind::{ChainBlindSeal, ParseError, SingleBlindSeal}; pub use bp::seals::txout::TxoSeal; -use bp::seals::txout::{BlindSeal, CloseMethod, ExplicitSeal, SealTxid, VerifyError, Witness}; +use bp::seals::txout::{BlindSeal, CloseMethod, ExplicitSeal, SealTxid}; pub use bp::seals::SecretSeal; -use bp::{dbc, Outpoint, Tx, Txid, Vout}; -use commit_verify::{mpc, Conceal}; -use single_use_seals::SealWitness; +use bp::{Outpoint, Txid, Vout}; +use commit_verify::Conceal; use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; -use crate::operation::xchain::Impossible; use crate::{XChain, XOutpoint}; pub type GenesisSeal = SingleBlindSeal; @@ -41,9 +39,6 @@ pub type GraphSeal = ChainBlindSeal; pub type OutputSeal = ExplicitSeal; -// TODO: Move to vm::Contract -pub type XWitnessId = XChain; - pub type XGenesisSeal = XChain; pub type XGraphSeal = XChain; pub type XOutputSeal = XChain; @@ -135,97 +130,6 @@ impl XChain { pub fn to_outpoint(&self) -> XOutpoint { self.map_ref(GenesisSeal::to_outpoint).into() } } -impl XChain { - pub fn method(self) -> CloseMethod - where U: TxoSeal { - match self { - XChain::Bitcoin(seal) => seal.method(), - XChain::Liquid(seal) => seal.method(), - XChain::Other(_) => unreachable!(), - } - } - - #[inline] - pub fn to_output_seal(self) -> Option - where U: TxoSeal { - Some(match self { - XChain::Bitcoin(seal) => { - let outpoint = seal.outpoint()?; - XChain::Bitcoin(ExplicitSeal::new(seal.method(), outpoint)) - } - XChain::Liquid(seal) => { - let outpoint = seal.outpoint()?; - XChain::Liquid(ExplicitSeal::new(seal.method(), outpoint)) - } - XChain::Other(_) => unreachable!(), - }) - } - - pub fn try_to_output_seal(self, witness_id: XWitnessId) -> Result - where U: TxoSeal { - self.to_output_seal() - .or(match (self, witness_id) { - (XChain::Bitcoin(seal), XWitnessId::Bitcoin(txid)) => { - Some(XChain::Bitcoin(ExplicitSeal::new(seal.method(), seal.outpoint_or(txid)))) - } - (XChain::Liquid(seal), XWitnessId::Liquid(txid)) => { - Some(XChain::Liquid(ExplicitSeal::new(seal.method(), seal.outpoint_or(txid)))) - } - _ => None, - }) - .ok_or(self) - } -} - -// TODO: Move to vm::Contract -pub type XWitnessTx = XChain; - -impl XWitnessTx { - pub fn witness_id(&self) -> XWitnessId { - match self { - Self::Bitcoin(tx) => XWitnessId::Bitcoin(tx.txid()), - Self::Liquid(tx) => XWitnessId::Liquid(tx.txid()), - Self::Other(_) => unreachable!(), - } - } -} - -impl XChain> { - pub fn witness_id(&self) -> XWitnessId { - match self { - Self::Bitcoin(w) => XWitnessId::Bitcoin(w.txid), - Self::Liquid(w) => XWitnessId::Liquid(w.txid), - Self::Other(_) => unreachable!(), - } - } -} - -impl SealWitness for XChain> { - type Message = mpc::Commitment; - type Error = VerifyError; - - fn verify_seal(&self, seal: &Seal, msg: &Self::Message) -> Result<(), Self::Error> { - match self { - Self::Bitcoin(witness) | Self::Liquid(witness) => witness.verify_seal(seal, msg), - Self::Other(_) => unreachable!(), - } - } - - fn verify_many_seals<'seal>( - &self, - seals: impl IntoIterator, - msg: &Self::Message, - ) -> Result<(), Self::Error> - where - Seal: 'seal, - { - match self { - Self::Bitcoin(witness) | Self::Liquid(witness) => witness.verify_many_seals(seals, msg), - Self::Other(_) => unreachable!(), - } - } -} - impl XChain> { /// Converts revealed seal into concealed. #[inline] diff --git a/src/stl.rs b/src/stl.rs index 627e295a..d7cc755a 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -29,9 +29,9 @@ use strict_types::typelib::LibBuilder; use strict_types::{CompileError, TypeLib}; use crate::validation::DbcProof; -use crate::vm::GlobalOrd; +use crate::vm::{GlobalOrd, XWitnessId}; use crate::{ - Extension, Genesis, OpCommitment, Schema, TransitionBundle, XWitnessId, LIB_NAME_RGB_COMMIT, + Extension, Genesis, OpCommitment, Schema, TransitionBundle, LIB_NAME_RGB_COMMIT, LIB_NAME_RGB_LOGIC, }; diff --git a/src/validation/consignment.rs b/src/validation/consignment.rs index 77f83bff..6dce37bb 100644 --- a/src/validation/consignment.rs +++ b/src/validation/consignment.rs @@ -31,8 +31,8 @@ use amplify::confinement::Confined; use strict_types::TypeSystem; use super::EAnchor; -use crate::vm::OpRef; -use crate::{BundleId, Genesis, OpId, Operation, Schema, TransitionBundle, XWitnessId}; +use crate::vm::{OpRef, XWitnessId}; +use crate::{BundleId, Genesis, OpId, Operation, Schema, TransitionBundle}; pub const CONSIGNMENT_MAX_LIBS: usize = 1024; diff --git a/src/validation/status.rs b/src/validation/status.rs index 0761cb58..288c1589 100644 --- a/src/validation/status.rs +++ b/src/validation/status.rs @@ -27,12 +27,12 @@ use amplify::num::u24; use commit_verify::mpc::InvalidProof; use strict_types::SemId; -use crate::operation::Opout; use crate::schema::{self, SchemaId}; use crate::validation::WitnessResolverError; +use crate::vm::XWitnessId; use crate::{ - BundleId, ContractId, Layer1, OccurrencesMismatch, OpFullType, OpId, StateType, Vin, - XGraphSeal, XOutputSeal, XWitnessId, + BundleId, ContractId, Layer1, OccurrencesMismatch, OpFullType, OpId, Opout, StateType, Vin, + XGraphSeal, XOutputSeal, }; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Display)] diff --git a/src/validation/validator.rs b/src/validation/validator.rs index 402b2ca8..69026463 100644 --- a/src/validation/validator.rs +++ b/src/validation/validator.rs @@ -32,10 +32,13 @@ use single_use_seals::SealWitness; use super::status::Failure; use super::{CheckedConsignment, ConsignmentApi, DbcProof, EAnchor, Status, Validity}; -use crate::vm::{ContractStateAccess, ContractStateEvolve, OpOrd, OpRef, TxOrd, WitnessOrd}; +use crate::vm::{ + ContractStateAccess, ContractStateEvolve, OpOrd, OpRef, TxOrd, WitnessOrd, XWitnessId, + XWitnessTx, +}; use crate::{ validation, AltLayer1, BundleId, ContractId, Layer1, OpId, OpType, Operation, Opout, Schema, - SchemaId, TransitionBundle, XChain, XOutpoint, XOutputSeal, XWitnessId, XWitnessTx, + SchemaId, TransitionBundle, XChain, XOutpoint, XOutputSeal, }; #[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] diff --git a/src/vm/contract.rs b/src/vm/contract.rs index 02f31fbf..6eb1ebce 100644 --- a/src/vm/contract.rs +++ b/src/vm/contract.rs @@ -29,15 +29,112 @@ use std::rc::Rc; use amplify::num::u24; use amplify::Bytes32; +use bp::seals::txout::{CloseMethod, ExplicitSeal, VerifyError, Witness}; +use bp::{dbc, Tx, Txid}; +use commit_verify::mpc; +use single_use_seals::SealWitness; use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; use crate::{ AssetTags, AssignmentType, Assignments, AssignmentsRef, AttachState, ContractId, DataState, - Extension, ExtensionType, FungibleState, Genesis, GlobalState, GlobalStateType, GraphSeal, - Inputs, Metadata, OpFullType, OpId, OpType, Operation, Transition, TransitionType, - TypedAssigns, Valencies, XOutpoint, XWitnessId, LIB_NAME_RGB_LOGIC, + ExposedSeal, Extension, ExtensionType, FungibleState, Genesis, GlobalState, GlobalStateType, + GraphSeal, Impossible, Inputs, Metadata, OpFullType, OpId, OpType, Operation, Transition, + TransitionType, TxoSeal, TypedAssigns, Valencies, XChain, XOutpoint, XOutputSeal, + LIB_NAME_RGB_LOGIC, }; +pub type XWitnessId = XChain; + +pub type XWitnessTx = XChain; + +impl XWitnessTx { + pub fn witness_id(&self) -> XWitnessId { + match self { + Self::Bitcoin(tx) => XWitnessId::Bitcoin(tx.txid()), + Self::Liquid(tx) => XWitnessId::Liquid(tx.txid()), + Self::Other(_) => unreachable!(), + } + } +} + +impl XChain> { + pub fn witness_id(&self) -> XWitnessId { + match self { + Self::Bitcoin(w) => XWitnessId::Bitcoin(w.txid), + Self::Liquid(w) => XWitnessId::Liquid(w.txid), + Self::Other(_) => unreachable!(), + } + } +} + +impl SealWitness for XChain> { + type Message = mpc::Commitment; + type Error = VerifyError; + + fn verify_seal(&self, seal: &Seal, msg: &Self::Message) -> Result<(), Self::Error> { + match self { + Self::Bitcoin(witness) | Self::Liquid(witness) => witness.verify_seal(seal, msg), + Self::Other(_) => unreachable!(), + } + } + + fn verify_many_seals<'seal>( + &self, + seals: impl IntoIterator, + msg: &Self::Message, + ) -> Result<(), Self::Error> + where + Seal: 'seal, + { + match self { + Self::Bitcoin(witness) | Self::Liquid(witness) => witness.verify_many_seals(seals, msg), + Self::Other(_) => unreachable!(), + } + } +} + +impl XChain { + pub fn method(self) -> CloseMethod + where U: TxoSeal { + match self { + XChain::Bitcoin(seal) => seal.method(), + XChain::Liquid(seal) => seal.method(), + XChain::Other(_) => unreachable!(), + } + } + + #[inline] + pub fn to_output_seal(self) -> Option + where U: TxoSeal { + Some(match self { + XChain::Bitcoin(seal) => { + let outpoint = seal.outpoint()?; + XChain::Bitcoin(ExplicitSeal::new(seal.method(), outpoint)) + } + XChain::Liquid(seal) => { + let outpoint = seal.outpoint()?; + XChain::Liquid(ExplicitSeal::new(seal.method(), outpoint)) + } + XChain::Other(_) => unreachable!(), + }) + } + + pub fn try_to_output_seal(self, witness_id: XWitnessId) -> Result + where U: TxoSeal { + self.to_output_seal() + .or(match (self, witness_id) { + (XChain::Bitcoin(seal), XWitnessId::Bitcoin(txid)) => { + Some(XChain::Bitcoin(ExplicitSeal::new(seal.method(), seal.outpoint_or(txid)))) + } + (XChain::Liquid(seal), XWitnessId::Liquid(txid)) => { + Some(XChain::Liquid(ExplicitSeal::new(seal.method(), seal.outpoint_or(txid)))) + } + _ => None, + }) + .ok_or(self) + } +} + #[derive(Copy, Clone, PartialEq, Eq, Debug, From)] pub enum OpRef<'op> { #[from] diff --git a/src/vm/mod.rs b/src/vm/mod.rs index b3099a3f..9d47aa52 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -35,7 +35,7 @@ mod contract; pub use aluvm::aluasm_isa; pub use contract::{ ContractStateAccess, ContractStateEvolve, GlobalContractState, GlobalOrd, GlobalStateIter, - OpOrd, OpRef, TxOrd, TxPos, UnknownGlobalStateType, WitnessOrd, + OpOrd, OpRef, TxOrd, TxPos, UnknownGlobalStateType, WitnessOrd, XWitnessId, XWitnessTx, }; pub(crate) use contract::{OpInfo, VmContext}; pub use isa::RgbIsa; From 29f0625833528bce5f9bef5e6f3e4b6be0dd3e5e Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 30 Jul 2024 19:31:07 +0200 Subject: [PATCH 20/21] chore: add XWitnessId to prelude --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 7e65a85c..abef3430 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,6 +56,7 @@ pub mod prelude { pub use commit_verify::ReservedBytes; pub use operation::*; pub use schema::*; + pub use vm::XWitnessId; #[cfg(feature = "stl")] pub use super::stl; From a71b1e76a3c55558ea22890b50f05bdd1639391a Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 31 Jul 2024 13:34:01 +0200 Subject: [PATCH 21/21] vm: docs for witness transaction ordering types --- src/vm/contract.rs | 56 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/src/vm/contract.rs b/src/vm/contract.rs index 6eb1ebce..a601e885 100644 --- a/src/vm/contract.rs +++ b/src/vm/contract.rs @@ -273,6 +273,10 @@ impl PartialOrd for TxPos { } impl Ord for TxPos { + /// Since we support multiple layer 1, we have to order basing on the + /// timestamp information and not height. The timestamp data are consistent + /// accross multiple blockchains, while height evolves with a different + /// speed and can't be used in comparisons. fn cmp(&self, other: &Self) -> Ordering { assert!(self.timestamp > 0); assert!(other.timestamp > 0); @@ -280,8 +284,11 @@ impl Ord for TxPos { } } -/// RGB consensus information about the current mined height of a witness -/// transaction defining the ordering of the contract state data. +/// RGB consensus information about the status of a witness transaction. This +/// information is used in ordering state transition and state extension +/// processing in the AluVM during the validation, as well as consensus ordering +/// of the contract global state data, as they are presented to all contract +/// users. #[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, Display, From)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_LOGIC, tags = order)] @@ -291,16 +298,51 @@ impl Ord for TxPos { serde(crate = "serde_crate", rename_all = "camelCase", untagged) )] pub enum TxOrd { + /// Witness transaction must be excluded from the state processing. + /// + /// Cases for the exclusion: + /// - transaction was removed from blockchain after a re-org and its inputs + /// were spent by other transaction; + /// - previous transaction(s) after RBF replacement, once it is excluded + /// from the mempool and replaced by RBFed successors; + /// - past state channel transactions once a new channel state is signed + /// (and until they may become valid once again due to an uncooperative + /// channel closing). #[display("archived")] #[strict_type(dumb)] Archived, + /// Transaction is included into layer 1 blockchain at a specific height and + /// timestamp. + /// + /// NB: only timestamp is used in consensus ordering though, see + /// [`TxPos::ord`] for the details. #[from] #[display(inner)] OnChain(TxPos), + /// Valid witness transaction which commits the most recent RGB state, but + /// is not (yet) included into a layer 1 blockchain. Such transactions have + /// a higher priority over onchain transactions (i.e. they are processed by + /// the VM at the very end, and their global state becomes at the top of the + /// contract state). + /// + /// NB: not each and every signed offchain transaction should have this + /// status; all offchain cases which fall under [`Self::Archived`] must be + /// excluded. Valid cases for assigning [`Self::Offchain`] status are: + /// - transaction is present in the memepool; + /// - transaction is a part of transaction graph inside a state channel + /// (only actual channel state is accounted for; all previous channel + /// state must have corresponding transactions set to [`Self::Archived`]); + /// - transaction is an RBF replacement prepared to be broadcast (with the + /// previous transaction set to [`Self::Archived`] at the same moment). #[display("offchain@{priority}")] - OffChain { priority: u32 }, + OffChain { + /// Used for internal ordering inside the offchain transaction graph, + /// for instance to ensure that HTLC transactions in a lightning channel + /// have higher priority (i.e. computed after) than commitment. + priority: u32, + }, } impl TxOrd { @@ -308,7 +350,13 @@ impl TxOrd { pub fn offchain(priority: u32) -> Self { TxOrd::OffChain { priority } } } -/// Txid and height information ordered according to the RGB consensus rules. +/// Information about public witness used for ordering according to the RGB +/// consensus rules. +/// +/// First, we account for [`TxOrd`], such that those state which witness +/// transactions were mined earlier come into the state computing earlier as +/// well. However, if two witness transactions were mined in the same block, we +/// order them lexicographically basing on the witness id. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_LOGIC)]