RPC/txoutproof: Support including (and verifying) proofs of wtxid#32844
RPC/txoutproof: Support including (and verifying) proofs of wtxid#32844luke-jr wants to merge 3 commits into
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code Coverage & BenchmarksFor details see: https://corecheck.dev/bitcoin/bitcoin/pulls/32844. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please copy-paste ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. LLM Linter (✨ experimental)Possible typos and grammar issues:
No other typos were found. drahtbot_id_4_m |
Wow, thank you for working on this! I was meaning to open an issue to ask for this, but did not even get to that yet. The request I would like an electrum server, assuming txindex=1, to be able to serve is:
return a dict containing:
Obviously the electrum server can act as middleware and transform the response, assuming the necessary fields are available or obtainable. As far as I can tell, but I haven't tried yet, the RPC response from this PR can be transformed to what I describe above. So the RPC looks to be doing what I need. :) I think it is non-trivial, so let me detail how an electrum/light client would then use
|
|
Concept ACK. @SomberNight it's still useful if you open an issue to track the reason you need this, just in case this implementation PR doesn't make. |
Sjors
left a comment
There was a problem hiding this comment.
Took an initial look at the code, but got a bit confused. Will check again later.
3abfd6d to
e826ffd
Compare
…saction (not a CBlock)
e95981b to
4b3a33a
Compare
|
Reworked this to cover @SomberNight 's requirements and address feedback. Test is now passing. |
4b3a33a to
23edd3d
Compare
|
🐙 This pull request conflicts with the target branch and needs rebase. |
| /** Public only for unit testing */ | ||
| CBlockHeader header; | ||
| CPartialMerkleTree txn; | ||
| /** Only used by subclass WtxidInBlockMerkleProof */ |
There was a problem hiding this comment.
There is no such subclass?
I think all this logic should entirely be in a separate class though. For efficiency probably two paths:
- if the generation tx has no witness commitment; provde all (w)txids and the generation tx via the block partial merkle tree.
- if the generation tx does have a witness commitment; provide just the generation tx's merkle path back to the block header, and prove all wtxids via a partial merkle tree back to the witness commitment
| {"proof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex-encoded proof generated by gettxoutproof"}, | ||
| {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "", | ||
| { | ||
| {"verify_witness", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, also verifies the associated wtxid/hash of the specified transactions (if included in proof)"}, |
There was a problem hiding this comment.
I think this should probably be automatic, with the current "array of txids" result being stuck behind a -deprecatedrpc option.
There was a problem hiding this comment.
I think that makes sense and we could even do the same for gettxoutproof I think (if that wasn't already intended with the comment as well).
| {RPCResult::Type::STR_HEX, "blockhash", "The block hash this proof links to"}, | ||
| {RPCResult::Type::NUM, "blockheight", "The height of the block this proof links to"}, | ||
| {RPCResult::Type::NUM, "confirmations", /*optional=*/true, "Number of blocks (including the one with the transactions) confirming these transactions"}, | ||
| {RPCResult::Type::NUM, "confirmations_assumed", /*optional=*/true, "The number of unverified blocks confirming these transactions (eg, in an assumed-valid UTXO set)"}, |
There was a problem hiding this comment.
This information (height, confirmations, assumeutxo info) seems better obtained via getblockheader on the blockhash to me.
| if (merkleBlock.m_gentx->GetHash() != vMatch[0]) return res; | ||
| if (!merkleBlock.m_gentx->IsCoinBase()) return res; | ||
| witness_commit_outidx = GetWitnessCommitmentIndex(*merkleBlock.m_gentx); | ||
| if (witness_commit_outidx == NO_WITNESS_COMMITMENT) { |
There was a problem hiding this comment.
I would have expected this logic to be in merkleblock.cpp as a standard part of verifying a proof (eg so that it could be included in kernel), not in the RPC code.
|
|
||
| const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(merkleBlock.header.GetHash()); | ||
| const auto& active_chain = chainman.ActiveChain(); | ||
| if (!pindex || !active_chain.Contains(pindex) || pindex->nTx == 0) { |
There was a problem hiding this comment.
Being able to easily prove/verify that a tx was included in a reorged block seems fine?
fjahr
left a comment
There was a problem hiding this comment.
Concept ACK
Is there something special about the naming "generation tx" here? It seems to be just an older alias for the coinbase transaction without any other special meaning. I can not recall seeing it used anywhere in the code base or online discourse. If I am not overlooking something it would probably be better to just call it coinbase tx instead which should be less confusing to newer contributors that haven't heard this term before.
| expected_proven['confirmations'] = 1 | ||
| del expected_proven['tx'][0]['txid'] | ||
| del expected_proven['tx'][1]['txid'] | ||
| assert_equal(self.nodes[0].verifytxoutproof(proofres['proof'], verify_witness=True), expected_proven) |
There was a problem hiding this comment.
Should also cover an invalid proof here
| {"proof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex-encoded proof generated by gettxoutproof"}, | ||
| {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "", | ||
| { | ||
| {"verify_witness", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, also verifies the associated wtxid/hash of the specified transactions (if included in proof)"}, |
There was a problem hiding this comment.
I think that makes sense and we could even do the same for gettxoutproof I think (if that wasn't already intended with the comment as well).
|
⌛ There hasn't been much activity lately and the patch still needs rebase. What is the status here?
|
|
There's been unaddressed review comments here for some time already. @luke-jr do you plan to respond to these? If not, maybe one of the reviewers could take charge of this change? |
|
I plan to take this over and address earlier feedback, unless someone else beats me to it. |
|
Here's an initial sketch: Sjors#116. I plan to open a PR on this repo after some polishing. For the test vectors I used small and early blocks, so we can include them as fixtures for a roundtrip test. These could be turned into a BIP, but I prefer if someone else does that, @SomberNight? There might be a better set of test vectors, I can switch to those. I limited my PR to proving a single transaction at a time. Is there a need to provide multiple at once? In that case we might need a BIP to define an encoding for that, as it's less trivial than just an array of hashes. The RPC command takes an array of wtxid's, so it's easy to add support for this later. |
This comment was marked as off-topic.
This comment was marked as off-topic.
|
@SomberNight wrote:
I assume you can also make the request by |
Feature requested by @SomberNight for Electrum's Lightning stuff. (Please confirm this does what you need)
Unfortunately WIP because the wtxid merkle root calculation doesn't match and I don't have time to figure out why not yet (maybe after concept ACK? or if anyone else wants to take a look...)
Mostly backward compatible, but a segwit-enabled proof will verify the generation tx in old versions.