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 a7077ab commit 1ea9532
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 76 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.

6 changes: 3 additions & 3 deletions src/contract/attachment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use commit_verify::{CommitVerify, Conceal, StrictEncodedProtocol};
use strict_encoding::StrictEncode;

use super::{ConfidentialState, ExposedState};
use crate::{MediaType, StateCommitment, StateData, StateType, LIB_NAME_RGB};
use crate::{ConcealedState, MediaType, RevealedState, StateType, LIB_NAME_RGB};

/// Unique data attachment identifier
#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, From)]
Expand Down Expand Up @@ -110,7 +110,7 @@ impl RevealedAttach {
impl ExposedState for RevealedAttach {
type Confidential = ConcealedAttach;
fn state_type(&self) -> StateType { StateType::Attachment }
fn state_data(&self) -> StateData { StateData::Attachment(self.clone()) }
fn state_data(&self) -> RevealedState { RevealedState::Attachment(self.clone()) }
}

impl Conceal for RevealedAttach {
Expand Down Expand Up @@ -139,7 +139,7 @@ pub struct ConcealedAttach(

impl ConfidentialState for ConcealedAttach {
fn state_type(&self) -> StateType { StateType::Attachment }
fn state_commitment(&self) -> StateCommitment { StateCommitment::Attachment(*self) }
fn state_commitment(&self) -> ConcealedState { ConcealedState::Attachment(*self) }
}

impl CommitVerify<RevealedAttach, StrictEncodedProtocol> for ConcealedAttach {
Expand Down
10 changes: 5 additions & 5 deletions src/contract/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use commit_verify::{CommitVerify, Conceal, StrictEncodedProtocol};
use strict_encoding::{StrictSerialize, StrictType};

use super::{ConfidentialState, ExposedState};
use crate::{StateCommitment, StateData, StateType, LIB_NAME_RGB};
use crate::{ConcealedState, RevealedState, StateType, LIB_NAME_RGB};

/// Struct using for storing Void (i.e. absent) state
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Display, Default)]
Expand All @@ -43,13 +43,13 @@ pub struct VoidState(());

impl ConfidentialState for VoidState {
fn state_type(&self) -> StateType { StateType::Void }
fn state_commitment(&self) -> StateCommitment { StateCommitment::Void }
fn state_commitment(&self) -> ConcealedState { ConcealedState::Void }
}

impl ExposedState for VoidState {
type Confidential = VoidState;
fn state_type(&self) -> StateType { StateType::Void }
fn state_data(&self) -> StateData { StateData::Void }
fn state_data(&self) -> RevealedState { RevealedState::Void }
}

impl Conceal for VoidState {
Expand Down Expand Up @@ -102,7 +102,7 @@ impl RevealedData {
impl ExposedState for RevealedData {
type Confidential = ConcealedData;
fn state_type(&self) -> StateType { StateType::Structured }
fn state_data(&self) -> StateData { StateData::Structured(self.clone()) }
fn state_data(&self) -> RevealedState { RevealedState::Structured(self.clone()) }
}

impl Conceal for RevealedData {
Expand Down Expand Up @@ -155,7 +155,7 @@ pub struct ConcealedData(

impl ConfidentialState for ConcealedData {
fn state_type(&self) -> StateType { StateType::Structured }
fn state_commitment(&self) -> StateCommitment { StateCommitment::Structured(*self) }
fn state_commitment(&self) -> ConcealedState { ConcealedState::Structured(*self) }
}

impl CommitVerify<RevealedData, StrictEncodedProtocol> for ConcealedData {
Expand Down
6 changes: 3 additions & 3 deletions src/contract/fungible.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ use strict_encoding::{
};

use super::{ConfidentialState, ExposedState};
use crate::{schema, AssignmentType, StateCommitment, StateData, StateType, LIB_NAME_RGB};
use crate::{schema, AssignmentType, ConcealedState, RevealedState, StateType, LIB_NAME_RGB};

#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)]
#[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)]
Expand Down Expand Up @@ -327,7 +327,7 @@ impl RevealedValue {
impl ExposedState for RevealedValue {
type Confidential = ConcealedValue;
fn state_type(&self) -> StateType { StateType::Fungible }
fn state_data(&self) -> StateData { StateData::Fungible(*self) }
fn state_data(&self) -> RevealedState { RevealedState::Fungible(*self) }
}

impl Conceal for RevealedValue {
Expand Down Expand Up @@ -470,7 +470,7 @@ pub struct ConcealedValue {

impl ConfidentialState for ConcealedValue {
fn state_type(&self) -> StateType { StateType::Fungible }
fn state_commitment(&self) -> StateCommitment { StateCommitment::Fungible(*self) }
fn state_commitment(&self) -> ConcealedState { ConcealedState::Fungible(*self) }
}

impl CommitVerify<RevealedValue, PedersenProtocol> for ConcealedValue {
Expand Down
171 changes: 168 additions & 3 deletions src/contract/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,24 @@
// 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::{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, ExtensionType, Ffv, GlobalState, GlobalStateType, Redeemed,
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 +135,160 @@ impl OpId {
Bytes32::copy_from_slice(slice).map(Self)
}
}

pub type ContractType = 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!()))]
pub enum OpType {
#[strict_type(tag = 0)]
Genesis(ContractType),

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

#[strict_type(tag = 2)]
Extension(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 OpCommit {
pub ffv: Ffv,
pub contract_id: ContractId,
pub op_type: OpType,
pub metadata: StrictHash,
pub globals: MerkleHash,
pub inputs: MerkleHash,
pub assignments: MerkleHash,
pub redeemed: StrictHash,
pub valencies: StrictHash,
}

impl Transition {
pub fn commit(&self) -> OpCommit {
let mut meta_hasher = Sha256::default();
let _ = self
.metadata
.strict_write(u16::MAX as usize, &mut meta_hasher)
.ok();
OpCommit {
ffv: self.ffv,
contract_id: self.contract_id,
op_type: OpType::Transition(self.transition_type),
metadata: meta_hasher.finish().into(),
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 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()
}
}
2 changes: 1 addition & 1 deletion src/contract/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub use seal::{
ExposedSeal, GenesisSeal, GraphSeal, OutputSeal, SecretSeal, TxoSeal, WitnessId, WitnessOrd,
WitnessPos, XGenesisSeal, XGraphSeal, XOutputSeal, XPubWitness, XWitness,
};
pub use state::{ConfidentialState, ExposedState, StateCommitment, StateData, StateType};
pub use state::{ConcealedState, ConfidentialState, ExposedState, RevealedState, StateType};
pub use xchain::{
AltLayer1, AltLayer1Set, XChain, XChainParseError, XOutpoint, XCHAIN_BITCOIN_PREFIX,
XCHAIN_LIQUID_PREFIX,
Expand Down
15 changes: 14 additions & 1 deletion 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,6 +39,8 @@ 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),
Expand All @@ -58,6 +60,8 @@ 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),
Expand Down Expand Up @@ -91,9 +95,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
Loading

0 comments on commit 1ea9532

Please sign in to comment.