Skip to content

Commit

Permalink
Merge pull request #227 from RGB-WG/mining
Browse files Browse the repository at this point in the history
Support new witness filtering
  • Loading branch information
dr-orlovsky authored Aug 9, 2024
2 parents f0316a6 + 8563b58 commit cb0b8ff
Show file tree
Hide file tree
Showing 11 changed files with 198 additions and 166 deletions.
184 changes: 85 additions & 99 deletions Cargo.lock

Large diffs are not rendered by default.

9 changes: 4 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ descriptors = { workspace = true }
bp-wallet = { workspace = true }
rgb-std = { workspace = true }
rgb-psbt = { workspace = true }
rgb-interfaces = { workspace = true }
indexmap = { workspace = true }
chrono = { workspace = true }
serde_crate = { workspace = true, optional = true }
Expand Down Expand Up @@ -102,7 +101,7 @@ descriptors = { git = "https://github.com/BP-WG/bp-std", branch = "master" }
psbt = { git = "https://github.com/BP-WG/bp-std", branch = "master" }
bp-std = { git = "https://github.com/BP-WG/bp-std", branch = "master" }
bp-wallet = { git = "https://github.com/BP-WG/bp-wallet", branch = "master" }
rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "master" }
rgb-invoice = { git = "https://github.com/RGB-WG/rgb-std", branch = "txid" }
rgb-std = { git = "https://github.com/RGB-WG/rgb-std", branch = "txid" }
rgb-interfaces = { git = "https://github.com/RGB-WG/rgb-interfaces.git", branch = "master" }
rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "mining" }
rgb-invoice = { git = "https://github.com/RGB-WG/rgb-std", branch = "mining" }
rgb-std = { git = "https://github.com/RGB-WG/rgb-std", branch = "mining" }
rgb-interfaces = { git = "https://github.com/RGB-WG/rgb-interfaces.git", branch = "mining" }
42 changes: 36 additions & 6 deletions cli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

use std::fs;
use std::io::ErrorKind;
use std::ops::{Deref, DerefMut};
use std::path::PathBuf;

use bpstd::{Wpkh, XpubDerivable};
Expand Down Expand Up @@ -63,13 +64,27 @@ impl DescriptorOpts for DescrRgbOpts {

/// Command-line arguments
#[derive(Parser)]
#[derive(Wrapper, WrapperMut, Clone, Eq, PartialEq, Debug, From)]
#[wrapper(Deref)]
#[wrapper_mut(DerefMut)]
#[derive(Clone, Eq, PartialEq, Debug)]
#[command(author, version, about)]
pub struct RgbArgs {
#[clap(flatten)]
pub inner: BpArgs<Command, DescrRgbOpts>,

/// Specify blockchain height starting from which witness transactions
/// should be checked for re-orgs
#[clap(short = 'h', long, requires = "sync")]
pub from_height: Option<u32>,
}

impl Deref for RgbArgs {
type Target = BpArgs<Command, DescrRgbOpts>;
#[inline]
fn deref(&self) -> &Self::Target { &self.inner }
}

impl DerefMut for RgbArgs {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }
}

