Skip to content

Commit

Permalink
contract: solve operation commitment determinism
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Feb 11, 2024
1 parent 2308c17 commit e1d9939
Show file tree
Hide file tree
Showing 6 changed files with 254 additions and 20 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

208 changes: 205 additions & 3 deletions src/contract/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,26 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
use std::{fmt, vec};

use amplify::hex::{FromHex, ToHex};
use amplify::num::u256;
use amplify::{hex, ByteArray, Bytes32, FromSliceError, Wrapper};
use baid58::{Baid58ParseError, Chunking, FromBaid58, ToBaid58, CHUNKING_32CHECKSUM};
use commit_verify::{mpc, CommitmentId, DigestExt, Sha256};
use commit_verify::{
mpc, CommitEncode, CommitEngine, CommitId, CommitmentId, Conceal, DigestExt, MerkleHash,
MerkleLeaves, Sha256, StrictHash,
};
use strict_encoding::StrictEncode;

use crate::LIB_NAME_RGB;
use crate::{
Assign, AssignmentType, Assignments, ConcealedData, ConcealedState, ConfidentialState,
ExposedSeal, ExposedState, Extension, ExtensionType, Ffv, Genesis, GlobalState,
GlobalStateType, Redeemed, SchemaId, SecretSeal, Transition, TransitionType, TypedAssigns,
XChain, LIB_NAME_RGB,
};

/// Unique contract identifier equivalent to the contract genesis commitment
#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)]
Expand Down Expand Up @@ -127,3 +137,195 @@ impl OpId {
Bytes32::copy_from_slice(slice).map(Self)
}
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB)]
pub struct BaseCommitment {
pub schema_id: SchemaId,
pub testnet: bool,
pub alt_layers1: StrictHash,
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB, tags = custom, dumb = Self::Transition(strict_dumb!(), strict_dumb!()))]
pub enum TypeCommitment {
#[strict_type(tag = 0)]
Genesis(BaseCommitment),

#[strict_type(tag = 1)]
Transition(ContractId, TransitionType),

#[strict_type(tag = 2)]
Extension(ContractId, ExtensionType),
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB)]
#[derive(CommitEncode)]
#[commit_encode(strategy = strict, id = OpId)]
pub struct OpCommitment {
pub ffv: Ffv,
pub op_type: TypeCommitment,
pub metadata: StrictHash,
pub globals: MerkleHash,
pub inputs: MerkleHash,
pub assignments: MerkleHash,
pub redeemed: StrictHash,
pub valencies: StrictHash,
}

impl Genesis {
pub fn commit(&self) -> OpCommitment {
let base = BaseCommitment {
schema_id: self.schema_id,
testnet: self.testnet,
alt_layers1: self.alt_layers1.commit_id(),
};
OpCommitment {
ffv: self.ffv,
op_type: TypeCommitment::Genesis(base),
metadata: self.metadata.commit_id(),
globals: MerkleHash::merklize(&self.globals),
inputs: MerkleHash::void(0, u256::ZERO),
assignments: MerkleHash::merklize(&self.assignments),
redeemed: Redeemed::default().commit_id(),
valencies: self.valencies.commit_id(),
}
}
}

impl Transition {
pub fn commit(&self) -> OpCommitment {
OpCommitment {
ffv: self.ffv,
op_type: TypeCommitment::Transition(self.contract_id, self.transition_type),
metadata: self.metadata.commit_id(),
globals: MerkleHash::merklize(&self.globals),
inputs: MerkleHash::merklize(&self.inputs),
assignments: MerkleHash::merklize(&self.assignments),
redeemed: Redeemed::default().commit_id(),
valencies: self.valencies.commit_id(),
}
}
}

impl Extension {
pub fn commit(&self) -> OpCommitment {
OpCommitment {
ffv: self.ffv,
op_type: TypeCommitment::Extension(self.contract_id, self.extension_type),
metadata: self.metadata.commit_id(),
globals: MerkleHash::merklize(&self.globals),
inputs: MerkleHash::void(0, u256::ZERO),
assignments: MerkleHash::merklize(&self.assignments),
redeemed: self.redeemed.commit_id(),
valencies: self.valencies.commit_id(),
}
}
}

