Skip to content

Conversation

@achow101
Copy link
Member

@achow101 achow101 commented Jun 8, 2018

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.

@fanquake fanquake requested a review from sipa June 9, 2018 01:04
@sipa
Copy link
Member

sipa commented Jun 9, 2018

Here is an extra simplification we discussed IRL: https://github.com/sipa/bitcoin/commits/achow_sigdata-partial-sigs

CScript scriptSig;
CScriptWitness scriptWitness;
std::map<CPubKey, std::vector<unsigned char>> signatures;
std::map<uint160, CScript> scripts;
Copy link
Member

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?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

struct SignatureData {
CScript scriptSig;
CScriptWitness scriptWitness;
std::map<CPubKey, std::vector<unsigned char>> signatures;
Copy link
Member

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.

Copy link
Member Author

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

Copy link
Member

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


// Get scripts
txnouttype script_type;
std::vector<std::vector<unsigned char> > solutions;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: > >.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

extern const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR;

struct SignatureData {
CScript scriptSig;
Copy link
Member

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:

  • scriptSig and scriptWitness are used for both complete signatures, and for old-style partial signatures.
  • signatures and scripts are only used for new-style partial signatures, but may be present for complete signatures too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

* Solvability is unrelated to whether we consider this output to be ours. */
bool IsSolvable(const SigningProvider& provider, const CScript& script);

class SignatureExtractorChecker : public MutableTransactionSignatureChecker
Copy link
Member

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.

Copy link
Member Author

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.

Copy link
Member

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).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right. Done.

// 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);
Copy link
Member

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

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]);
Copy link
Member

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?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@achow101 achow101 force-pushed the sigdata-partial-sigs branch from 40d5ce7 to 6ce5a28 Compare June 9, 2018 19:36
@achow101
Copy link
Member Author

achow101 commented Jun 9, 2018

I have included squashed in @sipa's suggested commits.

Copy link
Member

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@sipa
Copy link
Member

sipa commented Jun 9, 2018

You're missing the DUMMY_SIGNING_PROVIDER instance.

@achow101 achow101 force-pushed the sigdata-partial-sigs branch from 6ce5a28 to 340201b Compare June 9, 2018 20:48
@achow101
Copy link
Member Author

achow101 commented Jun 9, 2018

You're missing the DUMMY_SIGNING_PROVIDER instance.

Fixed

@achow101 achow101 force-pushed the sigdata-partial-sigs branch from 340201b to 64f4a71 Compare June 9, 2018 21:16
Copy link
Member

@sipa sipa left a 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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: mi->second.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be const auto&.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

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).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

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);.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

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?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@achow101 achow101 force-pushed the sigdata-partial-sigs branch 3 times, most recently from 2099402 to 862c0d1 Compare June 9, 2018 22:51
@sipa
Copy link
Member

sipa commented Jun 9, 2018

utACK 862c0d1749e28c46fd7c5fb951ac41f6d5dfad06

Perhaps something to add to the rationale: by having all processing be done by ProduceSignature (which now can take existing partial signatures as input), the model much more closely matches BIP 174 procedures. The changes here should make it possible for the BIP174 implementation to largely reuse the existing signing code.

@achow101
Copy link
Member Author

I added a helper function for createSig which handles the fetching and placing of signatures from the SignatureData.

@achow101 achow101 force-pushed the sigdata-partial-sigs branch from f55cfa3 to 93f4cec Compare June 12, 2018 18:03
@achow101
Copy link
Member Author

Removed the newsigs map from the first commit. Also moved some changes around to commits where they actually made sense to be in.

Copy link
Member

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).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@sipa
Copy link
Member

sipa commented Jun 12, 2018

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.

@achow101 achow101 changed the title Moving final scriptSig construction from CombineSignatures to ProduceSignature Moving final scriptSig construction from CombineSignatures to ProduceSignature (PSBT signer logic) Jun 12, 2018
@achow101 achow101 force-pushed the sigdata-partial-sigs branch from 93f4cec to 1d5c2bb Compare June 12, 2018 19:02
@achow101
Copy link
Member Author

Updated the title to include "PSBT signer logic".

@meshcollider
Copy link
Contributor

Concept ACK

Copy link
Member

@sipa sipa left a 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.

Copy link
Member

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).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@achow101 achow101 force-pushed the sigdata-partial-sigs branch from 1d5c2bb to 9e5fdc7 Compare June 14, 2018 01:49
@laanwj laanwj added the Wallet label Jun 14, 2018
achow101 added 3 commits July 3, 2018 17:18
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.
@achow101 achow101 force-pushed the sigdata-partial-sigs branch from ef0c9fb to b815600 Compare July 4, 2018 00:19
@laanwj
Copy link
Member

laanwj commented Jul 5, 2018

utACK b815600

@laanwj laanwj merged commit b815600 into bitcoin:master Jul 5, 2018
laanwj added a commit that referenced this pull request Jul 5, 2018
…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
laanwj added a commit that referenced this pull request Jul 18, 2018
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
UdjinM6 pushed a commit to UdjinM6/dash that referenced this pull request Jun 7, 2021
UdjinM6 pushed a commit to UdjinM6/dash that referenced this pull request Jun 28, 2021
…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
PastaPastaPasta added a commit to dashpay/dash that referenced this pull request Jul 13, 2021
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Sep 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants