Skip to content

Commit

Permalink
unified seals
Browse files Browse the repository at this point in the history
  • Loading branch information
zoedberg committed Jan 29, 2025
1 parent eb84e9f commit b434a33
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 152 deletions.
29 changes: 3 additions & 26 deletions cli/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ use std::str::FromStr;

use amplify::confinement::{SmallOrdMap, TinyOrdMap, TinyOrdSet, U16 as MAX16};
use baid64::DisplayBaid64;
use bp::seals::txout::CloseMethod;
use bp::Txid;
use bpstd::psbt::{Psbt, PsbtVer};
use bpstd::seals::SecretSeal;
Expand All @@ -46,9 +45,9 @@ use rgb::schema::SchemaId;
use rgb::validation::Validity;
use rgb::vm::{RgbIsa, WitnessOrd};
use rgb::{
Allocation, BundleId, ContractId, DescriptorRgb, GenesisSeal, GraphSeal, Identity, OpId,
Outpoint, OutputSeal, OwnedFraction, RgbDescr, RgbKeychain, RgbWallet, StateType, TokenIndex,
TransferParams, WalletError, WalletProvider,
Allocation, BundleId, ContractId, GenesisSeal, GraphSeal, Identity, OpId, Outpoint, OutputSeal,
OwnedFraction, RgbDescr, RgbKeychain, RgbWallet, StateType, TokenIndex, TransferParams,
WalletError, WalletProvider,
};
use rgbstd::interface::{AllocatedState, ContractIface, OwnedIface};
use rgbstd::persistence::{MemContractState, StockError};
Expand Down Expand Up @@ -157,9 +156,6 @@ pub enum Command {
/// Schema name to use for the contract
schema: SchemaId, //String,

/// Contract close method
close_method: Option<CloseMethod>,

/// Issuer identity string
issuer: Identity,

Expand Down Expand Up @@ -671,12 +667,10 @@ impl Exec for RgbArgs {
}
Command::Issue {
schema: schema_id,
close_method,
issuer,
contract,
} => {
let mut stock = self.rgb_stock()?;
let wallet = self.rgb_wallet(&config)?;

let file = fs::File::open(contract)?;

Expand Down Expand Up @@ -707,20 +701,7 @@ impl Exec for RgbArgs {
))
})?;