impl ConcealedState {
fn commit_encode(&self, e: &mut CommitEngine) {
match self {
ConcealedState::Void => {}
ConcealedState::Fungible(val) => e.commit_to(&val.commitment),
ConcealedState::Structured(dat) => e.commit_to(dat),
ConcealedState::Attachment(att) => e.commit_to(att),
}
}
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct AssignmentCommitment {
pub ty: AssignmentType,
pub state: ConcealedState,
pub seal: XChain<SecretSeal>,
}

impl CommitEncode for AssignmentCommitment {
type CommitmentId = MerkleHash;

fn commit_encode(&self, e: &mut CommitEngine) {
e.commit_to(&self.ty);
self.state.commit_encode(e);
e.commit_to(&self.seal);
e.set_finished();
}
}

impl<State: ExposedState, Seal: ExposedSeal> Assign<State, Seal> {
pub fn commitment(&self, ty: AssignmentType) -> AssignmentCommitment {
let Self::Confidential { seal, state } = self.conceal() else {
unreachable!();
};
AssignmentCommitment {
ty,
state: state.state_commitment(),
seal,
}
}
}

impl<Seal: ExposedSeal> MerkleLeaves for Assignments<Seal> {
type Leaf = AssignmentCommitment;
type LeafIter<'tmp> = vec::IntoIter<AssignmentCommitment> where Seal: 'tmp;

fn merkle_leaves(&self) -> Self::LeafIter<'_> {
self.iter()
.flat_map(|(ty, a)| {
match a {
TypedAssigns::Declarative(list) => {
list.iter().map(|a| a.commitment(*ty)).collect::<Vec<_>>()
}
TypedAssigns::Fungible(list) => {
list.iter().map(|a| a.commitment(*ty)).collect()
}
TypedAssigns::Structured(list) => {
list.iter().map(|a| a.commitment(*ty)).collect()
}
TypedAssigns::Attachment(list) => {
list.iter().map(|a| a.commitment(*ty)).collect()
}
}
.into_iter()
})
.collect::<Vec<_>>()
.into_iter()
}
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct GlobalCommitment {
pub ty: GlobalStateType,
pub state: ConcealedData,
}

impl CommitEncode for GlobalCommitment {
type CommitmentId = MerkleHash;

fn commit_encode(&self, e: &mut CommitEngine) {
e.commit_to(&self.ty);
e.commit_to(&self.state);
e.set_finished();
}
}

impl MerkleLeaves for GlobalState {
type Leaf = GlobalCommitment;
type LeafIter<'tmp> = vec::IntoIter<GlobalCommitment>;

fn merkle_leaves(&self) -> Self::LeafIter<'_> {
self.iter()
.flat_map(|(ty, list)| {
list.iter().map(|val| GlobalCommitment {
ty: *ty,
state: val.conceal(),
})
})
.collect::<Vec<_>>()
.into_iter()
}
}
7 changes: 5 additions & 2 deletions src/contract/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,12 @@ pub use fungible::{
InvalidFieldElement, NoiseDumb, PedersenCommitment, RangeProof, RangeProofError, RevealedValue,
};
pub use global::{GlobalState, GlobalValues};
pub use id::{ContractId, OpId};
pub use id::{
AssignmentCommitment, BaseCommitment, ContractId, GlobalCommitment, OpCommitment, OpId,
TypeCommitment,
};
pub use operations::{
Extension, Genesis, Input, Inputs, OpRef, Operation, Redeemed, Transition, Valencies,
Extension, Genesis, Input, Inputs, Metadata, OpRef, Operation, Redeemed, Transition, Valencies,
};
pub use seal::{
ExposedSeal, GenesisSeal, GraphSeal, OutputSeal, SecretSeal, TxoSeal, WitnessId, WitnessOrd,
Expand Down
44 changes: 34 additions & 10 deletions src/contract/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use std::iter;

use amplify::confinement::{SmallBlob, TinyOrdMap, TinyOrdSet};
use amplify::Wrapper;
use commit_verify::{CommitId, Conceal};
use commit_verify::{CommitId, Conceal, MerkleHash, MerkleLeaves, StrictHash};
use strict_encoding::{StrictDeserialize, StrictEncode, StrictSerialize};

use crate::schema::{self, ExtensionType, OpFullType, OpType, SchemaId, TransitionType};
Expand All @@ -39,10 +39,26 @@ use crate::{
#[wrapper_mut(DerefMut)]
#[derive(StrictType, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB)]
#[derive(CommitEncode)]
#[commit_encode(strategy = strict, id = StrictHash)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate", rename_all = "camelCase")
serde(crate = "serde_crate", transparent)
)]
pub struct Metadata(SmallBlob);

