From 3b089b8820d51517aac5d364805d3e5769091497 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 27 Mar 2024 18:09:25 +0100 Subject: [PATCH] validation: move type system from schema to consignment --- src/schema/mod.rs | 7 +-- src/schema/schema.rs | 5 +-- src/schema/script.rs | 83 ----------------------------------- src/stl.rs | 2 +- src/validation/consignment.rs | 11 ++++- src/validation/logic.rs | 43 +++++++++--------- src/validation/schema.rs | 23 ++++++---- src/validation/state.rs | 20 ++++----- src/validation/validator.rs | 4 +- 9 files changed, 63 insertions(+), 135 deletions(-) diff --git a/src/schema/mod.rs b/src/schema/mod.rs index a4261371..138d2141 100644 --- a/src/schema/mod.rs +++ b/src/schema/mod.rs @@ -32,9 +32,6 @@ pub use operations::{ AssignmentType, AssignmentsSchema, ExtensionSchema, GenesisSchema, GlobalSchema, OpFullType, OpSchema, OpType, TransitionSchema, ValencySchema, ValencyType, }; -pub use schema::{ - ExtensionType, GlobalStateType, Schema, SchemaId, - TransitionType, -}; -pub use script::{Script, Types, VmType}; +pub use schema::{ExtensionType, GlobalStateType, Schema, SchemaId, TransitionType}; +pub use script::{Script, VmType}; pub use state::{FungibleType, GlobalStateSchema, MediaType, StateSchema}; diff --git a/src/schema/schema.rs b/src/schema/schema.rs index 95a92f52..f40de49d 100644 --- a/src/schema/schema.rs +++ b/src/schema/schema.rs @@ -37,7 +37,7 @@ use super::{ AssignmentType, ExtensionSchema, GenesisSchema, Script, StateSchema, TransitionSchema, ValencyType, }; -use crate::{Ffv, GlobalStateSchema, Occurrences, Types, LIB_NAME_RGB}; +use crate::{Ffv, GlobalStateSchema, Occurrences, LIB_NAME_RGB}; #[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Display)] #[wrapper(FromStr, LowerHex, UpperHex)] @@ -162,8 +162,6 @@ pub struct Schema { pub extensions: TinyOrdMap, pub transitions: TinyOrdMap, - /// Type system - pub types: Types, /// Validation code. pub script: Script, } @@ -182,7 +180,6 @@ impl CommitEncode for Schema { e.commit_to_map(&self.extensions); e.commit_to_map(&self.transitions); - e.commit_to_serialized(&self.types.id()); e.commit_to_serialized(&self.script); } } diff --git a/src/schema/script.rs b/src/schema/script.rs index 3d38e464..f900a2f3 100644 --- a/src/schema/script.rs +++ b/src/schema/script.rs @@ -25,10 +25,6 @@ //! Components related to the scripting system used by schema or applied at the //! specific contract operation level -use std::ops::{Deref, DerefMut}; - -use strict_types::TypeSystem; - use crate::vm::AluScript; use crate::LIB_NAME_RGB; @@ -80,82 +76,3 @@ impl Script { alu } } - -/// Types used by a schema and virtual machine -#[derive(Clone, Eq, PartialEq, Debug, From)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB, tags = custom)] -pub enum Types { - #[from] - #[strict_type(tag = 0x01)] - Strict(TypeSystem), -} - -impl Deref for Types { - type Target = TypeSystem; - - fn deref(&self) -> &Self::Target { - match self { - Types::Strict(sys) => sys, - } - } -} - -impl DerefMut for Types { - fn deref_mut(&mut self) -> &mut Self::Target { - match self { - Types::Strict(sys) => sys, - } - } -} - -impl Default for Types { - fn default() -> Self { Types::Strict(none!()) } -} - -impl Types { - pub fn as_strict(&self) -> &TypeSystem { - match self { - Types::Strict(ts) => ts, - } - } - - pub fn into_strict(self) -> TypeSystem { - match self { - Types::Strict(ts) => ts, - } - } -} - -#[cfg(feature = "serde")] -mod _serde { - use armor::AsciiArmor; - use serde_crate::de::Error; - use serde_crate::{Deserialize, Deserializer, Serialize, Serializer}; - - use super::*; - - impl Serialize for Types { - fn serialize(&self, serializer: S) -> Result - where S: Serializer { - if serializer.is_human_readable() { - serializer.serialize_str(&self.as_strict().to_ascii_armored_string()) - } else { - self.as_strict().serialize(serializer) - } - } - } - - impl<'de> Deserialize<'de> for Types { - fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> { - if deserializer.is_human_readable() { - let s = String::deserialize(deserializer)?; - let sys = TypeSystem::from_ascii_armored_str(&s).map_err(D::Error::custom)?; - Ok(Types::Strict(sys)) - } else { - Ok(Types::Strict(TypeSystem::deserialize(deserializer)?)) - } - } - } -} diff --git a/src/stl.rs b/src/stl.rs index ff81908e..a83f8056 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -34,7 +34,7 @@ use crate::{ /// Strict types id for the library providing data types for RGB consensus. pub const LIB_ID_RGB: &str = - "urn:ubideco:stl:B5QUyVAAiot39pdJNqKAGy1vPaqpJYBK8eF1DUB5Q19w#aroma-spider-wave"; + "urn:ubideco:stl:8c6sWAHuApYB1te5zqKLZK2JcqNHNdBn1p2VtvQBv4y8#suzuki-soda-talent"; fn _rgb_core_stl() -> Result { LibBuilder::new(libname!(LIB_NAME_RGB), tiny_bset! { diff --git a/src/validation/consignment.rs b/src/validation/consignment.rs index 5087e8f0..af1e36ee 100644 --- a/src/validation/consignment.rs +++ b/src/validation/consignment.rs @@ -27,9 +27,11 @@ use std::collections::{BTreeMap, BTreeSet}; use std::rc::Rc; +use strict_types::TypeSystem; + use crate::{ - AnchoredBundle, AssetTag, AssignmentType, BundleId, Genesis, OpId, OpRef, Operation, - SecretSeal, Schema, WitnessId, XChain, + AnchoredBundle, AssetTag, AssignmentType, BundleId, Genesis, OpId, OpRef, Operation, Schema, + SecretSeal, WitnessId, XChain, }; pub struct CheckedConsignment<'consignment, C: ConsignmentApi>(&'consignment C); @@ -43,6 +45,8 @@ impl<'consignment, C: ConsignmentApi> ConsignmentApi for CheckedConsignment<'con fn schema(&self) -> &Schema { self.0.schema() } + fn types(&self) -> &TypeSystem { self.0.types() } + fn asset_tags(&self) -> &BTreeMap { self.0.asset_tags() } fn operation(&self, opid: OpId) -> Option { @@ -78,6 +82,9 @@ pub trait ConsignmentApi { /// Returns reference to the schema object used by the consignment. fn schema(&self) -> &Schema; + /// Returns reference to the type system. + fn types(&self) -> &TypeSystem; + /// Asset tags uses in the confidential asset validation. fn asset_tags(&self) -> &BTreeMap; diff --git a/src/validation/logic.rs b/src/validation/logic.rs index 89f5eca9..d8d4da31 100644 --- a/src/validation/logic.rs +++ b/src/validation/logic.rs @@ -24,7 +24,7 @@ use std::collections::{BTreeMap, BTreeSet}; use amplify::confinement::{Confined, SmallBlob}; use amplify::Wrapper; -use strict_types::SemId; +use strict_types::{SemId, TypeSystem}; use crate::schema::{AssignmentsSchema, GlobalSchema, ValencySchema}; use crate::validation::{CheckedConsignment, ConsignmentApi, VirtualMachine}; @@ -137,8 +137,8 @@ impl Schema { // Validate type system status += self.validate_type_system(); - status += self.validate_metadata(id, *metadata_schema, op.metadata()); - status += self.validate_global_state(id, op.globals(), global_schema); + status += self.validate_metadata(id, *metadata_schema, op.metadata(), consignment.types()); + status += self.validate_global_state(id, op.globals(), global_schema, consignment.types()); let prev_state = if let OpRef::Transition(transition) = op { let prev_state = extract_prev_state(consignment, id, &transition.inputs, &mut status); status += self.validate_prev_state(id, &prev_state, owned_schema); @@ -155,10 +155,10 @@ impl Schema { } status += match op.assignments() { AssignmentsRef::Genesis(assignments) => { - self.validate_owned_state(id, assignments, assign_schema) + self.validate_owned_state(id, assignments, assign_schema, consignment.types()) } AssignmentsRef::Graph(assignments) => { - self.validate_owned_state(id, assignments, assign_schema) + self.validate_owned_state(id, assignments, assign_schema, consignment.types()) } }; @@ -197,11 +197,11 @@ impl Schema { opid: OpId, sem_id: SemId, metadata: &SmallBlob, + types: &TypeSystem, ) -> validation::Status { let mut status = validation::Status::new(); - if self - .types + if types .strict_deserialize_type(sem_id, metadata.as_ref()) .is_err() { @@ -216,6 +216,7 @@ impl Schema { opid: OpId, global: &GlobalState, global_schema: &GlobalSchema, + types: &TypeSystem, ) -> validation::Status { let mut status = validation::Status::new(); @@ -257,8 +258,7 @@ impl Schema { // Validating data types for data in set { - if self - .types + if types .strict_deserialize_type(*sem_id, data.value.as_ref()) .is_err() { @@ -335,6 +335,7 @@ impl Schema { id: OpId, owned_state: &Assignments, assign_schema: &AssignmentsSchema, + types: &TypeSystem, ) -> validation::Status { let mut status = validation::Status::new(); @@ -369,18 +370,18 @@ impl Schema { match owned_state.get(state_id) { None => {} - Some(TypedAssigns::Declarative(set)) => set.iter().for_each(|data| { - status += assignment.validate(&self.types, &id, *state_id, data) - }), - Some(TypedAssigns::Fungible(set)) => set.iter().for_each(|data| { - status += assignment.validate(&self.types, &id, *state_id, data) - }), - Some(TypedAssigns::Structured(set)) => set.iter().for_each(|data| { - status += assignment.validate(&self.types, &id, *state_id, data) - }), - Some(TypedAssigns::Attachment(set)) => set.iter().for_each(|data| { - status += assignment.validate(&self.types, &id, *state_id, data) - }), + Some(TypedAssigns::Declarative(set)) => set + .iter() + .for_each(|data| status += assignment.validate(id, *state_id, data, types)), + Some(TypedAssigns::Fungible(set)) => set + .iter() + .for_each(|data| status += assignment.validate(id, *state_id, data, types)), + Some(TypedAssigns::Structured(set)) => set + .iter() + .for_each(|data| status += assignment.validate(id, *state_id, data, types)), + Some(TypedAssigns::Attachment(set)) => set + .iter() + .for_each(|data| status += assignment.validate(id, *state_id, data, types)), }; } diff --git a/src/validation/schema.rs b/src/validation/schema.rs index 28a3411f..21a35c01 100644 --- a/src/validation/schema.rs +++ b/src/validation/schema.rs @@ -20,18 +20,20 @@ // See the License for the specific language governing permissions and // limitations under the License. +use strict_types::TypeSystem; + use crate::{validation, OpFullType, OpSchema, Schema, StateSchema, TransitionType}; impl Schema { - pub fn verify(&self) -> validation::Status { + pub fn verify(&self, types: &TypeSystem) -> validation::Status { let mut status = validation::Status::new(); - status += self.verify_operation(OpFullType::Genesis, &self.genesis); + status += self.verify_operation(OpFullType::Genesis, &self.genesis, types); for (type_id, schema) in &self.transitions { - status += self.verify_operation(OpFullType::StateTransition(*type_id), schema); + status += self.verify_operation(OpFullType::StateTransition(*type_id), schema, types); } for (type_id, schema) in &self.extensions { - status += self.verify_operation(OpFullType::StateExtension(*type_id), schema); + status += self.verify_operation(OpFullType::StateExtension(*type_id), schema, types); } // Check that the schema doesn't contain reserved type ids if self.transitions.contains_key(&TransitionType::BLANK) { @@ -39,7 +41,7 @@ impl Schema { } for (type_id, schema) in &self.global_types { - if !self.types.contains_key(&schema.sem_id) { + if !types.contains_key(&schema.sem_id) { status.add_failure(validation::Failure::SchemaGlobalSemIdUnknown( *type_id, schema.sem_id, @@ -49,7 +51,7 @@ impl Schema { for (type_id, schema) in &self.owned_types { if let StateSchema::Structured(sem_id) = schema { - if !self.types.contains_key(sem_id) { + if !types.contains_key(sem_id) { status.add_failure(validation::Failure::SchemaOwnedSemIdUnknown( *type_id, *sem_id, )); @@ -60,10 +62,15 @@ impl Schema { status } - fn verify_operation(&self, op_type: OpFullType, schema: &impl OpSchema) -> validation::Status { + fn verify_operation( + &self, + op_type: OpFullType, + schema: &impl OpSchema, + types: &TypeSystem, + ) -> validation::Status { let mut status = validation::Status::new(); - if !self.types.contains_key(&schema.metadata()) { + if !types.contains_key(&schema.metadata()) { status.add_failure(validation::Failure::SchemaOpMetaSemIdUnknown( op_type, schema.metadata(), diff --git a/src/validation/state.rs b/src/validation/state.rs index 878aa75e..d3603ebe 100644 --- a/src/validation/state.rs +++ b/src/validation/state.rs @@ -31,10 +31,10 @@ use crate::{ impl StateSchema { pub fn validate( &self, - type_system: &TypeSystem, - opid: &OpId, + opid: OpId, state_type: AssignmentType, data: &Assign, + type_system: &TypeSystem, ) -> validation::Status { let mut status = validation::Status::new(); match data { @@ -45,7 +45,7 @@ impl StateSchema { // [SECURITY-CRITICAL]: Bulletproofs validation if let Err(err) = value.verify_range_proof() { status.add_failure(validation::Failure::BulletproofsInvalid( - *opid, + opid, state_type, err.to_string(), )); @@ -53,18 +53,18 @@ impl StateSchema { } (StateSchema::Structured(_), ConcealedState::Structured(_)) => { status.add_info(validation::Info::UncheckableConfidentialState( - *opid, state_type, + opid, state_type, )); } (StateSchema::Attachment(_), ConcealedState::Attachment(_)) => { status.add_info(validation::Info::UncheckableConfidentialState( - *opid, state_type, + opid, state_type, )); } // all other options are mismatches (state_schema, found) => { status.add_failure(validation::Failure::StateTypeMismatch { - opid: *opid, + opid, state_type, expected: state_schema.state_type(), found: found.state_type(), @@ -79,7 +79,7 @@ impl StateSchema { if !attach.media_type.conforms(media_type) => { status.add_failure(validation::Failure::MediaTypeMismatch { - opid: *opid, + opid, state_type, expected: *media_type, found: attach.media_type, @@ -89,7 +89,7 @@ impl StateSchema { if v.value.fungible_type() != *schema => { status.add_failure(validation::Failure::FungibleTypeMismatch { - opid: *opid, + opid, state_type, expected: *schema, found: v.value.fungible_type(), @@ -102,14 +102,14 @@ impl StateSchema { .is_err() { status.add_failure(validation::Failure::SchemaInvalidOwnedValue( - *opid, state_type, *sem_id, + opid, state_type, *sem_id, )); }; } // all other options are mismatches (state_schema, found) => { status.add_failure(validation::Failure::StateTypeMismatch { - opid: *opid, + opid, state_type, expected: state_schema.state_type(), found: found.state_type(), diff --git a/src/validation/validator.rs b/src/validation/validator.rs index ea098a61..0f061c55 100644 --- a/src/validation/validator.rs +++ b/src/validation/validator.rs @@ -178,7 +178,9 @@ impl<'consignment, 'resolver, C: ConsignmentApi, R: ResolveWitness> } // *** PART I: Schema validation - fn validate_schema(&mut self, schema: &Schema) { self.status += schema.verify(); } + fn validate_schema(&mut self, schema: &Schema) { + self.status += schema.verify(self.consignment.types()); + } // *** PART II: Validating business logic fn validate_logic(&mut self, schema: &'consignment Schema) {