Skip to content

Commit

Permalink
wallet: distinguish spent and unspent outputs
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Sep 20, 2024
1 parent 954f7f2 commit d90e674
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 30 deletions.
5 changes: 2 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,5 @@ serde = ["serde_crate", "serde_yaml", "bp-std/serde", "descriptors/serde", "rgb-
features = ["all"]

[patch.crates-io]
bp-wallet = { git = "https://github.com/BP-WG/bp-wallet", branch = "develop" }
rgb-std = { git = "https://github.com/RGB-WG/rgb-std", branch = "fix/rgb-252" }
21 changes: 13 additions & 8 deletions cli/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pub enum Command {
/// Reports information about state of a contract
#[display("state")]
State {
/// Show all state - not just the one owned by the wallet
/// Show all state, including already spent and not owned by the wallet
#[clap(short, long)]
all: bool,

Expand Down Expand Up @@ -379,9 +379,9 @@ impl Exec for RgbArgs {
witness,
} in history

Check warning on line 380 in cli/src/command.rs

View check run for this annotation

Codecov / codecov/patch

cli/src/command.rs#L374-L380

Added lines #L374 - L380 were not covered by tests
{
print!("{direction: <9}\t");
print!("{direction:<9}\t");
if let AllocatedState::Amount(amount) = state {
print!("{: >9}", amount.value());
print!("{:>9}", amount.value());
} else {
print!("{state}");
}
Expand Down Expand Up @@ -563,9 +563,10 @@ impl Exec for RgbArgs {
id: Option<XWitnessId>,
) -> bool {

Check warning on line 564 in cli/src/command.rs

View check run for this annotation

Codecov / codecov/patch

cli/src/command.rs#L560-L564

Added lines #L560 - L564 were not covered by tests
match self {
Filter::Wallet(wallet) => {
wallet.wallet().filter().should_include(outpoint, id)
}
Filter::Wallet(wallet) => wallet
.wallet()
.filter_unspent()
.should_include(outpoint, id),

Check warning on line 569 in cli/src/command.rs

View check run for this annotation

Codecov / codecov/patch

cli/src/command.rs#L566-L569

Added lines #L566 - L569 were not covered by tests
_ => true,
}
}
Expand All @@ -574,11 +575,15 @@ impl Exec for RgbArgs {
fn comment(&self, outpoint: XOutpoint) -> &'static str {
match self {
Filter::Wallet(wallet) | Filter::WalletAll(wallet)
if wallet.wallet().filter().should_include(outpoint, None) =>
if wallet
.wallet()
.filter_unspent()
.should_include(outpoint, None) =>

Check warning on line 581 in cli/src/command.rs

View check run for this annotation

Codecov / codecov/patch

cli/src/command.rs#L578-L581

Added lines #L578 - L581 were not covered by tests
{
""
}
_ => "-- owner unknown",
Filter::WalletAll(_) => "",
_ => "-- third-party",

Check warning on line 586 in cli/src/command.rs

View check run for this annotation

Codecov / codecov/patch

cli/src/command.rs#L585-L586

Added lines #L585 - L586 were not covered by tests
}
}
}
Expand Down
37 changes: 28 additions & 9 deletions src/filters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use bp::Bp;
use bpwallet::Wallet;
use rgbstd::interface::AssignmentsFilter;

use crate::{DescriptorRgb, WalletProvider, XChain, XOutpoint, XWitnessId};
use crate::{DescriptorRgb, XChain, XOutpoint, XWitnessId};

pub struct WalletOutpointsFilter<'a, K, D: DescriptorRgb<K>>(pub &'a Wallet<K, D>);

Expand All @@ -35,23 +36,41 @@ impl<'a, K, D: DescriptorRgb<K>> Clone for WalletOutpointsFilter<'a, K, D> {

impl<'a, K, D: DescriptorRgb<K>> AssignmentsFilter for WalletOutpointsFilter<'a, K, D> {
fn should_include(&self, output: impl Into<XOutpoint>, _: Option<XWitnessId>) -> bool {
let output = output.into();
self.0
.outpoints()
.any(|outpoint| XChain::Bitcoin(outpoint) == *output)
match output.into().into_bp() {
Bp::Bitcoin(outpoint) => self.0.has_outpoint(outpoint),
Bp::Liquid(_) => false,

Check warning on line 41 in src/filters.rs

View check run for this annotation

Codecov / codecov/patch

src/filters.rs#L38-L41

Added lines #L38 - L41 were not covered by tests
}
}

Check warning on line 43 in src/filters.rs

View check run for this annotation

Codecov / codecov/patch

src/filters.rs#L43

Added line #L43 was not covered by tests
}

pub struct WalletUnspentFilter<'a, K, D: DescriptorRgb<K>>(pub &'a Wallet<K, D>);

// We need manual derivation to ensure we can be copied and cloned even if descriptor is not
// copyable/clonable.
impl<'a, K, D: DescriptorRgb<K>> Copy for WalletUnspentFilter<'a, K, D> {}
impl<'a, K, D: DescriptorRgb<K>> Clone for WalletUnspentFilter<'a, K, D> {
fn clone(&self) -> Self { *self }

Check warning on line 52 in src/filters.rs

View check run for this annotation

Codecov / codecov/patch

src/filters.rs#L52

Added line #L52 was not covered by tests
}

impl<'a, K, D: DescriptorRgb<K>> AssignmentsFilter for WalletUnspentFilter<'a, K, D> {
fn should_include(&self, output: impl Into<XOutpoint>, _: Option<XWitnessId>) -> bool {
match output.into().into_bp() {
Bp::Bitcoin(outpoint) => self.0.is_unspent(outpoint),
Bp::Liquid(_) => false,

Check warning on line 59 in src/filters.rs

View check run for this annotation

Codecov / codecov/patch

src/filters.rs#L56-L59

Added lines #L56 - L59 were not covered by tests
}
}

Check warning on line 61 in src/filters.rs

View check run for this annotation

Codecov / codecov/patch

src/filters.rs#L61

Added line #L61 was not covered by tests
}

pub struct WitnessOutpointsFilter<'a, K, D: DescriptorRgb<K>>(pub &'a Wallet<K, D>);
pub struct WalletWitnessFilter<'a, K, D: DescriptorRgb<K>>(pub &'a Wallet<K, D>);

