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

Make Wallet require a change descriptor #1390

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

ValuedMammal
Copy link
Contributor

@ValuedMammal ValuedMammal commented Mar 27, 2024

All Wallet constructors are modified to require a change descriptor, where previously it was optional. Additionally we enforce uniqueness of the change descriptor to avoid ambiguity when deriving scripts and ensure the wallet will always have two distinct keychains.

Notable changes

  • Add error DescriptorError::ExternalAndInternalAreTheSame
  • Remove error CreateTxError::ChangePolicyDescriptor
  • No longer rely on map_keychain

fixes #1383

Notes to the reviewers

Changelog notice

Changed:

Constructing a Wallet now requires two distinct descriptors.

Checklists

All Submissions:

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

@ValuedMammal
Copy link
Contributor Author

ValuedMammal commented Mar 27, 2024

Do we want to keep the change descriptor optional for example_cli? I'm guessing it won't hurt anything since we don't actually use the wallet.

Copy link
Contributor

@storopoli storopoli left a comment

Choose a reason for hiding this comment

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

Some comments

crates/bdk/examples/compiler.rs Outdated Show resolved Hide resolved
crates/bdk/examples/compiler.rs Outdated Show resolved Hide resolved
crates/bdk/src/descriptor/error.rs Outdated Show resolved Hide resolved
crates/bdk/src/descriptor/template.rs Outdated Show resolved Hide resolved
crates/bdk/src/descriptor/template.rs Outdated Show resolved Hide resolved
crates/bdk/src/descriptor/template.rs Outdated Show resolved Hide resolved
crates/bdk/src/descriptor/template.rs Outdated Show resolved Hide resolved
crates/bdk/src/wallet/export.rs Outdated Show resolved Hide resolved
@ValuedMammal ValuedMammal force-pushed the refactor/wallet-descriptor branch 2 times, most recently from edd290d to 238c292 Compare March 27, 2024 23:30
@ValuedMammal ValuedMammal marked this pull request as ready for review March 27, 2024 23:30
@casey-bowman
Copy link
Contributor

casey-bowman commented Mar 28, 2024

If two descriptors are the same except that each has a different extended public key that is replaced by the corresponding extended private key, do these qualify as distinct?

Also, to clarify, the receive descriptors for any two wallets must also be distinct with this change, too, correct?
UPDATE - Oh, I see the issue #1383

Copy link
Member

@evanlinjin evanlinjin left a comment

Choose a reason for hiding this comment

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

I'm concerned with the way we are checking whether the 2 keychains are "distinct". I have a few questions.

  1. How can we guarantee that into_wallet_descriptor returns the same public-descriptor string for all non-distinct descriptors?
  2. How can we ensure that a non-wildcard descriptor and a wildcard descriptor has no overlaps (the non-wildcard descriptor's spk can be derived from the wildcard descriptor).

For 2. also refer to my comment here: #1383 (comment)

crates/bdk/src/wallet/mod.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@LLFourn LLFourn left a comment

Choose a reason for hiding this comment

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

ACK 04c8750

I'm going to be away so not going to get another chance to look at this. It LGTM. Feel free to keep shedding. Thanks for taking on this rather tedious PR.

crates/bdk/src/descriptor/error.rs Outdated Show resolved Hide resolved
@ValuedMammal ValuedMammal force-pushed the refactor/wallet-descriptor branch 2 times, most recently from e3ba751 to cba43de Compare April 5, 2024 13:28
@ValuedMammal
Copy link
Contributor Author

Small changes

  • Fixed key_* names in descriptor template docs
  • Changed the new descriptor error to just ExternalAndInternalAreTheSame

@ValuedMammal
Copy link
Contributor Author

1. How can we guarantee that `into_wallet_descriptor` returns the same public-descriptor string for all non-distinct descriptors?

2. How can we ensure that a non-wildcard descriptor and a wildcard descriptor has no overlaps (the non-wildcard descriptor's spk can be derived from the wildcard descriptor).

To point 1) I don't think you're objecting to checking equality for two values of Descriptor<DescriptorPublicKey>, which is only true for identical descriptors, i.e. ones that derive 100% of the same scripts. Maybe this was addressed in the discussion around point 2?

Note that the public descriptor will be common whether the wallet is given a public or private descriptor. So for example this should pass:

#[test]
fn same_descriptor_public_private() {
    // public + private of same descriptor should fail to create wallet
    let desc = "wpkh(tprv8ZgxMBicQKsPdcAqYBpzAFwU5yxBUo88ggoBqu1qPcHUfSbKK1sKMLmC7EAk438btHQrSdu3jGGQa6PA71nvH5nkDexhLteJqkM4dQmWF9g/84'/1'/0'/0/*)";
    let change = "wpkh([3c31d632/84'/1'/0']tpubDCYwFkks2cg78N7eoYbBatsFEGje8vW8arSKW4rLwD1AU1s9KJMDRHE32JkvYERuiFjArrsH7qpWSpJATed5ShZbG9KsskA5Rmi6NSYgYN2/0/*)";

    let err = Wallet::new_no_persist(desc, change, Network::Testnet);
    assert!(matches!(
        err,
        Err(DescriptorError::ExternalAndInternalAreTheSame),
    ));
}

@ValuedMammal
Copy link
Contributor Author

Rebased on 358e842

Copy link
Contributor

@storopoli storopoli left a comment

Choose a reason for hiding this comment

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

ACK cddefbb

All `Wallet` constructors are modified to require a change
descriptor, where previously it was optional. Additionally
we enforce uniqueness of the change descriptor to avoid
ambiguity when deriving scripts and ensure the wallet will
always have two distinct keystores.

Notable changes

* Add error DescriptorError::ExternalAndInternalAreTheSame
* Remove error CreateTxError::ChangePolicyDescriptor
* No longer rely on `map_keychain`
Since we will have persisted descriptors for both
keychains.

This also means we're guaranteed to have gotten a
descriptor in the case `LoadedDescriptorDoesNotMatch`.
@ValuedMammal
Copy link
Contributor Author

Rebased on 7607b49 and added two commits, but this may need more discussion and testing to decide if it's a reasonable solution

Copy link
Contributor

@storopoli storopoli left a comment

Choose a reason for hiding this comment

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

Totally agree with the infallible.

ACK aec4dda

Note that you might want to update the original PR message details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api A breaking API change module-wallet
Projects
Status: Needs Review
Development

Successfully merging this pull request may close these issues.

Wallet must have unique Internal and External descriptors
6 participants