#[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default, From)]
#[wrapper(Deref)]
#[wrapper_mut(DerefMut)]
#[derive(StrictType, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB)]
#[derive(CommitEncode)]
#[commit_encode(strategy = strict, id = StrictHash)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate", transparent)
)]
pub struct Valencies(TinyOrdSet<schema::ValencyType>);

Expand All @@ -58,10 +74,12 @@ impl<'a> IntoIterator for &'a Valencies {
#[wrapper_mut(DerefMut)]
#[derive(StrictType, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB)]
#[derive(CommitEncode)]
#[commit_encode(strategy = strict, id = StrictHash)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate", rename_all = "camelCase")
serde(crate = "serde_crate", transparent)
)]
pub struct Redeemed(TinyOrdMap<schema::ValencyType, OpId>);

Expand All @@ -80,7 +98,7 @@ impl<'a> IntoIterator for &'a Redeemed {
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate", rename_all = "camelCase")
serde(crate = "serde_crate", transparent)
)]
pub struct Inputs(TinyOrdSet<Input>);

Expand All @@ -91,9 +109,18 @@ impl<'a> IntoIterator for &'a Inputs {
fn into_iter(self) -> Self::IntoIter { self.0.iter().copied() }
}

impl MerkleLeaves for Inputs {
type Leaf = Input;
type LeafIter<'tmp> = <TinyOrdSet<Input> as MerkleLeaves>::LeafIter<'tmp>;

fn merkle_leaves(&self) -> Self::LeafIter<'_> { self.0.merkle_leaves() }
}

#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB)]
#[derive(CommitEncode)]
#[commit_encode(strategy = strict, id = MerkleHash)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
Expand Down Expand Up @@ -179,9 +206,8 @@ pub struct Genesis {
pub schema_id: SchemaId,
pub testnet: bool,
pub alt_layers1: AltLayer1Set,
pub metadata: SmallBlob,
pub metadata: Metadata,
pub globals: GlobalState,
// TODO: Merklize assignments for the commitment
pub assignments: Assignments<GenesisSeal>,
pub valencies: Valencies,
}
Expand All @@ -203,9 +229,8 @@ pub struct Extension {
pub ffv: Ffv,
pub contract_id: ContractId,
pub extension_type: ExtensionType,
pub metadata: SmallBlob,
pub metadata: Metadata,
pub globals: GlobalState,
// TODO: Merklize assignments for the commitment
pub assignments: Assignments<GenesisSeal>,
pub redeemed: Redeemed,
pub valencies: Valencies,
Expand All @@ -228,10 +253,9 @@ pub struct Transition {
pub ffv: Ffv,
pub contract_id: ContractId,
pub transition_type: TransitionType,
pub metadata: SmallBlob,
pub metadata: Metadata,
pub globals: GlobalState,
pub inputs: Inputs,
// TODO: Merklize assignments for the commitment
pub assignments: Assignments<GraphSeal>,
pub valencies: Valencies,
}
Expand Down
4 changes: 3 additions & 1 deletion src/contract/xchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use std::{fmt, io};

use amplify::confinement::TinyOrdSet;
use bp::{Bp, Outpoint};
use commit_verify::Conceal;
use commit_verify::{Conceal, StrictHash};
use strict_encoding::{
DecodeError, DefineUnion, ReadTuple, ReadUnion, StrictDecode, StrictDumb, StrictEncode,
StrictSum, StrictType, StrictUnion, TypedRead, TypedWrite, WriteUnion,
Expand Down Expand Up @@ -81,6 +81,8 @@ impl AltLayer1 {
#[wrapper_mut(DerefMut)]
#[derive(StrictType, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB)]
#[derive(CommitEncode)]
#[commit_encode(strategy = strict, id = StrictHash)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
Expand Down
Loading

0 comments on commit e1d9939

Please sign in to comment.