diff --git a/src/schema/mod.rs b/src/schema/mod.rs index 3e26fb7f..f03616e8 100644 --- a/src/schema/mod.rs +++ b/src/schema/mod.rs @@ -20,16 +20,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod operations; +mod types; #[allow(clippy::module_inception)] mod schema; mod state; -mod occurrences; -pub use occurrences::{Occurrences, OccurrencesMismatch}; -pub use operations::{ - AssignmentType, AssignmentsSchema, ExtensionSchema, GenesisSchema, GlobalSchema, MetaSchema, - OpFullType, OpSchema, OpType, TransitionSchema, ValencySchema, ValencyType, +pub use schema::{Schema, SchemaId}; +pub use state::{FielCount, GlobalStateSchema, OwnedStateSchema, PublicationSchema}; +pub use types::{ + AssignmentType, ExtensionType, GlobalStateType, MetaType, OpFullType, OpType, TransitionType, + ValencyType, }; -pub use schema::{ExtensionType, GlobalStateType, MetaType, Schema, SchemaId, TransitionType}; -pub use state::{GlobalStateSchema, OwnedStateSchema}; diff --git a/src/schema/occurrences.rs b/src/schema/occurrences.rs deleted file mode 100644 index de12e19a..00000000 --- a/src/schema/occurrences.rs +++ /dev/null @@ -1,263 +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. - -use std::io; -use std::ops::RangeInclusive; - -use strict_encoding::{ - DecodeError, ReadStruct, StrictDecode, StrictEncode, StrictProduct, StrictStruct, StrictType, - TypeName, TypedRead, TypedWrite, WriteStruct, -}; - -use crate::LIB_NAME_RGB_COMMIT; - -#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[repr(u8)] -pub enum Occurrences { - #[default] - Once, - NoneOrOnce, - NoneOrMore, - OnceOrMore, - NoneOrUpTo(u16), - OnceOrUpTo(u16), - Exactly(u16), - Range(RangeInclusive), -} - -impl Occurrences { - pub fn min_value(&self) -> u16 { - match self { - Occurrences::Once => 1, - Occurrences::NoneOrOnce => 0, - Occurrences::NoneOrMore => 0, - Occurrences::OnceOrMore => 1, - Occurrences::NoneOrUpTo(_) => 0, - Occurrences::OnceOrUpTo(_) => 1, - Occurrences::Exactly(val) => *val, - Occurrences::Range(range) => *range.start(), - } - } - - pub fn max_value(&self) -> u16 { - match self { - Occurrences::Once | Occurrences::NoneOrOnce => 1, - Occurrences::NoneOrMore | Occurrences::OnceOrMore => u16::MAX, - Occurrences::OnceOrUpTo(max) | Occurrences::NoneOrUpTo(max) => *max, - Occurrences::Exactly(val) => *val, - Occurrences::Range(range) => *range.end(), - } - } - - pub fn check(&self, count: u16) -> Result<(), OccurrencesMismatch> { - let orig_count = count; - match self { - Occurrences::Once if count == 1 => Ok(()), - Occurrences::NoneOrOnce if count <= 1 => Ok(()), - Occurrences::OnceOrMore if count > 0 => Ok(()), - Occurrences::OnceOrUpTo(max) if count > 0 && count <= *max => Ok(()), - Occurrences::NoneOrMore => Ok(()), - Occurrences::NoneOrUpTo(max) if count <= *max => Ok(()), - Occurrences::Exactly(val) if count == *val => Ok(()), - Occurrences::Range(range) if range.contains(&count) => Ok(()), - _ => Err(OccurrencesMismatch { - min: self.min_value(), - max: self.max_value(), - found: orig_count, - }), - } - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)] -#[display(doc_comments)] -pub enum OccurrencesError { - /// unable to construct occurrences value with both minimum and maximum - /// number set to zero. - Zero, - - /// unable to construct occurrences value with minimum number exceeding - /// maximum - MinExceedsMax, -} - -impl TryFrom> for Occurrences { - type Error = OccurrencesError; - - fn try_from(range: RangeInclusive) -> Result { - Ok(match (*range.start(), *range.end()) { - (0, 0) => return Err(OccurrencesError::Zero), - (a, b) if a > b => return Err(OccurrencesError::MinExceedsMax), - (0, 1) => Occurrences::NoneOrOnce, - (1, 1) => Occurrences::Once, - (0, u16::MAX) => Occurrences::NoneOrMore, - (1, u16::MAX) => Occurrences::OnceOrMore, - (0, max) => Occurrences::NoneOrUpTo(max), - (1, max) => Occurrences::OnceOrUpTo(max), - (a, b) if a == b => Occurrences::Exactly(a), - (min, max) => Occurrences::Range(min..=max), - }) - } -} - -impl StrictType for Occurrences { - const STRICT_LIB_NAME: &'static str = LIB_NAME_RGB_COMMIT; - fn strict_name() -> Option { Some(tn!("Occurrences")) } -} -impl StrictProduct for Occurrences {} -impl StrictStruct for Occurrences { - const ALL_FIELDS: &'static [&'static str] = &["min", "max"]; -} -impl StrictEncode for Occurrences { - fn strict_encode(&self, writer: W) -> io::Result { - writer.write_struct::(|w| { - Ok(w.write_field(fname!("min"), &self.min_value())? - .write_field(fname!("max"), &self.max_value())? - .complete()) - }) - } -} -impl StrictDecode for Occurrences { - fn strict_decode(reader: &mut impl TypedRead) -> Result { - reader.read_struct(|r| { - let min = r.read_field(fname!("min"))?; - let max = r.read_field(fname!("max"))?; - Occurrences::try_from(min..=max) - .map_err(|err| DecodeError::DataIntegrityError(err.to_string())) - }) - } -} - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Display)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] -#[display("expected from {min} to {max} elements, while {found} were provided")] -pub struct OccurrencesMismatch { - pub min: u16, - pub max: u16, - pub found: u16, -} - -#[cfg(test)] -mod test { - use super::Occurrences; - - #[test] - fn test_once_check_count() { - let occurrence: Occurrences = Occurrences::Once; - occurrence.check(1).unwrap(); - } - #[test] - #[should_panic(expected = "OccurrencesMismatch { min: 1, max: 1, found: 0 }")] - fn test_once_check_count_fail_zero() { - let occurrence: Occurrences = Occurrences::Once; - occurrence.check(0).unwrap(); - } - #[test] - #[should_panic(expected = "OccurrencesMismatch { min: 1, max: 1, found: 2 }")] - fn test_once_check_count_fail_two() { - let occurrence: Occurrences = Occurrences::Once; - occurrence.check(2).unwrap(); - } - - #[test] - fn test_none_or_once_check_count() { - let occurrence: Occurrences = Occurrences::NoneOrOnce; - occurrence.check(1).unwrap(); - } - #[test] - fn test_none_or_once_check_count_zero() { - let occurrence: Occurrences = Occurrences::NoneOrOnce; - occurrence.check(0).unwrap(); - } - #[test] - #[should_panic(expected = "OccurrencesMismatch { min: 0, max: 1, found: 2 }")] - fn test_none_or_once_check_count_fail_two() { - let occurrence: Occurrences = Occurrences::NoneOrOnce; - occurrence.check(2).unwrap(); - } - - #[test] - fn test_once_or_up_to_none() { - let occurrence: Occurrences = Occurrences::OnceOrMore; - occurrence.check(1).unwrap(); - } - #[test] - fn test_once_or_up_to_none_large() { - let occurrence: Occurrences = Occurrences::OnceOrMore; - occurrence.check(u16::MAX).unwrap(); - } - #[test] - #[should_panic(expected = "OccurrencesMismatch { min: 1, max: 65535, found: 0 }")] - fn test_once_or_up_to_none_fail_zero() { - let occurrence: Occurrences = Occurrences::OnceOrMore; - occurrence.check(0).unwrap(); - } - #[test] - fn test_once_or_up_to_42() { - let occurrence: Occurrences = Occurrences::OnceOrUpTo(42); - occurrence.check(42).unwrap(); - } - #[test] - #[should_panic(expected = "OccurrencesMismatch { min: 1, max: 42, found: 43 }")] - fn test_once_or_up_to_42_large() { - let occurrence: Occurrences = Occurrences::OnceOrUpTo(42); - occurrence.check(43).unwrap(); - } - #[test] - #[should_panic(expected = "OccurrencesMismatch { min: 1, max: 42, found: 0 }")] - fn test_once_or_up_to_42_fail_zero() { - let occurrence: Occurrences = Occurrences::OnceOrUpTo(42); - occurrence.check(0).unwrap(); - } - - #[test] - fn test_none_or_up_to_none_zero() { - let occurrence: Occurrences = Occurrences::NoneOrMore; - occurrence.check(0).unwrap(); - } - #[test] - fn test_none_or_up_to_none_large() { - let occurrence: Occurrences = Occurrences::NoneOrMore; - occurrence.check(u16::MAX).unwrap(); - } - #[test] - fn test_none_or_up_to_42_zero() { - let occurrence: Occurrences = Occurrences::NoneOrMore; - occurrence.check(0).unwrap(); - } - #[test] - fn test_none_or_up_to_42() { - let occurrence: Occurrences = Occurrences::NoneOrMore; - occurrence.check(42).unwrap(); - } - #[test] - #[should_panic(expected = "OccurrencesMismatch { min: 0, max: 42, found: 43 }")] - fn test_none_or_up_to_42_large() { - let occurrence: Occurrences = Occurrences::NoneOrUpTo(42); - occurrence.check(43).unwrap(); - } -} diff --git a/src/schema/schema.rs b/src/schema/schema.rs index 6fc8640f..c9bcaf9a 100644 --- a/src/schema/schema.rs +++ b/src/schema/schema.rs @@ -25,7 +25,7 @@ use std::collections::BTreeSet; use std::fmt::{self, Display, Formatter}; use std::str::FromStr; -use aluvm::library::LibId; +use aluvm::library::{LibId, LibSite}; use amplify::confinement::{TinyOrdMap, TinyOrdSet}; use amplify::{ByteArray, Bytes32}; use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; @@ -37,83 +37,12 @@ use strict_encoding::{ }; use strict_types::SemId; -use super::{ - AssignmentType, ExtensionSchema, GenesisSchema, OwnedStateSchema, TransitionSchema, ValencyType, -}; +use super::{AssignmentType, OwnedStateSchema, ValencyType}; use crate::{ - impl_serde_baid64, Ffv, GlobalStateSchema, Identity, Occurrences, LIB_NAME_RGB_COMMIT, + impl_serde_baid64, ExtensionType, Ffv, FielCount, GlobalStateSchema, GlobalStateType, Identity, + MetaType, TransitionType, LIB_NAME_RGB_COMMIT, }; -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Display)] -#[wrapper(FromStr, LowerHex, UpperHex)] -#[display("0x{0:04X}")] -#[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") -)] -pub struct MetaType(u16); -impl MetaType { - pub const fn with(ty: u16) -> Self { Self(ty) } - pub const fn to_u16(&self) -> u16 { self.0 } -} - -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Display)] -#[wrapper(FromStr, LowerHex, UpperHex)] -#[display("0x{0:04X}")] -#[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") -)] -pub struct GlobalStateType(u16); -impl GlobalStateType { - pub const fn with(ty: u16) -> Self { Self(ty) } - pub const fn to_u16(&self) -> u16 { self.0 } -} - -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Display)] -#[wrapper(FromStr, LowerHex, UpperHex)] -#[display("0x{0:04X}")] -#[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") -)] -pub struct ExtensionType(u16); -impl ExtensionType { - pub const fn with(ty: u16) -> Self { Self(ty) } - pub const fn to_u16(&self) -> u16 { self.0 } -} - -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Display)] -#[wrapper(FromStr, LowerHex, UpperHex)] -#[display("0x{0:04X}")] -#[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") -)] -pub struct TransitionType(u16); -impl TransitionType { - pub const fn with(ty: u16) -> Self { Self(ty) } - pub const fn to_u16(&self) -> u16 { self.0 } -} - -impl TransitionType { - pub const BLANK: Self = TransitionType(u16::MAX); - /// Easily check if the TransitionType is blank with convention method - pub fn is_blank(self) -> bool { self == Self::BLANK } -} - /// Schema identifier. /// /// Schema identifier commits to all the schema data. @@ -132,7 +61,7 @@ impl From for SchemaId { } impl CommitmentId for SchemaId { - const TAG: &'static str = "urn:lnp-bp:rgb:schema#2024-02-03"; + const TAG: &'static str = "urn:lnp-bp:rgb:schema#2024-10-23"; } impl DisplayBaid64 for SchemaId { @@ -164,26 +93,32 @@ impl_serde_baid64!(SchemaId); )] pub struct Schema { pub ffv: Ffv, - pub flags: ReservedBytes<1, 0>, + pub flags: ReservedBytes<1>, pub name: TypeName, pub timestamp: i64, pub developer: Identity, - pub meta_types: TinyOrdMap, + pub meta_types: TinyOrdMap, pub global_types: TinyOrdMap, pub owned_types: TinyOrdMap, pub valency_types: TinyOrdSet, - pub genesis: GenesisSchema, - pub extensions: TinyOrdMap, - pub transitions: TinyOrdMap, - pub reserved: ReservedBytes<8, 0>, + // Validation script entry points + // NB: To add other VM use `flags`, `ffv` or `reserved` byte. + pub genesis_validator: LibSite, + pub extension_validators: TinyOrdMap, + pub transition_validators: TinyOrdMap, + pub default_transition_validator: LibSite, + pub default_extension_validator: LibSite, + + pub reserved: ReservedBytes<8>, } impl CommitEncode for Schema { type CommitmentId = SchemaId; + // TODO: We need to use merklization everywhere in order to simplify future commitments fn commit_encode(&self, e: &mut CommitEngine) { e.commit_to_serialized(&self.ffv); e.commit_to_serialized(&self.flags); @@ -196,9 +131,9 @@ impl CommitEncode for Schema { e.commit_to_map(&self.global_types); e.commit_to_map(&self.owned_types); e.commit_to_set(&self.valency_types); - e.commit_to_serialized(&self.genesis); - e.commit_to_map(&self.extensions); - e.commit_to_map(&self.transitions); + e.commit_to_serialized(&self.genesis_validator); + e.commit_to_map(&self.extension_validators); + e.commit_to_map(&self.transition_validators); e.commit_to_serialized(&self.reserved); } @@ -223,31 +158,18 @@ impl Schema { #[inline] pub fn schema_id(&self) -> SchemaId { self.commit_id() } - pub fn blank_transition(&self) -> TransitionSchema { - let mut schema = TransitionSchema::default(); - for id in self.owned_types.keys() { - schema.inputs.insert(*id, Occurrences::NoneOrMore).ok(); - schema.assignments.insert(*id, Occurrences::NoneOrMore).ok(); - } - schema - } - pub fn types(&self) -> BTreeSet { - self.meta_types + self.global_types .values() - .copied() - .chain(self.global_types.values().map(|i| i.sem_id)) - .chain(self.owned_types.values().map(|s| s.sem_id)) + .filter_map(|i| i.sem_id) .collect() } pub fn libs(&self) -> BTreeSet { - self.genesis - .validator - .iter() - .copied() - .chain(self.transitions.values().filter_map(|i| i.validator)) - .chain(self.extensions.values().filter_map(|i| i.validator)) + [self.genesis_validator] + .into_iter() + .chain(self.transition_validators.values().copied()) + .chain(self.extension_validators.values().copied()) .map(|site| site.lib) .collect() } diff --git a/src/schema/state.rs b/src/schema/state.rs index 839d886f..d7ea7d56 100644 --- a/src/schema/state.rs +++ b/src/schema/state.rs @@ -20,13 +20,29 @@ // See the License for the specific language governing permissions and // limitations under the License. -use amplify::num::u24; +use amplify::num::{u24, u3}; use commit_verify::ReservedBytes; use strict_types::SemId; use crate::LIB_NAME_RGB_COMMIT; -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +/// Number of field elements, from 1 to 8. Can't be zero. +// TODO: Use NonZeroU3 when available. +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_COMMIT)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +pub struct FielCount(u3); + +/// NB: Schema can't check presence of structured state data and attachments for the owned state, +/// since this state is omitted from the history after compression, and the check can't be +/// arithmetized. Thus, while owned state may have a structured data and an attachment, they are +/// opaque for the RGB consensus validation. +#[derive(Clone, PartialEq, Eq, Hash, Debug)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_COMMIT)] #[cfg_attr( @@ -35,17 +51,40 @@ use crate::LIB_NAME_RGB_COMMIT; serde(crate = "serde_crate", rename_all = "camelCase") )] pub struct OwnedStateSchema { + /// Reserved for the future versions pub reserved: ReservedBytes<1>, - pub sem_id: SemId, + + /// Presence and number of field elements. + pub fiel_count: Option, } -impl From for OwnedStateSchema { - fn from(sem_id: SemId) -> Self { - Self { - reserved: none!(), - sem_id, - } - } +/// Indicates whether a state should be included into the contract history. +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_COMMIT, tags = custom)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase", tag = "type") +)] +pub enum PublicationSchema { + /// The state is local to the operation subgraph between owned state and genesis. + #[strict_type(tag = 0x00, dumb)] + Local, + + /// The state structured data and attachment must be always included in the contract history + /// even when are not part of the ancestor operations; and they must persist even when the + /// history is compressed. + #[strict_type(tag = 0x01)] + Published { + /// Maximal number of elements of this global state which are kept as a part of the + /// contract state. + depth: u24, + }, +} + +impl PublicationSchema { + pub fn is_published(self) -> bool { matches!(self, Self::Published { .. }) } } #[derive(Clone, PartialEq, Eq, Hash, Debug)] @@ -57,25 +96,29 @@ impl From for OwnedStateSchema { serde(crate = "serde_crate", rename_all = "camelCase") )] pub struct GlobalStateSchema { + /// Reserved for the future versions pub reserved: ReservedBytes<1>, - pub sem_id: SemId, - pub max_items: u24, + + /// Presence and number of field elements. + pub fiel_count: Option, + + /// Semantic type id for the structured unverifiable part of the state, if such is present. + pub sem_id: Option, + + /// Indicates whether the state should - or must include an attachment. + pub attach: Option, + + /// Indicates whether a state should be included into the contract history. + pub publication: PublicationSchema, } impl GlobalStateSchema { - pub fn once(sem_id: SemId) -> Self { - GlobalStateSchema { - reserved: default!(), - sem_id, - max_items: u24::ONE, - } - } + pub fn is_published(&self) -> bool { self.publication.is_published() } - pub fn many(sem_id: SemId) -> Self { - GlobalStateSchema { - reserved: default!(), - sem_id, - max_items: u24::MAX, - } + /// All global state which is either public, or contains unverifiable data (structured state or + /// attachments) can't be ommitted from the history on compression, and thus preserved in its + /// explicit form. + pub fn is_preserved(&self) -> bool { + self.publication.is_published() || self.sem_id.is_some() || self.attach.is_some() } } diff --git a/src/schema/operations.rs b/src/schema/types.rs similarity index 57% rename from src/schema/operations.rs rename to src/schema/types.rs index b12d4ece..60173952 100644 --- a/src/schema/operations.rs +++ b/src/schema/types.rs @@ -20,14 +20,80 @@ // See the License for the specific language governing permissions and // limitations under the License. -use aluvm::library::LibSite; -use amplify::confinement::{TinyOrdMap, TinyOrdSet}; use amplify::Wrapper; -use super::{ExtensionType, GlobalStateType, Occurrences, TransitionType}; -use crate::schema::schema::MetaType; use crate::LIB_NAME_RGB_COMMIT; +#[derive(amplify::Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Display)] +#[wrapper(FromStr, LowerHex, UpperHex)] +#[display("0x{0:04X}")] +#[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") +)] +pub struct MetaType(u16); +impl MetaType { + pub const fn with(ty: u16) -> Self { Self(ty) } + pub const fn to_u16(&self) -> u16 { self.0 } +} + +#[derive(amplify::Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Display)] +#[wrapper(FromStr, LowerHex, UpperHex)] +#[display("0x{0:04X}")] +#[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") +)] +pub struct GlobalStateType(u16); +impl GlobalStateType { + pub const fn with(ty: u16) -> Self { Self(ty) } + pub const fn to_u16(&self) -> u16 { self.0 } +} + +#[derive(amplify::Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Display)] +#[wrapper(FromStr, LowerHex, UpperHex)] +#[display("0x{0:04X}")] +#[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") +)] +pub struct ExtensionType(u16); +impl ExtensionType { + pub const fn with(ty: u16) -> Self { Self(ty) } + pub const fn to_u16(&self) -> u16 { self.0 } +} + +#[derive(amplify::Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Display)] +#[wrapper(FromStr, LowerHex, UpperHex)] +#[display("0x{0:04X}")] +#[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") +)] +pub struct TransitionType(u16); +impl TransitionType { + pub const fn with(ty: u16) -> Self { Self(ty) } + pub const fn to_u16(&self) -> u16 { self.0 } +} + +impl TransitionType { + pub const BLANK: Self = TransitionType(u16::MAX); + /// Easily check if the TransitionType is blank with convention method + pub fn is_blank(self) -> bool { self == Self::BLANK } +} + #[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Display)] #[wrapper(FromStr, LowerHex, UpperHex)] #[display("0x{0:04X}")] @@ -62,12 +128,6 @@ impl ValencyType { pub const fn to_u16(&self) -> u16 { self.0 } } -pub type MetaSchema = TinyOrdSet; -pub type GlobalSchema = TinyOrdMap; -pub type ValencySchema = TinyOrdSet; -pub type InputsSchema = TinyOrdMap; -pub type AssignmentsSchema = TinyOrdMap; - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)] #[cfg_attr( feature = "serde", @@ -131,116 +191,3 @@ impl OpFullType { pub fn is_extension(self) -> bool { matches!(self, Self::StateExtension(_)) } } - -/// Trait defining common API for all operation type schemata -pub trait OpSchema { - fn op_type(&self) -> OpType; - fn metadata(&self) -> &MetaSchema; - fn globals(&self) -> &GlobalSchema; - fn inputs(&self) -> Option<&InputsSchema>; - fn redeems(&self) -> Option<&ValencySchema>; - fn assignments(&self) -> &AssignmentsSchema; - fn valencies(&self) -> &ValencySchema; -} - -#[derive(Clone, PartialEq, Eq, Debug, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct GenesisSchema { - pub metadata: MetaSchema, - pub globals: GlobalSchema, - pub assignments: AssignmentsSchema, - pub valencies: ValencySchema, - // NB: it is possible to transform option into enum covering other virtual machines - pub validator: Option, -} - -#[derive(Clone, PartialEq, Eq, Debug, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct ExtensionSchema { - pub metadata: MetaSchema, - pub globals: GlobalSchema, - pub redeems: ValencySchema, - pub assignments: AssignmentsSchema, - pub valencies: ValencySchema, - pub validator: Option, -} - -#[derive(Clone, PartialEq, Eq, Debug, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct TransitionSchema { - pub metadata: MetaSchema, - pub globals: GlobalSchema, - pub inputs: InputsSchema, - pub assignments: AssignmentsSchema, - pub valencies: ValencySchema, - pub validator: Option, -} - -impl OpSchema for GenesisSchema { - #[inline] - fn op_type(&self) -> OpType { OpType::Genesis } - #[inline] - fn metadata(&self) -> &MetaSchema { &self.metadata } - #[inline] - fn globals(&self) -> &GlobalSchema { &self.globals } - #[inline] - fn inputs(&self) -> Option<&InputsSchema> { None } - #[inline] - fn redeems(&self) -> Option<&ValencySchema> { None } - #[inline] - fn assignments(&self) -> &AssignmentsSchema { &self.assignments } - #[inline] - fn valencies(&self) -> &ValencySchema { &self.valencies } -} - -impl OpSchema for ExtensionSchema { - #[inline] - fn op_type(&self) -> OpType { OpType::StateExtension } - #[inline] - fn metadata(&self) -> &MetaSchema { &self.metadata } - #[inline] - fn globals(&self) -> &GlobalSchema { &self.globals } - #[inline] - fn inputs(&self) -> Option<&InputsSchema> { None } - #[inline] - fn redeems(&self) -> Option<&ValencySchema> { Some(&self.redeems) } - #[inline] - fn assignments(&self) -> &AssignmentsSchema { &self.assignments } - #[inline] - fn valencies(&self) -> &ValencySchema { &self.valencies } -} - -impl OpSchema for TransitionSchema { - #[inline] - fn op_type(&self) -> OpType { OpType::StateTransition } - #[inline] - fn metadata(&self) -> &MetaSchema { &self.metadata } - #[inline] - fn globals(&self) -> &GlobalSchema { &self.globals } - #[inline] - fn inputs(&self) -> Option<&AssignmentsSchema> { Some(&self.inputs) } - #[inline] - fn redeems(&self) -> Option<&ValencySchema> { None } - #[inline] - fn assignments(&self) -> &AssignmentsSchema { &self.assignments } - #[inline] - fn valencies(&self) -> &ValencySchema { &self.valencies } -} diff --git a/src/stl.rs b/src/stl.rs index 7a032bf8..8397639b 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -37,10 +37,10 @@ use crate::{ /// Strict types id for the library providing data types for RGB consensus. pub const LIB_ID_RGB_COMMIT: &str = - "stl:pRLMM7OS-$w8IXpK-!Jl$Sf4-3SrX$vn-OQi9Uzx-USWTXJY#cake-banjo-legend"; + "stl:7pVCkJVx-to9W$lu-uBNBwdr-ftezpr1-nA4sohY-VZGFoYM#mile-answer-karl"; /// Strict types id for the library providing data types for RGB consensus. pub const LIB_ID_RGB_LOGIC: &str = - "stl:rBp7sjZK-WyD4iXW-itLfRey-JguuaFA-ACsLvk2-$P6V0ok#rose-match-almanac"; + "stl:uIWSFM4g-fc20tku-5jM9yK7-yNiSbHe-QMoaD3k-7YZY2wI#ivan-erosion-warning"; fn _rgb_commit_stl() -> Result { LibBuilder::new(libname!(LIB_NAME_RGB_COMMIT), tiny_bset! { diff --git a/src/validation/consignment.rs b/src/validation/consignment.rs index 9499d2e1..af7fb3d8 100644 --- a/src/validation/consignment.rs +++ b/src/validation/consignment.rs @@ -31,7 +31,7 @@ use amplify::confinement::Confined; use strict_types::TypeSystem; use super::EAnchor; -use crate::vm::XWitnessId; +use crate::vm::{WitnessOrd, XWitnessId, XWitnessTx}; use crate::{ AssignmentType, AssignmentsRef, BundleId, ContractId, Extension, ExtensionType, Genesis, GlobalState, GraphSeal, Inputs, Metadata, OpFullType, OpId, OpType, Operation, Schema, @@ -158,13 +158,13 @@ impl<'op> Operation for OpRef<'op> { } } -pub struct CheckedConsignment<'consignment, C: ConsignmentApi>(&'consignment C); +pub struct CheckedApi<'consignment, C: ContractApi>(&'consignment C); -impl<'consignment, C: ConsignmentApi> CheckedConsignment<'consignment, C> { +impl<'consignment, C: ContractApi> CheckedApi<'consignment, C> { pub fn new(consignment: &'consignment C) -> Self { Self(consignment) } } -impl<'consignment, C: ConsignmentApi> ConsignmentApi for CheckedConsignment<'consignment, C> { +impl<'consignment, C: ContractApi> ContractApi for CheckedApi<'consignment, C> { fn schema(&self) -> &Schema { self.0.schema() } fn types(&self) -> &TypeSystem { self.0.types() } @@ -190,6 +190,19 @@ impl<'consignment, C: ConsignmentApi> ConsignmentApi for CheckedConsignment<'con } fn op_witness_id(&self, opid: OpId) -> Option { self.0.op_witness_id(opid) } + + fn witness_pub(&self, witness_id: XWitnessId) -> Option { + let witness = self.0.witness_pub(witness_id)?; + let actual_id = witness.witness_id(); + if actual_id != witness_id { + panic!() + } + Some(witness) + } + + fn witness_ord(&self, witness_id: XWitnessId) -> Option { + self.0.witness_ord(witness_id) + } } /// Trait defining common data access API for all storage-related RGB structures @@ -199,7 +212,7 @@ impl<'consignment, C: ConsignmentApi> ConsignmentApi for CheckedConsignment<'con /// data within the storage or container. If the methods are called on an /// invalid or absent data, the API must always return [`None`] or empty /// collections/iterators. -pub trait ConsignmentApi { +pub trait ContractApi { /// Returns reference to the schema object used by the consignment. fn schema(&self) -> &Schema; @@ -228,4 +241,8 @@ pub trait ConsignmentApi { /// Returns witness id for a given operation. fn op_witness_id(&self, opid: OpId) -> Option; + + fn witness_pub(&self, witness_id: XWitnessId) -> Option; + + fn witness_ord(&self, witness_id: XWitnessId) -> Option; } diff --git a/src/validation/logic.rs b/src/validation/logic.rs index ea353be0..1d9c2d7f 100644 --- a/src/validation/logic.rs +++ b/src/validation/logic.rs @@ -21,7 +21,7 @@ // limitations under the License. use std::cell::RefCell; -use std::collections::{BTreeMap, BTreeSet}; +use std::collections::BTreeMap; use std::rc::Rc; use aluvm::data::Number; @@ -31,131 +31,52 @@ use aluvm::Vm; use amplify::confinement::Confined; use amplify::Wrapper; -use crate::schema::{AssignmentsSchema, GlobalSchema, ValencySchema}; -use crate::validation::{CheckedConsignment, ConsignmentApi}; +use crate::validation::{CheckedApi, ContractApi}; use crate::vm::{ContractStateAccess, ContractStateEvolve, OpInfo, OrdOpRef, RgbIsa, VmContext}; use crate::{ - validation, AssignmentType, Assignments, AssignmentsRef, ExposedSeal, Extension, GlobalState, - GlobalStateSchema, GlobalValues, GraphSeal, Inputs, MetaSchema, Metadata, OpId, Operation, - Opout, Schema, Transition, TypedAssigns, Valencies, + validation, AssignmentType, Assignments, Extension, GraphSeal, Inputs, OpId, Operation, Opout, + Schema, Transition, TypedAssigns, Valencies, }; impl Schema { pub fn validate_state< 'validator, - C: ConsignmentApi, + C: ContractApi, S: ContractStateAccess + ContractStateEvolve, >( &'validator self, - consignment: &'validator CheckedConsignment<'_, C>, + consignment: &'validator CheckedApi<'_, C>, op: OrdOpRef, contract_state: Rc>, ) -> validation::Status { let opid = op.id(); let mut status = validation::Status::new(); - let empty_assign_schema = AssignmentsSchema::default(); - let empty_valency_schema = ValencySchema::default(); - let blank_transition = self.blank_transition(); - let ( - metadata_schema, - global_schema, - owned_schema, - redeem_schema, - assign_schema, - valency_schema, - validator, - ty, - ) = match op { - OrdOpRef::Genesis(_) => ( - &self.genesis.metadata, - &self.genesis.globals, - &empty_assign_schema, - &empty_valency_schema, - &self.genesis.assignments, - &self.genesis.valencies, - self.genesis.validator, - None::, - ), + let (validator, ty) = match op { + OrdOpRef::Genesis(_) => (self.genesis_validator, None::), OrdOpRef::Transition( Transition { transition_type, .. }, .., ) => { - // Right now we do not have actions to implement; but later - // we may have embedded procedures which must be verified - // here - /* - if let Some(procedure) = transition_type.abi.get(&TransitionAction::NoOp) { - - } - */ - - let transition_schema = match self.transitions.get(transition_type) { - None if transition_type.is_blank() => &blank_transition, - None => { - return validation::Status::with_failure( - validation::Failure::SchemaUnknownTransitionType( - opid, - *transition_type, - ), - ); - } - Some(transition_schema) => transition_schema, - }; - - ( - &transition_schema.metadata, - &transition_schema.globals, - &transition_schema.inputs, - &empty_valency_schema, - &transition_schema.assignments, - &transition_schema.valencies, - transition_schema.validator, - Some(transition_type.into_inner()), - ) + let transition_schema = *self + .transition_validators + .get(transition_type) + .unwrap_or(&self.default_transition_validator); + (transition_schema, Some(transition_type.into_inner())) } OrdOpRef::Extension(Extension { extension_type, .. }, ..) => { - // Right now we do not have actions to implement; but later - // we may have embedded procedures which must be verified - // here - /* - if let Some(procedure) = extension_type.abi.get(&ExtensionAction::NoOp) { - - } - */ - - let extension_schema = match self.extensions.get(extension_type) { - None => { - return validation::Status::with_failure( - validation::Failure::SchemaUnknownExtensionType(opid, *extension_type), - ); - } - Some(extension_schema) => extension_schema, - }; - - ( - &extension_schema.metadata, - &extension_schema.globals, - &empty_assign_schema, - &extension_schema.redeems, - &extension_schema.assignments, - &extension_schema.redeems, - extension_schema.validator, - Some(extension_type.into_inner()), - ) + let extension_schema = *self + .extension_validators + .get(extension_type) + .unwrap_or(&self.default_extension_validator); + (extension_schema, Some(extension_type.into_inner())) } }; - // Validate type system - status += self.validate_type_system(); - status += self.validate_metadata(opid, op.metadata(), metadata_schema); - status += self.validate_global_state(opid, op.globals(), global_schema); let prev_state = if let OrdOpRef::Transition(transition, ..) = op { - let prev_state = extract_prev_state(consignment, opid, &transition.inputs, &mut status); - status += self.validate_prev_state(opid, &prev_state, owned_schema); - prev_state + extract_prev_state(consignment, opid, &transition.inputs, &mut status) } else { Assignments::default() }; @@ -164,18 +85,7 @@ impl Schema { for valency in extension.redeemed.keys() { redeemed.push(*valency).expect("same size"); } - status += self.validate_redeemed(opid, &redeemed, redeem_schema); } - status += match op.assignments() { - AssignmentsRef::Genesis(assignments) => { - self.validate_owned_state(opid, assignments, assign_schema) - } - AssignmentsRef::Graph(assignments) => { - self.validate_owned_state(opid, assignments, assign_schema) - } - }; - - status += self.validate_valencies(opid, op.valencies(), valency_schema); let genesis = consignment.genesis(); let op_info = OpInfo::with(opid, &op, &prev_state, &redeemed); @@ -188,232 +98,33 @@ impl Schema { // 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(); - if let Some(ty) = ty { - vm.registers.set_n(RegA::A16, Reg32::Reg0, ty); - } - 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, - error_code.map(u8::from), - None, - )); - // We return here since all other validations will have no valid state to access - return status; - } - let contract_state = context.contract_state; - if contract_state.borrow_mut().evolve_state(op).is_err() { - status.add_failure(validation::Failure::ContractStateFilled(opid)); - // We return here since all other validations will have no valid state to access - return status; - } - } - status - } - - fn validate_type_system(&self) -> validation::Status { - validation::Status::new() - // TODO: Validate type system - // Currently, validation is performed at the level of state values, i.e. - // if the system is inconsistent (references semantic ids not - // present in it) this will be detected during state validation. - // We should not prohibit schema with inconsistent type system, instead - // we need just to issue warnings here if some of semantic ids are - // missed - and add information messages if some excessive semantic ids - // are present. - } - - fn validate_metadata( - &self, - opid: OpId, - metadata: &Metadata, - metadata_schema: &MetaSchema, - ) -> validation::Status { - let mut status = validation::Status::new(); - - metadata - .keys() - .copied() - .collect::>() - .difference(metadata_schema.as_unconfined()) - .for_each(|type_id| { - status.add_failure(validation::Failure::SchemaUnknownMetaType(opid, *type_id)); - }); - - status - } - - fn validate_global_state( - &self, - opid: OpId, - global: &GlobalState, - global_schema: &GlobalSchema, - ) -> validation::Status { - let mut status = validation::Status::new(); - - global - .keys() - .collect::>() - .difference(&global_schema.keys().collect()) - .for_each(|field_id| { - status.add_failure(validation::Failure::SchemaUnknownGlobalStateType( - opid, **field_id, - )); - }); - - for (type_id, occ) in global_schema { - let set = global - .get(type_id) - .cloned() - .map(GlobalValues::into_inner) - .map(Confined::release) - .unwrap_or_default(); - - let GlobalStateSchema { - sem_id: _, - max_items, - reserved: _, - } = self.global_types.get(type_id).expect( - "if the field were absent, the schema would not be able to pass the internal \ - validation and we would not reach this point", - ); - - // Checking number of field occurrences - let count = set.len() as u16; - if let Err(err) = occ.check(count) { - status.add_failure(validation::Failure::SchemaGlobalStateOccurrences( - opid, *type_id, err, - )); - } - if count as u32 > max_items.to_u32() { - status.add_failure(validation::Failure::SchemaGlobalStateLimit( - opid, *type_id, count, *max_items, - )); - } + let scripts = consignment.scripts(); + let mut vm = Vm::>>::new(); + if let Some(ty) = ty { + vm.registers.set_n(RegA::A16, Reg32::Reg0, ty); } - - status - } - - fn validate_prev_state( - &self, - id: OpId, - owned_state: &Assignments, - assign_schema: &AssignmentsSchema, - ) -> validation::Status { - let mut status = validation::Status::new(); - - owned_state - .keys() - .collect::>() - .difference(&assign_schema.keys().collect()) - .for_each(|owned_type_id| { - status.add_failure(validation::Failure::SchemaUnknownAssignmentType( - id, - **owned_type_id, - )); - }); - - for (owned_type_id, occ) in assign_schema { - let len = owned_state - .get(owned_type_id) - .map(|ta| ta.len_u16()) - .unwrap_or(0); - - // Checking number of ancestor's assignment occurrences - if let Err(err) = occ.check(len) { - status.add_failure(validation::Failure::SchemaInputOccurrences( - id, - *owned_type_id, - err, - )); - } + 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, + error_code.map(u8::from), + None, + )); + // We return here since all other validations will have no valid state to access + return status; } - - status - } - - fn validate_redeemed( - &self, - id: OpId, - valencies: &Valencies, - valency_schema: &ValencySchema, - ) -> validation::Status { - let mut status = validation::Status::new(); - - valencies - .difference(valency_schema) - .for_each(|public_type_id| { - status.add_failure(validation::Failure::SchemaUnknownValencyType( - id, - *public_type_id, - )); - }); - - status - } - - fn validate_owned_state( - &self, - id: OpId, - owned_state: &Assignments, - assign_schema: &AssignmentsSchema, - ) -> validation::Status { - let mut status = validation::Status::new(); - - owned_state - .keys() - .collect::>() - .difference(&assign_schema.keys().collect()) - .for_each(|assignment_type_id| { - status.add_failure(validation::Failure::SchemaUnknownAssignmentType( - id, - **assignment_type_id, - )); - }); - - for (state_id, occ) in assign_schema { - let len = owned_state - .get(state_id) - .map(|ta| ta.len_u16()) - .unwrap_or(0); - - // Checking number of assignment occurrences - if let Err(err) = occ.check(len) { - status.add_failure(validation::Failure::SchemaAssignmentOccurrences( - id, *state_id, err, - )); - } + let contract_state = context.contract_state; + if contract_state.borrow_mut().evolve_state(op).is_err() { + status.add_failure(validation::Failure::ContractStateFilled(opid)); + // We return here since all other validations will have no valid state to access + return status; } status } - - fn validate_valencies( - &self, - id: OpId, - valencies: &Valencies, - valency_schema: &ValencySchema, - ) -> validation::Status { - let mut status = validation::Status::new(); - - valencies - .difference(valency_schema) - .for_each(|public_type_id| { - status.add_failure(validation::Failure::SchemaUnknownValencyType( - id, - *public_type_id, - )); - }); - - status - } } -fn extract_prev_state( +fn extract_prev_state( consignment: &C, opid: OpId, inputs: &Inputs, diff --git a/src/validation/mod.rs b/src/validation/mod.rs index c7c3eb09..e7144502 100644 --- a/src/validation/mod.rs +++ b/src/validation/mod.rs @@ -20,7 +20,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod schema; mod logic; mod validator; mod consignment; @@ -28,6 +27,6 @@ mod status; mod commitments; pub use commitments::{DbcError, DbcProof, EAnchor}; -pub use consignment::{CheckedConsignment, ConsignmentApi, OpRef, Scripts, CONSIGNMENT_MAX_LIBS}; +pub use consignment::{CheckedApi, ContractApi, OpRef, Scripts, CONSIGNMENT_MAX_LIBS}; pub use status::{Failure, Info, Status, Validity, Warning}; -pub use validator::{ResolveWitness, Validator, WitnessResolverError}; +pub use validator::Validator; diff --git a/src/validation/schema.rs b/src/validation/schema.rs deleted file mode 100644 index 4c9dbbe2..00000000 --- a/src/validation/schema.rs +++ /dev/null @@ -1,107 +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. - -use strict_types::TypeSystem; - -use crate::{validation, OpFullType, OpSchema, Schema, TransitionType}; - -impl Schema { - pub fn verify(&self, types: &TypeSystem) -> validation::Status { - let mut status = validation::Status::new(); - - status += self.verify_operation(OpFullType::Genesis, &self.genesis); - for (type_id, schema) in &self.transitions { - status += self.verify_operation(OpFullType::StateTransition(*type_id), schema); - } - for (type_id, schema) in &self.extensions { - status += self.verify_operation(OpFullType::StateExtension(*type_id), schema); - } - // Check that the schema doesn't contain reserved type ids - if self.transitions.contains_key(&TransitionType::BLANK) { - status.add_failure(validation::Failure::SchemaBlankTransitionRedefined); - } - - for (type_id, sem_id) in &self.meta_types { - if !types.contains_key(sem_id) { - status.add_failure(validation::Failure::SchemaMetaSemIdUnknown(*type_id, *sem_id)); - } - } - - for (type_id, schema) in &self.global_types { - if !types.contains_key(&schema.sem_id) { - status.add_failure(validation::Failure::SchemaGlobalSemIdUnknown( - *type_id, - schema.sem_id, - )); - } - } - - for (type_id, schema) in &self.owned_types { - if !types.contains_key(&schema.sem_id) { - status.add_failure(validation::Failure::SchemaOwnedSemIdUnknown( - *type_id, - schema.sem_id, - )); - } - } - - status - } - - fn verify_operation(&self, op_type: OpFullType, schema: &impl OpSchema) -> validation::Status { - let mut status = validation::Status::new(); - - for type_id in schema.metadata() { - if !self.meta_types.contains_key(type_id) { - status.add_failure(validation::Failure::SchemaOpMetaTypeUnknown(op_type, *type_id)); - } - } - if matches!(schema.inputs(), Some(inputs) if inputs.is_empty()) { - status.add_failure(validation::Failure::SchemaOpEmptyInputs(op_type)); - } - if matches!(schema.redeems(), Some(inputs) if inputs.is_empty()) { - status.add_failure(validation::Failure::SchemaOpEmptyInputs(op_type)); - } - for type_id in schema.globals().keys() { - if !self.global_types.contains_key(type_id) { - status - .add_failure(validation::Failure::SchemaOpGlobalTypeUnknown(op_type, *type_id)); - } - } - for type_id in schema.assignments().keys() { - if !self.owned_types.contains_key(type_id) { - status.add_failure(validation::Failure::SchemaOpAssignmentTypeUnknown( - op_type, *type_id, - )); - } - } - for type_id in schema.valencies() { - if !self.valency_types.contains(type_id) { - status.add_failure(validation::Failure::SchemaOpValencyTypeUnknown( - op_type, *type_id, - )); - } - } - - status - } -} diff --git a/src/validation/status.rs b/src/validation/status.rs index 89e6d395..85e77212 100644 --- a/src/validation/status.rs +++ b/src/validation/status.rs @@ -23,17 +23,11 @@ use core::ops::AddAssign; use std::fmt::{self, Display, Formatter}; -use amplify::num::u24; use commit_verify::mpc::InvalidProof; -use strict_types::SemId; use crate::schema::{self, SchemaId}; -use crate::validation::WitnessResolverError; use crate::vm::XWitnessId; -use crate::{ - BundleId, ContractId, Layer1, OccurrencesMismatch, OpFullType, OpId, Opout, Vin, XGraphSeal, - XOutputSeal, -}; +use crate::{BundleId, ContractId, Layer1, OpId, Opout, Vin, XGraphSeal, XOutputSeal}; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Display)] #[repr(u8)] @@ -175,55 +169,6 @@ pub enum Failure { /// Actual schema id provided by the consignment. actual: SchemaId, }, - /// schema uses reserved type for the blank state transition. - SchemaBlankTransitionRedefined, - - /// schema global state #{0} uses semantic data type absent in type library - /// ({1}). - SchemaGlobalSemIdUnknown(schema::GlobalStateType, SemId), - /// schema owned state #{0} uses semantic data type absent in type library - /// ({1}). - SchemaOwnedSemIdUnknown(schema::AssignmentType, SemId), - /// schema metadata #{0} uses semantic data type absent in type library - /// ({1}). - SchemaMetaSemIdUnknown(schema::MetaType, SemId), - - /// schema for {0} has zero inputs. - SchemaOpEmptyInputs(OpFullType), - /// schema for {0} references undeclared metadata type {1}. - SchemaOpMetaTypeUnknown(OpFullType, schema::MetaType), - /// schema for {0} references undeclared global state type {1}. - SchemaOpGlobalTypeUnknown(OpFullType, schema::GlobalStateType), - /// schema for {0} references undeclared owned state type {1}. - SchemaOpAssignmentTypeUnknown(OpFullType, schema::AssignmentType), - /// schema for {0} references undeclared valency type {1}. - SchemaOpValencyTypeUnknown(OpFullType, schema::ValencyType), - - /// operation {0} uses invalid state extension type {1}. - SchemaUnknownExtensionType(OpId, schema::ExtensionType), - /// operation {0} uses invalid state transition type {1}. - SchemaUnknownTransitionType(OpId, schema::TransitionType), - /// operation {0} uses invalid metadata type {1}. - SchemaUnknownMetaType(OpId, schema::MetaType), - /// operation {0} uses invalid global state type {1}. - SchemaUnknownGlobalStateType(OpId, schema::GlobalStateType), - /// operation {0} uses invalid assignment type {1}. - SchemaUnknownAssignmentType(OpId, schema::AssignmentType), - /// operation {0} uses invalid valency type {1}. - SchemaUnknownValencyType(OpId, schema::ValencyType), - - /// invalid number of global state entries of type {1} in operation {0} - - /// {2} - SchemaGlobalStateOccurrences(OpId, schema::GlobalStateType, OccurrencesMismatch), - /// number of global state entries of type {1} in operation {0} exceeds - /// schema-defined maximum for that global state type ({2} vs {3}). - SchemaGlobalStateLimit(OpId, schema::GlobalStateType, u16, u24), - /// required metadata type {1} is not present in the operation {0}. - SchemaNoMetadata(OpId, schema::MetaType), - /// invalid number of input entries of type {1} in operation {0} - {2} - SchemaInputOccurrences(OpId, schema::AssignmentType, OccurrencesMismatch), - /// invalid number of assignment entries of type {1} in operation {0} - {2} - SchemaAssignmentOccurrences(OpId, schema::AssignmentType, OccurrencesMismatch), // Consignment consistency errors /// operation {0} is referenced within the history multiple times. RGB @@ -237,10 +182,9 @@ pub enum Failure { 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), + /// bundle {0} public witness {1} is not known; validation stopped since operations can't be + /// consensus-ordered. + WitnessUnresolved(BundleId, XWitnessId), /// operation {0} is under a different contract {1}. ContractMismatch(OpId, ContractId), @@ -268,9 +212,8 @@ pub enum Failure { /// seal defined in the history as a part of operation output {0} is /// confidential and can't be validated. ConfidentialSeal(Opout), - /// bundle {0} public witness {1} is not known to the resolver. Resolver - /// reported error {2} - SealNoPubWitness(BundleId, XWitnessId, WitnessResolverError), + /// bundle {0} public witness {1} is not known. + SealNoPubWitness(BundleId, XWitnessId), /// 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 diff --git a/src/validation/validator.rs b/src/validation/validator.rs index 941bc14f..8f3456d9 100644 --- a/src/validation/validator.rs +++ b/src/validation/validator.rs @@ -31,104 +31,15 @@ use commit_verify::mpc; use single_use_seals::SealWitness; use super::status::Failure; -use super::{CheckedConsignment, ConsignmentApi, DbcProof, EAnchor, OpRef, Status, Validity}; -use crate::vm::{ - ContractStateAccess, ContractStateEvolve, OrdOpRef, WitnessOrd, XWitnessId, XWitnessTx, -}; +use super::{CheckedApi, ContractApi, DbcProof, EAnchor, OpRef, Status, Validity}; +use crate::vm::{ContractStateAccess, ContractStateEvolve, OrdOpRef, XWitnessId, XWitnessTx}; use crate::{ - validation, AltLayer1, BundleId, ContractId, Layer1, OpId, OpType, Operation, Opout, Schema, - SchemaId, TransitionBundle, XChain, XOutpoint, XOutputSeal, + AltLayer1, BundleId, ContractId, Layer1, OpId, OpType, Operation, Opout, SchemaId, + TransitionBundle, XChain, XOutpoint, XOutputSeal, }; -#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] -#[display(doc_comments)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum WitnessResolverError { - /// actual witness id {actual} doesn't match expected id {expected}. - IdMismatch { - actual: XWitnessId, - expected: XWitnessId, - }, - /// witness {0} does not exist. - Unknown(XWitnessId), - /// unable to retrieve witness {0}, {1} - Other(XWitnessId, String), -} - -pub trait ResolveWitness { - // TODO: Return with SPV proof data - fn resolve_pub_witness( - &self, - witness_id: XWitnessId, - ) -> Result; - - fn resolve_pub_witness_ord( - &self, - witness_id: XWitnessId, - ) -> Result; -} - -impl ResolveWitness for &T { - fn resolve_pub_witness( - &self, - witness_id: XWitnessId, - ) -> 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 { - inner: R, -} - -impl From for CheckedWitnessResolver { - fn from(inner: R) -> Self { Self { inner } } -} - -impl ResolveWitness for CheckedWitnessResolver { - fn resolve_pub_witness( - &self, - witness_id: XWitnessId, - ) -> Result { - let witness = self.inner.resolve_pub_witness(witness_id)?; - let actual_id = witness.witness_id(); - if actual_id != witness_id { - return Err(WitnessResolverError::IdMismatch { - actual: actual_id, - expected: witness_id, - }); - } - 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, - S: ContractStateAccess + ContractStateEvolve, - C: ConsignmentApi, - R: ResolveWitness, -> { - consignment: CheckedConsignment<'consignment, C>, +pub struct Validator<'contract, S: ContractStateAccess + ContractStateEvolve, C: ContractApi> { + contract: CheckedApi<'contract, C>, status: RefCell, @@ -138,26 +49,19 @@ pub struct Validator< contract_state: Rc>, validated_op_seals: RefCell>, - - resolver: CheckedWitnessResolver<&'resolver R>, } -impl< - 'consignment, - 'resolver, - S: ContractStateAccess + ContractStateEvolve, - C: ConsignmentApi, - R: ResolveWitness, - > Validator<'consignment, 'resolver, S, C, R> +impl<'contract, S: ContractStateAccess + ContractStateEvolve, C: ContractApi> + Validator<'contract, S, C> { - fn init(consignment: &'consignment C, resolver: &'resolver R, context: S::Context<'_>) -> Self { + fn init(contract: &'contract C, context: S::Context<'_>) -> Self { // We use validation status object to store all detected failures and // warnings let status = Status::default(); - let consignment = CheckedConsignment::new(consignment); + let contract = CheckedApi::new(contract); // Frequently used computation-heavy data - let genesis = consignment.genesis(); + let genesis = contract.genesis(); let contract_id = genesis.contract_id(); let schema_id = genesis.schema_id; @@ -168,13 +72,12 @@ impl< layers1.extend(genesis.alt_layers1.iter().map(AltLayer1::layer1)); Self { - consignment, + contract, status: RefCell::new(status), schema_id, contract_id, layers1, validated_op_seals, - resolver: CheckedWitnessResolver::from(resolver), contract_state: Rc::new(RefCell::new(S::init(context))), } } @@ -186,18 +89,13 @@ impl< /// /// When a failure detected, validation is not stopped; the failure is /// 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, - context: S::Context<'_>, - ) -> Status { - let mut validator = Self::init(consignment, resolver, context); + /// rest of the contract data. This can help to debug and detect all + /// problems with the contract. + pub fn validate(contract: &'contract C, testnet: bool, context: S::Context<'_>) -> Status { + let mut validator = Self::init(contract, 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 { + if testnet != validator.contract.genesis().testnet { validator .status .borrow_mut() @@ -205,7 +103,6 @@ impl< return validator.status.into_inner(); } - validator.validate_schema(consignment.schema()); // We must return here, since if the schema is not valid there is no reason to // validate contract nodes against it: it will produce a plenty of errors. if validator.status.borrow().validity() == Validity::Invalid { @@ -225,14 +122,9 @@ impl< validator.status.into_inner() } - // *** PART I: Schema validation - fn validate_schema(&mut self, schema: &Schema) { - *self.status.borrow_mut() += schema.verify(self.consignment.types()); - } - - // *** PART II: Validating business logic + // *** PART I: Validating business logic fn validate_logic(&self) { - let schema = self.consignment.schema(); + let schema = self.contract.schema(); // [VALIDATION]: Making sure that we were supplied with the schema // that corresponds to the schema of the contract genesis @@ -244,48 +136,47 @@ impl< actual: schema.schema_id(), }); // Unlike other failures, here we return immediately, since there is no point - // to validate all consignment data against an invalid schema: it will result in + // to validate all contract data against an invalid schema: it will result in // a plenty of meaningless errors return; } // [VALIDATION]: Validate genesis *self.status.borrow_mut() += schema.validate_state( - &self.consignment, - OrdOpRef::Genesis(self.consignment.genesis()), + &self.contract, + OrdOpRef::Genesis(self.contract.genesis()), self.contract_state.clone(), ); - // [VALIDATION]: Iterating over all consignment operations, ordering them according to the + // [VALIDATION]: Iterating over all contract operations, ordering them according to the // consensus ordering rules. let mut ops = BTreeSet::::new(); - for bundle_id in self.consignment.bundle_ids() { + for bundle_id in self.contract.bundle_ids() { let bundle = self - .consignment + .contract .bundle(bundle_id) - .expect("invalid checked consignment"); + .expect("invalid checked contract"); let (witness_id, _) = self - .consignment + .contract .anchor(bundle_id) - .expect("invalid checked consignment"); - let witness_ord = - match self.resolver.resolve_pub_witness_ord(witness_id) { - Ok(ord) => 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; - } - }; + .expect("invalid checked contract"); + let witness_ord = match self.contract.witness_ord(witness_id) { + Some(ord) => ord, + None => { + self.status + .borrow_mut() + .add_failure(Failure::WitnessUnresolved(bundle_id, witness_id)); + // We need to stop validation there since we can't order operations + return; + } + }; for op in bundle.known_transitions.values() { ops.insert(OrdOpRef::Transition(op, witness_id, witness_ord)); for input in &op.inputs { // We will error in `validate_operations` below on the absent extension from the - // consignment. + // contract. if let Some(OpRef::Extension(extension)) = - self.consignment.operation(input.prev_out.op) + self.contract.operation(input.prev_out.op) { let ext = OrdOpRef::Extension(extension, witness_id, witness_ord); // Account only for the first time when extension seal was closed @@ -314,8 +205,8 @@ impl< } } - fn validate_operation(&self, operation: OrdOpRef<'consignment>) { - let schema = self.consignment.schema(); + fn validate_operation(&self, operation: OrdOpRef<'contract>) { + let schema = self.contract.schema(); let opid = operation.id(); if operation.contract_id() != self.contract_id { @@ -333,7 +224,7 @@ impl< } // [VALIDATION]: Verify operation against the schema and scripts *self.status.borrow_mut() += - schema.validate_state(&self.consignment, operation, self.contract_state.clone()); + schema.validate_state(&self.contract, operation, self.contract_state.clone()); match operation { OrdOpRef::Genesis(_) => { @@ -341,7 +232,7 @@ impl< } OrdOpRef::Transition(transition, ..) => { for input in &transition.inputs { - if self.consignment.operation(input.prev_out.op).is_none() { + if self.contract.operation(input.prev_out.op).is_none() { self.status .borrow_mut() .add_failure(Failure::OperationAbsent(input.prev_out.op)); @@ -350,7 +241,7 @@ impl< } OrdOpRef::Extension(extension, ..) => { for (valency, prev_id) in &extension.redeemed { - let Some(prev_op) = self.consignment.operation(*prev_id) else { + let Some(prev_op) = self.contract.operation(*prev_id) else { self.status .borrow_mut() .add_failure(Failure::ValencyNoParent { @@ -376,16 +267,16 @@ impl< } } - // *** PART III: Validating single-use-seals + // *** PART II: Validating single-use-seals fn validate_commitments(&mut self) { - for bundle_id in self.consignment.bundle_ids() { - let Some(bundle) = self.consignment.bundle(bundle_id) else { + for bundle_id in self.contract.bundle_ids() { + let Some(bundle) = self.contract.bundle(bundle_id) else { self.status .borrow_mut() .add_failure(Failure::BundleAbsent(bundle_id)); continue; }; - let Some((witness_id, anchor)) = self.consignment.anchor(bundle_id) else { + let Some((witness_id, anchor)) = self.contract.anchor(bundle_id) else { self.status .borrow_mut() .add_failure(Failure::AnchorAbsent(bundle_id)); @@ -463,24 +354,24 @@ impl< // Check that the anchor is committed into a transaction spending all the // transition inputs. // Here the method can do SPV proof instead of querying the indexer. The SPV - // proofs can be part of the consignments, but do not require . - match self.resolver.resolve_pub_witness(witness_id) { - Err(err) => { + // proofs can be part of the contracts, but do not require . + match self.contract.witness_pub(witness_id) { + None => { // We wre unable to retrieve corresponding transaction, so can't check. // Reporting this incident and continuing further. Why this happens? No // connection to Bitcoin Core, Electrum or other backend etc. So this is not a - // failure in a strict sense, however we can't be sure that the consignment is + // failure in a strict sense, however we can't be sure that the contract is // valid. // This also can mean that there is no known transaction with the id provided by - // the anchor, i.e. consignment is invalid. We are proceeding with further + // the anchor, i.e. contract is invalid. We are proceeding with further // validation in order to detect the rest of problems (and reporting the // failure!) self.status .borrow_mut() - .add_failure(Failure::SealNoPubWitness(bundle_id, witness_id, err)); + .add_failure(Failure::SealNoPubWitness(bundle_id, witness_id)); None } - Ok(pub_witness) => { + Some(pub_witness) => { let seals = seals.as_ref(); for seal in seals .iter() @@ -539,9 +430,9 @@ impl< for input in &transition.inputs { let Opout { op, ty, no } = input.prev_out; - let Some(prev_op) = self.consignment.operation(op) else { - // Node, referenced as the ancestor, was not found in the consignment. - // Usually this means that the consignment data are broken + let Some(prev_op) = self.contract.operation(op) else { + // Node, referenced as the ancestor, was not found in the contract. + // Usually this means that the contract data are broken self.status .borrow_mut() .add_failure(Failure::OperationAbsent(op)); @@ -589,7 +480,7 @@ impl< } let seal = if prev_op.op_type() == OpType::StateTransition { - let Some(witness_id) = self.consignment.op_witness_id(op) else { + let Some(witness_id) = self.contract.op_witness_id(op) else { self.status .borrow_mut() .add_failure(Failure::OperationAbsent(op)); diff --git a/stl/AnchoredBundle.vesper b/stl/AnchoredBundle.vesper index 87c771aa..6eefcb34 100644 --- a/stl/AnchoredBundle.vesper +++ b/stl/AnchoredBundle.vesper @@ -37,7 +37,7 @@ TransitionBundle rec globals map len=0..MAX8 aka=GlobalState key is U16 aka=GlobalStateType value list len=1..MAX16 aka=GlobalValues - StateData union + UnverifiedState union static bytes len=0..MAX16 wrapped tag=0 inputs set len=0..MAX16 aka=Inputs Input rec @@ -56,7 +56,12 @@ TransitionBundle rec liquid bytes len=32 wrapped aka=SecretSeal tag=1 state rec State reserved bytes len=1 aka=ReservedBytes1 - data union StateData + verifiable list len=0..4 + Fiel union + m31 is U32 wrapped tag=0 + le64bit is U64 wrapped tag=1 + le128Bit is U128 wrapped tag=2 + unverified union UnverifiedState static bytes len=0..MAX16 wrapped tag=0 some bytes len=32 option wrapped aka=AttachId tag=1 lock bytes len=2 aka=ReservedBytes2 @@ -78,7 +83,12 @@ TransitionBundle rec blinding is U64 state rec State reserved bytes len=1 aka=ReservedBytes1 - data union StateData + verifiable list len=0..4 + Fiel union + m31 is U32 wrapped tag=0 + le64bit is U64 wrapped tag=1 + le128Bit is U128 wrapped tag=2 + unverified union UnverifiedState static bytes len=0..MAX16 wrapped tag=0 some bytes len=32 option wrapped aka=AttachId tag=1 lock bytes len=2 aka=ReservedBytes2 diff --git a/stl/RGBCommit@0.1.0.sta b/stl/RGBCommit@0.1.0.sta index 64e516e4..bac38cd6 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:pRLMM7OS-$w8IXpK-!Jl$Sf4-3SrX$vn-OQi9Uzx-USWTXJY#cake-banjo-legend +Id: stl:7pVCkJVx-to9W$lu-uBNBwdr-ftezpr1-nA4sohY-VZGFoYM#mile-answer-karl Name: RGBCommit Dependencies: StrictTypes#century-comrade-chess, @@ -8,7 +8,7 @@ Dependencies: CommitVerify#miller-pancake-elastic, Std#ralph-blue-lucky, Bitcoin#signal-color-cipher -Check-SHA256: 38b8f23c84e63b75c8821c0af26956c73850df520dff0c6fccc8ee6e09bc437e +Check-SHA256: 2898f3ae42cc861cad1a41fa34cca546adcde10462ec3881da341bc0881315f0 2~tNwLvL+uX>Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI)Q*?4^V{}w`aAk8=6V}(%hjW>8 uUwNXi!t*yd7K}=K!`A`1OPgv%fUznLQq3*a%Ez0HGd)H?<6X>I}lA>%$n Rs>XdX=DsTZ*6U9bXH|@X=Zr^063mQh9?yTI7S;;e;>sZfv!yd427@;7veO2zMB=|GYU;*a%*g5NMUnm ZLh7x^`{^P$fKg#%8c8X#<$(NgM!uni2C|Kr}onZ3R84)X=8LqVRLAc_h5K%L=laq&yA1JoJ^{7>oKLk F4~iax8KK|47hp@Qe|^xa&~28LV0v$b1}=fEj#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RawDWpib6 -c4cHjd30rSGX8=VN#A(BKKz&v`r;e6DUv<<*U}cmb;*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|nr2|;XhOksItaxnt|25f0@b!lV)3_)ykOksItaxqh7bOiwb2?5A!f_n>Eea4Xl -By!~KtpQ8M_qJyiO1VIUJ=H=)@ii_1#@&^bY%gl9|{AI -iBXS>x{dh6%v!mOA{=H?DCT=p%;*%}eo4IqY;R+00(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@O -Cd;@jJLYKfb7gWS-+`&{Sr=ykNJ#YFTr_BQwWqKF0RaedWp-s@Y-MBs1_K0hWnpXqkGsO?N19ILP2yc~ -f4%w>xYW^+v~7{W03rq(;firJ1#@&^bY%gl9|{AIiBXS>x{dh6%v!mOA{=H?DCT=p%;*%}eo4IqY;R+0 +c4cHjd30rSGX8=VN#A(BKKz&v`r;e6DUv<<*U}c1Oi(W05|TJ%PM*ricn_Pm +Xk-Xfd2nS;VQpn=1fvw5rj-B|XP@r^w5ufb=C_Ju$l1`nW&GEpSWb-vQ)O*QWHA5b8F#`bx +Y-w?IX=DKmL2PtPVR>b8F;iu91pxpF0my5Ddkb29#*qXha^)f?kI>J>8dqqbOFybHKpQ-MBLDyZ00000 +0RI300000002D!Ub7^O8LTqVnWK(5fY*ctqbaDg&01RVqZf0p@Wo~q7VQc^f0|awrVQc~0idq_i6cBYN +^7xEELu$lFU37Sf$J;ty5yrmOX|)6eb97;JWdSkXItUWDPa1b66_m&=UTQUHBFIo{dp&(5BcOrA$>;=Z +Z)0l$dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th;=ZZ)0l$dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0ThMdwWnpYocu;h51pxpG0f+wLWmt%8=p4R=gtK{L +Clh6Z#kObxUW*hKHnBv9xdF;IrB0zF{0wB>z!lhp62W>5?QLF`|6_~6PkRTFxZeN(000000093000000 +000<4b8~5DZf#|5baO&%X>MdwWnpYocxhw>0RRdChyLPaScq)s9KMExvw34D6J>+NwrBxfixd_%u|$Wt +0d`KPm{wZ}rN4p~32M*si-000000RI300000000=>JbYWv?Nn`~900#g7 +Kp+4PLSb`dLvL+uX>@I6Zgd6)1!invXLAC210COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUE}_h5K% +L=laq&yA1JoJ^{7>oKLkF4~iax8KK|47hp-b7N>_ZDC1d0hChH+XJhss8OG%_CC-Q>(otsF+cqN0Qy}d +dQ=3E5D9c?ZDn(GVQp{#07wRDb8~fNasqk-9p7nv%krpqNuJC38-{*D7fZ(%hZo23R4S;p`Q9JBQllDytVQh3vVR>b8b1?#X10COKearHwcS=7M7YzYa +I8*bvhMOc?)(rkC#nUEjudT)PryvH%qoUf%jN6#Tx81sfg4O?s`uaep_R|ImLvL<$a$#e1Nn`~900#g7 +Kp+4KMR;^&ZgXjGZUzejW@dH)+M7`mSQb`xkca!3baG*1bV+0Z +p9m~TI>-W|y2ahx3nF|Vuawki#7NH?S|Q-Q!u2{b1#WL{V`TsU2n}U;bY*UHX>V>+d2nR`WOW`wsTH9- +LlJ`2|Ay5Z(?oEikl{+~pis;@Q*TJ#2yJC_VPs)+VFC4eO*mP8`7qV21dnrCyk{{a-lF$FG0V5TNAc?T +c{K-TY;R&=Y;ytJzM83VSJI4l?Dt2BId6-0esDVXkAI9p+)e@WuPPr5ftu@@z<*O39}j`u&O7io3b$Is?RA$O$l~kY-wa+bZ>G3dIKHbX?@G` +sCP;~6&DQwR5(-fxrUo0Th_>4e9YQ#rf -ba;u!+d5tm#=h2RwFCuobYXO50jVDf1CWVPkBhpE_{7Xwxr`zlW>P5TdsEEl6yAPGy##D;V`~C>10COK -earHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%92y$h1 -WnpY(WB>*O1aoC!YypA{4XEgn0epQk*PX+nL>xOm%pK>soMo}bYXO50jVDf1CWVPkBhpE -_{7Xwxr`zlW>P5TdsEEl6yAPGy##D;V`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8 -X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%ML349yXKrm}Zgf<6aAgGn0006RL349yXKrm}Zgg`(Y-w&} -Q)OXnRCrKyas>eZ3IT`y;$>KfZ0H=mhJ>?uVZ*V)X6+0000000030000000000OL349yXKrm}Zgg`(Y-w&}Q)OXnRCsA*1pxpG0f+wL -Wmt%8=p4R=gtK{LClh6Z#kObxUW*hKHnBv9xdA(lIh$*g@T?;tu#}^5p4x8lu;-}qTDb5bYX39002k^X>)URWpV;~10COKearHw -cS=7M7YzYaI8*bvhMOc?)(rkC#nUEjudT)PryvH%qoUf%jN6#Tx81sfg4O?s`uaep_R|IjbY*jNZe?@= -$}AplgPGkh3_fq3Q7_j=2#kPT_9!;lWR>~GYywm#VTK~nd#>D+0ot2U6Id2jc94hrndMfL -ayEe1ISdA&%p{mB1!VWk)e2*8Zgg^CV{}Pm0iOsgNjk^^qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6G6imL -ZewKt00<3bcywiMb7^mGRC#b^0c3R^La7y@JVOzJ)&GXo9MeQ_qmbcB?4VH0I#X{*-Uw}FbYWy+bYTJY -dQCW4e)%xftOSp9TD)g5B;KO;Krzd=y+`rt_<1!4XKZg`VQg~&@lU8jE(OD@jIn+&V5Enw)!?q_7&g|X -@-dvAm{Q*e3t@9}X=iS2Wo~qH0qOIB?vN#-Vw&c`EaZ`bmE6P*s>H+AYtSdOxTqwM0SIzsWMyS-Wn=;0 -ρhviK~w*eJg04e;HYn$=SsX>loIF_owDud_=c42H~ZewX>a{=9jW&m$tWDykZj`7#3_zANbB(SO{ -shhGe=&H{tM@vO> --_DBy8`Vb0jGrW9$=2qSMXvL3HGEG0000000000 -{{R30000002XbX(Wo2!100{v`?dHP>9R0ZFSEMRj;Km4qfBYZ5UUs>0bg9bqiCNA7000000003000000 -0000BVRLh7XKrm}Zgg`13IT`y;$>KfZ0H=mhJ>?uVa{vheM(yUq2ps*m=2xUDT;RqC -gn#@WzFu~@adfH5^@&-|0000000000{{R300000033g#@X=Gt^Z*l+x0ssVVZ*FA(00035b8l^B00jX8 -VsJHoA?4$swuZp1Wc+9AOf`(TIbyKWjTy4WkGaM+ZSSEb;k|42*wg~2q@3^Lq|9zft}OB~jx>)hO7 -4Mli#Wo~n6Z*Ek1aAgGn00065MrL*e0RR932S;UYWpinB1`GpcW_AJEn^6;37FKqUhx?i3R+Mr!fY&(; -2BFL(m@EZk_srD@b7N>_ZDC1d0hChH+XJhss8OG%_CC-Q>(otsF+cqN0Qy}ddQ=3E5CvvzVP|s!dIKHb -X?@G`sCP;~6&DQwR5(-fxrUo0Th~ -Wpi|4ZEyepNCs(hb9H5M0k-IXh8!q$B6|*YuiTY;OURW8#d%1{rxIXtTaY^?oCkDeb98QHbOOpO9&dx0 --7pM3Z=O*v*GCA9fL-<|HrZsA`NnJlR3~AEBGG%U@MZ$v=XJ?|;InIPy66cFfOYp#JM2r7_Du?5Y;;Uv -d1Z2QF##l3QrKmH@SMtOBR5nML?B>%qbz^!%<&Wu0B;HjDvStiWprU=VRT^u^?FS>S$_F2)vN@Mb6UJ- -F(lri_dqerx4lR4>iBsz2WM<=Vqt7^0r5|$LoNlwtBkRJFkqyIt<~VJ=@>TFrt&eIo|sbK2n%6zb7^O8 -ZDnqBa{=k|f$oqcqGFon!7SvFf|cCF4ywe%)@#rww794wkO2vHVQgh?V`*h`0o{dW0B>Pr5ftu@@z<*O -39}j`u&O7io3b$Is?RA$O$l~kY-wa+bZ>G3dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0ThvO>-_DBy -8`Vb0jGrW9$=2qSMXvL3HGEG0000000000{{R30 -000003t@9}X=iS2Wo~qH015$z{^Dg=h-~N_zJ`Red1EINWrM}GXaQb}6c#qIM2EQnHo-KZ`k;Xmr`<4s -JYKN!!u{G5u+^j1lf!PF4>GEG0000000000{{R300000033g#@Wo~0>Wpe-t0Y>fS!w4MxxaL=+DqP^k -2!wz9AHH68xp8!<%Jqp^&Hw-a000000RI3000000010+sY-wa+bZ>G11OfmAZf|a7000011aog~WdH>M -0%CAAe<9`Lptgpr6F_xjAC6(~TLj#*ewiHf`^rCgHqw;r~cW`-Qc;Wd#8M3IWybk`76TvuW{aQ_%-X`?VwZ$5L?~`!+pRSq0(b70UsGkaHMtG~~f>{%bk} -jqU2U-ioF~K?Z%o$(J+YA{RFR0000000030000000000HM{I9mVQf=$VRU6vV`ybC`}q*rYXqYdo~D%m7H6OD0<^0n_2##VWXRdj -y=DB@qgYOj2yJ0_Npxjxa{vGX4@YcoVqt7kbYXO5RC#b^1pxp60t`oNZ(?C=R$**)Wpf1q00;q0Qx7!C -PXFHOo2KrE{Y|r^`i&$e4;$+}oNEKWWM*^$0000000030{{R3000008Nn~YibZK;X1pxpB0s_h`9&dx0 --7pM3Z=O*v*GCA9fL-<|HrZsA`NnJlR3}KjBNr;@ghiU?gEXK9KMDE{F?;HZBRuDVqlk6qmbd^20?I5N -Z-bfLFbqC#o>4E?M+l67UG^w8*<_XZ#%uyqCrG{{7b@t4MVjY>G@u4Q3HlB(d+LiLJm-R=h;`?dxBvhE -000000RImF0000000l{IaCLMB0taw%Wp+<>bODnPynwMZT8l5kSW@l}O=!>^xB4~9n`Dx!RtcK)nwJQ2 -Wpib6c4cG&dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0ThRw7=FYk8VVufK10Q-T=FR= -Q=>S+XYD&vO>-_DBy8`Vb0jGrW9$=2qSMXvL3Hj|@I6Zgd6<17>D+ -0ot2U6Id2jc94hrndMfLayEe1ISdA&%p{mB1!VWk)dg;EZewKt00;(ea8!A4WdT9RTeTEeEoEcZkq99% -9y`(Ly)L1)ktPMRFX-d`h(QQ#WprU=VRT^vdIKHbX?@G`sCP;~6&DQwR5(-fxrUo0ThsZfv!yd427@;7veO2zMB=|GX`mHaCLNZ0(t`--)Viz@~C%8KNS}Z0aQ3s -^SOqbBwN-D{wl@OCODo$h9?yTI7S;;e;>sZfv!yd427@;7veO2zMB=|GYesJb7^O8ZDnqBa{_t;9p7nv -%krpqNWpe_010COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUEjudT)PryvH%qoUf%jN6#T -x81sfg4O?s`uaep_R|IjcWHEPWpi@^dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0ThClv)a -MjKgwAH@`bu1x<7g|G$};xvA~n-$_S33g#@X=Gt^Z*l^910COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC -#nUEjudT)PryvH%qoUf%jN6#Tx81sfg4O?s`uaep_R|IgPjE?O1pxpD002NB00mEQZ*_DA0|IYw0hP$+ -dLDIRU(}XWLTZugenOC;Z(5k~zEJnJiX;;E#R7DB0f+wLWmt%8=p4R=gtK{LClh6Z#kObxUW*hKHnBv9 -xdLu)0006IPj_x*WK(oubY)XxXk~3-1_B6jWpib6c4cG&dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0ThNn`>=>Z4!V_T!KNI`QJ|h6;Zj^jB$M -PK+?7Lu3>C`4HJ_1fvw5rj-B|XP@r^w5ufb=C_Ju$l1`nW&GEpSWb-yQe|XiWo>0-1pxpG0Y>fS!w4Mx -xaL=+DqP^k2!wz9AHH68xp8!<%Jqp^&HwZFzp>JB4@xD;^wu&SY_r(AJ00000 -0093000000000J4V`yboKLkF4~iax8KK|47hp( -ZeeX@0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*;5t>gcQkwbf~^M){{|8P%hsRk~m~ep32F1 -51Y4WWC?U>ZDn(GVQp{#07waBWp-t3Z*XOD0k-IXh8!q$B6|*YuiTY;OURW8#d%1{rxIXtTaY^?oC$4Z -bYWC^aAk7<3ITQGP59r=ivkZ4!V_T!KNI`QJ|h6;Zj^jB$M -PK+?7Lu3>C`4HJ_1fvw5rj-B|XP@r^w5ufb=C_Ju$l1`nW&GEpSWb-q0000000030000000000BXKZg` -VQf@+aAk7<3IWybk`76TvuW{aQ_%-X`?VwZ$5L?~`!+pRSq0(b70Urr5zRxYEK#t?kH-RPfvS1oe0PQO -`VOrdl$-fvv-}wV0000000030000000000AZ+C8GWK?-@Wpe-u0f+wLWmt%8=p4R=gtK{LClh6Z#kObx -UW*hKHnBv9xdBsz+X>O7j~NF%g#J+iq45unJ`5_e64+kv93|H3u2=v7000000093000000000bjVQgh? -V|i40aAk7<2?0j!=EDda{kY~=q$*tC#t4Le{2#tvcDZqMsmk?$P>NY&HCT(P)^FVARS*Zg3m2dUS*m(weL9PhQe$_)hyWq5RDZgXjGZgT(%0c3R^La7y@JVOzJ)&GXo -9MeQ_qmbcB?4VH0I#X{*-T?z>0?er0_e!9%6%WL6o5Q7yVM7GXa@w44CHDB`4cq_#000000093000000 -000Yga$#@6CZgT(%0W?w%t`n9TUcD*&5hFi^PVx{q1b@^7zTcrn*%qZTXaRP$8)%E7`<-;ovk@YS -J+V~kNcmIwC6DJ=V=(On#Ml4;000000093000000000PbWpib6c4cG&dIKHbX?@G`sCP;~6&DQwR5(-f -xrUo0Th;v2Uql0Ev@(iYu*+LHGLwE58<2vcKdWo=Zb7|K94GrtXLRO|zu>jU*-y8|yusYXiSzW^@K&baY{3XaEEP -00eGtZe;)f009JZZ*64&1pxtsaSf9!PV~dK2uo>;u!nFdemP_$e?^hl+JkM;eY!XaQ*>c;Wkg|gVFUpH -26J>_bZKJ%1pxpE002M$0000000030{{R300000ARB~Z%b7^#GZ*B$)17>D+0ot2U6Id2jc94hrndMfL -ayEe1ISdA&%p{mB1!VWk)e2*8Zgg^CV{}Pm0iOsgNjk^^qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6G6imL -ZewKt00<6ra$#@6CZd7@2WdSr&53UoI8eY9A{1GERg--GiI0S#x1is&)M%fmnGH3{GWprU=VRT^u -^?FS>S$_F2)vN@Mb6UJ-F(lri_dqerx4lR4>iBsz2WM<=Vqt7^0r5|$LoNlwtBkRJFkqyIt<~VJ=@>TF -rt&eIo|sbK2nK0xaCLNZ0jZ*TSChz_$|Xx}eRkFNAr%^eLl(1e@}~9=0-ijXfD2)Bb7^O8ZDnqBa{;OS -3~HQXW-oGm^~73C5-+!jGthNMriE}%x)if3>_`cAVQgh?V`*h`0o{dW0B>Pr5ftu@@z<*O39}j`u&O7i -o3b$Is?RA$O$l~kY-wa+bZ>G3dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th$AHP6|FsuXsI;G3ONG`V!CAn^87TS9h9ibhaZ&^Bcn*B*;w|~I;-PD|t>j-IX -aCLM|VQ>KznP+6nwW~k}RP!NmuV?G015$>$mV(; -bz)!CmQ_M(k?Vd!kfCo{nDM?)_qK{868FUc?=1|{x^#*6Zw4O&>qKuQcuX_U9cUaeX|w?en#w1#0RR91 -00000|Nj60000005L9wuZgXjLX>V>*V`ybM?JbaMa- -0f+wLWmt%8=p4R=gtK{LClh6Z#kObxUW*hKHnBv9xdAr8G@<&SffJ|QFn~N>u=2wF+7z(Wqt=tdZk`V^ -s(Ana000000093000000000YNb8~5DZf#|5baMa-0f+wLWmt%8=p4R=gtK{LClh6Z#kObxUW*hKHnBv9 -xdAr8G@<&SffJ|QFn~N>u=2wF+7z(Wqt=tdZk`V^s(Ana000000093000000000SgVQgh?V`*h`00{v` -?dHP>9R0ZFSEMRj;Km4qfBYZ5UUs>0bg9bqiCNA700000000300000000009c42I3WMOn~asUJZ00eGt -Ze;)f009JZZ*64&1pxwLa5aA+<>R2XhQO_4{AcS-HH^7AVzASV8M4NYxyCka@1Z8)ymjIKNK5;L!8Fkf -GTe+FK;UUh9M-4n+}vRfRB~Z%b7^#GZ*Ek1aAgGn0006GRC#b^LvL+uX>@I6Zgd0#00(DfZe??6a{vVa -0eYBoW<;S=hz7(nM>#ZYFDFBsuX37z{Rmhlw67{`z5xn!a$#@6CZU6-W0iOsgNjk^^qPoT1+zTRn -Ag`3vXv9d*8d@RXy~6c6G66JF53UoI8eY9A{1GERg--GiI0S#x1is&)M%fmnGH3z`Wq5RDZgXjGZU6-W -0iOsgNjk^^qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6G67_D9zv-Vp*%wog4O?q)g04AaHEjnO6;Ie%sNwV -NZuM$d2nT9L349yXKr&sY-w&}Q)OXnRCrKyas>eZ2mx*8kYNN3&UdX>dj91(yDQyg{VADB)^$BaZ2p8B -wp0NC000000096000000000?Od2nT9L349yXKr&sY-w&}Q)OXnRCsA*1pxpE0at2fNM5hbe(pA;ULH_< -)qgA={!)0DVov#r-kv=fkpTbz000000RR600000000~xMY-Mg^X=QT-0RRaBM(yUq2ps*m=2xUDT;RqC -gn#@WzFu~@adfH5^@&-|0000000000{{R30000003szxlWo~16RC#b^1pxp60u)$7Xklq?LTqVnWK(5f -Y*ctqbaDg&00&}ebYpL6ZU6-V0#*~&*VKn|nRBmPlPrrd^EP>$AHP6|FsuXsI;G3ONJb~9E>N`F8f<{_ -M@^MEhcVy#omh=bI-rl&{j_4Y)d2=oOFWB>&L0#*~&*VKn|nRBmPlPrrd^EP>$AHP6|FsuXsI;G3O -NJb~9E>N`F8f<{_M@^MEhcVy#omh=bI-rl&{j_4Y)e~4lXklq?LTqVnWK(5fY*ct@WCQ{L2V!Y-V{d70 -00jX8Ruk6O)Q5AKbFW;JEQ>MoHhG*Mzd(pEtONi$rOUxcu*Pw&hI`xNV4B0;>oUbhHyi-Y#=22)QEgSw -gMoHhG*Mzd(pEtONi$rOUxcu*Pw&hI`xNV4B0;>oUbh -Hyi-Y#=22)QEgSwgbW>$vYy<)T2V!Y-V{d7000jX8Ruk6O)Q5AKbFW;JEQ>Mo -HhG*Mzd(pEtONi$rOUxcXc_Cg)w39@m$R6qOEzWQ+NTC@=;MoHhG*Mzd(pEtONi$rOUxcXc_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=FYk -8VaL=Li5Yl(a@n1+Ku60FILp}Zw|!7cE!MGSxid=WmW +0S!fXbY*UHX>V>+d2nR~0RR9314d?c1pxp60t7~BWo!fk0t0O`F#rVt000CK2W(|FG-7FV00jX600X +z_E$1J(MWfObsk*ZoKLkF4~iax8KK|47hp;bZKp6 +b97;CZ~y>E25ED1b!Bn^w&;L{94K`ndk%K5+?9Jv$dw7jc}U5p5@2#$kUJ%u2Xtj~bZ%vI0?I5NZ-bfL +FbqC#o>4E?M+l67UG^w8*<_XZ#%uyqCt-#n(R;4&W&+>mb;*F>vukd;=m`ygb@x#_>`RmOO$uRbbWCA+ +WpZ;d0VG#a*kyq5oXTn=H&hZtAYgo>EPw9I@e~jMZwd)2j0kOIbYWy+bYTJYdQCW4e)%xftOSp9TD)g5 +B;KO;Krzd=y+`rt_<1!4XKZg`VQg~&+`gKraaYoecoKLkF4~iax8KK|47hp=M{I9mVQf=$VRU5$0RRdC)$WoGNrftOUClBuA^-pY000000RI300000001-!Q +Z(?C=Q*>c;Wm98lWo=;w1qgCwb7gXNWn=<+10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUE}_h5K% +L=laq&yA1JoJ^{7>oKLkF4~iax8KK|47hp;W@%+?LvM9%bN~bb00eGtZe;)f009JZZ*64&1pxsVCE!v; +GfWJZ(GL~^sY=yU<|1c(-^pGLfv|DgWgMvmb7gHwWB>#L00eGtZe;)f009JZZ*64&1pxv@>Z4!V_T!KN +I`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HJ_1fvw5rj-B|XP@r^w5ufb=C_Ju$l1`nW&GEpSWb-wVRUq1V`u;b +0ssVVZ*FA(00035b8l^B00jX8$}AplgPGkh3_fq3Q7_j=2#kPT_9!;lWR>~GYywm#VTK~nd#>H;8`88$pKL-FVc;WmI`^Wd#8M00In0Y;R&=Y*t}xb!Bq}0RRXAkB!IuX&}SIZF%0P*XWOUd+slm(OMpG +o&kNWoh~Xw0RR9100000|Nj60000002uWmRZggpMc?AIg1p)%fEFN!zncXl9K5w2;FV{y1jDTJCC^p$- +mHEbO0#qkRz9SbZ=!8X@=Yuq$20sb<4l#S`iz7Vef}@Ca=a#qt2m;D19&dx0-7pM3Z=O*v*GCA9fL-<| +HrZsA`NnJlR3}KjBNr;@ghiU?gEXK9KMDE{F?;HZBRuDVqlk6qmbd@_000000093F00000000F^Zg6#U +1_B3ga%FZ;b#wuf5WIk~G+K)5%bR49t5yk`^qQ9la%FR6a&~280(t`--)Viz@~C%8 +KNS}Z0aQ3s^SOqbBwN-D{wl@OCd;@jJLYKfb7gWS-+`&{Sr=ykNJ#YFTr_BQwWqKF0SHNMaCLM|VQ>Wj +015*2Y!hN5_Bp3Y36tDMM#=e#tGI($UA5U3KNx<*C>jbO<32;hs$B9ZCsU(1!DsC|W1LOd&b_IRG-(&Q +$wPGkmB{9L9(7`0)Rt93YLV-HLXe?vTA1;^Q1`ZqBog<<0RR9100000|Nj600000021#ykb#!wD0RRaB +)s0^W44ZlVN`i=Wd#8M00Ie3 +WprUyVQh6}1pxpE002M$0000000030{{R3000008O=WapWMOn+1pxpG0d?d}_}|Wp0vpvv$c&#PW69R$ +ltr%da5t5w^x+8!q5%{oJdRMsrjHBJ^EIe4enz&iEACnc`NWk%>en!wdoTb1000000093000000000b6 +a6@lxZE19EWo~o^3j=0mb^+R(Q4?4eR(6nw`MZ*F5{000OEZ*Ww3 +aAg5O$Xm4(SS@8^*O3SzF&;b7>AfzYwvi?UvoGl5{)j;cZDn*}WMOn+0(t`--)Viz@~C%8KNS}Z0aQ3s +^SOqbBwN-D{wl@OCT*{+#r3Bk2FRnL+RBXEn8vr=x`Tq%|A_kfK&ST81_x(sZ(?C=a{_t;9p7nv%krpq +N0-0(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCT*{+#r3Bk2FRnL ++RBXEn8vr=x`Tq%|A_kfK&ST81_^dyY-Mg^X=QT)dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0ThsZfv!yd427@;7veO2zMB=|GYNKKY-wa+bZ>G3dIKHbX?@G`sCP;~ +6&DQwR5(-fxrUo0ThV1_J_bZ~>Lb=6W7=VqesjRYGc!>wZFzp>JB4@xD;^wu&SY_r(Hqc>#z1;$>KfZ0H=mhJ>?u +VM0T?CVQbjXN442Ul76PeC)l}vpXMNwvUJZe;aoc4asS!|hVr*$+VRUJ4 +Zc}4uWo=;u0ssYUZ)0I>0000132=2{Y-w|7Wn=&b0R?1baCB$@00Rh8Wn^V#ZDnKy0RRdCM(yUq2ps*m +=2xUDT;RqCgn#@WzFu~@adfH5^@&-|0hP$+dLDIRU(}XWLTZugenOC;Z(5k~zEJnJiX;;E#Q*>R00000 +0RI300000000vWIXk~3-1`h*fW_AJEn^6;37FKqUhx?i3R+Mr!fY&(;2BFL(m@EZk_srD=W^7?+a{_t; +9p7nv%krpqNC`}q*rQx*t>6v={gsJ=SZlTl1iF5eQ8IAl(q%E@>S +o406W33O>~Wpi|4ZEyepNC{+Rc4cgDaAk4Ty +$zBbCuyNaE9H{^R000000093000000000YTY;R&=Y*cx0Wpe-u0oCr34oQf!Y4K`P(FaQVwIle)QgI&p +Ha%8Z1>xis%K;f?RVIK&WT5ZEGjQ^3U_7LY7l^(-n#*_i>9t}KELi{m000000093000000000VacWz~5 +RC#b^a{vkfhyLPaScq)s9KMExvw34D6J>+NwrBxfixd_%u|$Wt0Rqe0dFP<je^}_@?h0l +C#OB3l>&MRmjD0&000000RI300000001S3vY-Mg^c~p6DWpe-t0Y>fS!w4MxxaL=+DqP^k2!wz9AHH68 +xp8!<%Jqp^&Hw-a000000RI300000001#(oZe??6b5>z&X=Gt^Z*l@+a5aA+<>R2XhQO_4{AcS-HH^7A +VzASV8M4NYxyCka@1Z8)ymjIKNK5;L!8FkfGTe+FK;UUh9M-4n+}vRkWq5RDZgXjGZdPGzX=Gt^Z*p@0 +3ISww9zv-Vp*%wog4O?q)g04AaHEjnO6;Ie%sNwVNZtZsa5aA+<>R2XhQO_4{AcS-HH^7AVzASV8M4NY +xyCka@1Z8)ymjIKNK5;L!8FkfGTe+FK;UUh9M-4n+}vRR0000000030000000000KbaG*Cb7^#GZ*Ep$ +Y-wa+bZ>HV015##QV*^ZmKt8YDf|&5KZQ>65I6*X)C9iYp+?yjr7~y&VsJHoA?4$swuZp1Wc+9AOf`(T +IbyKWjTy4WkGaM+ZSSEb;k|42*wg~2q@3^Lq|9zft}OB~jx>)hO70000000000{{R30000008f0Z= +VRdYDRB~Z%b7^#GZ*Ep$Y-wa+bZ>G3VsJHoA?4$swuZp1Wc+9AOf`(TIbyKWjTy4WkGaM+ZSSEb;k +|42*wg~2q@3^Lq|9zft}OB~jx>)hO78DwQR2XhQO_4 +{AcS-HH^7AVzASV8M4NYxyCka@1Z8)ymjIKNK5;L!8FkfGTe+FK;UUh9M-4n+}vRZa%FR6a&~280(t`- +-)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCjNpJN#A(BKKz&v`r;e6DUv<<*U}cc;Wd;NYa%FR6a&~280(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@O +CX@GIcyL4!ji%3ykIV=@3j=0mb^+R(Q4?4eR(6nw`65I6*X)C9iYp+?yjr7~y;ZDn*}WMOn+0rh%KI9Y!AFx9LCk8@hQXE7w+qW3^C +%eTEp@#^?_H3w&GZ(?C=a{=7GnyGPD(u{cQ_eY62Z;N(*a60#oe~d!hP66|;FJlI2Zg6#Ua{;NMdRLRk +o603iZGCpt_aPM;fa{=9jW&m$tWDykZj`7#3_zANbB(SO{shhGe=&H{tM@@6CZbEf#WNc*y0}EqpZ*yf$Wprq7WCB(b*4NaBbD49mT$3z|G4nQgoFBhHh%l@K +06L}1!ALH*5GA>8Wft0d6dj=*oo`t>c$)o5X19O9`rXu=lIsX*Zg6#UO<`~W6`5yb%eAXO2UPPRaj@(( +`=>9Tsh)f38uw_!yYu^q5NmF4cWzX2VQzD2bZKvHa{vkfmB{9L9(7`0)Rt93YLV-HLXe?vTA1;^Q1`Zq +Bog<<0b|ubb8VKaaXCb7^w`1pxtim~&=Cp;L$k#4|@ZG;J>@L!7U2nt=TX +SSGZuDr~+13UqQ|ZgXjLX>V=-1p)z|2rNlD$O59e#ogQsB77jPl+h5j^*S;EG*S<)6P6lY +y(#<=BR_>s@(?%#f7ArN-=Rj?7Ns(10tsb!bY*UHX>V=-1p)z|2rNlD$O59e#ogQsB77jPl+h5j^*S;EWOW`wsTH9-LlJ`2|Ay5Z(?oEikl{+~pis;@Q*TJ#8dQ03Wn@8fb7^O8b3$xsZe&wsVQf@* +P;_zy0RRXAH1}G*X}7wp1%uG6oYy%s57EMih;he;`QJY$OgR)G0RR9100000|Nj60000008B}?2Wn@8f +b7^O8b3$xsZe&wsVQf@*X=DWf00;qqbk&`Rr`Lplt4p1Vn?ce=2QF>~2|d|VrH8;PZxF}<0000000030 +{{R300000FRc>}=a%pC1Wn@!yVRU5#0RRSbbYXO9V*mvK00;m8KmY&$000000RR600000000~xMY-Mg^ +X=QT-0RRaBM(yUq2ps*m=2xUDT;RqCgn#@WzFu~@adfH5^@&-|0000000000{{R30000003szxlWo~16 +RC#b^1pxp60u)$7Xklq?LTqVnWK(5fY*ctqbaDg&00&}ebYpL6ZU6-V0#*~&*VKn|nRBmPlPrrd^EP>$ +AHP6|FsuXsI;G3ONJb~9E>N`F8f<{_M@^MEhcVy#omh=bI-rl&{j_4Y)d2=oOFWB>&L0#*~&*VKn| +nRBmPlPrrd^EP>$AHP6|FsuXsI;G3ONJb~9E>N`F8f<{_M@^MEhcVy#omh=bI-rl&{j_4Y)e~4lXklq? +LTqVnWK(5fY*ct@WCQ{L2V!Y-V{d7000jX8Ruk6O)Q5AKbFW;JEQ>MoHhG*Mzd(pEtONi$rOUxcu*Pw& +hI`xNV4B0;>oUbhHyi-Y#=22)QEgSwgMoHhG*Mzd(pE +tONi$rOUxcu*Pw&hI`xNV4B0;>oUbhHyi-Y#=22)QEgSwgbW>$vYy<)T2V!Y- +V{d7000jX8Ruk6O)Q5AKbFW;JEQ>MoHhG*Mzd(pEtONi$rOUxcXc_Cg)w39@m$R6qOEzWQ+NTC@=;MoHhG*Mzd(pEtONi$rOUxcXc_Cg)w39@m$R6q +OEzWQ+NTC@=;?<6X>I@o0Rr`G6JjIwIj2eqliWu}$@z+_ +xPw?-wb>Rw7=FYk8VaL=Li5Yl(a@n1+Ku60FILp}Zw|!7cE!MGSxid=WmW+OY-w?IX=DHe0Rr`G6JjIw +Ij2eqliWu}$@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 47af5410..9a9a259a 100644 Binary files a/stl/RGBCommit@0.1.0.stl and b/stl/RGBCommit@0.1.0.stl differ diff --git a/stl/RGBCommit@0.1.0.sty b/stl/RGBCommit@0.1.0.sty index 8324aba1..f0232532 100644 --- a/stl/RGBCommit@0.1.0.sty +++ b/stl/RGBCommit@0.1.0.sty @@ -1,5 +1,5 @@ {- - Id: stl:pRLMM7OS-$w8IXpK-!Jl$Sf4-3SrX$vn-OQi9Uzx-USWTXJY#cake-banjo-legend + Id: stl:7pVCkJVx-to9W$lu-uBNBwdr-ftezpr1-nA4sohY-VZGFoYM#mile-answer-karl Name: RGBCommit Version: 0.1.0 Description: Consensus commitment layer for RGB smart contracts @@ -35,6 +35,7 @@ import CommitVerify#miller-pancake-elastic import Std#ralph-blue-lucky use AsciiPrintable#ultra-sunset-format + use U3#burma-travel-diet use Bool#oxygen-complex-duet use AlphaNumLodash#percent-bingo-caesar use AlphaCapsLodash#duet-hammer-labor @@ -103,20 +104,20 @@ data Extension : ffv Ffv , validator CommitVerify.ReservedBytes1 , witness CommitVerify.ReservedBytes2 -@mnemonic(delta-elastic-germany) -data ExtensionSchema : metadata {MetaType ^ ..0xff} - , globals {GlobalStateType -> ^ ..0xff Occurrences} - , redeems {ValencyType ^ ..0xff} - , assignments {AssignmentType -> ^ ..0xff Occurrences} - , valencies {ValencyType ^ ..0xff} - , validator AluVM.LibSite? - @mnemonic(apropos-scoop-viva) data ExtensionType : U16 @mnemonic(pigment-career-hippie) data Ffv : U16 +@mnemonic(baggage-decade-waiter) +data Fiel : m31#2 U32 + | le64bit#16 U64 + | le128Bit U128 + +@mnemonic(ivan-epoxy-macro) +data FielCount : Std.U3 + @mnemonic(reptile-life-sunday) data Genesis : ffv Ffv , schemaId SchemaId @@ -131,26 +132,21 @@ data Genesis : ffv Ffv , valencies Valencies , validator CommitVerify.ReservedBytes1 -@mnemonic(concept-gloria-shock) -data GenesisSchema : metadata {MetaType ^ ..0xff} - , globals {GlobalStateType -> ^ ..0xff Occurrences} - , assignments {AssignmentType -> ^ ..0xff Occurrences} - , valencies {ValencyType ^ ..0xff} - , validator AluVM.LibSite? - @mnemonic(initial-malta-sierra) data GlobalState : {GlobalStateType -> ^ ..0xff GlobalValues} -@mnemonic(silk-college-august) +@mnemonic(gossip-stick-yogurt) data GlobalStateSchema : reserved CommitVerify.ReservedBytes1 - , semId StrictTypes.SemId - , maxItems U24 + , fielCount FielCount? + , semId StrictTypes.SemId? + , attach Std.Bool? + , publication PublicationSchema @mnemonic(yoga-quick-jasmine) data GlobalStateType : U16 -@mnemonic(trinity-jaguar-michael) -data GlobalValues : [StateData ^ 1..] +@mnemonic(chant-plaza-voice) +data GlobalValues : [UnverifiedState ^ 1..] @mnemonic(smart-pioneer-nominal) data Identity : Std.AsciiPrintable, [Std.AsciiPrintable ^ ..0xfff] @@ -173,9 +169,6 @@ data MetaValue : [Byte] @mnemonic(retro-mozart-formal) data Metadata : {MetaType -> ^ ..0xff MetaValue} -@mnemonic(source-olga-mirage) -data Occurrences : min U16, max U16 - @mnemonic(survive-citizen-harris) data OpCommitment : ffv Ffv , nonce U64 @@ -197,38 +190,42 @@ data Opout : op OpId , ty AssignmentType , no U16 -@mnemonic(cover-shampoo-weather) -data OwnedStateSchema : reserved CommitVerify.ReservedBytes1, semId StrictTypes.SemId +@mnemonic(pacific-depend-vision) +data OwnedStateSchema : reserved CommitVerify.ReservedBytes1, fielCount FielCount? + +@mnemonic(hobby-cola-betty) +data PublicationSchema : local () + | published depth U24 @mnemonic(anita-vega-pirate) data Redeemed : {ValencyType -> ^ ..0xff OpId} -@mnemonic(corona-igloo-sierra) +@mnemonic(strange-quality-menu) data Schema : ffv Ffv , flags CommitVerify.ReservedBytes1 , name StrictTypes.TypeName , timestamp I64 , developer Identity - , metaTypes {MetaType -> ^ ..0xff StrictTypes.SemId} + , metaTypes {MetaType -> ^ ..0xff FielCount} , globalTypes {GlobalStateType -> ^ ..0xff GlobalStateSchema} , ownedTypes {AssignmentType -> ^ ..0xff OwnedStateSchema} , valencyTypes {ValencyType ^ ..0xff} - , genesis GenesisSchema - , extensions {ExtensionType -> ^ ..0xff ExtensionSchema} - , transitions {TransitionType -> ^ ..0xff TransitionSchema} + , genesisValidator AluVM.LibSite + , extensionValidators {ExtensionType -> ^ ..0xff AluVM.LibSite} + , transitionValidators {TransitionType -> ^ ..0xff AluVM.LibSite} + , defaultTransitionValidator AluVM.LibSite + , defaultExtensionValidator AluVM.LibSite , reserved CommitVerify.ReservedBytes8 @mnemonic(ramirez-patron-simon) data SchemaId : [Byte ^ 32] -@mnemonic(logo-plato-shadow) +@mnemonic(fabric-million-cobalt) data State : reserved CommitVerify.ReservedBytes1 - , data StateData + , verifiable [Fiel ^ ..0x4] + , unverified UnverifiedState , attach AttachId? -@mnemonic(pasta-pardon-hazard) -data StateData : static [Byte] | (|) - @mnemonic(michael-exact-eric) data Transition : ffv Ffv , contractId ContractId @@ -247,14 +244,6 @@ data TransitionBundle : closeMethod BPCore.Method , inputMap InputMap , knownTransitions {OpId -> ^ 1.. Transition} -@mnemonic(pirate-lithium-side) -data TransitionSchema : metadata {MetaType ^ ..0xff} - , globals {GlobalStateType -> ^ ..0xff Occurrences} - , inputs {AssignmentType -> ^ ..0xff Occurrences} - , assignments {AssignmentType -> ^ ..0xff Occurrences} - , valencies {ValencyType ^ ..0xff} - , validator AluVM.LibSite? - @mnemonic(picture-reflex-brigade) data TransitionType : U16 @@ -269,6 +258,9 @@ data TypedAssignsBlindSealTxPtr : [AssignBlindSealTxPtr ^ 1..] @mnemonic(anita-galaxy-orca) data TypedAssignsBlindSealTxid : [AssignBlindSealTxid ^ 1..] +@mnemonic(aztec-saga-isabel) +data UnverifiedState : static [Byte] + @mnemonic(shock-jester-orion) data Valencies : {ValencyType ^ ..0xff} diff --git a/stl/RGBLogic@0.1.0.sta b/stl/RGBLogic@0.1.0.sta index 4a748dd6..7fa8c92d 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:rBp7sjZK-WyD4iXW-itLfRey-JguuaFA-ACsLvk2-$P6V0ok#rose-match-almanac +Id: stl:uIWSFM4g-fc20tku-5jM9yK7-yNiSbHe-QMoaD3k-7YZY2wI#ivan-erosion-warning Name: RGBLogic Dependencies: BPCore#austin-story-retro, - RGBCommit#cake-banjo-legend, + RGBCommit#mile-answer-karl, Bitcoin#signal-color-cipher -Check-SHA256: 878b8ed79e2291594001dc3718f479c05682897cb829b6ad263d44d6f83088b8 +Check-SHA256: 8d193ea916808898942603ff4fc8162f579474f1e5ff1ad030991c392ca3908b -2vSEvOmAmtV*^$b*4NaBbD49mT$3z|G4nQgoFBhHh%l@K06L}1!AJ%|P(yEWWu+3#GqaNa4+vh8z9wJN -e~r?ufA5^+BK1u1Q6-aHmI+cvLPKwDZE1A%Y!hN5_Bp3Y36tDMM#=e#tGI($UA5U3KNx<*C>ja}LTPkk +2vSEvOmAmtV*^$b*4NaBbD49mT$3z|G4nQgoFBhHh%l@K06L}1!AJ%|P(yEWW$u+ikd<+^k5>L$t_09< +cDL<&I&0Q&II@UXRgs0Eg9%bcLPKwDZE1A%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#( @@ -24,15 +24,15 @@ iRT*14O40w5C%+Pd1Z1jmB{9L9(7`0)Rt93YLV-HLXe?vTA1;^Q1`ZqBog<<1W#~DWCZ{SL}Fu5a&K>D n*!v8^Ea7rh?dzC2n+%RZ*X#DbN~eb0#*~&*VKn|nRBmPlPrrd^EP>$AHP6|FsuXsI;G3ONJmc3T+rxD K6vW;JU&?LxLM72H?wDC1Zo}=N}D)4mkCE~Z(?C=PjX}i0tIhyPjX}d{&9|4h)I8ST&b@+9Xb<*p%rmo+{|^XWlD;Ni(tnN8t$**F@6CZU6=Z -2X|?7Ze??G0dl)S$QV;yG0%+u`Lqfm#|FpRuujhTP8r)T_J?np;R1Ad0;LknGqaNa4+vh8z9wJNe~r?u -fA5^+BK1u1Q6-aHmNZfit`n9TUcD*&5hFi^PVx{q1b@^7zTcrn*%qZTXa#O>ZewKt00;zcaA{-$r4r0D -vy%T02wsxDCSTHjjnb`u@0{c!^-S?mC6ip1mB{9L9(7`0)Rt93YLV-HLXe?vTA1;^Q1`ZqBog<<3Rh`# +LdY0XT`|v$|M|2EBF6^D+OST}`A!+zFZPFTn&AR;c>?a0LXeelwvSf+TdoAqaCW!tdpc{@a5%DvSXGgQ +p@U>~9zv-Vp*%wog4O?q)g04AaHEjnO6;Ie%sNwVNZti*Z*F5{000OCZ*Xa30`8SUkd<+^k5>L$t_09< +cDL<&I&0Q&II@UXRgs0EgO$kUdLDIRU(}XWLTZugenOC;Z(5k~zEJnJiX;;E#s3O)a$#@6CZU6=Z +2X|?7Ze??G0dl)S$QV;yG0%+u`Lqfm#|FpRuujhTP8r)T_J?np;R1Ad0`8SUkd<+^k5>L$t_09ZewKt00;zcaA{-$?v+B2 +m2tL@R{mSA1kiAHx9xj6Yu0c$vWQq!k%ggymB{9L9(7`0)Rt93YLV-HLXe?vTA1;^Q1`ZqBog<<3Rh`# Ze??GPjX}g0{{qNa${&|c4cG$00036ZE0?0WB>&L0bJY;BNZ=sBHM?<`J6+Fr=ADb5bYX39002k +5&{WyWo~p~bZK^F0000AS7~%^Wpi^-Z*v9%25ez@WpXhB?v+B2m2tL@R{mSA1kiAHx9xj6Yu0c$vWQq! +k%ggydBoUB2y8Zom7+;NN8Xgkb3WeV)QDb*=NiflQ)(Iz254nzXJ~W)00aqiX>Db5bYX39002k -----END STRICT TYPE LIB----- diff --git a/stl/RGBLogic@0.1.0.stl b/stl/RGBLogic@0.1.0.stl index 9c71494e..f72e13c6 100644 Binary files a/stl/RGBLogic@0.1.0.stl and b/stl/RGBLogic@0.1.0.stl differ diff --git a/stl/RGBLogic@0.1.0.sty b/stl/RGBLogic@0.1.0.sty index bcfdee67..1edd0169 100644 --- a/stl/RGBLogic@0.1.0.sty +++ b/stl/RGBLogic@0.1.0.sty @@ -1,5 +1,5 @@ {- - Id: stl:rBp7sjZK-WyD4iXW-itLfRey-JguuaFA-ACsLvk2-$P6V0ok#rose-match-almanac + Id: stl:uIWSFM4g-fc20tku-5jM9yK7-yNiSbHe-QMoaD3k-7YZY2wI#ivan-erosion-warning Name: RGBLogic Version: 0.1.0 Description: Consensus logic layer for RGB smart contracts @@ -18,7 +18,7 @@ import BPCore#austin-story-retro use TapretRightBranch#miracle-patriot-touch use OpretProof#good-village-flex -import RGBCommit#cake-banjo-legend +import RGBCommit#mile-answer-karl use TransitionType#picture-reflex-brigade use ExtensionType#apropos-scoop-viva use Layer1#camilla-basket-justin diff --git a/stl/Schema.vesper b/stl/Schema.vesper index de44582c..040c1743 100644 --- a/stl/Schema.vesper +++ b/stl/Schema.vesper @@ -7,15 +7,15 @@ Schema vesper lexicon=types+commitments -SchemaId commitment hasher=SHA256 tagged=urn:lnp-bp:rgb:schema#2024-02-03 +SchemaId commitment hasher=SHA256 tagged=urn:lnp-bp:rgb:schema#2024-10-23 Ffv serialized ReservedBytes1 serialized TypeName serialized I64 serialized Identity serialized - SemId map len=0..MAX8 + FielCount map len=0..MAX8 MetaType mapKey - SemId mapValue + FielCount mapValue GlobalStateSchema map len=0..MAX8 GlobalStateType mapKey GlobalStateSchema mapValue @@ -24,13 +24,13 @@ SchemaId commitment hasher=SHA256 tagged=urn:lnp-bp:rgb:schema#2024-02-03 OwnedStateSchema mapValue ValencyType set len=0..MAX8 ValencyType element - GenesisSchema serialized - ExtensionSchema map len=0..MAX8 + LibSite serialized + LibSite map len=0..MAX8 ExtensionType mapKey - ExtensionSchema mapValue - TransitionSchema map len=0..MAX8 + LibSite mapValue + LibSite map len=0..MAX8 TransitionType mapKey - TransitionSchema mapValue + LibSite mapValue ReservedBytes8 serialized Schema rec @@ -41,83 +41,51 @@ Schema rec developer ascii aka=Identity first=AsciiPrintable rest=AsciiPrintable len=1..4096 metaTypes map len=0..MAX8 key is U16 aka=MetaType - value bytes len=32 aka=SemId + value enum { + U3 aka=FielCount _0=0 _1=1 _2=2 _3=3 _4=4 _5=5 _6=6 + _7=7 + } globalTypes map len=0..MAX8 key is U16 aka=GlobalStateType value rec GlobalStateSchema reserved bytes len=1 aka=ReservedBytes1 - semId bytes len=32 aka=SemId - maxItems is U24 + some enum { + U3 option wrapped aka=FielCount _0=0 _1=1 _2=2 _3=3 _4=4 + _5=5 _6=6 _7=7 tag=1 + } + some bytes len=32 option wrapped aka=SemId tag=1 + some enum Bool option wrapped false=0 true=1 tag=1 + publication union PublicationSchema + local is Unit tag=0 + published rec tag=1 + depth is U24 ownedTypes map len=0..MAX8 key is U16 aka=AssignmentType value rec OwnedStateSchema reserved bytes len=1 aka=ReservedBytes1 - semId bytes len=32 aka=SemId + some enum { + U3 option wrapped aka=FielCount _0=0 _1=1 _2=2 _3=3 _4=4 + _5=5 _6=6 _7=7 tag=1 + } valencyTypes set len=0..MAX8 element is U16 aka=ValencyType - genesis rec GenesisSchema - metadata set len=0..MAX8 - element is U16 aka=MetaType - globals map len=0..MAX8 - key is U16 aka=GlobalStateType - value rec Occurrences - min is U16 - max is U16 - assignments map len=0..MAX8 - key is U16 aka=AssignmentType - value rec Occurrences - min is U16 - max is U16 - valencies set len=0..MAX8 - element is U16 aka=ValencyType - some rec LibSite option wrapped tag=1 - lib bytes len=32 aka=LibId - pos is U16 - extensions map len=0..MAX8 + genesisValidator rec LibSite + lib bytes len=32 aka=LibId + pos is U16 + extensionValidators map len=0..MAX8 key is U16 aka=ExtensionType - value rec ExtensionSchema - metadata set len=0..MAX8 - element is U16 aka=MetaType - globals map len=0..MAX8 - key is U16 aka=GlobalStateType - value rec Occurrences - min is U16 - max is U16 - redeems set len=0..MAX8 - element is U16 aka=ValencyType - assignments map len=0..MAX8 - key is U16 aka=AssignmentType - value rec Occurrences - min is U16 - max is U16 - valencies set len=0..MAX8 - element is U16 aka=ValencyType - some rec LibSite option wrapped tag=1 - lib bytes len=32 aka=LibId - pos is U16 - transitions map len=0..MAX8 + value rec LibSite + lib bytes len=32 aka=LibId + pos is U16 + transitionValidators map len=0..MAX8 key is U16 aka=TransitionType - value rec TransitionSchema - metadata set len=0..MAX8 - element is U16 aka=MetaType - globals map len=0..MAX8 - key is U16 aka=GlobalStateType - value rec Occurrences - min is U16 - max is U16 - inputs map len=0..MAX8 - key is U16 aka=AssignmentType - value rec Occurrences - min is U16 - max is U16 - assignments map len=0..MAX8 - key is U16 aka=AssignmentType - value rec Occurrences - min is U16 - max is U16 - valencies set len=0..MAX8 - element is U16 aka=ValencyType - some rec LibSite option wrapped tag=1 - lib bytes len=32 aka=LibId - pos is U16 + value rec LibSite + lib bytes len=32 aka=LibId + pos is U16 + defaultTransitionValidator rec LibSite + lib bytes len=32 aka=LibId + pos is U16 + defaultExtensionValidator rec LibSite + lib bytes len=32 aka=LibId + pos is U16 diff --git a/stl/Transition.vesper b/stl/Transition.vesper index d65ff77b..ff295379 100644 --- a/stl/Transition.vesper +++ b/stl/Transition.vesper @@ -47,7 +47,7 @@ Transition rec globals map len=0..MAX8 aka=GlobalState key is U16 aka=GlobalStateType value list len=1..MAX16 aka=GlobalValues - StateData union + UnverifiedState union static bytes len=0..MAX16 wrapped tag=0 inputs set len=0..MAX16 aka=Inputs Input rec @@ -66,7 +66,12 @@ Transition rec liquid bytes len=32 wrapped aka=SecretSeal tag=1 state rec State reserved bytes len=1 aka=ReservedBytes1 - data union StateData + verifiable list len=0..4 + Fiel union + m31 is U32 wrapped tag=0 + le64bit is U64 wrapped tag=1 + le128Bit is U128 wrapped tag=2 + unverified union UnverifiedState static bytes len=0..MAX16 wrapped tag=0 some bytes len=32 option wrapped aka=AttachId tag=1 lock bytes len=2 aka=ReservedBytes2 @@ -88,7 +93,12 @@ Transition rec blinding is U64 state rec State reserved bytes len=1 aka=ReservedBytes1 - data union StateData + verifiable list len=0..4 + Fiel union + m31 is U32 wrapped tag=0 + le64bit is U64 wrapped tag=1 + le128Bit is U128 wrapped tag=2 + unverified union UnverifiedState static bytes len=0..MAX16 wrapped tag=0 some bytes len=32 option wrapped aka=AttachId tag=1 lock bytes len=2 aka=ReservedBytes2