Skip to content

Commit

Permalink
epic: abstract script and type libraries out of consensus structures
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Mar 13, 2024
1 parent 2e01d87 commit e3966db
Show file tree
Hide file tree
Showing 18 changed files with 674 additions and 865 deletions.
12 changes: 7 additions & 5 deletions src/schema/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ use amplify::{ByteArray, Bytes32};
use armor::StrictArmor;
use baid58::{Baid58ParseError, Chunking, FromBaid58, ToBaid58, CHUNKING_32};
use commit_verify::{CommitEncode, CommitEngine, CommitId, CommitmentId, DigestExt, Sha256};
use strict_encoding::{StrictDecode, StrictDeserialize, StrictEncode, StrictSerialize, StrictType};
use strict_encoding::{
StrictDecode, StrictDeserialize, StrictDumb, StrictEncode, StrictSerialize, StrictType,
};

use super::{
AssignmentType, ExtensionSchema, GenesisSchema, Script, StateSchema, TransitionSchema,
Expand Down Expand Up @@ -141,7 +143,7 @@ impl SchemaId {
pub fn to_mnemonic(&self) -> String { self.to_baid58().mnemonic() }
}

pub trait SchemaRoot: Clone + Eq + StrictType + StrictEncode + StrictDecode + Default {
pub trait SchemaRoot: Clone + Eq + StrictType + StrictEncode + StrictDecode + StrictDumb {
fn schema_id(&self) -> SchemaId;
}
impl SchemaRoot for () {
Expand All @@ -153,8 +155,8 @@ impl SchemaRoot for RootSchema {
pub type RootSchema = Schema<()>;
pub type SubSchema = Schema<RootSchema>;

#[derive(Clone, Eq, Default, Debug)]
#[derive(StrictType, StrictEncode, StrictDecode)]
#[derive(Clone, Eq, Debug)]

Check warning on line 158 in src/schema/schema.rs

View check run for this annotation

Codecov / codecov/patch

src/schema/schema.rs#L158

Added line #L158 was not covered by tests
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB)]
#[cfg_attr(
feature = "serde",
Expand Down Expand Up @@ -194,7 +196,7 @@ impl<Root: SchemaRoot> CommitEncode for Schema<Root> {
e.commit_to_map(&self.extensions);
e.commit_to_map(&self.transitions);

e.commit_to_serialized(&self.types.id());
e.commit_to_serialized(&*self.types);

Check warning on line 199 in src/schema/schema.rs

View check run for this annotation

Codecov / codecov/patch

src/schema/schema.rs#L199

Added line #L199 was not covered by tests
e.commit_to_serialized(&self.script);
}
}
Expand Down
56 changes: 12 additions & 44 deletions src/schema/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
use std::ops::Deref;

use strict_types::TypeSystem;
use strict_types::TypeSysId;

use crate::vm::AluScript;
use crate::LIB_NAME_RGB;
Expand Down Expand Up @@ -83,16 +83,21 @@ impl Script {

/// Types used by a schema and virtual machine
#[derive(Clone, Eq, PartialEq, Debug, From)]
#[derive(StrictType, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB, tags = custom)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB, tags = custom, dumb = Self::Strict(strict_dumb!()))]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),

Check warning on line 90 in src/schema/script.rs

View check run for this annotation

Codecov / codecov/patch

src/schema/script.rs#L90

Added line #L90 was not covered by tests
serde(crate = "serde_crate", rename_all = "camelCase", tag = "type")
)]
pub enum Types {
#[from]
#[strict_type(tag = 0x01)]
Strict(TypeSystem),
Strict(TypeSysId),
}

