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

API sanation for state types #200

Merged
merged 7 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
27 changes: 21 additions & 6 deletions src/contract/attachment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

use amplify::{ByteArray, Bytes32};
use baid58::{Baid58ParseError, Chunking, FromBaid58, ToBaid58, CHUNKING_32};
use bp::secp256k1::rand::{thread_rng, RngCore};
use bp::secp256k1::rand::{random, Rng, RngCore};
use commit_verify::{CommitVerify, Conceal, StrictEncodedProtocol};
use strict_encoding::StrictEncode;

Expand Down Expand Up @@ -83,13 +83,28 @@
}

impl RevealedAttach {
/// Creates new revealed attachment for the attachment id and MIME type.
/// Uses `thread_rng` to initialize [`RevealedAttach::salt`].
pub fn new(id: AttachId, media_type: MediaType) -> Self {
/// Constructs new state using the provided value using random blinding
/// factor.
pub fn new_random_salt(id: AttachId, media_type: impl Into<MediaType>) -> Self {
Self::with_salt(id, media_type, random())
}

Check warning on line 90 in src/contract/attachment.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/attachment.rs#L88-L90

Added lines #L88 - L90 were not covered by tests

/// Constructs new state using the provided value and random generator for
/// creating blinding factor.
pub fn with_rng<R: Rng + RngCore>(
id: AttachId,
media_type: impl Into<MediaType>,
rng: &mut R,
) -> Self {
Self::with_salt(id, media_type, rng.next_u64())
}

Check warning on line 100 in src/contract/attachment.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/attachment.rs#L94-L100

Added lines #L94 - L100 were not covered by tests

/// Convenience constructor.
pub fn with_salt(id: AttachId, media_type: impl Into<MediaType>, salt: u64) -> Self {

Check warning on line 103 in src/contract/attachment.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/attachment.rs#L103

Added line #L103 was not covered by tests
Self {
id,
media_type,
salt: thread_rng().next_u64(),
media_type: media_type.into(),
salt,

Check warning on line 107 in src/contract/attachment.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/attachment.rs#L106-L107

Added lines #L106 - L107 were not covered by tests
}
}
}
Expand Down
86 changes: 64 additions & 22 deletions src/contract/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@
use strict_encoding::{StrictDecode, StrictDumb, StrictEncode};

use crate::{
Assign, AssignmentType, Assignments, AssignmentsRef, ContractId, ExposedSeal, ExposedState,
Extension, Genesis, GlobalStateType, OpId, Operation, RevealedAttach, RevealedData,
RevealedValue, SchemaId, SubSchema, Transition, TypedAssigns, VoidState, WitnessAnchor,
WitnessId, XChain, XOutputSeal, LIB_NAME_RGB,
Assign, AssignmentType, Assignments, AssignmentsRef, ContractId, DataState, ExposedSeal,
ExposedState, Extension, Genesis, GlobalStateType, OpId, Operation, RevealedAttach,
RevealedData, RevealedValue, SchemaId, SubSchema, Transition, TypedAssigns, VoidState,
WitnessAnchor, WitnessId, XChain, XOutputSeal, LIB_NAME_RGB,
};

#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)]
Expand Down Expand Up @@ -92,22 +92,59 @@
}
}

#[derive(Clone, Eq, Debug)]
/// Trait used by contract state. Unlike [`ExposedState`] it doesn't allow
/// concealment of the state, i.e. may contain incomplete data without blinding
/// factors, asset tags etc.
pub trait KnownState: Debug + StrictDumb + StrictEncode + StrictDecode + Eq + Clone {}
impl<S: ExposedState> KnownState for S {}

impl KnownState for () {}
impl KnownState for DataState {}

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display, From)]

Check warning on line 104 in src/contract/contract.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/contract.rs#L104

Added line #L104 was not covered by tests
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB, tags = custom)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),

Check warning on line 109 in src/contract/contract.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/contract.rs#L109

Added line #L109 was not covered by tests
serde(crate = "serde_crate", rename_all = "camelCase")
)]
pub enum AssignmentWitness {
#[display("~")]
#[strict_type(tag = 0, dumb)]
Absent,

#[from]
#[display(inner)]
#[strict_type(tag = 1)]
Present(WitnessId),
}

