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
Taproot P2TR address #563
Taproot P2TR address #563
Conversation
One thing to keep in mind here: you need the new bech32 version for the |
@apoelstra what do you think on refactoring |
I've opened rust-bitcoin/rust-bech32#50 to add Bech32m support to the bech32 library. |
Ideally that would not be the case. Bech32m was only necessary due to a bug in bech32. BIP173 also states
Which seems to indicate that we'd still need an "unknown" variant. |
Here is my take on implementation for Bech32m checksums, based on BIP-0350 and |
Thank you, @clarkmoody, your changes are merged |
@sgeisler not necessary. We are talking about addresses, not descriptors; and not each script can be represented by an address (payload). I think it's absolutely fine not to support future unknown address formats and not provide a full witness program for them: ppl needing this will be able to use a special descriptor. In return, we will have a copy'able type like #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
pub enum AddressPayload {
PubkeyHash(PubkeyHash),
ScriptHash(ScriptHash),
WPubkeyHash(WPubkeyHash),
WScriptHash(WScriptHash),
Taproot(secp256k1::schnorrsig::PublicKey),
} and unability to parse the address will be denoted by |
Imo "[…] but implementations MUST allow the use of any version." is intended to provide forwards compatibility. We don't need to understand a witness script to send money to it and future users shouldn't have to upgrade to send money to version >=2 witness addresses. That upgrading is necessary for sending funds to Taproot addresses is a very unfortunate mishap and not the norm. |
However you are sending funds to a scriptPubkey, not an address. So Bech32m have not broken the funds which were stent to witness v1 outputs, and not supporting parsing of an address does not implies preventing users from sending funds wherever they want to. Anyway, it's not that important so I'm fine if it is not needed in the library. |
We absolutely should support versions >1. The whole point of bech32(m) is that you can support future versions. Users send money to addresses, not scriptPubKeys. |
The main bitcoin repo has an enum variant for unknown witness version that it uses when classifying outputs. enum class TxoutType {
NONSTANDARD,
// 'standard' transaction types:
PUBKEY,
PUBKEYHASH,
SCRIPTHASH,
MULTISIG,
NULL_DATA, //!< unspendable OP_RETURN script that carries data
WITNESS_V0_SCRIPTHASH,
WITNESS_V0_KEYHASH,
WITNESS_V1_TAPROOT,
WITNESS_UNKNOWN, //!< Only for Witness versions not already defined above
}; |
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.
LGTM it seems that this version does support segwit versions > 1, right?
I would suggest a follow-up PR to add an extra AddressType::UnknownSegwitVersion(SegwitVersion)
or something.
in which sense? We have enum values for all allowed versions >1 |
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.
utACK, looks good from a high level, would be nice if someone (possibly myself, but later) could take a more detailed look.
That we can a) parse and format and b) send transactions to addresses of unknown witness version.
Yes, this makes it possible. |
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.
Some nits and a bug where we don't check program length for taproot witness programs.
Also added another point for discussion about having a different type for tweaked keys. Curious to see feedback from other reviewers on it.
@dr-orlovsky if your concern is waiting for 2 reviewer ACKs again, we can also create a follow-up PR with the changes. |
Thanks @sanket1729, I will add commits to this PR. Just need more time to finish other stuff before switching to this one |
@sanket1729 addressed all of your suggestions in the new commit, aside from the first one (for which I gave rationale why I think the current code is better). @stevenroose, @sgeisler now this will be pending your re-ACK UPD: Review suggestions addressing #563 issues went into there (and this PR is rebased on top of them) |
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.
tACK 7c32c7f
Test log:
Apr 06 17:26:33.766 INFO testinator: Installing rust toolchain 'nightly'
Apr 06 17:26:36.389 INFO testinator: Installing rust toolchain 'stable'
Apr 06 17:26:36.643 INFO testinator: Installing rust toolchain '1.29.0'
Apr 06 17:26:36.873 INFO testinator: Preparing environment for rust nightly tests (9 configurations)
Apr 06 17:26:36.874 INFO testinator: Preparing environment for rust stable tests (8 configurations)
Apr 06 17:26:36.874 INFO testinator: Preparing environment for rust 1.29.0 tests (8 configurations)
Apr 06 17:27:44.850 INFO testinator: Running rust nightly tests in /tmp/rust-bitcoin-nightly.q0GCXPPVY41z/rust-bitcoin
Apr 06 17:27:44.854 INFO testinator: Running rust 1.29.0 tests in /tmp/rust-bitcoin-1.29.0.fJk1f8F3peCL/rust-bitcoin
Apr 06 17:27:44.854 DEBUG testinator: Generating lock file with rust=1.29.0
Apr 06 17:27:44.858 INFO testinator: Running rust stable tests in /tmp/rust-bitcoin-stable.ChE2yLlxWOgK/rust-bitcoin
Apr 06 17:27:46.656 DEBUG testinator: Pinning cc to 1.0.41
Apr 06 17:27:46.839 DEBUG testinator: Pinning serde to 1.0.98
Apr 06 17:27:47.030 DEBUG testinator: Pinning serde_derive to 1.0.98
Apr 06 17:27:47.305 DEBUG testinator: Pinning byteorder to 1.3.4
Apr 06 17:28:28.440 INFO testinator: Test rust=nightly, features=[secp-recovery] succeeded!
Apr 06 17:28:37.784 INFO testinator: Test rust=stable, features=[secp-recovery] succeeded!
Apr 06 17:29:03.816 INFO testinator: Test rust=1.29.0, features=[secp-recovery] succeeded!
Apr 06 17:29:13.877 INFO testinator: Test rust=nightly, features=[use-serde] succeeded!
Apr 06 17:29:33.909 INFO testinator: Test rust=stable, features=[use-serde] succeeded!
Apr 06 17:29:35.676 INFO testinator: Test rust=nightly, features=[base64] succeeded!
Apr 06 17:30:05.646 INFO testinator: Test rust=stable, features=[base64] succeeded!
Apr 06 17:30:08.549 INFO testinator: Test rust=nightly, features=[secp-lowmemory] succeeded!
Apr 06 17:30:29.381 INFO testinator: Test rust=nightly, features=[rand] succeeded!
Apr 06 17:30:36.467 INFO testinator: Test rust=stable, features=[secp-lowmemory] succeeded!
Apr 06 17:30:51.175 INFO testinator: Test rust=1.29.0, features=[use-serde] succeeded!
Apr 06 17:30:52.423 INFO testinator: Test rust=nightly, features=[unstable] succeeded!
Apr 06 17:31:09.924 INFO testinator: Test rust=stable, features=[rand] succeeded!
Apr 06 17:31:42.735 INFO testinator: Test rust=nightly, features=[bitcoinconsensus] succeeded!
Apr 06 17:32:01.278 INFO testinator: Test rust=1.29.0, features=[base64] succeeded!
Apr 06 17:32:07.630 INFO testinator: Test rust=nightly, features=[secp-recovery,use-serde,base64,secp-lowmemory,rand,unstable,bitcoinconsensus] succeeded!
Apr 06 17:32:12.992 INFO testinator: Test rust=stable, features=[bitcoinconsensus] succeeded!
Apr 06 17:32:48.787 INFO testinator: Test rust=nightly, features=[] succeeded!
Apr 06 17:32:57.434 INFO testinator: Test rust=1.29.0, features=[secp-lowmemory] succeeded!
Apr 06 17:33:10.115 INFO testinator: Test rust=stable, features=[secp-recovery,use-serde,base64,secp-lowmemory,rand,bitcoinconsensus] succeeded!
Apr 06 17:33:51.636 INFO testinator: Test rust=1.29.0, features=[rand] succeeded!
Apr 06 17:33:51.638 INFO testinator: Test rust=stable, features=[] succeeded!
Apr 06 17:34:40.626 INFO testinator: Test rust=1.29.0, features=[bitcoinconsensus] succeeded!
Apr 06 17:35:28.786 INFO testinator: Test rust=1.29.0, features=[secp-recovery,use-serde,base64,secp-lowmemory,rand,bitcoinconsensus] succeeded!
Apr 06 17:36:10.203 INFO testinator: Test rust=1.29.0, features=[] succeeded!
Apr 06 17:36:14.164 INFO testinator: Fuzzing deserialize_script
Apr 06 17:37:25.152 INFO testinator: Successfully fuzzed deserialize_script
Apr 06 17:37:25.152 INFO testinator: Fuzzing uint128_fuzz
Apr 06 17:38:27.100 INFO testinator: Successfully fuzzed uint128_fuzz
Apr 06 17:38:27.100 INFO testinator: Fuzzing deserialize_amount
Apr 06 17:39:28.101 INFO testinator: Successfully fuzzed deserialize_amount
Apr 06 17:39:28.101 INFO testinator: Fuzzing deserialize_transaction
Apr 06 17:40:30.258 INFO testinator: Successfully fuzzed deserialize_transaction
Apr 06 17:40:30.258 INFO testinator: Fuzzing deser_net_msg
Apr 06 17:41:33.076 INFO testinator: Successfully fuzzed deser_net_msg
Apr 06 17:41:33.076 INFO testinator: Fuzzing deserialize_address
Apr 06 17:42:34.071 INFO testinator: Successfully fuzzed deserialize_address
Apr 06 17:42:34.071 INFO testinator: Fuzzing deserialize_block
Apr 06 17:43:36.235 INFO testinator: Successfully fuzzed deserialize_block
Apr 06 17:43:36.235 INFO testinator: Fuzzing outpoint_string
Apr 06 17:44:38.151 INFO testinator: Successfully fuzzed outpoint_string
Apr 06 17:44:38.151 INFO testinator: Fuzzing deserialize_psbt
Apr 06 17:45:41.146 INFO testinator: Successfully fuzzed deserialize_psbt
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.
ACK 3d23ac7
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.
utACK 3d23ac7
I left a few nits, but none were blocking in the end imo. I could understand if you don't want to invalidate reviews. Haven't had much time for it recently :( hope it gets better
src/util/address.rs
Outdated
match (version, prog.len()) { | ||
(WitnessVersion::V0, 20) => Ok(AddressType::P2wpkh), | ||
(WitnessVersion::V0, 32) => Ok(AddressType::P2wsh), | ||
(WitnessVersion::V0, len) => Err(Error::InvalidWitnessProgramLength(len)), |
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.
Shouldn't this be InvalidSegwitV0ProgramLength
(if we want to keep that type)?
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.
Still relevant: why not InvalidSegwitV0ProgramLength
? Seems to be made for exactly this case.
@sgeisler thank you for the review! We have two ACKs from maintainers and one ACK from community, so I will merge it for now. But anyway lets finish the discussion of your nits in the comments and I will do another PR addressing them |
Ok, we have version conflicts so re-review will be required anyway. I will address your nits with it - we just need to arrive to some end result with them |
1767bcc
Rebased. @sgeisler I see your point with the |
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.
utACK
src/util/address.rs
Outdated
Error::InvalidWitnessProgramLength(l) => write!(f, | ||
"the witness program must be between 2 and 40 bytes in length: length={}", l, | ||
Error::InvalidWitnessProgramLength(len) => write!(f, | ||
"the witness program must be between 2 and 40 bytes in length: length={}", len, |
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.
One more general thought on error design, not related to this PR specifically: something like serde::de::Visitor::expecting
method or parse_arg::ParseArg::describe_type
could be useful.
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.
Not sure I entirely get what do you mean by that design
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.
Separate what is expected from what is the error. The intention is mainly to allow nicer/more flexible formatting of error messages.
@Kixunil my point is that solving this issue will require more discussion and must involve many more changes from other PRs and issues (like #648, #642, #643, #646). The primary focus of this PR is to enable P2TR addresses at the current master, and we've being discussing and working on this trivial task already for 8 months having more than a hundred comments. So while I am definitely up for a much better API for addresses, such task is more generic that just adding support for P2TR proposed in this PR, and will require (potentially many more) month(s) of discussion – so I propose to finally merge this one and move forward, unlocking a way for Taproot-supporting release. |
@dr-orlovsky Either I misclicked or GitHub have screwed up my comment, it was referencing line https://github.com/rust-bitcoin/rust-bitcoin/pull/563/files#diff-c55d0186f3d5990b5e223c1a8aa1bbe60988201c452dd13b3324e892bc33119eR88 I believe the documentation should say "but such address, while parsed, may return errors from some methods". (Parsing == converting string to internal representation) This is unrelated to future designs as the documentation should reflect the state of things in code as written right now. |
@Kixunil updated both error docs and display with the most verbose form I was able to compose. Pls review |
I mean, I specifically have issue with the word "parsing", which means converting string to internal representation. The literal |
src/util/address.rs
Outdated
version.bech32_variant() | ||
} | ||
} | ||
|
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 don't like this commit. It seems to violate the spirit of From
.
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.
Is it because you find those types unrelated? That's what I feel but curious if you have another reason.
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.
Yeah, I think that's what it is. It seems like this is changing, conceptually, what the data is.
src/util/address.rs
Outdated
(WitnessVersion::V0, 32) => Ok(AddressType::P2wsh), | ||
(WitnessVersion::V0, len) => Err(Error::InvalidWitnessProgramLength(len)), | ||
(WitnessVersion::V1, 32) => Ok(AddressType::P2tr), | ||
(version, length) => Err(Error::FutureWitnessVariant { version, program_len: length }), |
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.
Why is this an error? I don't like this commit either.
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 the context of address type it does make sense (we don't know the address type) but maybe it enourages users to reject future versions, so should be a variant of AddressType
instead?
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.
@apoelstra you can't make it not a error unless we go further than just enabling P2TR addresses and will modify AddressType
to support arbitrary future softforks - which will be a case for debate, already started in #648, #642, #643, #646...
Pls also see my explanations in #563 (comment)
Replace BIP-0173 test vectors with those in BIP-0350.
@apoelstra, @Kixunil, I have removed both controversial commits and made this PR to be only about P2TR address support. So now:
The support of future Witness versions is independent from P2TR addresses and will be addressed in a separate PR(s), together with the rest of required address refactoring (#648, #642, #643, #646...). |
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.
ACK c1991d7
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.
crACK c1991d7
@Kixunil eaiting for you approval to merge this. I have removed all controversial part which was not directly related to P2TR address |
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.
Sorry for holding up, didn't make my mind when I saw your change and didn't know you want my review too.
ACK from me for this lighter change, I look forward into resolving the questions about invariants in the future.
Part of Taproot project https://github.com/orgs/rust-bitcoin/projects/3 and epic #503. Depends on #617