impl Deref for Types {
type Target = TypeSystem;
type Target = TypeSysId;

fn deref(&self) -> &Self::Target {
match self {
Expand All @@ -101,47 +106,10 @@ impl Deref for Types {
}
}

impl Default for Types {
fn default() -> Self { Types::Strict(none!()) }
}

impl Types {
pub fn as_strict(&self) -> &TypeSystem {
pub fn as_strict(&self) -> &TypeSysId {

Check warning on line 110 in src/schema/script.rs

View check run for this annotation

Codecov / codecov/patch

src/schema/script.rs#L110

Added line #L110 was not covered by tests
match self {
Types::Strict(ts) => ts,
}
}
}

#[cfg(feature = "serde")]
mod _serde {
use armor::AsciiArmor;
use serde_crate::de::Error;
use serde_crate::{Deserialize, Deserializer, Serialize, Serializer};

use super::*;

impl Serialize for Types {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {
if serializer.is_human_readable() {
serializer.serialize_str(&self.as_strict().to_ascii_armored_string())
} else {
self.as_strict().serialize(serializer)
}
}
}

impl<'de> Deserialize<'de> for Types {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de> {
if deserializer.is_human_readable() {
let s = String::deserialize(deserializer)?;
let sys = TypeSystem::from_ascii_armored_str(&s).map_err(D::Error::custom)?;
Ok(Types::Strict(sys))
} else {
Ok(Types::Strict(TypeSystem::deserialize(deserializer)?))
}
Types::Strict(id) => id,

Check warning on line 112 in src/schema/script.rs

View check run for this annotation

Codecov / codecov/patch

src/schema/script.rs#L112

Added line #L112 was not covered by tests
}
}
}
2 changes: 1 addition & 1 deletion src/stl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use crate::{

/// Strict types id for the library providing data types for RGB consensus.
pub const LIB_ID_RGB: &str =
"urn:ubideco:stl:6NAFZspAZ14Y1NynHeQBJVNqep4arKkKx8zchhHrESvr#airport-border-match";
"urn:ubideco:stl:2YLR1EqJCDGB97JAD22mTwNdg6Gpbzi8PwkGKE6UsDx8#hotel-comet-grand";

fn _rgb_core_stl() -> Result<TypeLib, CompileError> {
LibBuilder::new(libname!(LIB_NAME_RGB), tiny_bset! {
Expand Down
27 changes: 26 additions & 1 deletion src/validation/consignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@
use std::collections::{BTreeMap, BTreeSet};
use std::rc::Rc;

use aluvm::isa::Instr;
use aluvm::library::LibId;
use aluvm::Program;
use strict_types::{TypeSysId, TypeSystem};

use crate::vm::RgbIsa;
use crate::{
AnchoredBundle, AssetTag, AssignmentType, BundleId, Genesis, OpId, OpRef, Operation,
SecretSeal, SubSchema, WitnessId, XChain,
Expand All @@ -40,6 +46,7 @@ impl<'consignment, C: ConsignmentApi> CheckedConsignment<'consignment, C> {

impl<'consignment, C: ConsignmentApi> ConsignmentApi for CheckedConsignment<'consignment, C> {
type Iter<'placeholder> = C::Iter<'placeholder>;
type Program = C::Program;

fn schema(&self) -> &SubSchema { self.0.schema() }

Expand All @@ -62,6 +69,15 @@ impl<'consignment, C: ConsignmentApi> ConsignmentApi for CheckedConsignment<'con
}

fn op_witness_id(&self, opid: OpId) -> Option<WitnessId> { self.0.op_witness_id(opid) }

fn program<'a>(
&self,
libs: impl IntoIterator<Item = &'a LibId>,
) -> Result<&Self::Program, LibId> {
self.0.program(libs)
}

Check warning on line 78 in src/validation/consignment.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/consignment.rs#L73-L78

Added lines #L73 - L78 were not covered by tests

fn type_system(&self, id: TypeSysId) -> Option<&TypeSystem> { self.0.type_system(id) }

Check warning on line 80 in src/validation/consignment.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/consignment.rs#L80

Added line #L80 was not covered by tests
}

/// Trait defining common data access API for all storage-related RGB structures
Expand All @@ -75,13 +91,15 @@ pub trait ConsignmentApi {
/// Iterator for all bundle ids present in the consignment.
type Iter<'a>: Iterator<Item = BundleId>;

type Program: Program<Isa = Instr<RgbIsa>>;

/// Returns reference to the schema object used by the consignment.
fn schema(&self) -> &SubSchema;

/// Asset tags uses in the confidential asset validation.
fn asset_tags(&self) -> &BTreeMap<AssignmentType, AssetTag>;

/// Retrieves reference to a operation (genesis, state transition or state
/// Retrieves reference to an operation (genesis, state transition or state
/// extension) matching the provided id, or `None` otherwise
fn operation(&self, opid: OpId) -> Option<OpRef>;

Expand All @@ -107,4 +125,11 @@ pub trait ConsignmentApi {

/// Returns witness id for a given operation.
fn op_witness_id(&self, opid: OpId) -> Option<WitnessId>;

fn program<'a>(
&self,
libs: impl IntoIterator<Item = &'a LibId>,
) -> Result<&Self::Program, LibId>;

fn type_system(&self, id: TypeSysId) -> Option<&TypeSystem>;
}
51 changes: 29 additions & 22 deletions src/validation/logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ use std::collections::{BTreeMap, BTreeSet};

use amplify::confinement::{Confined, SmallBlob};
use amplify::Wrapper;
use strict_types::SemId;
use strict_types::{SemId, TypeSystem};

use crate::schema::{AssignmentsSchema, GlobalSchema, ValencySchema};
use crate::validation::{CheckedConsignment, ConsignmentApi, VirtualMachine};
use crate::validation::{CheckedConsignment, ConsignmentApi, Failure, VirtualMachine};
use crate::{
validation, AssetTag, AssignmentType, Assignments, AssignmentsRef, ContractId, ExposedSeal,
GlobalState, GlobalStateSchema, GlobalValues, GraphSeal, Inputs, OpFullType, OpId, OpRef,
Expand Down Expand Up @@ -135,10 +135,16 @@ impl<Root: SchemaRoot> Schema<Root> {

let mut status = validation::Status::new();

let sys_id = *consignment.schema().types;
let Some(type_sys) = consignment.type_system(sys_id) else {
status.add_failure(Failure::TypesAbsent(sys_id));
return status;

Check warning on line 141 in src/validation/logic.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/logic.rs#L138-L141

Added lines #L138 - L141 were not covered by tests
};

// Validate type system
status += self.validate_type_system();
status += self.validate_metadata(id, *metadata_schema, op.metadata());
status += self.validate_global_state(id, op.globals(), global_schema);
status += self.validate_metadata(id, type_sys, *metadata_schema, op.metadata());
status += self.validate_global_state(id, type_sys, op.globals(), global_schema);

Check warning on line 147 in src/validation/logic.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/logic.rs#L146-L147

Added lines #L146 - L147 were not covered by tests
let prev_state = if let OpRef::Transition(transition) = op {
let prev_state = extract_prev_state(consignment, id, &transition.inputs, &mut status);
status += self.validate_prev_state(id, &prev_state, owned_schema);
Expand All @@ -155,10 +161,10 @@ impl<Root: SchemaRoot> Schema<Root> {
}
status += match op.assignments() {
AssignmentsRef::Genesis(assignments) => {
self.validate_owned_state(id, assignments, assign_schema)
self.validate_owned_state(id, type_sys, assignments, assign_schema)

Check warning on line 164 in src/validation/logic.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/logic.rs#L164

Added line #L164 was not covered by tests
}
AssignmentsRef::Graph(assignments) => {
self.validate_owned_state(id, assignments, assign_schema)
self.validate_owned_state(id, type_sys, assignments, assign_schema)

Check warning on line 167 in src/validation/logic.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/logic.rs#L167

Added line #L167 was not covered by tests
}
};

Expand Down Expand Up @@ -196,13 +202,13 @@ impl<Root: SchemaRoot> Schema<Root> {
fn validate_metadata(
&self,
opid: OpId,
type_sys: &TypeSystem,

Check warning on line 205 in src/validation/logic.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/logic.rs#L205

Added line #L205 was not covered by tests
sem_id: SemId,
metadata: &SmallBlob,
) -> validation::Status {
let mut status = validation::Status::new();

if self
.types
if type_sys

Check warning on line 211 in src/validation/logic.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/logic.rs#L211

Added line #L211 was not covered by tests
.strict_deserialize_type(sem_id, metadata.as_ref())
.is_err()
{
Expand All @@ -215,6 +221,7 @@ impl<Root: SchemaRoot> Schema<Root> {
fn validate_global_state(
&self,
opid: OpId,
type_sys: &TypeSystem,

Check warning on line 224 in src/validation/logic.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/logic.rs#L224

Added line #L224 was not covered by tests
global: &GlobalState,
global_schema: &GlobalSchema,
) -> validation::Status {
Expand Down Expand Up @@ -258,8 +265,7 @@ impl<Root: SchemaRoot> Schema<Root> {

// Validating data types
for data in set {
if self
.types
if type_sys

Check warning on line 268 in src/validation/logic.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/logic.rs#L268

Added line #L268 was not covered by tests
.strict_deserialize_type(*sem_id, data.value.as_ref())
.is_err()
{
Expand Down Expand Up @@ -334,6 +340,7 @@ impl<Root: SchemaRoot> Schema<Root> {
fn validate_owned_state<Seal: ExposedSeal>(
&self,
id: OpId,
type_sys: &TypeSystem,

Check warning on line 343 in src/validation/logic.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/logic.rs#L343

Added line #L343 was not covered by tests
owned_state: &Assignments<Seal>,
assign_schema: &AssignmentsSchema,
) -> validation::Status {
Expand Down Expand Up @@ -370,18 +377,18 @@ impl<Root: SchemaRoot> Schema<Root> {

match owned_state.get(state_id) {
None => {}
Some(TypedAssigns::Declarative(set)) => set.iter().for_each(|data| {
status += assignment.validate(&self.types, &id, *state_id, data)
}),
Some(TypedAssigns::Fungible(set)) => set.iter().for_each(|data| {
status += assignment.validate(&self.types, &id, *state_id, data)
}),
Some(TypedAssigns::Structured(set)) => set.iter().for_each(|data| {
status += assignment.validate(&self.types, &id, *state_id, data)
}),
Some(TypedAssigns::Attachment(set)) => set.iter().for_each(|data| {
status += assignment.validate(&self.types, &id, *state_id, data)
}),
Some(TypedAssigns::Declarative(set)) => set
.iter()
.for_each(|data| status += assignment.validate(type_sys, &id, *state_id, data)),
Some(TypedAssigns::Fungible(set)) => set
.iter()
.for_each(|data| status += assignment.validate(type_sys, &id, *state_id, data)),
Some(TypedAssigns::Structured(set)) => set
.iter()
.for_each(|data| status += assignment.validate(type_sys, &id, *state_id, data)),
Some(TypedAssigns::Attachment(set)) => set
.iter()
.for_each(|data| status += assignment.validate(type_sys, &id, *state_id, data)),

Check warning on line 391 in src/validation/logic.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/logic.rs#L380-L391

Added lines #L380 - L391 were not covered by tests
};
}

Expand Down
27 changes: 1 addition & 26 deletions src/validation/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
// limitations under the License.

use crate::validation::Status;
use crate::{validation, OpFullType, OpSchema, Schema, StateSchema, SubSchema, TransitionType};
use crate::{validation, OpFullType, OpSchema, Schema, SubSchema, TransitionType};

impl SubSchema {
pub fn verify(&self) -> validation::Status {
Expand Down Expand Up @@ -52,37 +52,12 @@ impl SubSchema {
status.add_failure(validation::Failure::SchemaBlankTransitionRedefined);
}

for (type_id, schema) in &self.global_types {
if !self.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 let StateSchema::Structured(sem_id) = schema {
if !self.types.contains_key(sem_id) {
status.add_failure(validation::Failure::SchemaOwnedSemIdUnknown(
*type_id, *sem_id,
));
}
}
}

status
}

fn verify_operation(&self, op_type: OpFullType, schema: &impl OpSchema) -> Status {
let mut status = validation::Status::new();

if !self.types.contains_key(&schema.metadata()) {
status.add_failure(validation::Failure::SchemaOpMetaSemIdUnknown(
op_type,
schema.metadata(),
));
}
if matches!(schema.inputs(), Some(inputs) if inputs.is_empty()) {
status.add_failure(validation::Failure::SchemaOpEmptyInputs(op_type));
}
Expand Down
17 changes: 6 additions & 11 deletions src/validation/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use aluvm::isa::Instr;
use aluvm::Program;

use crate::validation;
use crate::validation::OpInfo;
use crate::vm::AluRuntime;
use crate::{validation, Script};
use crate::vm::{AluRuntime, RgbIsa};

/// Trait for concrete types wrapping virtual machines to be used from inside
/// RGB schema validation routines.
Expand All @@ -32,15 +35,7 @@ pub trait VirtualMachine {
fn validate(&self, info: OpInfo) -> Result<(), validation::Failure>;
}

impl VirtualMachine for Script {
fn validate(&self, info: OpInfo) -> Result<(), validation::Failure> {
match self {
Script::AluVM(script) => AluRuntime::new(script).validate(info),
}
}
}

impl<'script> VirtualMachine for AluRuntime<'script> {
impl<'consignment, P: Program<Isa = Instr<RgbIsa>>> VirtualMachine for AluRuntime<'consignment, P> {
fn validate(&self, info: OpInfo) -> Result<(), validation::Failure> {
let id = info.id;
self.run_validations(&info)
Expand Down
Loading

0 comments on commit e3966db

Please sign in to comment.