impl From<Option<WitnessId>> for AssignmentWitness {
fn from(value: Option<WitnessId>) -> Self {
match value {
None => AssignmentWitness::Absent,
Some(id) => AssignmentWitness::Present(id),

Check warning on line 127 in src/contract/contract.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/contract.rs#L124-L127

Added lines #L124 - L127 were not covered by tests
}
}

Check warning on line 129 in src/contract/contract.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/contract.rs#L129

Added line #L129 was not covered by tests
}

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

Check warning on line 132 in src/contract/contract.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/contract.rs#L132

Added line #L132 was not covered by tests
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate", rename_all = "camelCase")
)]
pub struct OutputAssignment<State: ExposedState> {
pub struct OutputAssignment<State: KnownState> {
pub opout: Opout,
pub seal: XOutputSeal,
pub state: State,
pub witness: Option<WitnessId>,
pub witness: AssignmentWitness,
}

impl<State: ExposedState> PartialEq for OutputAssignment<State> {
impl<State: KnownState> PartialEq for OutputAssignment<State> {
fn eq(&self, other: &Self) -> bool {
if self.opout == other.opout &&
(self.seal != other.seal ||
Expand All @@ -127,11 +164,11 @@
}
}

impl<State: ExposedState> PartialOrd for OutputAssignment<State> {
impl<State: KnownState> PartialOrd for OutputAssignment<State> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
}

impl<State: ExposedState> Ord for OutputAssignment<State> {
impl<State: KnownState> Ord for OutputAssignment<State> {
fn cmp(&self, other: &Self) -> Ordering {
if self == other {
return Ordering::Equal;
Expand All @@ -140,7 +177,7 @@
}
}

impl<State: ExposedState> OutputAssignment<State> {
impl<State: KnownState> OutputAssignment<State> {
/// # Panics
///
/// If the processing is done on invalid stash data, the seal is
Expand All @@ -160,7 +197,7 @@
match anchor's chain",
),
state,
witness: Some(witness_id),
witness: witness_id.into(),

Check warning on line 200 in src/contract/contract.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/contract.rs#L200

Added line #L200 was not covered by tests
}
}

Expand All @@ -182,7 +219,17 @@
information since it comes from genesis or extension",
),
state,
witness: None,
witness: AssignmentWitness::Absent,
}
}

Check warning on line 224 in src/contract/contract.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/contract.rs#L222-L224

Added lines #L222 - L224 were not covered by tests

pub fn transmute<S: KnownState>(self) -> OutputAssignment<S>
where S: From<State> {
OutputAssignment {
opout: self.opout,
seal: self.seal,
state: self.state.into(),
witness: self.witness,

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

View check run for this annotation

Codecov / codecov/patch

src/contract/contract.rs#L226-L232

Added lines #L226 - L232 were not covered by tests
}
}
}
Expand Down Expand Up @@ -234,11 +281,6 @@
}
}

pub type RightsOutput = OutputAssignment<VoidState>;
pub type FungibleOutput = OutputAssignment<RevealedValue>;
pub type DataOutput = OutputAssignment<RevealedData>;
pub type AttachOutput = OutputAssignment<RevealedAttach>;

/// Contract history accumulates raw data from the contract history, extracted
/// from a series of consignments over the time. It does consensus ordering of
/// the state data, but it doesn't interpret or validates the state against the
Expand All @@ -262,10 +304,10 @@
contract_id: ContractId,
#[getter(skip)]
global: TinyOrdMap<GlobalStateType, LargeOrdMap<GlobalOrd, RevealedData>>,
rights: LargeOrdSet<RightsOutput>,
fungibles: LargeOrdSet<FungibleOutput>,
data: LargeOrdSet<DataOutput>,
attach: LargeOrdSet<AttachOutput>,
rights: LargeOrdSet<OutputAssignment<VoidState>>,
fungibles: LargeOrdSet<OutputAssignment<RevealedValue>>,
data: LargeOrdSet<OutputAssignment<RevealedData>>,
attach: LargeOrdSet<OutputAssignment<RevealedAttach>>,

Check warning on line 310 in src/contract/contract.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/contract.rs#L307-L310

Added lines #L307 - L310 were not covered by tests
}

