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

add add_global_state_det #190

Closed
wants to merge 2 commits into from
Closed
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
98 changes: 96 additions & 2 deletions src/interface/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use std::collections::{BTreeMap, HashSet};

use amplify::confinement::{Confined, SmallOrdSet, TinyOrdMap, U16};
use amplify::{confinement, Wrapper};
use bp::secp256k1::rand::random;
use chrono::Utc;
use invoice::{Allocation, Amount};
use rgb::{
Expand Down Expand Up @@ -135,11 +136,15 @@ impl TxOutpoint for XOutpoint {
fn map_to_xchain<U>(self, f: impl FnOnce(Outpoint) -> U) -> XChain<U> { self.map(f) }
}

#[derive(Clone, Debug)]
#[derive(Getters, Clone, Debug)]
pub struct ContractBuilder {
#[getter(skip)]
builder: OperationBuilder<GenesisSeal>,
#[getter(skip)]
testnet: bool,
#[getter(skip)]
alt_layers1: AltLayer1Set,
deterministic: bool,
}

impl ContractBuilder {
Expand All @@ -153,9 +158,21 @@ impl ContractBuilder {
builder: OperationBuilder::with(iface, schema, iimpl)?,
testnet,
alt_layers1: none!(),
deterministic: false,
})
}

pub fn with_det(
iface: Iface,
schema: SubSchema,
iimpl: IfaceImpl,
testnet: bool,
) -> Result<Self, WrongImplementation> {
let mut contract_builder = Self::with(iface, schema, iimpl, testnet)?;
contract_builder.deterministic = true;
Ok(contract_builder)
}

pub fn mainnet(
iface: Iface,
schema: SubSchema,
Expand All @@ -165,9 +182,20 @@ impl ContractBuilder {
builder: OperationBuilder::with(iface, schema, iimpl)?,
testnet: false,
alt_layers1: none!(),
deterministic: false,
})
}

pub fn mainnet_det(
iface: Iface,
schema: SubSchema,
iimpl: IfaceImpl,
) -> Result<Self, WrongImplementation> {
let mut contract_builder = Self::mainnet(iface, schema, iimpl)?;
contract_builder.deterministic = true;
Ok(contract_builder)
}

pub fn testnet(
iface: Iface,
schema: SubSchema,
Expand All @@ -177,9 +205,20 @@ impl ContractBuilder {
builder: OperationBuilder::with(iface, schema, iimpl)?,
testnet: true,
alt_layers1: none!(),
deterministic: false,
})
}

pub fn testnet_det(
iface: Iface,
schema: SubSchema,
iimpl: IfaceImpl,
) -> Result<Self, WrongImplementation> {
let mut contract_builder = Self::testnet(iface, schema, iimpl)?;
contract_builder.deterministic = true;
Ok(contract_builder)
}

