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 Spending Policy API #612

Closed
wants to merge 12 commits into from

Conversation

BitcoinZavior
Copy link
Contributor

@BitcoinZavior BitcoinZavior commented Oct 25, 2024

Description

Fixes the follwoing bug:

Encountering a Spending policy required: External error when attempting to build a transaction using a multi-sig descriptor. Currently, bdk-ffi does not provide a policy_path() in txBuilder, which is necessary for specifying the correct policy path during transaction creation.

The PR fix has the following changes:

  • Expose policies() from the wallet to retrieve available spending policies.
  • Add support for policy_path() in txBuilder to allow specifying the correct policy path when building the transaction.

Changelog notice

### Fixes

  • Resolved issue with building a transaction using a multi-sig descriptor resulted in a Spending policy error.
  • Added support for specifying a policy path in tx_builder using policy_path, enabling correct multi-sig spending policy specification during transaction creation.

Enhancements

  • Exposed policies() from the wallet to allow users to retrieve available spending policies for their wallet.

Checklists

All Submissions:

  • I've signed all my commits
  • I followed the contribution guidelines
  • I ran cargo fmt and cargo clippy before committing

New Features:

  • I've added tests for the new feature

Bugfixes:

@BitcoinZavior BitcoinZavior marked this pull request as ready for review October 28, 2024 14:08
Copy link
Collaborator

@reez reez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Thanks!!

A couple comments that are just notes and don't require any action, and then one question and two nits, but nothing that blocks me approving this or us merging as is:

ACK 4925a8d

Side question:

  • I see you checked I've added tests for the new feature in the PR template does that mean you are planning on adding a test (I didn't see one in current code)? Not even saying it's needed (and I'm assuming you tested on an external application since you opened Spending Policy Required: External error on tx builder finish #605 ). Note: I didn't test on an external app during this PR review.

@@ -401,6 +401,9 @@ interface Wallet {

string descriptor_checksum(KeychainKind keychain);

[Throws=DescriptorError]
Policy? policies(KeychainKind keychain);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -441,6 +444,10 @@ interface Wallet {

interface Update {};

interface Policy {
string id();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the only field you need/want for your use case? Just curious really, since we can expose other fields later if needed obv.

Regardless, looks good https://docs.rs/bdk_wallet/latest/bdk_wallet/descriptor/policy/struct.Policy.html

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other fields have been exposed now.

@@ -456,6 +463,8 @@ interface TxBuilder {

TxBuilder add_utxo(OutPoint outpoint);

TxBuilder policy_path(record<string, sequence<u64>> policy_path, KeychainKind keychain);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thanks!

use bdk_wallet::AddressInfo as BdkAddressInfo;
use bdk_wallet::Balance as BdkBalance;
use bdk_wallet::KeychainKind;
use bdk_wallet::LocalOutput as BdkLocalOutput;
use bdk_wallet::Update as BdkUpdate;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think we can keep this blank line since we seem to break these use in groups

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

@@ -154,8 +161,7 @@ impl Wallet {

pub(crate) fn sign(
&self,
psbt: Arc<Psbt>,
// sign_options: Option<SignOptions>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: might be nice to keep this on a separate line, but at the same time not any sort of blocker to approving this PR (and we might just remove the whole commented line before 1.0 beta anyway on bdk-ffi)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@thunderbiscuit
Copy link
Member

thunderbiscuit commented Oct 30, 2024

I'm trying to understand this Policy type better. Reading the Wallet::policies example I imagine this policy to be a tree/list of policy nodes, each with an ID. But the Wallet::policies() method returns a single Policy that has a single id?

How do I know which path (u32) to choose if I'm not given the whole tree and options to choose from? I see that the Policy type potentially contains a field of type SatisfiableItem, which itself could be of the variant

Thresh {
    items: Vec<Policy>,
    threshold: usize,
},

Should we expose this field too so that users can query the satifiable item(s)?

I'm just not clear on this API and I want to make sure we get you what you need.

Follow up

I tried using one of the multisig examples in the BIP-383 test vectors:

wsh(multi(2,xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*))

And I get this as a Policy:

Policy {
    id: "lrvxqx7c", 
    item: Multisig { 
        keys: [Fingerprint(bd16bee5), Fingerprint(5a61ff8e), Fingerprint(3442193e)],
        threshold: 2 
    }, 
    satisfaction: Partial {
        n: 3, 
        m: 2, 
        items: [], 
        sorted: Some(false),
        conditions: {} 
    },
    contribution: PartialComplete {
        n: 3, 
        m: 2, 
        items: [0, 1, 2], 
        sorted: Some(false),
        conditions: {
            [0, 1]: {Condition { csv: None, timelock: None }},
            [0, 2]: {Condition { csv: None, timelock: None }},
            [1, 2]: {Condition { csv: None, timelock: None }}
        } 
    } 
}

Is the vector you'd want to provide to the TxBuilder::policy_path method one of the options in the conditions field of the contribution field?

@afilini we might need your input here just to make sure we expose the correct behaviour and options.

@BitcoinZavior
Copy link
Contributor Author

Thanks @thunderbiscuit I have exposed other fields as well now.

@BitcoinZavior
Copy link
Contributor Author

Should we expose this field too so that users can query the satifiable item(s)?

I have now exposed this field

@BitcoinZavior
Copy link
Contributor Author

I'm trying to understand this Policy type better. Reading the Wallet::policies example I imagine this policy to be a tree/list of policy nodes, each with an ID. But the Wallet::policies() method returns a single Policy that has a single id?

How do I know which path (u32) to choose if I'm not given the whole tree and options to choose from? I see that the Policy type potentially contains a field of type SatisfiableItem, which itself could be of the variant

Thresh {
    items: Vec<Policy>,
    threshold: usize,
},

Should we expose this field too so that users can query the satifiable item(s)?

I'm just not clear on this API and I want to make sure we get you what you need.

@thunderbiscuit
I have now exposed that field too.

@BitcoinZavior
Copy link
Contributor Author

I'm just not clear on this API and I want to make sure we get you what you need.

@thunderbiscuit Yes this is what we need. An integration test has been added here for the use case using the new exposed API:
https://github.com/LtbLightning/bdk-flutter/pull/147/files#diff-7c1bbba299e1163f3f58b2261196dbc0d886e22f40451fdb463ca1409d2b9ef6

@thunderbiscuit
Copy link
Member

Thanks for the work @BitcoinZavior! I squashed and rebased. Merging now.

@thunderbiscuit
Copy link
Member

For some reason I can't force push to your branch. But I added your commit in #626.

@thunderbiscuit
Copy link
Member

Merged in #629. Thanks for the work @BitcoinZavior!

@reez
Copy link
Collaborator

reez commented Nov 15, 2024

Awesome work @BitcoinZavior !!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Spending Policy Required: External error on tx builder finish
3 participants