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

Support new witness filtering #227

Merged
merged 6 commits into from
Aug 9, 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
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
Loading