impl Default for RgbArgs {
Expand All @@ -87,7 +102,7 @@ impl RgbArgs {
eprint!("Loading stock from `{}` ... ", stock_path.display());
}

let stock = Stock::load(stock_path.clone()).map_err(WalletError::from).or_else(|err| {
let mut stock = Stock::load(stock_path.clone()).map_err(WalletError::from).or_else(|err| {
if matches!(err, WalletError::Deserialize(DeserializeError::Decode(DecodeError::Io(ref err))) if err.kind() == ErrorKind::NotFound) {
if self.verbose > 1 {
eprint!("stock file is absent, creating a new one ... ");
Expand All @@ -101,6 +116,22 @@ impl RgbArgs {
Err(err)
})?;

if self.sync {
let resolver = self.resolver()?;
let from_height = self.from_height.unwrap_or(1);
eprint!("Updating witness information starting from height {from_height} ... ");
let res = stock.update_witnesses(resolver, from_height)?;
eprint!("{} transactions were checked and updated", res.succeeded);
if res.failed.is_empty() {
eprintln!();
} else {
eprintln!(", {} resolution failures:", res.failed.len());
for (witness_id, failure) in res.failed {
eprintln!(" - {witness_id}: {failure}");
}
}
}

if self.verbose > 1 {
eprintln!("success");
}
Expand All @@ -118,8 +149,7 @@ impl RgbArgs {
&self,
config: &Config,
) -> Result<RgbWallet<Wallet<XpubDerivable, RgbDescr>>, WalletError> {
let stock_path = self.general.base_dir();
let stock = self.load_stock(stock_path)?;
let stock = self.rgb_stock()?;
self.rgb_wallet_from_stock(config, stock)
}

Expand Down
18 changes: 12 additions & 6 deletions cli/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ use rgb::{
RgbKeychain, RgbWallet, StateType, TransferParams, WalletError, WalletProvider, XChain,
XOutpoint, XOutputSeal,
};
use rgbstd::containers::ConsignmentExt;
use serde_crate::{Deserialize, Serialize};
use strict_types::encoding::{FieldName, TypeName};
use strict_types::StrictVal;
Expand Down Expand Up @@ -345,23 +346,23 @@ impl Exec for RgbArgs {
standard: Some(IfaceStandard::Rgb20),
} => {
let stock = self.rgb_stock()?;
for info in stock.contracts_by::<Rgb20>()? {
for info in stock.contracts_by::<Rgb20<_>>()? {
print!("{info}");
}
}
Command::Contracts {
standard: Some(IfaceStandard::Rgb21),
} => {
let stock = self.rgb_stock()?;
for info in stock.contracts_by::<Rgb21>()? {
for info in stock.contracts_by::<Rgb21<_>>()? {
print!("{info}");
}
}
Command::Contracts {
standard: Some(IfaceStandard::Rgb25),
} => {
let stock = self.rgb_stock()?;
for info in stock.contracts_by::<Rgb25>()? {
for info in stock.contracts_by::<Rgb25<_>>()? {
print!("{info}");
}
}
Expand Down Expand Up @@ -488,7 +489,8 @@ impl Exec for RgbArgs {

let contract = stock.contract_iface(*contract_id, tn!(iface.to_owned()))?;

let filter = match self.rgb_wallet_from_stock(&config, stock) {
// TODO: Remove clone
let filter = match self.rgb_wallet_from_stock(&config, stock.clone()) {
Ok(wallet) if *all => Filter::WalletAll(wallet),
Ok(wallet) => Filter::Wallet(wallet),
Err(_) => {
Expand Down Expand Up @@ -1011,10 +1013,14 @@ impl Exec for RgbArgs {
// TODO: Add sigs debugging

// State
for (id, history) in stock.as_state_provider().debug_history() {
fs::write(
format!("{root_dir}/state/witnesses.yaml"),
serde_yaml::to_string(stock.as_state_provider().debug_witnesses())?,
)?;
for (id, state) in stock.as_state_provider().debug_contracts() {
fs::write(
format!("{root_dir}/state/{id:-}.yaml"),
serde_yaml::to_string(history)?,
serde_yaml::to_string(state)?,
)?;
}

Expand Down
11 changes: 6 additions & 5 deletions src/indexers/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ use std::collections::HashMap;
use bp::Tx;
use bpstd::Network;
use rgbstd::containers::Consignment;
use rgbstd::resolvers::ResolveHeight;
use rgbstd::resolvers::ResolveWitnessAnchor;
use rgbstd::validation::{ResolveWitness, WitnessResolverError};
use rgbstd::{WitnessAnchor, XWitnessId, XWitnessTx};
use rgbstd::vm::WitnessAnchor;
use rgbstd::{XWitnessId, XWitnessTx};

use crate::{Txid, WitnessOrd, XChain};

Expand Down Expand Up @@ -106,15 +107,15 @@ impl AnyResolver {
}
}

impl ResolveHeight for AnyResolver {
fn resolve_height(&mut self, witness_id: XWitnessId) -> Result<WitnessAnchor, String> {
impl ResolveWitnessAnchor for AnyResolver {
fn resolve_witness_anchor(&mut self, witness_id: XWitnessId) -> Result<WitnessAnchor, String> {
let XWitnessId::Bitcoin(txid) = witness_id else {
return Err(format!("{} is not supported as layer 1 network", witness_id.layer1()));
};

if self.terminal_txes.contains_key(&txid) {
return Ok(WitnessAnchor {
witness_ord: WitnessOrd::OffChain,
witness_ord: WitnessOrd::offchain(0),
witness_id,
});
}
Expand Down
9 changes: 7 additions & 2 deletions src/indexers/electrum_blocking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ use std::iter;
use bp::ConsensusDecode;
use bpstd::{Network, Tx, Txid};
use electrum::{Client, ElectrumApi, Error, Param};
use rgbstd::{WitnessAnchor, WitnessOrd, WitnessPos, XWitnessId};
use rgbstd::vm::WitnessAnchor;
use rgbstd::{WitnessOrd, WitnessPos, XWitnessId};

use super::RgbResolver;

Expand Down Expand Up @@ -70,7 +71,7 @@ impl RgbResolver for Client {

fn resolve_height(&mut self, txid: Txid) -> Result<WitnessAnchor, String> {
let mut witness_anchor = WitnessAnchor {
witness_ord: WitnessOrd::OffChain,
witness_ord: WitnessOrd::Archived,
witness_id: XWitnessId::Bitcoin(txid),
};

Expand Down Expand Up @@ -103,6 +104,10 @@ impl RgbResolver for Client {
.and_then(|x| u32::try_from(x).ok())
.ok_or(Error::InvalidResponse(tx_details.clone()))
);
if confirmations == 0 {
witness_anchor.witness_ord = WitnessOrd::OffChain { priority: 1 };
return Ok(witness_anchor);
}
let block_time = check!(
tx_details
.get("blocktime")
Expand Down
6 changes: 4 additions & 2 deletions src/indexers/esplora_blocking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
use bp::Tx;
use bpstd::{Network, Txid};
use esplora::{BlockingClient, Error};
use rgbstd::{WitnessAnchor, WitnessOrd, WitnessPos};
use rgbstd::vm::WitnessAnchor;
use rgbstd::{WitnessOrd, WitnessPos};

use super::RgbResolver;
use crate::XWitnessId;
Expand All @@ -46,7 +47,8 @@ impl RgbResolver for BlockingClient {
Some((h, t)) => {
WitnessOrd::OnChain(WitnessPos::new(h, t as i64).ok_or(Error::InvalidServerData)?)
}
None => WitnessOrd::OffChain,
// TODO: Figure out how to detect mempool transactions
None => WitnessOrd::Archived,
};
Ok(WitnessAnchor {
witness_ord: ord,
Expand Down
2 changes: 1 addition & 1 deletion src/indexers/mempool_blocking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
use bp::Tx;
use bpstd::{Network, Txid};
use esplora::{BlockingClient, Config, Error};
use rgbstd::WitnessAnchor;
use rgbstd::vm::WitnessAnchor;

use super::RgbResolver;

Expand Down
64 changes: 39 additions & 25 deletions src/pay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,18 @@ use psrgbt::{
TxParams,
};
use rgbstd::containers::Transfer;
use rgbstd::interface::{OutpointFilter, WitnessFilter};
use rgbstd::interface::OutpointFilter;
use rgbstd::invoice::{Amount, Beneficiary, InvoiceState, RgbInvoice};
use rgbstd::persistence::{IndexProvider, StashProvider, StateProvider, Stock};
use rgbstd::{ContractId, DataState, XChain, XOutpoint};
use rgbstd::resolvers::ResolveWitnessAnchor;
use rgbstd::{ContractId, DataState, WitnessOrd, XChain, XOutpoint};

use crate::invoice::NonFungible;
use crate::vm::WitnessAnchor;
use crate::wrapper::WalletWrapper;
use crate::{CompletionError, CompositionError, DescriptorRgb, PayError, RgbKeychain, Txid};
use crate::{
CompletionError, CompositionError, DescriptorRgb, PayError, RgbKeychain, Txid, XWitnessId,
};

#[derive(Clone, PartialEq, Debug)]
pub struct TransferParams {
Expand Down Expand Up @@ -95,7 +99,7 @@ where W::Descr: DescriptorRgb<K>
pub trait WalletProvider<K>: PsbtConstructor
where Self::Descr: DescriptorRgb<K>
{
type Filter<'a>: Copy + WitnessFilter + OutpointFilter
type Filter<'a>: Copy + OutpointFilter
where Self: 'a;
fn filter(&self) -> Self::Filter<'_>;
fn descriptor_mut<R>(&mut self, f: impl FnOnce(&mut WalletDescr<K, Self::Descr>) -> R) -> R;
Expand All @@ -111,7 +115,7 @@ where Self::Descr: DescriptorRgb<K>
) -> Result<(Psbt, PsbtMeta, Transfer), PayError> {
let (mut psbt, meta) = self.construct_psbt_rgb(stock, invoice, params)?;
// ... here we pass PSBT around signers, if necessary
let transfer = self.transfer(stock, invoice, &mut psbt)?;
let transfer = self.transfer(stock, invoice, &mut psbt, 2)?;
Ok((psbt, meta, transfer))
}

Expand All @@ -127,9 +131,6 @@ where Self::Descr: DescriptorRgb<K>

let iface_name = invoice.iface.clone().ok_or(CompositionError::NoIface)?;
let iface = stock.iface(iface_name.clone()).map_err(|e| e.to_string())?;
let contract = stock
.contract_iface(contract_id, iface_name)
.map_err(|e| e.to_string())?;
let operation = invoice
.operation
.as_ref()
Expand All @@ -148,14 +149,17 @@ where Self::Descr: DescriptorRgb<K>
.cloned()
.ok_or(CompositionError::NoAssignment)?;

let filter = ContractOutpointsFilter {
contract_id,
stock,
wallet: self,
_phantom: PhantomData,
};
let contract = stock
.contract_iface(contract_id, iface_name)
.map_err(|e| e.to_string())?;
let prev_outputs = match invoice.owned_state {
InvoiceState::Amount(amount) => {
let filter = ContractOutpointsFilter {
contract_id,
stock,
wallet: self,
_phantom: PhantomData,
};
let state: BTreeMap<_, Vec<Amount>> = contract
.fungible(assignment_name, &filter)?
.fold(bmap![], |mut set, a| {
Expand Down Expand Up @@ -183,17 +187,9 @@ where Self::Descr: DescriptorRgb<K>
.collect::<BTreeSet<_>>()
}
InvoiceState::Data(NonFungible::RGB21(allocation)) => {
let filter = ContractOutpointsFilter {
contract_id,
stock,
wallet: self,
_phantom: PhantomData,
};
let state = contract.data(assignment_name, &filter)?.collect::<Vec<_>>();

let data_state = DataState::from(allocation);
state
.into_iter()
contract
.data(assignment_name, &filter)?
.filter(|x| x.state == data_state)
.map(|x| x.seal)
.collect::<BTreeSet<_>>()
Expand Down Expand Up @@ -278,6 +274,7 @@ where Self::Descr: DescriptorRgb<K>
stock: &mut Stock<S, H, P>,
invoice: &RgbInvoice,
psbt: &mut Psbt,
priority: u32,
) -> Result<Transfer, CompletionError> {
let contract_id = invoice.contract.ok_or(CompletionError::NoContract)?;

Expand Down Expand Up @@ -311,7 +308,24 @@ where Self::Descr: DescriptorRgb<K>
Beneficiary::BlindedSeal(seal) => (vec![XChain::Bitcoin(seal)], vec![]),
};

stock.consume_fascia(fascia).map_err(|e| e.to_string())?;
struct FasciaResolver {
priority: u32,
}
impl ResolveWitnessAnchor for FasciaResolver {
fn resolve_witness_anchor(
&mut self,
witness_id: XWitnessId,
) -> Result<WitnessAnchor, String> {
Ok(WitnessAnchor {
witness_ord: WitnessOrd::offchain(self.priority),
witness_id,
})
}
}

stock
.consume_fascia(fascia, FasciaResolver { priority })
.map_err(|e| e.to_string())?;
let transfer = stock
.transfer(contract_id, beneficiary2, beneficiary1)
.map_err(|e| e.to_string())?;
Expand Down
4 changes: 2 additions & 2 deletions src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ where W::Descr: DescriptorRgb<K>
.contract_iface(contract_id, iref)
.map_err(|e| e.to_string())?;
Ok(contract
.fungible_ops::<AmountChange>(state_name, wallet.filter(), wallet.filter())
.fungible_ops::<AmountChange>(state_name, wallet.filter())
.map_err(|e| e.to_string())?)
}

Expand Down Expand Up @@ -159,6 +159,6 @@ where W::Descr: DescriptorRgb<K>
invoice: &RgbInvoice,
psbt: &mut Psbt,
) -> Result<Transfer, CompletionError> {
self.wallet.transfer(&mut self.stock, invoice, psbt)
self.wallet.transfer(&mut self.stock, invoice, psbt, 2)
}
}
Loading

0 comments on commit cb0b8ff

Please sign in to comment.