Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validation: use consensus order and compute contract state #264

Merged
merged 27 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
38bb0ba
validation: provide contract state with witness information
dr-orlovsky Jul 30, 2024
98bf1fe
validation: fix missed extensions in the operation queue
dr-orlovsky Jul 30, 2024
bc2b7b8
validation: account for operation type in consensus ordering
dr-orlovsky Jul 30, 2024
2b15c09
validation: restore ConsignmentAPI to return op without witnesses
dr-orlovsky Jul 30, 2024
17db9f3
validation: fulfill remaining todos
dr-orlovsky Jul 30, 2024
4df97b7
vm: fix Ord impl for GlobalOrd
dr-orlovsky Jul 29, 2024
0a3a1b8
validation: simplify logic by removing redundant validation index
dr-orlovsky Jul 29, 2024
fc72178
vm: implement opcodes for contract global state introspection
dr-orlovsky Jul 30, 2024
2604db8
vm: support confinement errors on contract state evolution
dr-orlovsky Jul 31, 2024
5712d7a
Merge branch 'movearound' into contract-state2
dr-orlovsky Jul 31, 2024
28f22e9
operations: introduce nonce according to RCP-240731A
dr-orlovsky Jul 31, 2024
59e9228
vm: remove unused WitnessOrd type
dr-orlovsky Jul 31, 2024
a90a13b
vm: rename TxOrd to WitnessOrd, TxPos to WitnessPos
dr-orlovsky Jul 31, 2024
7d835fa
vm: simplify ordering types
dr-orlovsky Jul 31, 2024
a126fb6
vm: docs improvements in ordering-related types
dr-orlovsky Jul 31, 2024
da6e314
validation: fix and ensure that we account for extensions only once
dr-orlovsky Jul 31, 2024
b1f6319
vm: complete APIs related to consensus ordering types
dr-orlovsky Jul 31, 2024
d366dda
validation: fix ordering of state extensions
dr-orlovsky Jul 31, 2024
1e90b75
vm: add WitnessOrd::is_valid method
dr-orlovsky Jul 31, 2024
d06c627
stl: update
dr-orlovsky Aug 1, 2024
1a7ec62
vm: fix macroasm use of generics
dr-orlovsky Aug 1, 2024
8a26d37
vm: fix accounting for last item in global state iterator
dr-orlovsky Aug 2, 2024
e485571
vm: rename AnchoredOpRef into OrdOpRef
dr-orlovsky Aug 6, 2024
1e1e9fb
validation: simplify operation ordering
dr-orlovsky Aug 6, 2024
ce6321b
vm: remove nonce from OrdOpRef, since it is a part of an operation
dr-orlovsky Aug 6, 2024
e114999
validation: add explanatory comment
dr-orlovsky Aug 6, 2024
481132b
vm: make todo comment more precise
dr-orlovsky Aug 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/operation/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ pub enum TypeCommitment {
#[commit_encode(strategy = strict, id = OpId)]
pub struct OpCommitment {
pub ffv: Ffv,
pub nonce: u8,
pub op_type: TypeCommitment,
pub metadata: StrictHash,
pub globals: MerkleHash,
Expand All @@ -286,6 +287,7 @@ impl Genesis {
};
OpCommitment {
ffv: self.ffv,
nonce: u8::MAX,
op_type: TypeCommitment::Genesis(base),
metadata: self.metadata.commit_id(),
globals: MerkleHash::merklize(&self.globals),
Expand All @@ -305,6 +307,7 @@ impl Transition {
pub fn commit(&self) -> OpCommitment {
OpCommitment {
ffv: self.ffv,
nonce: self.nonce,
op_type: TypeCommitment::Transition(self.contract_id, self.transition_type),
metadata: self.metadata.commit_id(),
globals: MerkleHash::merklize(&self.globals),
Expand All @@ -322,6 +325,7 @@ impl Extension {
pub fn commit(&self) -> OpCommitment {
OpCommitment {
ffv: self.ffv,
nonce: self.nonce,
op_type: TypeCommitment::Extension(self.contract_id, self.extension_type),
metadata: self.metadata.commit_id(),
globals: MerkleHash::merklize(&self.globals),
Expand Down
15 changes: 15 additions & 0 deletions src/operation/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,10 @@ pub trait Operation {
/// Returns [`ContractId`] this operation belongs to.
fn contract_id(&self) -> ContractId;

/// Returns nonce used in consensus ordering of state transitions and
/// extensions.
fn nonce(&self) -> u8;

/// Returns [`Option::Some`]`(`[`TransitionType`]`)` for transitions or
/// [`Option::None`] for genesis and extension operation types
fn transition_type(&self) -> Option<TransitionType>;
Expand Down Expand Up @@ -378,6 +382,7 @@ impl StrictDeserialize for Genesis {}
pub struct Extension {
pub ffv: Ffv,
pub contract_id: ContractId,
pub nonce: u8,
pub extension_type: ExtensionType,
pub metadata: Metadata,
pub globals: GlobalState,
Expand Down Expand Up @@ -410,6 +415,7 @@ impl PartialOrd for Extension {
pub struct Transition {
pub ffv: Ffv,
pub contract_id: ContractId,
pub nonce: u8,
pub transition_type: TransitionType,
pub metadata: Metadata,
pub globals: GlobalState,
Expand Down Expand Up @@ -511,6 +517,9 @@ impl Operation for Genesis {
#[inline]
fn contract_id(&self) -> ContractId { ContractId::from_inner(self.id().into_inner()) }

#[inline]
fn nonce(&self) -> u8 { u8::MAX }

#[inline]
fn transition_type(&self) -> Option<TransitionType> { None }

Expand Down Expand Up @@ -553,6 +562,9 @@ impl Operation for Extension {
#[inline]
fn contract_id(&self) -> ContractId { self.contract_id }

#[inline]
fn nonce(&self) -> u8 { self.nonce }

#[inline]
fn transition_type(&self) -> Option<TransitionType> { None }

Expand Down Expand Up @@ -595,6 +607,9 @@ impl Operation for Transition {
#[inline]
fn contract_id(&self) -> ContractId { self.contract_id }

#[inline]
fn nonce(&self) -> u8 { self.nonce }

#[inline]
fn transition_type(&self) -> Option<TransitionType> { Some(self.transition_type) }

Expand Down
4 changes: 2 additions & 2 deletions src/stl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:tjFc6jD7-fe78CxG-WdJlH!l-uXlFfW0-XwG1!qV-MNdtNGE#orbit-airport-voice";
"stl:4WY0kCd1-qKjYuh5-4GgHKme-XIsmv98-W5Z9$8D-vMjFt!Y#miranda-blue-promise";
/// Strict types id for the library providing data types for RGB consensus.
pub const LIB_ID_RGB_LOGIC: &str =
"stl:pxDxFGo9-MbacU6J-Qug1G$1-6LsuROd-Um1H$hU-T6o2Lgk#lobster-dilemma-famous";
"stl:Yd7koRpf-hs7nsKX-TOLAnZl-hIfJ9wQ-M8J58hj-n60RcaA#pioneer-gong-smoke";

fn _rgb_commit_stl() -> Result<TypeLib, CompileError> {
LibBuilder::new(libname!(LIB_NAME_RGB_COMMIT), tiny_bset! {
Expand Down
124 changes: 122 additions & 2 deletions src/validation/consignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,133 @@ use amplify::confinement::Confined;
use strict_types::TypeSystem;

use super::EAnchor;
use crate::vm::{OpRef, XWitnessId};
use crate::{BundleId, Genesis, OpId, Operation, Schema, TransitionBundle};
use crate::vm::XWitnessId;
use crate::{
AssignmentType, AssignmentsRef, BundleId, ContractId, Extension, ExtensionType, Genesis,
GlobalState, GraphSeal, Inputs, Metadata, OpFullType, OpId, OpType, Operation, Schema,
Transition, TransitionBundle, TransitionType, TypedAssigns, Valencies,
};

pub const CONSIGNMENT_MAX_LIBS: usize = 1024;

pub type Scripts = Confined<BTreeMap<LibId, Lib>, 0, CONSIGNMENT_MAX_LIBS>;

#[derive(Copy, Clone, PartialEq, Eq, Debug, From)]
pub enum OpRef<'op> {
#[from]
Genesis(&'op Genesis),
#[from]
Transition(&'op Transition),
#[from]
Extension(&'op Extension),
}

impl<'op> Operation for OpRef<'op> {
fn op_type(&self) -> OpType {
match self {
Self::Genesis(op) => op.op_type(),
Self::Transition(op) => op.op_type(),
Self::Extension(op) => op.op_type(),
}
}

fn full_type(&self) -> OpFullType {
match self {
Self::Genesis(op) => op.full_type(),
Self::Transition(op) => op.full_type(),
Self::Extension(op) => op.full_type(),
}
}

fn id(&self) -> OpId {
match self {
Self::Genesis(op) => op.id(),
Self::Transition(op) => op.id(),
Self::Extension(op) => op.id(),
}
}

fn contract_id(&self) -> ContractId {
match self {
Self::Genesis(op) => op.contract_id(),
Self::Transition(op) => op.contract_id(),
Self::Extension(op) => op.contract_id(),
}
}

fn nonce(&self) -> u8 {
match self {
Self::Genesis(op) => op.nonce(),
Self::Transition(op) => op.nonce(),
Self::Extension(op) => op.nonce(),
}
}

fn transition_type(&self) -> Option<TransitionType> {
match self {
Self::Genesis(op) => op.transition_type(),
Self::Transition(op) => op.transition_type(),
Self::Extension(op) => op.transition_type(),
}
}

fn extension_type(&self) -> Option<ExtensionType> {
match self {
Self::Genesis(op) => op.extension_type(),
Self::Transition(op) => op.extension_type(),
Self::Extension(op) => op.extension_type(),
}
}

fn metadata(&self) -> &Metadata {
match self {
Self::Genesis(op) => op.metadata(),
Self::Transition(op) => op.metadata(),
Self::Extension(op) => op.metadata(),
}
}

fn globals(&self) -> &GlobalState {
match self {
Self::Genesis(op) => op.globals(),
Self::Transition(op) => op.globals(),
Self::Extension(op) => op.globals(),
}
}

fn valencies(&self) -> &Valencies {
match self {
Self::Genesis(op) => op.valencies(),
Self::Transition(op) => op.valencies(),
Self::Extension(op) => op.valencies(),
}
}

fn assignments(&self) -> AssignmentsRef<'op> {
match self {
Self::Genesis(op) => (&op.assignments).into(),
Self::Transition(op) => (&op.assignments).into(),
Self::Extension(op) => (&op.assignments).into(),
}
}

fn assignments_by_type(&self, t: AssignmentType) -> Option<TypedAssigns<GraphSeal>> {
match self {
Self::Genesis(op) => op.assignments_by_type(t),
Self::Transition(op) => op.assignments_by_type(t),
Self::Extension(op) => op.assignments_by_type(t),
}
}

fn inputs(&self) -> Inputs {
match self {
Self::Genesis(op) => op.inputs(),
Self::Transition(op) => op.inputs(),
Self::Extension(op) => op.inputs(),
}
}
}

pub struct CheckedConsignment<'consignment, C: ConsignmentApi>(&'consignment C);

impl<'consignment, C: ConsignmentApi> CheckedConsignment<'consignment, C> {
Expand Down
30 changes: 19 additions & 11 deletions src/validation/logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use strict_types::TypeSystem;

use crate::schema::{AssignmentsSchema, GlobalSchema, ValencySchema};
use crate::validation::{CheckedConsignment, ConsignmentApi};
use crate::vm::{ContractStateAccess, ContractStateEvolve, OpInfo, OpRef, RgbIsa, VmContext};
use crate::vm::{ContractStateAccess, ContractStateEvolve, OpInfo, OrdOpRef, RgbIsa, VmContext};
use crate::{
validation, Assign, AssignmentType, Assignments, AssignmentsRef, ConcealedState,
ConfidentialState, ExposedSeal, ExposedState, Extension, GlobalState, GlobalStateSchema,
Expand All @@ -43,15 +43,14 @@ use crate::{
};

impl Schema {
// TODO: Instead of returning status fail immediately
pub fn validate_state<
'validator,
C: ConsignmentApi,
S: ContractStateAccess + ContractStateEvolve,
>(
&'validator self,
consignment: &'validator CheckedConsignment<'_, C>,
op: OpRef,
op: OrdOpRef,
contract_state: Rc<RefCell<S>>,
) -> validation::Status {
let opid = op.id();
Expand All @@ -70,7 +69,7 @@ impl Schema {
validator,
ty,
) = match op {
OpRef::Genesis(genesis) => {
OrdOpRef::Genesis(genesis) => {
for id in genesis.asset_tags.keys() {
if !matches!(self.owned_types.get(id), Some(OwnedStateSchema::Fungible(_))) {
status.add_failure(validation::Failure::AssetTagNoState(*id));
Expand All @@ -95,9 +94,12 @@ impl Schema {
None::<u16>,
)
}
OpRef::Transition(Transition {
transition_type, ..
}) => {
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
Expand Down Expand Up @@ -131,7 +133,7 @@ impl Schema {
Some(transition_type.into_inner()),
)
}
OpRef::Extension(Extension { extension_type, .. }) => {
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
Expand Down Expand Up @@ -168,15 +170,15 @@ impl Schema {
status += self.validate_metadata(opid, op.metadata(), metadata_schema, consignment.types());
status +=
self.validate_global_state(opid, op.globals(), global_schema, consignment.types());
let prev_state = if let OpRef::Transition(transition) = op {
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
} else {
Assignments::default()
};
let mut redeemed = Valencies::default();
if let OpRef::Extension(extension) = op {
if let OrdOpRef::Extension(extension, ..) = op {
for valency in extension.redeemed.keys() {
redeemed.push(*valency).expect("same size");
}
Expand Down Expand Up @@ -218,9 +220,15 @@ impl Schema {
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;
contract_state.borrow_mut().evolve_state(op);
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
}
Expand Down
2 changes: 1 addition & 1 deletion src/validation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ mod status;
mod commitments;

pub use commitments::{DbcError, DbcProof, EAnchor};
pub use consignment::{CheckedConsignment, ConsignmentApi, Scripts, CONSIGNMENT_MAX_LIBS};
pub use consignment::{CheckedConsignment, ConsignmentApi, OpRef, Scripts, CONSIGNMENT_MAX_LIBS};
pub use status::{Failure, Info, Status, Validity, Warning};
pub use validator::{ResolveWitness, Validator, WitnessResolverError};
2 changes: 2 additions & 0 deletions src/validation/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,8 @@ pub enum Failure {
/// evaluation of AluVM script for operation {0} has failed with the code
/// {1:?} and message {2:?}.
ScriptFailure(OpId, Option<u8>, Option<String>),
/// contract state can't fit more data (at operation id {0}).
ContractStateFilled(OpId),

/// Custom error by external services on top of RGB Core.
#[display(inner)]
Expand Down
Loading
Loading