-
Notifications
You must be signed in to change notification settings - Fork 38.7k
Moving final scriptSig construction from CombineSignatures to ProduceSignature (PSBT signer logic) #13425
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
Conversation
|
Here is an extra simplification we discussed IRL: https://github.com/sipa/bitcoin/commits/achow_sigdata-partial-sigs |
src/script/sign.h
Outdated
| CScript scriptSig; | ||
| CScriptWitness scriptWitness; | ||
| std::map<CPubKey, std::vector<unsigned char>> signatures; | ||
| std::map<uint160, CScript> scripts; |
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.
Use CScriptID as key 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.
Done
src/script/sign.h
Outdated
| struct SignatureData { | ||
| CScript scriptSig; | ||
| CScriptWitness scriptWitness; | ||
| std::map<CPubKey, std::vector<unsigned char>> signatures; |
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.
If you use CKeyID as key type here, you can avoid the iteration to find matches.
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.
GetPubKey won't work if these are CKeyIDs
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.
Ah, good point. You could have an std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>> though, which stores both full public key and signature.
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.
Done
src/script/sign.cpp
Outdated
|
|
||
| // Get scripts | ||
| txnouttype script_type; | ||
| std::vector<std::vector<unsigned char> > solutions; |
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.
Nit: > >.
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.
Fixed
src/script/sign.h
Outdated
| extern const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR; | ||
|
|
||
| struct SignatureData { | ||
| CScript scriptSig; |
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.
Perhaps add a comment that explains the overlap in relevance of these fields:
scriptSigandscriptWitnessare used for both complete signatures, and for old-style partial signatures.signaturesandscriptsare only used for new-style partial signatures, but may be present for complete signatures too.
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.
Done
src/script/sign.h
Outdated
| * Solvability is unrelated to whether we consider this output to be ours. */ | ||
| bool IsSolvable(const SigningProvider& provider, const CScript& script); | ||
|
|
||
| class SignatureExtractorChecker : public MutableTransactionSignatureChecker |
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.
It feels a bit ugly to hardcode the dependency on MutableTransactionSignatureChecker, as there isn't technically anything in this class that requires it (you could pass in a BaseSignatureChecker reference instead).
This is just a nit, as it's really only used in DataFromTransaction and probably won't ever be used elsewhere.
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 not sure that that is possible since I need to use MutableTransactionSignatureChecker::CheckSig as I do not want to re-implement a signature checker when one already exists.
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.
Oh of course; I just mean that you pass in a BaseSignatureChecker* which is stored inside. You can then call its CheckSig member function (which is public).
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.
Ah, right. Done.
src/bitcoin-tx.cpp
Outdated
| // Only sign SIGHASH_SINGLE if there's a corresponding output: | ||
| if (!fHashSingle || (i < mergedTx.vout.size())) | ||
| ProduceSignature(keystore, MutableTransactionSignatureCreator(&mergedTx, i, amount, nHashType), prevPubKey, sigdata); | ||
| ProduceSignature(SignatureDataSigningProvider(&sigdata, &keystore), SignatureDataSignatureCreator(&sigdata, &mergedTx, i, amount, nHashType), prevPubKey, sigdata); |
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 "Replace CombineSignatures with ProduceSignature"
See my suggested commits in https://github.com/sipa/bitcoin/tree/achow_sigdata-partial-sigs to avoid introducing the SignatureDataSigningProvider and SignatureDataSignatureCreator classes 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.
Done
src/test/transaction_tests.cpp
Outdated
| CheckWithFlag(output2, input2, 0, false); | ||
| BOOST_CHECK(*output1 == *output2); | ||
| UpdateInput(input1.vin[0], CombineSignatures(output1->vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1->vout[0].nValue), DataFromTransaction(input1, 0, output1->vout[0]), DataFromTransaction(input2, 0, output1->vout[0]))); | ||
| sigdata = DataFromTransaction(input1, 0, output1->vout[0]); |
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.
Would it make sense to introduce a wrapper here as well for the pattern that replaces the CombineSignatures calls?
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.
Done
40d5ce7 to
6ce5a28
Compare
|
I have included squashed in @sipa's suggested commits. |
src/script/sign.cpp
Outdated
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.
If you'd introduce a sigdata.scripts.emplace(CScriptID(subscript), subscript); here (and similarly below for the TX_WITNESS_V0_SCRIPTHASH case), you get (I think) all functionality you need for operating on SignatureData objects without the need for the legacy partial signatures.
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.
Done
|
You're missing the |
6ce5a28 to
340201b
Compare
Fixed |
340201b to
64f4a71
Compare
sipa
left a comment
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 64f4a710bbddace7ee51ff6cfbc19f039e7739fa, only nits remaining.
src/script/sign.cpp
Outdated
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.
Nit: mi->second.
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.
Done
src/script/sign.cpp
Outdated
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 be const auto&.
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.
Done
src/script/sign.cpp
Outdated
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 probably rename vchPubKeyOut to pubkey or so now.
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.
Done
src/script/sign.cpp
Outdated
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 should probably rename this to pubkey.
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.
Done
src/script/sign.cpp
Outdated
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.
next_script = std::move(redeem_script).
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.
Done
src/script/sign.cpp
Outdated
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.
stack.script = std::move(stack.witness);.
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.
Done
src/script/sign.cpp
Outdated
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.
Style nit: { on the same line as for.
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.
Done
src/script/sign.cpp
Outdated
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.
Style nit: continue either on the same line as if, or indented while surrounded by braces.
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.
Done
src/script/sign.cpp
Outdated
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.
Style nit: { on the same line as if.
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.
Done
src/script/sign.h
Outdated
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.
Ultra nit: "update with signature data" sounds a bit weird for signature data itself. Perhaps call it Merge or so?
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.
Done
2099402 to
862c0d1
Compare
|
utACK 862c0d1749e28c46fd7c5fb951ac41f6d5dfad06 Perhaps something to add to the rationale: by having all processing be done by |
862c0d1 to
f55cfa3
Compare
|
I added a helper function for |
f55cfa3 to
93f4cec
Compare
|
Removed the |
src/script/sign.cpp
Outdated
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.
You could start this loop after the last successful key in previous iterations, as keys and signature need to have a corresponding order.
Otherwise you risk O(n^2) behaviour if they're in opposite order (perhaps we want to support that, but I don't think we currently do).
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.
Done
src/script/sign.cpp
Outdated
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 can end with a break as well, I think.
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.
Done
|
Perhaps this PR can be renamed to "PSBT signer logic"; it may not be clear right now that in addition to being a code simplification, this also effectively reduces the PSBT PR to serialization + RPC implementations. |
93f4cec to
1d5c2bb
Compare
|
Updated the title to include "PSBT signer logic". |
|
Concept ACK |
sipa
left a comment
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 1d5c2bbaba8e3b66195acefe37053d9048c81ecf
Some tiny nits only, feel free to ignore.
src/script/sign.cpp
Outdated
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 + 1 even, I think (the same signature can't be reused for another pubkey).
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.
Done
src/script/sign.cpp
Outdated
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.
Very nitty: this line and the next will perform an unnecessary copy. You can avoid it with scripts.insert(std::make_move_iterator(sigdata.scripts.begin()), std::make_move_iterator(sigdata.scripts.end()); etc.
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.
Done
1d5c2bb to
9e5fdc7
Compare
In addition to having the scriptSig and scriptWitness, have SignatureData also be able to store just the signatures (pubkeys mapped to sigs) and scripts (script ids mapped to scripts). Also have DataFromTransaction be able to extract signatures and scripts from the scriptSig and scriptWitness of an input to put them in SignatureData. Adds a new SignatureChecker which takes a SignatureData and puts pubkeys and signatures into it when it successfully verifies a signature. Adds a new field in SignatureData which stores whether the SignatureData was complete. This allows us to also update the scriptSig and scriptWitness to the final one when updating a SignatureData with another one.
Instead of using CombineSignatures to create the final scriptSig or scriptWitness of an input, use ProduceSignature itself. To allow for ProduceSignature to place signatures, pubkeys, and scripts that it does not know about, we pass down the SignatureData to SignStep which pulls out the information that it needs from the SignatureData.
Removes CombineSignatures and replaces its use in tests with ProduceSignature to test the same behavior for ProduceSignature.
ef0c9fb to
b815600
Compare
|
utACK b815600 |
…res to ProduceSignature (PSBT signer logic) b815600 Remove CombineSignatures and replace tests (Andrew Chow) ed94c8b Replace CombineSignatures with ProduceSignature (Andrew Chow) 0422beb Make SignatureData able to store signatures and scripts (Andrew Chow) b6edb4f Inline Sign1 and SignN (Andrew Chow) Pull request description: Currently CombineSignatures is used to create the final scriptSig or an input. However ProduceSignature is capable of doing this itself. Using both CombineSignatures and ProduceSignature results in code duplication which is unnecessary. To move the scriptSig construction to ProduceSignatures, the SignatureData class contains two maps to hold pubkeys mapped to signatures, and script ids mapped to scripts. DataFromTransaction is extended to be able to extract signatures, their public keys, and scripts from existing ScriptSigs. The SignaureData are then passed down to SignStep which can use the aforementioned maps to get the signatures, pubkeys, and scripts that it needs, falling back to the actual SigningProvider and SignatureCreator if the data are not available in the SignatureData. Additionally, Sign1 and SignN have been removed and their functionality inlined into SignStep since Sign1 is really just a wrapper around CreateSig. Since ProduceSignature can produce the final scriptSig or scriptWitness by using SignatureData which has extracted data from the transaction, CombineSignatures is unnecessary as ProduceSignature is able to replicate all of CombineSignatures' functionality. This also furthers BIP 174 support and begins moving towards a BIP 174 style backend. The tests have also been updated to use the new combining methodology. Tree-SHA512: 78cd58a4ebe37f79229bd5eee2958a0bb45cd7f36d0e993eee13ff685b3665dd76ef2dfd5f47d34678995bb587f5594100ee5f6c09b1c69ee96d3684d470d01e
020628e Tests for PSBT (Andrew Chow) a4b06fb Create wallet RPCs for PSBT (Andrew Chow) c27fe41 Create utility RPCs for PSBT (Andrew Chow) 8b5ef27 SignPSBTInput wrapper function (Andrew Chow) 58a8e28 Refactor transaction creation and transaction funding logic (Andrew Chow) e9d86a4 Methods for interacting with PSBT structs (Andrew Chow) 12bcc64 Add pubkeys and whether input was witness to SignatureData (Andrew Chow) 41c607f Implement PSBT Structures and un/serialization methods per BIP 174 (Andrew Chow) Pull request description: This Pull Request fully implements the [updated](bitcoin/bips#694) BIP 174 specification. It is based upon #13425 which implements the majority of the signing logic. BIP 174 specifies a binary transaction format which contains the information necessary for a signer to produce signatures for the transaction and holds the signatures for an input while the input does not have a complete set of signatures. This PR contains structs for PSBT, serialization, and deserialzation code. Some changes to `SignatureData` have been made to support detection of UTXO type and storing public keys. *** Many RPCs have been added to handle PSBTs. `walletprocesspsbt` takes a PSBT format transaction, updates the PSBT with any inputs related to this wallet, signs, and finalizes the transaction. There is also an option to not sign and just update. `walletcreatefundedpsbt` creates a PSBT from user provided data in the same form as createrawtransaction. It also funds the transaction and takes an options argument in the same form as `fundrawtransaction`. The resulting PSBT is blank with no input or output data filled in. It is analogous to a combination of `createrawtransaction` and `fundrawtransaction` `decodepsbt` takes a PSBT and decodes it to JSON. It is analogous to `decoderawtransaction` `combinepsbt` takes multiple PSBTs for the same tx and combines them. It is analogous to `combinerawtransaction` `finalizepsbt` takes a PSBT and finalizes the inputs. If all inputs are final, it extracts the network serialized transaction and returns that instead of a PSBT unless instructed otherwise. `createpsbt` is like `createrawtransaction` but for PSBTs instead of raw transactions. `convertpsbt` takes a network serialized transaction and converts it into a psbt. The resulting psbt will lose all signature data and an explicit flag must be set to allow transactions with signature data to be converted. *** This supersedes #12136 Tree-SHA512: 1ac7a79e5bc669933f0a6fcc93ded55263fdde9e8c144a30266b13ef9f62aacf43edd4cbca1ffbe003090b067e9643c9298c79be69d7c1b10231b32acafb6338
…ures to ProduceSignature
…Signatures to ProduceSignature (PSBT signer logic) b815600 Remove CombineSignatures and replace tests (Andrew Chow) ed94c8b Replace CombineSignatures with ProduceSignature (Andrew Chow) 0422beb Make SignatureData able to store signatures and scripts (Andrew Chow) b6edb4f Inline Sign1 and SignN (Andrew Chow) Pull request description: Currently CombineSignatures is used to create the final scriptSig or an input. However ProduceSignature is capable of doing this itself. Using both CombineSignatures and ProduceSignature results in code duplication which is unnecessary. To move the scriptSig construction to ProduceSignatures, the SignatureData class contains two maps to hold pubkeys mapped to signatures, and script ids mapped to scripts. DataFromTransaction is extended to be able to extract signatures, their public keys, and scripts from existing ScriptSigs. The SignaureData are then passed down to SignStep which can use the aforementioned maps to get the signatures, pubkeys, and scripts that it needs, falling back to the actual SigningProvider and SignatureCreator if the data are not available in the SignatureData. Additionally, Sign1 and SignN have been removed and their functionality inlined into SignStep since Sign1 is really just a wrapper around CreateSig. Since ProduceSignature can produce the final scriptSig or scriptWitness by using SignatureData which has extracted data from the transaction, CombineSignatures is unnecessary as ProduceSignature is able to replicate all of CombineSignatures' functionality. This also furthers BIP 174 support and begins moving towards a BIP 174 style backend. The tests have also been updated to use the new combining methodology. Tree-SHA512: 78cd58a4ebe37f79229bd5eee2958a0bb45cd7f36d0e993eee13ff685b3665dd76ef2dfd5f47d34678995bb587f5594100ee5f6c09b1c69ee96d3684d470d01e
merge bitcoin#13269, bitcoin#13425, bitcoin#13557, bitcoin#13721, bitcoin#13666, bitcoin#13723: BIP 174 PSBT Serializations and RPCs
Currently CombineSignatures is used to create the final scriptSig or an input. However ProduceSignature is capable of doing this itself. Using both CombineSignatures and ProduceSignature results in code duplication which is unnecessary.
To move the scriptSig construction to ProduceSignatures, the SignatureData class contains two maps to hold pubkeys mapped to signatures, and script ids mapped to scripts. DataFromTransaction is extended to be able to extract signatures, their public keys, and scripts from existing ScriptSigs.
The SignaureData are then passed down to SignStep which can use the aforementioned maps to get the signatures, pubkeys, and scripts that it needs, falling back to the actual SigningProvider and SignatureCreator if the data are not available in the SignatureData.
Additionally, Sign1 and SignN have been removed and their functionality inlined into SignStep since Sign1 is really just a wrapper around CreateSig.
Since ProduceSignature can produce the final scriptSig or scriptWitness by using SignatureData which has extracted data from the transaction, CombineSignatures is unnecessary as ProduceSignature is able to replicate all of CombineSignatures' functionality.
This also furthers BIP 174 support and begins moving towards a BIP 174 style backend.
The tests have also been updated to use the new combining methodology.