impl ContractHistory {
Expand Down
88 changes: 71 additions & 17 deletions src/contract/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use core::fmt::{self, Debug, Display, Formatter};
use core::fmt::{self, Debug, Formatter};
use std::cmp::Ordering;
use std::io::Write;

use amplify::confinement::SmallVec;
use amplify::confinement::SmallBlob;
use amplify::hex::ToHex;
use amplify::{Bytes32, Wrapper};
use commit_verify::{CommitVerify, Conceal, StrictEncodedProtocol};
use bp::secp256k1::rand::{random, Rng, RngCore};
use commit_verify::{CommitEncode, CommitVerify, Conceal, StrictEncodedProtocol};
use strict_encoding::{StrictSerialize, StrictType};

use super::{ConfidentialState, ExposedState};
Expand Down Expand Up @@ -57,13 +60,49 @@
fn conceal(&self) -> Self::Concealed { *self }
}

#[derive(Wrapper, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, From)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[derive(Wrapper, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash, From, Display, Default)]
#[display(LowerHex)]
#[wrapper(Deref, AsSlice, BorrowSlice, Hex)]
#[derive(StrictType, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB)]
#[derive(CommitEncode)]
#[commit_encode(conceal)]
#[commit_encode(strategy = strict)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))]
pub struct RevealedData(SmallVec<u8>);
pub struct DataState(SmallBlob);
impl StrictSerialize for DataState {}

impl From<RevealedData> for DataState {
fn from(data: RevealedData) -> Self { data.value }

Check warning on line 75 in src/contract/data.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/data.rs#L75

Added line #L75 was not covered by tests
}

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

Check warning on line 78 in src/contract/data.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/data.rs#L78

Added line #L78 was not covered by tests
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))]

Check warning on line 81 in src/contract/data.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/data.rs#L81

Added line #L81 was not covered by tests
pub struct RevealedData {
pub value: DataState,
pub salt: u128,
}

impl RevealedData {
/// Constructs new state using the provided value using random blinding
/// factor.
pub fn new_random_salt(value: impl Into<DataState>) -> Self { Self::with_salt(value, random()) }

Check warning on line 90 in src/contract/data.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/data.rs#L90

Added line #L90 was not covered by tests

/// Constructs new state using the provided value and random generator for
/// creating blinding factor.
pub fn with_rng<R: Rng + RngCore>(value: impl Into<DataState>, rng: &mut R) -> Self {
Self::with_salt(value, rng.gen())
}

Check warning on line 96 in src/contract/data.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/data.rs#L94-L96

Added lines #L94 - L96 were not covered by tests

/// Convenience constructor.
pub fn with_salt(value: impl Into<DataState>, salt: u128) -> Self {
Self {
value: value.into(),
salt,
}
}

Check warning on line 104 in src/contract/data.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/data.rs#L99-L104

Added lines #L99 - L104 were not covered by tests
}