pub fn has_layer1(&self, layer1: Layer1) -> bool {
match layer1 {
Layer1::Bitcoin => true,
Expand Down Expand Up @@ -221,16 +260,41 @@ impl ContractBuilder {
name: impl Into<FieldName>,
value: impl StrictSerialize,
) -> Result<Self, BuilderError> {
debug_assert!(
!self.deterministic,
"to add global state in deterministic way please use add_global_state_det method"
);
self.builder = self.builder.add_global_state(name, value)?;
Ok(self)
}

#[inline]
pub fn add_global_state_det(
mut self,
name: impl Into<FieldName>,
value: impl StrictSerialize,
salt: u128,
) -> Result<Self, BuilderError> {
debug_assert!(
self.deterministic,
"to add global state in deterministic way the contract builder has to be created \
using `*_det` constructor"
);
self.builder = self.builder.add_global_state_det(name, value, salt)?;
Ok(self)
}

pub fn add_owned_state_det(
mut self,
name: impl Into<FieldName>,
seal: impl Into<BuilderSeal<GenesisSeal>>,
state: PersistedState,
) -> Result<Self, BuilderError> {
debug_assert!(
self.deterministic,
"to add owned state in deterministic way the contract builder has to be created using \
`*_det` constructor"
);
let seal = seal.into();
self.check_layer1(seal.layer1())?;
self.builder = self.builder.add_owned_state_det(name, seal, state)?;
Expand All @@ -254,6 +318,10 @@ impl ContractBuilder {
seal: impl Into<BuilderSeal<GenesisSeal>>,
value: u64,
) -> Result<Self, BuilderError> {
debug_assert!(
!self.deterministic,
"to add fungible state in deterministic way please use add_owned_state_det method"
);
let name = name.into();
let seal = seal.into();
self.check_layer1(seal.layer1())?;
Expand Down Expand Up @@ -287,6 +355,10 @@ impl ContractBuilder {
seal: impl Into<BuilderSeal<GenesisSeal>>,
value: impl StrictSerialize,
) -> Result<Self, BuilderError> {
debug_assert!(
!self.deterministic,
"to add data in deterministic way please use add_owned_state_det method"
);
let seal = seal.into();
self.check_layer1(seal.layer1())?;
self.builder = self.builder.add_data(name, seal, value)?;
Expand All @@ -299,17 +371,30 @@ impl ContractBuilder {
seal: impl Into<BuilderSeal<GenesisSeal>>,
attachment: AttachedState,
) -> Result<Self, BuilderError> {
debug_assert!(
!self.deterministic,
"to add attachment in deterministic way please use add_owned_state_det method"
);
let seal = seal.into();
self.check_layer1(seal.layer1())?;
self.builder = self.builder.add_attachment(name, seal, attachment)?;
Ok(self)
}

pub fn issue_contract(self) -> Result<Contract, BuilderError> {
debug_assert!(
!self.deterministic,
"to issue the contract in deterministic way please use issue_contract_det method"
);
self.issue_contract_det(Utc::now().timestamp())
}

pub fn issue_contract_det(self, timestamp: i64) -> Result<Contract, BuilderError> {
debug_assert!(
self.deterministic,
"to issue the contract in deterministic way the contract builder has to be created \
using `*_det` constructor"
);
let (schema, iface_pair, global, assignments, asset_tags) = self.builder.complete(None);

let genesis = Genesis {
Expand Down Expand Up @@ -711,9 +796,18 @@ impl<Seal: ExposedSeal> OperationBuilder<Seal> {
}

pub fn add_global_state(
self,
name: impl Into<FieldName>,
value: impl StrictSerialize,
) -> Result<Self, BuilderError> {
self.add_global_state_det(name, value, random())
}

pub fn add_global_state_det(
mut self,
name: impl Into<FieldName>,
value: impl StrictSerialize,
salt: u128,
) -> Result<Self, BuilderError> {
let name = name.into();
let serialized = value.to_strict_serialized::<{ u16::MAX as usize }>()?;
Expand All @@ -739,7 +833,7 @@ impl<Seal: ExposedSeal> OperationBuilder<Seal> {
.strict_deserialize_type(sem_id, &serialized)?;

self.global
.add_state(type_id, RevealedData::new_random_salt(serialized))?;
.add_state(type_id, RevealedData::with_salt(serialized, salt))?;

Ok(self)
}
Expand Down
36 changes: 21 additions & 15 deletions src/interface/rgb20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,8 +335,9 @@ impl Rgb20 {
details: Option<&str>,
precision: Precision,
asset_tag: AssetTag,
salt: u128,
) -> Result<PrimaryIssue, InvalidIdent> {
PrimaryIssue::testnet_det::<C>(ticker, name, details, precision, asset_tag)
PrimaryIssue::testnet_det::<C>(ticker, name, details, precision, asset_tag, salt)
}

pub fn spec(&self) -> AssetSpec {
Expand Down Expand Up @@ -471,7 +472,6 @@ pub struct PrimaryIssue {
builder: ContractBuilder,
issued: Amount,
terms: AssetTerms,
deterministic: bool,
}

impl PrimaryIssue {
Expand All @@ -481,6 +481,7 @@ impl PrimaryIssue {
name: &str,
details: Option<&str>,
precision: Precision,
salt: Option<u128>,
) -> Result<Self, InvalidIdent> {
let spec = AssetSpec::with(ticker, name, precision, details)?;
let terms = AssetTerms {
Expand All @@ -489,16 +490,21 @@ impl PrimaryIssue {
};

let (schema, main_iface_impl) = issuer.into_split();
let builder = ContractBuilder::testnet(rgb20(), schema, main_iface_impl)
.expect("schema interface mismatch")
.add_global_state("spec", spec)
.expect("invalid RGB20 schema (token specification mismatch)");
let builder = if let Some(salt) = salt {
ContractBuilder::testnet_det(rgb20(), schema, main_iface_impl)
.expect("schema interface mismatch")
.add_global_state_det("spec", spec, salt)
} else {
ContractBuilder::testnet(rgb20(), schema, main_iface_impl)
.expect("schema interface mismatch")
.add_global_state("spec", spec)
}
.expect("invalid RGB20 schema (token specification mismatch)");

Ok(Self {
builder,
terms,
issued: Amount::ZERO,
deterministic: false,
})
}

Expand All @@ -508,7 +514,7 @@ impl PrimaryIssue {
details: Option<&str>,
precision: Precision,
) -> Result<Self, InvalidIdent> {
Self::testnet_int(C::issuer(), ticker, name, details, precision)
Self::testnet_int(C::issuer(), ticker, name, details, precision, None)
}

pub fn testnet_with(
Expand All @@ -518,7 +524,7 @@ impl PrimaryIssue {
details: Option<&str>,
precision: Precision,
) -> Result<Self, InvalidIdent> {
Self::testnet_int(issuer, ticker, name, details, precision)
Self::testnet_int(issuer, ticker, name, details, precision, None)
}

pub fn testnet_det<C: IssuerClass<IssuingIface = Rgb20>>(
Expand All @@ -527,13 +533,13 @@ impl PrimaryIssue {
details: Option<&str>,
precision: Precision,
asset_tag: AssetTag,
salt: u128,
) -> Result<Self, InvalidIdent> {
let mut me = Self::testnet_int(C::issuer(), ticker, name, details, precision)?;
let mut me = Self::testnet_int(C::issuer(), ticker, name, details, precision, Some(salt))?;
me.builder = me
.builder
.add_asset_tag("assetOwner", asset_tag)
.expect("invalid RGB20 schema (assetOwner mismatch)");
me.deterministic = true;
Ok(me)
}

Expand Down Expand Up @@ -562,7 +568,7 @@ impl PrimaryIssue {
amount: Amount,
) -> Result<Self, AllocationError> {
debug_assert!(
!self.deterministic,
!self.builder.deterministic(),
"for creating deterministic contracts please use allocate_det method"
);

Expand Down Expand Up @@ -599,7 +605,7 @@ impl PrimaryIssue {
amount_blinding: BlindingFactor,
) -> Result<Self, AllocationError> {
debug_assert!(
self.deterministic,
self.builder.deterministic(),
"to add asset allocation in deterministic way the contract builder has to be created \
using `*_det` constructor"
);
Expand Down Expand Up @@ -632,7 +638,7 @@ impl PrimaryIssue {
#[allow(clippy::result_large_err)]
pub fn issue_contract(self) -> Result<Contract, BuilderError> {
debug_assert!(
!self.deterministic,
!self.builder.deterministic(),
"to add asset allocation in deterministic way you must use issue_contract_det method"
);
self.issue_contract_int(Utc::now().timestamp())
Expand All @@ -641,7 +647,7 @@ impl PrimaryIssue {
#[allow(clippy::result_large_err)]
pub fn issue_contract_det(self, timestamp: i64) -> Result<Contract, BuilderError> {
debug_assert!(
self.deterministic,
self.builder.deterministic(),
"to add asset allocation in deterministic way the contract builder has to be created \
using `*_det` constructor"
);
Expand Down
Loading
Loading