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 a07dd51
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 9 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.

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)
}

Check warning on line 136 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L134-L136

Added lines #L134 - L136 were not covered by tests
}

pub type ContractType = StrictHash;

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]

Check warning on line 141 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L141

Added line #L141 was not covered by tests
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB, tags = custom, dumb = Self::Transition(strict_dumb!()))]
pub enum TypeCommitment {
#[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)]

Check warning on line 155 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L155

Added line #L155 was not covered by tests
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB)]
#[derive(CommitEncode)]

Check warning on line 158 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L158

Added line #L158 was not covered by tests
#[commit_encode(strategy = strict, id = OpId)]
pub struct OpCommitment {
pub ffv: Ffv,
pub contract_id: ContractId,
pub op_type: TypeCommitment,
pub metadata: StrictHash,
pub globals: MerkleHash,
pub inputs: MerkleHash,
pub assignments: MerkleHash,
pub redeemed: StrictHash,
pub valencies: StrictHash,
}

impl Transition {
pub fn commit(&self) -> OpCommitment {
let mut meta_hasher = Sha256::default();
let _ = self
.metadata
.strict_write(u16::MAX as usize, &mut meta_hasher)
.ok();
OpCommitment {
ffv: self.ffv,
contract_id: self.contract_id,
op_type: TypeCommitment::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(),
}
}

Check warning on line 190 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L173-L190

Added lines #L173 - L190 were not covered by tests
}

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),

Check warning on line 199 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L194-L199

Added lines #L194 - L199 were not covered by tests
}
}

Check warning on line 201 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L201

Added line #L201 was not covered by tests
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]

Check warning on line 204 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L204

Added line #L204 was not covered by tests
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();
}

Check warning on line 219 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L214-L219

Added lines #L214 - L219 were not covered by tests
}

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

Check warning on line 225 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L223-L225

Added lines #L223 - L225 were not covered by tests
};
AssignmentCommitment {
ty,
state: state.state_commitment(),
seal,
}
}

Check warning on line 232 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L227-L232

Added lines #L227 - L232 were not covered by tests
}

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<_>>()

Check warning on line 244 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L239-L244

Added lines #L239 - L244 were not covered by tests
}
TypedAssigns::Fungible(list) => {
list.iter().map(|a| a.commitment(*ty)).collect()

Check warning on line 247 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L246-L247

Added lines #L246 - L247 were not covered by tests
}
TypedAssigns::Structured(list) => {
list.iter().map(|a| a.commitment(*ty)).collect()

Check warning on line 250 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L249-L250

Added lines #L249 - L250 were not covered by tests
}
TypedAssigns::Attachment(list) => {
list.iter().map(|a| a.commitment(*ty)).collect()

Check warning on line 253 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L252-L253

Added lines #L252 - L253 were not covered by tests
}
}
.into_iter()
})
.collect::<Vec<_>>()
.into_iter()
}

Check warning on line 260 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L256-L260

Added lines #L256 - L260 were not covered by tests
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]

Check warning on line 263 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L263

Added line #L263 was not covered by tests
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();
}

Check warning on line 276 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L272-L276

Added lines #L272 - L276 were not covered by tests
}

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()
}

Check warning on line 293 in src/contract/id.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/id.rs#L283-L293

Added lines #L283 - L293 were not covered by tests
}
5 changes: 4 additions & 1 deletion src/contract/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ pub use fungible::{
InvalidFieldElement, NoiseDumb, PedersenCommitment, RangeProof, RangeProofError, RevealedValue,
};
pub use global::{GlobalState, GlobalValues};
pub use id::{ContractId, OpId};
pub use id::{
AssignmentCommitment, ContractId, ContractType, GlobalCommitment, OpCommitment, OpId,
TypeCommitment,
};
pub use operations::{
Extension, Genesis, Input, Inputs, OpRef, Operation, Redeemed, Transition, Valencies,
};
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() }

Check warning on line 102 in src/contract/operations.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/operations.rs#L102

Added line #L102 was not covered by tests
}

#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB)]
#[derive(CommitEncode)]

Check warning on line 108 in src/contract/operations.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/operations.rs#L108

Added line #L108 was not covered by tests
#[commit_encode(strategy = strict, id = MerkleHash)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
Expand Down
7 changes: 5 additions & 2 deletions src/stl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ use strict_types::stl::{std_stl, strict_types_stl};
use strict_types::typelib::LibBuilder;
use strict_types::{CompileError, TypeLib};

use crate::{AnchoredBundle, ContractState, Extension, Genesis, SubSchema, LIB_NAME_RGB};
use crate::{
AnchoredBundle, ContractState, Extension, Genesis, OpCommitment, SubSchema, LIB_NAME_RGB,
};

/// Strict types id for the library providing data types for RGB consensus.
pub const LIB_ID_RGB: &str =
"urn:ubideco:stl:2YfZKdnGf9Gibvh15WcNSqe3xN7WH1143j1gCbDgecvG#axiom-detail-panther";
"urn:ubideco:stl:EM23PYNhUUBDQ3V6pSTFXiuVN9qMDJiKsNHDKpF1JvX5#albert-wizard-gemini";

fn _rgb_core_stl() -> Result<TypeLib, CompileError> {
LibBuilder::new(libname!(LIB_NAME_RGB), tiny_bset! {
Expand All @@ -48,6 +50,7 @@ fn _rgb_core_stl() -> Result<TypeLib, CompileError> {
.transpile::<AnchoredBundle>()
.transpile::<Extension>()
.transpile::<ContractState>()
.transpile::<OpCommitment>()
.compile()
}

Expand Down

0 comments on commit a07dd51

Please sign in to comment.