impl ExposedState for RevealedData {
type Confidential = ConcealedData;
Expand All @@ -73,24 +112,39 @@

impl Conceal for RevealedData {
type Concealed = ConcealedData;

fn conceal(&self) -> Self::Concealed { ConcealedData::commit(self) }
}

impl StrictSerialize for RevealedData {}
impl CommitEncode for RevealedData {
fn commit_encode(&self, e: &mut impl Write) {
e.write_all(&self.value).ok();
e.write_all(&self.salt.to_le_bytes()).ok();
}

Check warning on line 123 in src/contract/data.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/data.rs#L120-L123

Added lines #L120 - L123 were not covered by tests
}

impl Debug for RevealedData {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let val = match String::from_utf8(self.0.to_inner()) {
Ok(s) => s,
Err(_) => self.0.to_hex(),
};
impl PartialOrd for RevealedData {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }

Check warning on line 127 in src/contract/data.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/data.rs#L127

Added line #L127 was not covered by tests
}

f.debug_tuple("RevealedData").field(&val).finish()
impl Ord for RevealedData {
fn cmp(&self, other: &Self) -> Ordering {
match self.value.cmp(&other.value) {
Ordering::Equal => self.salt.cmp(&other.salt),
other => other,

Check warning on line 134 in src/contract/data.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/data.rs#L131-L134

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

impl Display for RevealedData {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str(&self.as_ref().to_hex()) }
impl Debug for RevealedData {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let val = String::from_utf8(self.value.to_vec()).unwrap_or_else(|_| self.value.to_hex());

f.debug_struct("RevealedData")
.field("value", &val)
.field("salt", &self.salt)
.finish()
}

Check warning on line 147 in src/contract/data.rs

View check run for this annotation

Codecov / codecov/patch

src/contract/data.rs#L140-L147

Added lines #L140 - L147 were not covered by tests
}

/// Confidential version of an structured state data.
Expand Down
16 changes: 6 additions & 10 deletions src/contract/fungible.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ impl RevealedValue {

/// Constructs new state using the provided value and random generator for
/// creating blinding factor.
pub fn with_random_blinding<R: Rng + RngCore>(
pub fn with_rng<R: Rng + RngCore>(
value: impl Into<FungibleState>,
rng: &mut R,
tag: AssetTag,
Expand Down Expand Up @@ -531,7 +531,7 @@ mod test {
fn commitments_determinism() {
let tag = AssetTag::from_byte_array([1u8; 32]);

let value = RevealedValue::with_random_blinding(15, &mut thread_rng(), tag);
let value = RevealedValue::with_rng(15, &mut thread_rng(), tag);

let generators = (0..10)
.map(|_| {
Expand All @@ -548,15 +548,11 @@ mod test {
let mut r = thread_rng();
let tag = AssetTag::from_byte_array([1u8; 32]);

let a = PedersenCommitment::commit(&RevealedValue::with_random_blinding(15, &mut r, tag))
.into_inner();
let b = PedersenCommitment::commit(&RevealedValue::with_random_blinding(7, &mut r, tag))
.into_inner();
let a = PedersenCommitment::commit(&RevealedValue::with_rng(15, &mut r, tag)).into_inner();
let b = PedersenCommitment::commit(&RevealedValue::with_rng(7, &mut r, tag)).into_inner();

let c = PedersenCommitment::commit(&RevealedValue::with_random_blinding(13, &mut r, tag))
.into_inner();
let d = PedersenCommitment::commit(&RevealedValue::with_random_blinding(9, &mut r, tag))
.into_inner();
let c = PedersenCommitment::commit(&RevealedValue::with_rng(13, &mut r, tag)).into_inner();
let d = PedersenCommitment::commit(&RevealedValue::with_rng(9, &mut r, tag)).into_inner();

assert!(!secp256k1_zkp::verify_commitments_sum_to_equal(SECP256K1, &[a, b], &[c, d]))
}
Expand Down
6 changes: 3 additions & 3 deletions src/contract/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ pub use assignments::{
pub use attachment::{AttachId, ConcealedAttach, RevealedAttach};
pub use bundle::{BundleId, TransitionBundle, Vin};
pub use contract::{
AttachOutput, ContractHistory, ContractState, DataOutput, FungibleOutput, GlobalOrd, Opout,
OpoutParseError, OutputAssignment, RightsOutput,
AssignmentWitness, ContractHistory, ContractState, GlobalOrd, KnownState, Opout,
OpoutParseError, OutputAssignment,
};
pub use data::{ConcealedData, RevealedData, VoidState};
pub use data::{ConcealedData, DataState, RevealedData, VoidState};
pub use fungible::{
AssetTag, BlindingFactor, BlindingParseError, ConcealedValue, FungibleState,
InvalidFieldElement, NoiseDumb, PedersenCommitment, RangeProof, RangeProofError, RevealedValue,
Expand Down
2 changes: 1 addition & 1 deletion src/stl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use crate::{AnchoredBundle, ContractState, Extension, Genesis, SubSchema, LIB_NA

/// Strict types id for the library providing data types for RGB consensus.
pub const LIB_ID_RGB: &str =
"urn:ubideco:stl:2PcZtrPrfQCu27qw8b4Wz4cEqUn2PpgSkDHwF4qVyyrq#russian-child-member";
"urn:ubideco:stl:141hHBYBr2mzKyskZbRuwazYC9ki5x9ZrrzQHLbgBzx#oscar-rufus-tractor";

fn _rgb_core_stl() -> Result<TypeLib, CompileError> {
LibBuilder::new(libname!(LIB_NAME_RGB), tiny_bset! {
Expand Down
2 changes: 1 addition & 1 deletion src/validation/logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@
for data in set {
if self
.type_system
.strict_deserialize_type(*sem_id, data.as_ref())
.strict_deserialize_type(*sem_id, data.value.as_ref())

Check warning on line 263 in src/validation/logic.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/logic.rs#L263

Added line #L263 was not covered by tests
.is_err()
{
status.add_failure(validation::Failure::SchemaInvalidGlobalValue(
Expand Down
Loading
Loading