-
Notifications
You must be signed in to change notification settings - Fork 139
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
Expose inner DescriptorPublicKey
functionality
#570
base: master
Are you sure you want to change the base?
Expose inner DescriptorPublicKey
functionality
#570
Conversation
a1dbaf5
to
dcfcc25
Compare
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
maybe_fmt_master_id(f, &self.origin)?; | ||
self.xkey.fmt(f)?; | ||
fmt_derivation_path(f, &self.derivation_path)?; | ||
match self.wildcard { | ||
Wildcard::None => {} | ||
Wildcard::Unhardened => write!(f, "/*")?, | ||
Wildcard::Hardened => write!(f, "/*h")?, | ||
} | ||
Ok(()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good candidate to extract to a fmt_xkey(origin, [paths])
function.
.ok_or(ConversionError::HardenedChild)?, | ||
), | ||
}; | ||
let definite = DescriptorPublicKey::XPub(DescriptorXKey { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an awkward "upward" instantiation of the DescriptorPublicKey
type.
An idea: DefiniteDescriptorKey::new
could take a DescriptorInnerKey
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe DescriptorInnerKey
should have an Into<DescriptorPublicKey>
bound?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧠 💡
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Erm, that'll require DescriptorInnerKey
DescriptorKey
to be made object-safe. That's beyond my ken.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might be as simple as sticking a : Sized
bound on the trait? What error do you get?
a6f0354
to
14799e2
Compare
src/descriptor/key.rs
Outdated
@@ -525,6 +525,53 @@ impl error::Error for ConversionError { | |||
} | |||
} | |||
|
|||
pub trait DescriptorInnerKey { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In e4d9af4:
Do you think we should add fmt::Display
and std::str::FromStr
bounds on this? How about Eq
, Hash
, etc.? (My vote is yes to all four, and maybe fmt::Debug
too.)
cc @sanket1729 who may have opinions here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a big fan of that, since it was the lack of Display
/ FromStr
that motivated this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added Clone + fmt::Debug + fmt::Display + Eq + FromStr + std::hash::Hash + Ord
to match the existing derivations.
@@ -525,6 +525,53 @@ impl error::Error for ConversionError { | |||
} | |||
} | |||
|
|||
pub trait DescriptorInnerKey { | |||
/// The fingerprint of the master key associated with this key, `0x00000000` if none. | |||
fn master_fingerprint(&self) -> bip32::Fingerprint; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In e4d9af4:
As a separate issue, I think we should return an option here and then upstream we should have a bip32::Fingerprint::from_opt
function that would do the 0x00000000 thing. Though I'm unsure. Maybe this function is only ever used in contexts where the result needs to be serialized (PSBT, encoding xpubs) in which case users always want the existng behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's sure where I'm using it. 😅
src/descriptor/key.rs
Outdated
@@ -525,6 +525,53 @@ impl error::Error for ConversionError { | |||
} | |||
} | |||
|
|||
pub trait DescriptorInnerKey { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In e4d9af4:
This can go in a separate PR, but like to have a type-level relationship between DescriptorPublicKey
and DescriptorSecretKey
. This would help me downstream in elements-miniscript where I want to define a "view key" for a confidential transaction descriptor, which has a private key in one slot and a public key in every other slot. I think it would also simplify a lot of usage of xprv descriptors, which currently require you maintain an xpub descriptor alongside a hashmap, though I haven't worked out the details.
One way we could do this is to add two associated types, like
type SecretKey: DescriptorInnerKey;
type PublicKey: DescriptorInnerKey;
where almost always one of these would be Self
.
I would also like first-class support for unspendable keys in taproot. I am imagining an UnspendableKey
whose SecretKey
type would be !
, or something.
Anyway these are just half-baked ideas that don't belong in this PR. But I want to bring them up in case they could guide this API.
Overall 14799e2 looks good. It's a straightforward enough diff and I am confirming that all commits pass all tests (looking good so far).
I don't think it would be breaking, but I also don't know that we need to worry about breaking changes here. Especially if we can also figure out the "what is the right way to relate private and public keys" and "what is the right way to handle unspendable keys" API questions. But yes, it did occur to me when reading the code that it might make sense to implement this on
Maybe just
Good to know. Let's revisit that if we decide to do a breaking change.
So, with But having said that, for keys we have continuously moved toward more trait usage, adding more traits and associated types etc. |
397d435
to
ef617d5
Compare
ef617d5
to
b18ba59
Compare
👍
I added a commit that does that. It's "breaking" insofar as consumers now need to import a trait. (e.g. see the change in |
Hello, thanks for this PR. Am I correct in summarizing that if we have a If this the case, we provide the same APIs for We can then offer some granular types with some guidelines as
Tihs obviously implies that you cannot single keys in your descriptor. Curious what @apoelstra thinks about this. Comment about the trait approachI am not sure about adding a trait, 1) It requires users to import it and 2) we are not using it any bounds here. Are you planning it downstream? If so, can you share you want it to be used as a bound? As Andrew mentioned in the #386, we found ourselves into a similar issue where we group things for I do think the trait has value only if we go all the way so that cc @tcharding worked on changing the previous long names that we had |
Maybe? Honestly, the type hierarchy is too complex for me to follow. That said, there's a lot of useful functionality on
I strongly agree with this sentiment. |
Our codebase has |
If all functionality for |
type DescriptorSinglePublicKey = SinglePub; | ||
type DescriptorExtendedPublicKey = DescriptorXKey<bip32::ExtendedPubKey>; | ||
type DescriptorMultiExtendedPublicKey = DescriptorMultiXKey<bip32::ExtendedPubKey>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO we should not start putting Extended
back into the identifiers of keys. The only other place that appears is in bitcoin::bip32
which is not a module to copy :)
In general I prefer shorter names if there is no ambiguity or loss of clarity. Thanks. |
Hi friends, it's me again! 👋
In our use of miniscript, we find ourselves writing constantly writing this idiom:
I'd love to directly use the
DescriptorXKey<bip32::ExtendedPubKey>
type; but, its functionality is anemic when compared to all the useful functions onDescriptorPublicKey
.The closer I looked at
DescriptorPublicKey
, the more I realised it was mostlymatch
blocks itself that delegated to different implementations based on the internal enum type. And, so, here's a PR that leans into that and reifies a trait (DescriptorInnerKey
) that encapsulates all that behaviour and three types that implement it:DescriptorSinglePublicKey
(a type alias forSinglePub
🤒)DescriptorExtendedPublicKey
DescriptorMultiExtendedPublicKey
This all said, I feel like this PR is still lacking. A few questions:
DescriptorPublicKey
could implement the trait too; but, I suspect that be a breaking change? Moreover …DescriptorInnerKey
is a weird name, especially when contrasted against the already existingInnerXKey
trait. I'm open to a better name!DescriptorPublicKey::into_single_keys
has been awkwardly left out of the extraction because it returns a vector ofDescriptorPublicKey
s. If I was going to do a breaking refactor, I'd probably move that method on toDescriptorMultiExtendedPublicKey
itself. 🤷DescriptorPublicKey
as astruct
just disappeared … and instead there was only aDescriptorPublicKey
trait?