Skip to content

Commit

Permalink
validation: simplify operation ordering
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Aug 6, 2024
1 parent e485571 commit 1e1e9fb
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 59 deletions.
8 changes: 4 additions & 4 deletions src/validation/logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ impl Schema {
Transition {
transition_type, ..
},
_,
..,
) => {
// Right now we do not have actions to implement; but later
// we may have embedded procedures which must be verified
Expand Down Expand Up @@ -133,7 +133,7 @@ impl Schema {
Some(transition_type.into_inner()),
)
}
OrdOpRef::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 @@ -170,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 OrdOpRef::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 OrdOpRef::Extension(extension, _) = op {
if let OrdOpRef::Extension(extension, ..) = op {
for valency in extension.redeemed.keys() {
redeemed.push(*valency).expect("same size");
}
Expand Down
45 changes: 19 additions & 26 deletions src/validation/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use single_use_seals::SealWitness;
use super::status::Failure;
use super::{CheckedConsignment, ConsignmentApi, DbcProof, EAnchor, OpRef, Status, Validity};
use crate::vm::{
ContractStateAccess, ContractStateEvolve, OpOrd, OrdOpRef, WitnessOrd, XWitnessId, XWitnessTx,
ContractStateAccess, ContractStateEvolve, OrdOpRef, WitnessOrd, XWitnessId, XWitnessTx,
};
use crate::{
validation, AltLayer1, BundleId, ContractId, Layer1, OpId, OpType, Operation, Opout, Schema,
Expand Down Expand Up @@ -258,7 +258,7 @@ impl<

// [VALIDATION]: Iterating over all consignment operations, ordering them according to the
// consensus ordering rules.
let mut ops = BTreeMap::<OpOrd, OrdOpRef>::new();
let mut ops = BTreeSet::<OrdOpRef>::new();
for bundle_id in self.consignment.bundle_ids() {
let bundle = self
.consignment
Expand All @@ -279,41 +279,34 @@ impl<
return;
}
};
for (opid, op) in &bundle.known_transitions {
let mut ord = OpOrd::Transition {
witness: witness_ord,
nonce: op.nonce,
opid: *opid,
};
ops.insert(ord, OrdOpRef::Transition(op, witness_id));
for op in bundle.known_transitions.values() {
ops.insert(OrdOpRef::Transition(op, witness_id, witness_ord, op.nonce));
for input in &op.inputs {
// We will error in `validate_operations` below on the absent extension from the
// consignment.
if let Some(OpRef::Extension(extension)) =
self.consignment.operation(input.prev_out.op)
{
ord = OpOrd::Extension {
witness: witness_ord,
nonce: extension.nonce,
opid: *opid,
};
let ext = OrdOpRef::Extension(extension, witness_id, witness_ord, op.nonce);
// Account only for the first time when extension seal was closed
let prev = ops.iter().find(|(_, r)| matches!(r, OrdOpRef::Extension(ext, _) if ext.id() == extension.id())).map(|(a, _)| *a);
let ext = OrdOpRef::Extension(extension, witness_id);
if let Some(old) = prev {
if old > ord {
let prev = ops.iter().find(|r| matches!(r, OrdOpRef::Extension(ext, ..) if ext.id() == extension.id())).copied();
match prev {
Some(old) if old > ext => {
ops.remove(&old);
ops.insert(ord, ext);
ops.insert(ext)
}
}
if prev.is_none() {
ops.insert(ord, ext);
}
None => ops.insert(ext),
_ => {
/* the extension is already present in the queue and properly
* ordered, so we have nothing to add or change */
true
}
};
}
}
}
}
for op in ops.into_values() {
for op in ops {
self.validate_operation(op);
}
}
Expand Down Expand Up @@ -343,7 +336,7 @@ impl<
OrdOpRef::Genesis(_) => {
unreachable!("genesis is not a part of the operation history")
}
OrdOpRef::Transition(transition, _) => {
OrdOpRef::Transition(transition, ..) => {
for input in &transition.inputs {
if self.consignment.operation(input.prev_out.op).is_none() {
self.status
Expand All @@ -352,7 +345,7 @@ impl<
}
}
}
OrdOpRef::Extension(extension, _) => {
OrdOpRef::Extension(extension, ..) => {
for (valency, prev_id) in &extension.redeemed {
let Some(prev_op) = self.consignment.operation(*prev_id) else {
self.status
Expand Down
86 changes: 57 additions & 29 deletions src/vm/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,127 +135,155 @@ impl<U: ExposedSeal> XChain<U> {
}
}

/// The type is used during validation and computing a contract state. It
/// combines both the operation with the information required for its ordering
/// in the contract history (via construction of [`OpOrd`]) according to the
/// consensus rules.
#[derive(Copy, Clone, PartialEq, Eq, Debug, From)]
pub enum OrdOpRef<'op> {
#[from]
Genesis(&'op Genesis),
Transition(&'op Transition, XWitnessId),
Extension(&'op Extension, XWitnessId),
Transition(&'op Transition, XWitnessId, WitnessOrd, /** Nonce value, used in ordering */ u8),
Extension(&'op Extension, XWitnessId, WitnessOrd, /** Nonce value, used in ordering */ u8),
}

impl<'op> PartialOrd for OrdOpRef<'op> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
}

impl<'op> Ord for OrdOpRef<'op> {
fn cmp(&self, other: &Self) -> Ordering { self.op_ord().cmp(&other.op_ord()) }
}

impl<'op> OrdOpRef<'op> {
pub fn witness_id(&self) -> Option<XWitnessId> {
match self {
OrdOpRef::Genesis(_) => None,
OrdOpRef::Transition(_, witness_id) | OrdOpRef::Extension(_, witness_id) => {
OrdOpRef::Transition(_, witness_id, ..) | OrdOpRef::Extension(_, witness_id, ..) => {
Some(*witness_id)
}
}
}

pub fn op_ord(&self) -> OpOrd {
match self {
OrdOpRef::Genesis(_) => OpOrd::Genesis,
OrdOpRef::Transition(op, _, witness_ord, nonce) => OpOrd::Transition {
witness: *witness_ord,
nonce: *nonce,
opid: op.id(),
},
OrdOpRef::Extension(op, _, witness_ord, nonce) => OpOrd::Extension {
witness: *witness_ord,
nonce: *nonce,
opid: op.id(),
},
}
}
}

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

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

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

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

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

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

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

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

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

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

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

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

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

0 comments on commit 1e1e9fb

Please sign in to comment.