let wallet_close_method = wallet.wallet().close_method();
let contract_close_method = close_method.unwrap_or(wallet_close_method);
match (wallet_close_method, contract_close_method) {
(CloseMethod::OpretFirst, CloseMethod::TapretFirst) => {
return Err(WalletError::Custom(s!(
"an opret wallet cannot issue a tapret contract"
)));
}
(CloseMethod::OpretFirst, CloseMethod::OpretFirst) => {}
(CloseMethod::TapretFirst, CloseMethod::TapretFirst) => {}
(CloseMethod::TapretFirst, CloseMethod::OpretFirst) => {}
}
let mut builder = stock.contract_builder(
contract_close_method,
issuer.clone(),
*schema_id,
iface_id,
Expand Down Expand Up @@ -911,10 +892,6 @@ impl Exec for RgbArgs {
.set_contract(*contract_id)
.set_interface(iface_name.clone());

if wallet.wallet().close_method() == CloseMethod::OpretFirst {
builder = builder.set_close_methods(vec![CloseMethod::OpretFirst]);
}

if operation.is_some() {
builder = builder.set_operation(op_name);
if let Some(state) = state {
Expand Down
30 changes: 10 additions & 20 deletions psbt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ mod rgb;

use bp::dbc::opret::OpretProof;
use bp::dbc::tapret::TapretProof;
use bp::seals::txout::CloseMethod;
pub use bpstd::psbt::*;
pub use rgb::*;
use rgbstd::containers::{AnchorSet, Batch, CloseMethodSet, Fascia, PubWitness};
use rgbstd::containers::{AnchorSet, Batch, Fascia, PubWitness};

pub use self::rgb::{
ProprietaryKeyRgb, RgbExt, RgbInExt, RgbOutExt, RgbPsbtError, PSBT_GLOBAL_RGB_TRANSITION,
Expand Down Expand Up @@ -85,7 +86,7 @@ impl RgbPsbt for Psbt {
if !inputs.is_empty() {
return Err(EmbedError::AbsentInputs);
}
self.push_rgb_transition(info.transition, info.method)
self.push_rgb_transition(info.transition)
.expect("transitions are unique since they are in BTreeMap indexed by opid");
}
Ok(())
Expand All @@ -95,24 +96,13 @@ impl RgbPsbt for Psbt {
// Convert RGB data to MPCs? Or should we do it at the moment we add them... No,
// since we may require more DBC methods with each additional state transition
let bundles = self.rgb_bundles_to_mpc()?;
// DBC commitment for the required methods
let methods = bundles
.values()
.map(|b| CloseMethodSet::from(b.close_method))
.reduce(|methods, method| methods | method)
.ok_or(RgbPsbtError::NoContracts)?;
let (mut tapret_anchor, mut opret_anchor) = (None, None);
if methods.has_tapret_first() {
tapret_anchor = Some(self.dbc_commit::<TapretProof>()?);
}
if methods.has_opret_first() {
opret_anchor = Some(self.dbc_commit::<OpretProof>()?);
}
let anchor = match (tapret_anchor, opret_anchor) {
(None, None) => return Err(RgbPsbtError::NoContracts.into()),
(Some(tapret), None) => AnchorSet::Tapret(tapret),
(None, Some(opret)) => AnchorSet::Opret(opret),
(Some(tapret), Some(opret)) => AnchorSet::Double { tapret, opret },
// DBC commitment for the correct close method
let close_method = self
.rgb_close_method()?
.ok_or(RgbPsbtError::NoCloseMethod)?;
let anchor = match close_method {
CloseMethod::TapretFirst => AnchorSet::Tapret(self.dbc_commit::<TapretProof>()?),
CloseMethod::OpretFirst => AnchorSet::Opret(self.dbc_commit::<OpretProof>()?),
};
// TODO: Use signed transaction here!
let witness = PubWitness::with(self.to_unsigned_tx().into());
Expand Down
92 changes: 37 additions & 55 deletions psbt/src/rgb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ pub const PSBT_RGB_PREFIX: &str = "RGB";

/// Proprietary key subtype for storing RGB state transition in global map.
pub const PSBT_GLOBAL_RGB_TRANSITION: u64 = 0x01;
/// Proprietary key subtype for storing information on which closed methods
/// should be used for each of RGB state transitions.
pub const PSBT_GLOBAL_RGB_CLOSE_METHODS: u64 = 0x02;
/// Proprietary key subtype for storing information on which close method
/// should be used.
pub const PSBT_GLOBAL_RGB_CLOSE_METHOD: u64 = 0x02;
/// Proprietary key subtype for storing RGB state transition operation id which
/// consumes this input.
pub const PSBT_IN_RGB_CONSUMED_BY: u64 = 0x01;
Expand All @@ -67,12 +67,12 @@ pub trait ProprietaryKeyRgb {
data: opid.to_vec().into(),
}
}
/// Constructs [`PSBT_GLOBAL_RGB_CLOSE_METHODS`] proprietary key.
fn rgb_closing_methods(opid: OpId) -> PropKey {
/// Constructs [`PSBT_GLOBAL_RGB_CLOSE_METHOD`] proprietary key.
fn rgb_close_method() -> PropKey {
PropKey {
identifier: PSBT_RGB_PREFIX.to_owned(),
subtype: PSBT_GLOBAL_RGB_CLOSE_METHODS,
data: opid.to_vec().into(),
subtype: PSBT_GLOBAL_RGB_CLOSE_METHOD,
data: none!(),
}
}

Expand Down Expand Up @@ -121,12 +121,11 @@ pub enum RgbPsbtError {
#[from(FromSliceError)]
InvalidContractId,

/// state transition {0} doesn't provide information about seal closing
/// methods used by its inputs.
NoCloseMethod(OpId),
/// PSBT doesn't provide information about close method.
NoCloseMethod,

/// invalid close method data for opid {0}
InvalidCloseMethod(OpId),
/// PSBT provides invalid close method information.
InvalidCloseMethod,

/// PSBT doesn't specify an output which can host {0} commitment.
NoHostOutput(Method),
Expand Down Expand Up @@ -163,38 +162,29 @@ pub trait RgbExt {

fn rgb_transition(&self, opid: OpId) -> Result<Option<Transition>, RgbPsbtError>;

fn rgb_close_method(&self, opid: OpId) -> Result<Option<CloseMethod>, RgbPsbtError>;
fn rgb_close_method(&self) -> Result<Option<CloseMethod>, RgbPsbtError>;

fn push_rgb_transition(
&mut self,
transition: Transition,
method: CloseMethod,
) -> Result<bool, RgbPsbtError>;
fn set_rgb_close_method(&mut self, close_method: CloseMethod);

fn push_rgb_transition(&mut self, transition: Transition) -> Result<bool, RgbPsbtError>;

fn rgb_bundles(&self) -> Result<BTreeMap<ContractId, TransitionBundle>, RgbPsbtError> {
let mut map = BTreeMap::new();
for contract_id in self.rgb_contract_ids()? {
let mut contract_method = None;
let mut input_map: SmallOrdMap<Vin, OpId> = SmallOrdMap::new();
let mut known_transitions: SmallOrdMap<OpId, Transition> = SmallOrdMap::new();
let contract_consumers = self.rgb_contract_consumers(contract_id)?;
if contract_consumers.is_empty() {
return Err(RgbPsbtError::NoContractConsumers);
}
for (opid, vin) in contract_consumers {
let (transition, method) = (
self.rgb_transition(opid)?,
self.rgb_close_method(opid)?
.ok_or(RgbPsbtError::NoCloseMethod(opid))?,
);
contract_method = Some(method);
let transition = self.rgb_transition(opid)?;
input_map.insert(vin, opid)?;
if let Some(transition) = transition {
known_transitions.insert(opid, transition)?;
}
}
let bundle = TransitionBundle {
close_method: contract_method.unwrap(),
input_map: InputMap::from(
Confined::try_from(input_map.release())
.map_err(|_| RgbPsbtError::NoTransitions(contract_id))?,
Expand Down Expand Up @@ -257,29 +247,24 @@ impl RgbExt for Psbt {
Ok(Some(transition))
}

fn rgb_close_method(&self, opid: OpId) -> Result<Option<CloseMethod>, RgbPsbtError> {
let Some(m) = self.proprietary(&PropKey::rgb_closing_methods(opid)) else {
fn rgb_close_method(&self) -> Result<Option<CloseMethod>, RgbPsbtError> {
let Some(m) = self.proprietary(&PropKey::rgb_close_method()) else {
return Ok(None);
};
if m.len() == 1 {
if let Ok(method) = CloseMethod::try_from(m[0]) {
return Ok(Some(method));
}
}
Err(RgbPsbtError::InvalidCloseMethod(opid))
Err(RgbPsbtError::InvalidCloseMethod)
}

fn push_rgb_transition(
&mut self,
mut transition: Transition,
method: CloseMethod,
) -> Result<bool, RgbPsbtError> {
let opid = transition.id();
fn set_rgb_close_method(&mut self, close_method: CloseMethod) {
let _ = self.push_proprietary(PropKey::rgb_close_method(), vec![close_method as u8]);
}

let prev_method = self.rgb_close_method(opid)?;
if matches!(prev_method, Some(prev_method) if prev_method != method) {
return Err(RgbPsbtError::InvalidCloseMethod(opid));
}
fn push_rgb_transition(&mut self, mut transition: Transition) -> Result<bool, RgbPsbtError> {
let opid = transition.id();

let prev_transition = self.rgb_transition(opid)?;
if let Some(ref prev_transition) = prev_transition {
Expand All @@ -297,7 +282,6 @@ impl RgbExt for Psbt {
// existed
let _ =
self.push_proprietary(PropKey::rgb_transition(opid), serialized_transition.release());
let _ = self.push_proprietary(PropKey::rgb_closing_methods(opid), vec![method as u8]);
Ok(prev_transition.is_none())
}

Expand All @@ -306,24 +290,22 @@ impl RgbExt for Psbt {
) -> Result<Confined<BTreeMap<ContractId, TransitionBundle>, 1, U24>, RgbPsbtError> {
let bundles = self.rgb_bundles()?;

let close_method = self
.rgb_close_method()?
.ok_or(RgbPsbtError::NoCloseMethod)?;

let host = self
.outputs_mut()
.find(|output| match close_method {
CloseMethod::OpretFirst => output.is_opret_host(),
CloseMethod::TapretFirst => output.is_tapret_host(),
})
.ok_or(RgbPsbtError::NoHostOutput(close_method))?;

for (contract_id, bundle) in &bundles {
let protocol_id = mpc::ProtocolId::from(*contract_id);
let message = mpc::Message::from(bundle.bundle_id());
if bundle.close_method == CloseMethod::TapretFirst {
// We need to do it each time due to Rust borrow checker
let tapret_host = self
.outputs_mut()
.find(|output| output.is_tapret_host())
.ok_or(RgbPsbtError::NoHostOutput(Method::TapretFirst))?;
tapret_host.set_mpc_message(protocol_id, message)?;
} else if bundle.close_method == CloseMethod::OpretFirst {
// We need to do it each time due to Rust borrow checker
let opret_host = self
.outputs_mut()
.find(|output| output.is_opret_host())
.ok_or(RgbPsbtError::NoHostOutput(Method::OpretFirst))?;
opret_host.set_mpc_message(protocol_id, message)?;
}
host.set_mpc_message(protocol_id, message)?;
}

let map = Confined::try_from(bundles).map_err(|_| RgbPsbtError::NoContracts)?;
Expand Down
Loading

0 comments on commit b434a33

Please sign in to comment.