// We need manual derivation to ensure we can be copied and cloned even if descriptor is not
// copyable/clonable.
impl<'a, K, D: DescriptorRgb<K>> Copy for WitnessOutpointsFilter<'a, K, D> {}
impl<'a, K, D: DescriptorRgb<K>> Clone for WitnessOutpointsFilter<'a, K, D> {
impl<'a, K, D: DescriptorRgb<K>> Copy for WalletWitnessFilter<'a, K, D> {}
impl<'a, K, D: DescriptorRgb<K>> Clone for WalletWitnessFilter<'a, K, D> {
fn clone(&self) -> Self { *self }

Check warning on line 70 in src/filters.rs

View check run for this annotation

Codecov / codecov/patch

src/filters.rs#L70

Added line #L70 was not covered by tests
}

impl<'a, K, D: DescriptorRgb<K>> AssignmentsFilter for WitnessOutpointsFilter<'a, K, D> {
impl<'a, K, D: DescriptorRgb<K>> AssignmentsFilter for WalletWitnessFilter<'a, K, D> {
fn should_include(&self, _: impl Into<XOutpoint>, witness_id: Option<XWitnessId>) -> bool {
self.0
.history()
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,5 @@ pub mod resolvers {
}
}
}
pub use filters::{WalletOutpointsFilter, WitnessOutpointsFilter};
pub use filters::{WalletOutpointsFilter, WalletUnspentFilter, WalletWitnessFilter};
pub use wallet::RgbWallet;
19 changes: 11 additions & 8 deletions src/pay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,12 @@ use rgbstd::persistence::{IndexProvider, StashProvider, StateProvider, Stock};
use rgbstd::validation::ResolveWitness;
use rgbstd::{ContractId, DataState, XChain, XOutpoint};

use crate::filters::WalletOutpointsFilter;
use crate::invoice::NonFungible;
use crate::validation::WitnessResolverError;
use crate::vm::{WitnessOrd, XWitnessTx};
use crate::{
CompletionError, CompositionError, DescriptorRgb, PayError, RgbKeychain, Txid,
WitnessOutpointsFilter, XWitnessId,
WalletOutpointsFilter, WalletUnspentFilter, WalletWitnessFilter, XWitnessId,
};

#[derive(Clone, PartialEq, Debug)]
Expand Down Expand Up @@ -91,7 +90,7 @@ where W::Descr: DescriptorRgb<K>
{
fn should_include(&self, output: impl Into<XOutpoint>, id: Option<XWitnessId>) -> bool {

Check warning on line 91 in src/pay.rs

View check run for this annotation

Codecov / codecov/patch

src/pay.rs#L91

Added line #L91 was not covered by tests
let output = output.into();
if !self.wallet.filter().should_include(output, id) {
if !self.wallet.filter_unspent().should_include(output, id) {

Check warning on line 93 in src/pay.rs

View check run for this annotation

Codecov / codecov/patch

src/pay.rs#L93

Added line #L93 was not covered by tests
return false;
}
matches!(self.stock.contract_assignments_for(self.contract_id, [output]), Ok(list) if !list.is_empty())
Expand All @@ -101,13 +100,15 @@ where W::Descr: DescriptorRgb<K>
pub trait WalletProvider<K>: PsbtConstructor
where Self::Descr: DescriptorRgb<K>
{
fn filter(&self) -> impl AssignmentsFilter + Clone;
fn filter_outpoints(&self) -> impl AssignmentsFilter + Clone;
fn filter_unspent(&self) -> impl AssignmentsFilter + Clone;
fn filter_witnesses(&self) -> impl AssignmentsFilter + Clone;
fn with_descriptor_mut<R>(
&mut self,
f: impl FnOnce(&mut WalletDescr<K, Self::Descr>) -> R,
) -> R;
fn outpoints(&self) -> impl Iterator<Item = Outpoint>;
fn utxos(&self) -> impl Iterator<Item = Outpoint>;
fn txos(&self) -> impl Iterator<Item = Outpoint>;
fn txids(&self) -> impl Iterator<Item = Txid>;
fn history(&self) -> impl Iterator<Item = TxRow<impl Layer2Tx>> + '_;

Expand Down Expand Up @@ -352,12 +353,14 @@ where Self::Descr: DescriptorRgb<K>
}

impl<K, D: DescriptorRgb<K>> WalletProvider<K> for Wallet<K, D> {
fn filter(&self) -> impl AssignmentsFilter + Clone { WalletOutpointsFilter(self) }
fn filter_witnesses(&self) -> impl AssignmentsFilter + Clone { WitnessOutpointsFilter(self) }
fn filter_outpoints(&self) -> impl AssignmentsFilter + Clone { WalletOutpointsFilter(self) }
fn filter_unspent(&self) -> impl AssignmentsFilter + Clone { WalletUnspentFilter(self) }
fn filter_witnesses(&self) -> impl AssignmentsFilter + Clone { WalletWitnessFilter(self) }

Check warning on line 358 in src/pay.rs

View check run for this annotation

Codecov / codecov/patch

src/pay.rs#L356-L358

Added lines #L356 - L358 were not covered by tests
fn with_descriptor_mut<R>(&mut self, f: impl FnOnce(&mut WalletDescr<K, D>) -> R) -> R {
self.descriptor_mut(f)
}
fn outpoints(&self) -> impl Iterator<Item = Outpoint> { self.coins().map(|coin| coin.outpoint) }
fn utxos(&self) -> impl Iterator<Item = Outpoint> { self.coins().map(|coin| coin.outpoint) }
fn txos(&self) -> impl Iterator<Item = Outpoint> { self.txos().map(|txo| txo.outpoint) }

Check warning on line 363 in src/pay.rs

View check run for this annotation

Codecov / codecov/patch

src/pay.rs#L362-L363

Added lines #L362 - L363 were not covered by tests
fn txids(&self) -> impl Iterator<Item = Txid> { self.transactions().keys().copied() }

fn history(&self) -> impl Iterator<Item = TxRow<impl Layer2Tx>> + '_ { self.history() }

Check warning on line 366 in src/pay.rs

View check run for this annotation

Codecov / codecov/patch

src/pay.rs#L366

Added line #L366 was not covered by tests
Expand Down
2 changes: 1 addition & 1 deletion src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ where W::Descr: DescriptorRgb<K>
) -> Result<Vec<ContractOp>, StockError<S, H, P, ContractIfaceError>> {
let contract = self.stock.contract_iface(contract_id, iface.into())?;

Check warning on line 116 in src/wallet.rs

View check run for this annotation

Codecov / codecov/patch

src/wallet.rs#L115-L116

Added lines #L115 - L116 were not covered by tests
let wallet = &self.wallet;
Ok(contract.history(wallet.filter(), wallet.filter_witnesses()))
Ok(contract.history(wallet.filter_outpoints(), wallet.filter_witnesses()))

Check warning on line 118 in src/wallet.rs

View check run for this annotation

Codecov / codecov/patch

src/wallet.rs#L118

Added line #L118 was not covered by tests
}

#[allow(clippy::result_large_err)]
Expand Down

0 comments on commit d90e674

Please sign in to comment.