Skip to content

Commit

Permalink
validation: validate (& compute contract state) all operations in order
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Jul 29, 2024
1 parent 76970a7 commit e4e773e
Show file tree
Hide file tree
Showing 13 changed files with 264 additions and 218 deletions.
4 changes: 4 additions & 0 deletions src/contract/seal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ impl<U: ExposedSeal> XChain<U> {
serde(crate = "serde_crate", rename_all = "camelCase")
)]
#[display("{height}@{timestamp}")]
// TODO: Rename into `TxPos`
// TODO: Move into validation::Logic or vm::Contract
pub struct WitnessPos {
height: u32,
timestamp: i64,
Expand Down Expand Up @@ -221,6 +223,8 @@ impl Ord for WitnessPos {
derive(Serialize, Deserialize),
serde(crate = "serde_crate", rename_all = "camelCase", untagged)
)]
// TODO: Rename into `TxOrd`
// TODO: Move into validation::Logic or vm::Contract
pub enum WitnessOrd {
#[from]
#[display(inner)]
Expand Down
2 changes: 1 addition & 1 deletion src/stl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub const LIB_ID_RGB_COMMIT: &str =
"stl:tjFc6jD7-fe78CxG-WdJlH!l-uXlFfW0-XwG1!qV-MNdtNGE#orbit-airport-voice";
/// Strict types id for the library providing data types for RGB consensus.
pub const LIB_ID_RGB_LOGIC: &str =
"stl:htYXb5WT-hbjOSBy-XWFng1B-6HCQUkx-5oCOB2H-P4KgVV8#target-locate-justin";
"stl:BUSyF3Du-Fd$ARpR-oIQ2Wzx-vZ1iJQ8-PViDtnv-sj16HQo#clara-star-battery";

fn _rgb_commit_stl() -> Result<TypeLib, CompileError> {
LibBuilder::new(libname!(LIB_NAME_RGB_COMMIT), tiny_bset! {
Expand Down
File renamed without changes.
20 changes: 1 addition & 19 deletions src/validation/consignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,7 @@ use amplify::confinement::Confined;
use strict_types::TypeSystem;

use super::EAnchor;
use crate::{
BundleId, Genesis, OpId, OpRef, Operation, Schema, SecretSeal, TransitionBundle, XChain,
XWitnessId,
};
use crate::{BundleId, Genesis, OpId, OpRef, Operation, Schema, TransitionBundle, XWitnessId};

pub const CONSIGNMENT_MAX_LIBS: usize = 1024;

Expand All @@ -59,10 +56,6 @@ impl<'consignment, C: ConsignmentApi> ConsignmentApi for CheckedConsignment<'con

fn genesis(&self) -> &Genesis { self.0.genesis() }

fn terminals<'iter>(&self) -> impl Iterator<Item = (BundleId, XChain<SecretSeal>)> + 'iter {
self.0.terminals()
}

fn bundle_ids<'iter>(&self) -> impl Iterator<Item = BundleId> + 'iter { self.0.bundle_ids() }

fn bundle(&self, bundle_id: BundleId) -> Option<&TransitionBundle> {
Expand Down Expand Up @@ -103,17 +96,6 @@ pub trait ConsignmentApi {
/// Contract genesis.
fn genesis(&self) -> &Genesis;

/// The final state ("endpoints") provided by this consignment.
///
/// There are two reasons for having endpoints:
/// - navigation towards genesis from the final state is more
/// computationally efficient, since state transition/extension graph is
/// directed towards genesis (like bitcoin transaction graph)
/// - if the consignment contains concealed state (known by the receiver),
/// it will be computationally inefficient to understand which of the
/// state transitions represent the final state
fn terminals<'iter>(&self) -> impl Iterator<Item = (BundleId, XChain<SecretSeal>)> + 'iter;

/// Returns iterator over all bundle ids present in the consignment.
fn bundle_ids<'iter>(&self) -> impl Iterator<Item = BundleId> + 'iter;

Expand Down
27 changes: 23 additions & 4 deletions src/validation/logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use std::cell::RefCell;
use std::collections::BTreeSet;
use std::rc::Rc;

use aluvm::data::Number;
use aluvm::isa::Instr;
Expand All @@ -32,7 +34,7 @@ use strict_types::TypeSystem;

use crate::schema::{AssignmentsSchema, GlobalSchema, ValencySchema};
use crate::validation::{CheckedConsignment, ConsignmentApi};
use crate::vm::RgbIsa;
use crate::vm::{ContractState, RgbIsa};
use crate::{
validation, AssetTags, Assignments, AssignmentsRef, ContractId, ExposedSeal, Extension,
GlobalState, GlobalStateSchema, GlobalValues, GraphSeal, Inputs, MetaSchema, Metadata,
Expand All @@ -41,10 +43,12 @@ use crate::{
};

impl Schema {
pub fn validate_state<'validator, C: ConsignmentApi>(
// TODO: Instead of returning status fail immediately
pub fn validate_state<'validator, C: ConsignmentApi, S: ContractState>(
&'validator self,
consignment: &'validator CheckedConsignment<'_, C>,
op: OpRef,
contract_state: Rc<RefCell<S>>,
) -> validation::Status {
let opid = op.id();
let mut status = validation::Status::new();
Expand Down Expand Up @@ -194,24 +198,30 @@ impl Schema {
&redeemed,
&genesis.asset_tags,
);
let context = VmContext {
op_info,
contract_state,
};

// We need to run scripts as the very last step, since before that
// we need to make sure that the operation data match the schema, so
// scripts are not required to validate the structure of the state
if let Some(validator) = validator {
let scripts = consignment.scripts();
let mut vm = Vm::<Instr<RgbIsa>>::new();
let mut vm = Vm::<Instr<RgbIsa<S>>>::new();
if let Some(ty) = ty {
vm.registers.set_n(RegA::A16, Reg32::Reg0, ty);
}
if !vm.exec(validator, |id| scripts.get(&id), &op_info) {
if !vm.exec(validator, |id| scripts.get(&id), &context) {
let error_code: Option<Number> = vm.registers.get_n(RegA::A8, Reg32::Reg0).into();
status.add_failure(validation::Failure::ScriptFailure(
opid,
error_code.map(u8::from),
None,
));
}
let contract_state = context.contract_state;
contract_state.borrow_mut().evolve_state(op);
}
status
}
Expand Down Expand Up @@ -470,10 +480,19 @@ impl Schema {
}
}

// TODO: Move to VM module
pub struct VmContext<'op, S: ContractState> {
pub op_info: OpInfo<'op>,
pub contract_state: Rc<RefCell<S>>,
}

// TODO: Move to VM module
pub struct OpInfo<'op> {
// TODO: Move to VmContext
pub contract_id: ContractId,
pub id: OpId,
pub ty: OpFullType,
// TODO: Move to VmContext
pub asset_tags: &'op AssetTags,
pub metadata: &'op Metadata,
pub prev_state: &'op Assignments<GraphSeal>,
Expand Down
6 changes: 3 additions & 3 deletions src/validation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ mod state;
mod validator;
mod consignment;
mod status;
mod anchor;
mod commitments;

pub use anchor::{DbcError, DbcProof, EAnchor};
pub use commitments::{DbcError, DbcProof, EAnchor};
pub use consignment::{CheckedConsignment, ConsignmentApi, Scripts, CONSIGNMENT_MAX_LIBS};
pub(crate) use logic::OpInfo;
pub(crate) use logic::VmContext;
pub use status::{Failure, Info, Status, Validity, Warning};
pub use validator::{ResolveWitness, Validator, WitnessResolverError};
2 changes: 2 additions & 0 deletions src/validation/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

// TODO: Move into `logic` mod

use strict_types::TypeSystem;

use crate::schema::AssignmentType;
Expand Down
29 changes: 11 additions & 18 deletions src/validation/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ use crate::contract::Opout;
use crate::schema::{self, SchemaId};
use crate::validation::WitnessResolverError;
use crate::{
AssignmentType, BundleId, ContractId, Layer1, OccurrencesMismatch, OpFullType, OpId, OpType,
SecretSeal, StateType, Vin, XChain, XGraphSeal, XOutputSeal, XWitnessId,
BundleId, ContractId, Layer1, OccurrencesMismatch, OpFullType, OpId, StateType, Vin,
XGraphSeal, XOutputSeal, XWitnessId,
};

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Display)]
Expand Down Expand Up @@ -239,21 +239,16 @@ pub enum Failure {
CyclicGraph(OpId),
/// operation {0} is absent from the consignment.
OperationAbsent(OpId),
/// {ty} data doesn't match operation id {expected} (actual id is {actual}).
OperationIdMismatch {
ty: OpType,
expected: OpId,
actual: OpId,
},
/// transition bundle {0} referenced in consignment terminals is absent from
/// the consignment.
TerminalBundleAbsent(BundleId),
/// transition bundle {0} is absent in the consignment.
BundleAbsent(BundleId),
/// anchor for transitio bundle {0} is absent in the consignment.
AnchorAbsent(BundleId),
/// witness id for transition bundle {0} is absent in the consignment.
WitnessIdAbsent(BundleId),
/// bundle {0} public witness {1} is not known to the resolver; validation
/// stopped since operations can't be consensus-ordered. The resolver
/// responded with error {2}
WitnessUnresolved(BundleId, XWitnessId, WitnessResolverError),
/// operation {0} is under a different contract {1}.
ContractMismatch(OpId, ContractId),

Expand All @@ -271,9 +266,9 @@ pub enum Failure {
// Errors checking asset tags
/// asset type provided in genesis references unknown fungible state of type
/// {0}.
AssetTagNoState(AssignmentType),
AssetTagNoState(schema::AssignmentType),
/// fungible state {0} has no asset tag defined.
FungibleStateNoTag(AssignmentType),
FungibleStateNoTag(schema::AssignmentType),

// Errors checking seal closing
/// transition {opid} references state type {state_type} absent in the
Expand All @@ -288,8 +283,9 @@ pub enum Failure {
/// seal defined in the history as a part of operation output {0} is
/// confidential and can't be validated.
ConfidentialSeal(Opout),
/// public witness {0} is not known to the resolver.
SealNoPubWitness(XWitnessId, WitnessResolverError),
/// bundle {0} public witness {1} is not known to the resolver. Resolver
/// reported error {2}
SealNoPubWitness(BundleId, XWitnessId, WitnessResolverError),
/// witness layer 1 {anchor} doesn't match seal definition {seal}.
SealWitnessLayer1Mismatch { seal: Layer1, anchor: Layer1 },
/// seal {1} is defined on {0} which is not in the set of layers allowed
Expand Down Expand Up @@ -370,9 +366,6 @@ pub enum Failure {
)]
#[display(doc_comments)]
pub enum Warning {
/// terminal seal {1:?} referencing operation {0} is not present in
/// operation assignments.
TerminalSealAbsent(OpId, XChain<SecretSeal>),
/// operation {0} contains state in assignment {1} which is confidential and
/// thus was not validated.
UncheckableConfidentialState(OpId, schema::AssignmentType),
Expand Down
Loading

0 comments on commit e4e773e

Please sign in to comment.