-
Notifications
You must be signed in to change notification settings - Fork 335
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 extended descriptor multisig metadata to policy extraction #626
Conversation
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 went through the code briefly, and I have some comments on the MultisigScriptType
stuffs..
The script type should not multisig specific. We should be able to get the script type for any generic descriptors. So its should be a field inside the Policy
structure itself.
But the problem of doing that is our Policy
structure is recursive.. So we cannot just add an extra field inside the Policy
itself, as it will then get recursively added in the internal policy nodes too..
So Instead one way to do that would be to have a GlobalPolicy
structure, which includes the global ScriptType
and a Policy
. Then the remaining logic of Policy
structure remains the same, which can recursively include more policies in it.
Concept ACK on the XPub data..
@@ -76,6 +76,19 @@ pub enum PkOrF { | |||
XOnlyPubkey(XOnlyPublicKey), | |||
/// An extended key fingerprint | |||
Fingerprint(Fingerprint), | |||
/// serialization for xpub origin metadata |
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.
Can we call this "An XPub with origin metadata"?? As per the other item docs and sounds a bit more clear to me.
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 see the confusion. Basically because there's already something called origin
in the library (the field on the DescriptorXKey struct) so it's a little confusing. I guess I'm trying to find some name that represents the full struct necessary for defining an xpub in a meaningful way (e.g. when verifying membership in a multisig wallet, which is one of the primary use cases we're building this out for).
It's been a while since I've spent time in this code, so it's possible I'm missing something, but basically what I was originally thinking was where XpubOrigin
is an object that contains an Extended Public Key plus it's derivation/origin metadata.
OTOH, maybe I'm misunderstanding your comment and you're just asking to update this code comment 😅. In which case, maybe "serialization for xpub with derivation metadata" would be more clear to avoid the naming clash with origin?
@@ -76,6 +76,19 @@ pub enum PkOrF { | |||
XOnlyPubkey(XOnlyPublicKey), | |||
/// An extended key fingerprint | |||
Fingerprint(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.
Seems like we also don't need this FingerPrint
anymore as its included in the XpubOrigin??
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.
Yep! Good catch.
/// Raw public key or extended key fingerprint | ||
#[derive(Debug, Clone, Default, Serialize, PartialEq, Eq, Hash)] | ||
pub struct XpubOrigin { | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
fingerprint: Option<Fingerprint>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
derivation_path: Option<DerivationPath>, | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
xkey: Option<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.
This seems to me representing a full XPub, not just the origin.. So we can name it better as just an XPub
?
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.
Are you referring to the struct XpubOrigin
or this field, xkey
?
In the contexts I'm most familiar working in, an xpub origin has more information than the xpub (extended public key) itself. Namely the origin is the xpub and the information describing how it was derived: fingerprint for the root (xfp
which might be a better name for that field) and the derivation path from root. The xpub only has its parent fingerprint and depth encoded (with some other data too of course.)
As for renaming xkey
, I forget why I put it as this, but I feel like I remember there being a reason, maybe some sort of naming clash. If that isn't a problem though then I'm not against renaming that to xpub
.
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 was actually referring to the struct name XpubOrigin
.. The name suggests that its an origin
for Xpub
, but its more like an XpubWithOrigin
. But I agree its mostly nomenclature and there's no right way to do it.. I think just the doc comment as something like /// Extended Publickey with origin information
is good enough to clarify what this struct is for.. The struct name can remain as it is..
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.
OTOH if I am not wrong, after parsing a descriptor we will always have the origin information? If no fingerprint and path is provided in the descriptor, bdk assumes it as the master key? If that's the case we can simply name this struct Xpub
and it will imply that origin information is already included in it.. As we never put an Xpub into a policy without its origin..
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.
Even if bdk never puts an xpub w/o origin details, if we're given one to interpret can you safely assume it's the root key? You don't need the origin information for watch-only wallets for example since you only need those details to tell the master key how to sign. We do something like this for unchained wallet configurations (which I want to use this tooling to convert to descriptors) where we only show actual origin information for keys that are yours (the clients) and blank out the origin info for those you don't have permissions to sign with in our system (for example the unchained key). We do this to preserve privacy and avoid data leaks. The xpub's relation to the master seed (origin information) should be of no concern to the other party that's signing if that key is not going to be signed with. So, in this context the origin information is optional and this would be true for all keys if you only want a watch-only descriptor.
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.
Yes I agree.. For watch-only we don't need the origin info and its not prudent to assume its a master key.. ACK on that..
/// script type used to encode multisig script | ||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq)] | ||
pub enum MultisigScriptType { | ||
/// P2SH | ||
#[serde(rename = "P2SH")] | ||
P2sh, | ||
/// P2SH-P2WSH | ||
#[serde(rename = "P2SH_P2WSH")] | ||
P2shP2wsh, | ||
/// P2WSH | ||
#[serde(rename = "P2WSH")] | ||
P2wsh, | ||
} |
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.
We can use ScriptType
for any type of scripts.. Not just multisigs..
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.
Yep. Good point. I assume you're recommending the Enum be renamed to ScriptType
? And maybe `P2tr should be included here now too if we're moving this to policy?
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.
Yup sounds good.. I think bdk can already recognize p2tr
. A test with an example taproot descriptor into policy and checking if its parsing it correctly would be really nice..
/// The script type used to encode | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
script_type: Option<MultisigScriptType>, |
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 am feeling like we should be able to set the ScriptType
in the Policy
structure itself. Not just only multisigs.. And this should not be inside SatisfiableItem
..
Thanks for the review @rajarshimaitra! I’m afk for a little bit but at a high level this makes sense to me. Hopefully I can get some time to refactor when I’m back in September |
No issues.. This is a valuable PR IMO.. It will be helpful to get more info out from our policy language.. |
Thanks again for the review @rajarshimaitra. Just to be clear, the request for updates is basically two parts:
|
Hey, we are in the process of releasing BDK 1.0, which will under the hood work quite differently from the current BDK. For this reason, I'm closing all the PRs that don't really apply anymore. If you think this is a mistake, feel free to rebase on master and re-open! (More specifically, we're going to use the miniscript "planning module" instead of Policies) |
Got it. Thanks for the update! We do want to revisit this soon but sounds like it’ll make sense to do it on the new API. Largely if we can export the policy info (or whatever it’s called 😅) and have it accessible via wasm bindings than that is really all we were trying to get from this. |
Description
This is a first attempt at resolving #597. When using the policy module to parse descriptors, it can be useful to return additional information about the descriptor. This PR adds some of that in, namely key origin details about each key involved and the script type (p2sh, p2sh-p2wsh, or p2wsh).
Notes to the reviewers
An earlier version of this took advantage of
PkOrF
being astruct
, but unfortunately just as I was ready to push up for a PR a bunch of changes came in that impacted this, specifically using anenum
forPkOrF
instead which changed a lot of the assumptions and tests. The enum makes most sense when these objects are relatively one dimensional (also makes for more straightforward tests), but when the key item can have more properties such as including more of the key origin, it got a little trickier.I only updated the tests for the test I added for this feature plus one other I saw breaking. I thought I'd put it up as a draft first to get any feedback before tweaking any further. It also wasn't clear if some of the tests were breaking for other reasons.
The keys also come out a little weirder when serialized now then when they were done as a struct. Since they are basically tagged with the struct name, each key is an object with a single key
xpub_origin
whose value is an object with the origin details:fingerprint
(which might be better calledxfp
orroot_fingerprint
?),derivation_path
, andxkey
).I also considered whether or not to add the full_derivation_path or trailing path which you can sometimes have in a descriptor including wildcard (e.g.
/0/*
), but figured I could wait for that too.Note, I'm very new at Rust (this is my first production Rust code written), so I'm sure there's a lot that could be more idiomatic or that I've just done wrong completely. All suggestions on how to improve welcome!
Checklists
All Submissions:
cargo fmt
andcargo clippy
before committingNew Features:
CHANGELOG.md
Bugfixes: