achow101
commented at 3:04 am on June 28, 2018:
member
This Pull Request fully implements the updated 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.
103+// The separator is 0x00. Reading this in means that the unserializer can interpret it
104+// as a 0 length key. which indicates that this is the separator. The separator has no value.
105+static const uint8_t PSBT_SEPARATOR = 0x00;
106+
107+template<typename Stream, typename... X>
108+void SerializeToVector(Stream& s, const X&... args)
260+ // Build a map of pubkey -> signature by matching sigs to pubkeys:
261+ assert(solutions.size() > 1);
262+ unsigned int num_pubkeys = solutions.size()-2;
263+ unsigned int last_success_key = 0;
264+ for (const valtype& sig : stack.script) {
265+ for (unsigned int i = last_success_key; i < num_pubkeys; i++) {
DrahtBot
commented at 9:28 am on June 28, 2018:
member
#13359 (wallet: Directly operate with CMutableTransaction by MarcoFalke)
#13266 (refactoring: privatize SignatureExtractorChecker by Empact)
#13144 (RPC: Improve error messages on RPC endpoints that use GetTransaction by jimpo)
#13098 (Skip tx-rehashing on historic blocks by MarcoFalke)
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.
promag
commented at 9:33 am on June 28, 2018:
member
Review comments for:
fdcbcb380 - Inline Sign1 and SignN
a86d0679d - Make SignatureData able to store signatures and scripts
c5d47a58f - Replace CombineSignatures with ProduceSignature
95f5a38dd - Remove CombineSignatures and replace tests
fdcbcb380 is kind of unrelated here no?
achow101
commented at 5:52 pm on June 28, 2018:
member
@promag Just so you know, those commits are part of #13425
promag
commented at 6:01 pm on June 28, 2018:
member
achow101
commented at 6:05 pm on June 28, 2018:
member
No need to comment twice. I will update that PR and then rebase this onto that.
in
src/script/sign.h:286
in
bfb37cb741outdated
231+ // First byte of key is the type
232+ unsigned char type = key[0];
233+
234+ // Do stuff based on type
235+ switch(type) {
236+ case PSBT_IN_NON_WITNESS_UTXO:
Can you abstract out the serialization/deserialization code for derivation paths and scripts into separate functions? Otherwise it is needlessly duplicated across input and outputs.
612+ throw std::ios_base::failure("No unsigned transcation was provided");
613+ }
614+
615+ // Read input data
616+ unsigned int i = 0;
617+ while (!s.empty() && i < tx.vin.size()) {
If we reach EOF in the stream, this loop will exit and the if block below will throw the error as the number of inputs/outputs will differ from the number of inputs/outputs in the unsigned tx.
100+static constexpr uint8_t PSBT_OUT_WITNESSSCRIPT = 0x01;
101+static constexpr uint8_t PSBT_OUT_BIP32_DERIVATION = 0x02;
102+
103+// The separator is 0x00. Reading this in means that the unserializer can interpret it
104+// as a 0 length key. which indicates that this is the separator. The separator has no value.
105+static const uint8_t PSBT_SEPARATOR = 0x00;
127+ throw std::ios_base::failure("Size of value was not the stated size");
128+ }
129+}
130+
131+// Deserialize HD keypaths into a map
132+static void DeserializeHDKeypaths(const std::vector<unsigned char>& key, std::map<CPubKey, std::vector<uint32_t>>& hd_keypaths, Stream& s)
156+ // Add to map
157+ hd_keypaths.emplace(pubkey, keypath);
158+}
159+
160+// Serialize HD keypaths to a stream from a map
161+static void SerializeHDKeypaths(std::vector<uint32_t>>& hd_keypaths, Stream& s)
159+
160+// Serialize HD keypaths to a stream from a map
161+static void SerializeHDKeypaths(std::vector<uint32_t>>& hd_keypaths, Stream& s)
162+{
163+ for (auto keypath_pair : hd_keypaths) {
164+ SerializeToVector(s, PSBT_IN_BIP32_DERIVATION, MakeSpan(keypath_pair.first));
in
src/rpc/rawtransaction.cpp:1555
in
af544a96faoutdated
1550+ PartiallySignedTransaction merged_psbtx(psbtxs[0]); // Copy the first one
1551+ // Merge input data
1552+ for (unsigned int i = 0; i < merged_psbtx.tx.vin.size(); ++i) {
1553+ CTxIn& txin = merged_psbtx.tx.vin[i];
1554+
1555+ // Find the utxo from one of the psbtxs
I’m not sure what this entire UTXO handling section does. Is it sufficient to (a) rely on a generic combine PSBT function somewhere (suggested below) which also combined the utxo data, and then perhaps convert the logic in this section to a sanity check function?
I have refactored the merging stuff into a Merge() method for each PSBT struct. I also added a sanity checking method for each.
in
src/rpc/rawtransaction.cpp:1700
in
af544a96faoutdated
1695+ CTxOut utxo;
1696+ if (input.non_witness_utxo) {
1697+ utxo = input.non_witness_utxo->vout[txin.prevout.n];
1698+ }
1699+ // Now find the witness utxo if the non witness doesn't exist
1700+ else if (!input.witness_utxo.IsNull()) {
Well perhaps don’t say it implements a Finalizer unless it actually implements that :)
in
src/rpc/rawtransaction.cpp:1655
in
af544a96faoutdated
1650+ " extract and return the complete transaction in normal network serialization.\n"
1651+
1652+ "\nResult:\n"
1653+ "{\n"
1654+ " \"base64\" : \"value\", (string) The base64-encoded network transaction\n"
1655+ " \"hex\" : \"value\", (string) The hex-encoded partially signed transaction if extracted\n"
in
src/rpc/rawtransaction.cpp:1690
in
af544a96faoutdated
1685+ // if this input has a final scriptsig or scriptwitness, don't do anything with it
1686+ if (!input.final_script_sig.empty() || !input.final_script_witness.IsNull()) {
1687+ continue;
1688+ }
1689+
1690+ // Fill a SignatureData with input info
in
src/rpc/rawtransaction.cpp:1739
in
af544a96faoutdated
1734+UniValue createpsbt(const JSONRPCRequest& request)
1735+{
1736+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 4)
1737+ throw std::runtime_error(
1738+ "createpsbt [{\"txid\":\"id\",\"vout\":n},...] [{\"address\":amount},{\"data\":\"hex\"},...] ( locktime ) ( replaceable )\n"
1739+ "\nCreates and funds a transaction in the Partially Signed Transaction format. Inputs will be added if supplied inputs are not enough\n"
Perhaps clarify that it’s intended to work with createrawtransaction and fundrawtransaction, and createpsbt/createfundedpsbt should be used for new applications.
sipa
commented at 11:07 pm on June 28, 2018:
member
Comments on rawtransaction.cpp RPCs.
sipa
commented at 11:13 pm on June 28, 2018:
member
General comment on naming of RPC field names and input arguments, "base64" isn’t very informative I think. I suggest using "psbt" anywhere you have an input or output in base64. There isn’t any other encoding used, so there should never be any confusion. Using "hex" for fully signed or legacy partially signed transaction makes sense for consistency with the existing RPCs.
achow101 force-pushed
on Jun 29, 2018
achow101
commented at 2:26 am on June 29, 2018:
member
I did a bit of commit splitting and have reduced the size of the RPCs commit by splitting it up. Hopefully this will make review easier.
249+ CTxOut utxo;
250+ if (input.non_witness_utxo) {
251+ utxo = input.non_witness_utxo->vout[txin.prevout.n];
252+ }
253+ // Now find the witness utxo if the non witness doesn't exist
254+ else if (!input.witness_utxo.IsNull()) {
307+ // Read in the signature from value
308+ std::vector<unsigned char> sig;
309+ s >> sig;
310+
311+ // Add to list
312+ partial_sigs.emplace(pubkey.GetID(), SigPair(pubkey, sig));
in
src/rpc/rawtransaction.cpp:1569
in
d59ebaa3c0outdated
1564+ throw std::runtime_error(
1565+ "combinepsbt [\"base64string\",...]\n"
1566+ "\nCombine multiple partially signed Bitcoin transactions into one transaction.\n"
1567+ "Implements the Combiner and Finalizer roles.\n"
1568+ "\nArguments:\n"
1569+ "1. \"txs\" (string) A json array of hex strings of partially signed transactions\n"
in
src/rpc/rawtransaction.cpp:1611
in
d59ebaa3c0outdated
1604+ }
1605+ }
1606+
1607+ PartiallySignedTransaction merged_psbt(psbtxs[0]); // Copy the first one
1608+ // Merge them
1609+ for (const PartiallySignedTransaction& psbtx : psbtxs) {
Yes. EncodeBase64 takes an unsigned char* but ssTx.data() is a char *.
in
src/rpc/rawtransaction.cpp:1760
in
d59ebaa3c0outdated
1755+ "converttopsbt \"hexstring\" ( permitsigdata iswitness )\n"
1756+ "\nConverts a network serialized transaction to a PSBT. This should be used only with createrawtransaction and fundrawtransaction\n"
1757+ "createpsbt and walletcreatefundedpsbt should be used for new applications.\n"
1758+ "\nArguments:\n"
1759+ "1. \"hexstring\" (string, required) The hex string of a raw transaction\n"
1760+ "2. permitsigdata (boolean, optional) Whether the transaction hex contains any data in the scriptSigs or scriptWitnesses.\n"
This explanation is confusing. It’s an input argument, right? How about “If true, the RPC will ignore any signatures present in the input. When this argument is false, it will fail if signatures are present.”
Is this were a std::unique_ptr<CMutableTransaction> (or boost::optional<CMutableTransaction>), you could avoid the need for implementing IsNull or converting to CTransaction to decide whether it is set or not.
in
src/wallet/rpcwallet.cpp:4469
in
a871194feeoutdated
4464+bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const CTransaction* txConst, int sighash_type, bool sign)
4465+{
4466+ // Get all of the previous transactions
4467+ bool complete = true;
4468+ for (unsigned int i = 0; i < txConst->vin.size(); ++i) {
4469+ CTxIn txin = txConst->vin[i];
in
src/wallet/rpcwallet.cpp:4473
in
a871194feeoutdated
4468+ for (unsigned int i = 0; i < txConst->vin.size(); ++i) {
4469+ CTxIn txin = txConst->vin[i];
4470+ PSBTInput& input = psbtx.inputs.at(i);
4471+
4472+ // If we don't know about this input, skip it and let someone else deal with it
4473+ uint256 txhash = txin.prevout.hash;
in
src/rpc/rawtransaction.cpp:1661
in
a871194feeoutdated
1656+ }
1657+
1658+ // Get all of the previous transactions
1659+ bool complete = true;
1660+ for (unsigned int i = 0; i < psbtx.tx.vin.size(); ++i) {
1661+ CTxIn txin = psbtx.tx.vin[i];
in
src/wallet/rpcwallet.cpp:4554
in
a871194feeoutdated
4543+ + HelpRequiringPassphrase(pwallet) + "\n"
4544+
4545+ "\nArguments:\n"
4546+ "1. \"psbt\" (string, required) The transaction base64 string\n"
4547+ "2. \"sign\", (string, optional, default=true) Also sign the transaction when updating\n"
4548+ "3. \"sighashtype\" (string, optional, default=ALL) The signature hash type to sign with if not specified by the PSBT. Must be one of\n"
If you’d have a SigningProvider wrapper that removes access to private keys, you could use that instead of passing down a sign variable. The other call site doesn’t need a sign anyway, as it’s using a dummy provider.
Thinking more about this, I can’t find a reason why someone would not want to also Update the PSBT. Since in this case, the wallet is adding inputs and change, it is exactly in the position to also add keys/scripts/utxos for those. It shouldn’t include signing, though.
I meant: why should createfunded not automatically update? It by definition has all the data available, and I don’t think there is a reason why you wouldn’t run update immediately after anyway.
Alternatively: move the keypath_str += "/"; to the front of the loop and initialize with just "m". That way you can avoid adding and then stripping the final slash.
I think it’s bad practice to keep outputting “addresses” that correspond to a script. It’s confusing (they’re not really addresses, just multisig pubkeys represented through their corresponding P2PKH address) and also generally useless as it can’t introspect into P2SH and P2WSH.
I preference would be to just output “hex”, “asm” and “address” (only if a corresponding address is known through ExtractDestination).
What is this “script” intermediate layer? I don’t see that in the implementation (for this and for witness_script). Again, just “hex” and “asm” is sufficient here I think.
It seems you’ll need to change the type to UniValue::VOBJ above. Calling pushKV on an array has no effect (and also doesn’t assert/throw anything, it seems…).
psbtxs.pop_front() will do the same. Alternatively, you can write a loop like for (auto it = std::next(psbtx.begin()); ++it; it !=psbtx.end()) { merged_psbt.Merge(*it); }.
in
src/rpc/rawtransaction.cpp:1324
in
336f31d78doutdated
1319+ " {\n"
1320+ " \"pubkey\" : \"signature\", (string) The public key and signature that corresponds to it.\n"
1321+ " }\n"
1322+ " ,...\n"
1323+ " ]\n"
1324+ " \"sighash\" : \"type\", (string, optional) The sighash type recommended to be used\n"
It would be very useful to add the fee of the transaction here, if known. Make sure there is a consistency check that non-witness utxo’s txid matches the vin.prevout.hash.
in
src/rpc/rawtransaction.cpp:1706
in
336f31d78doutdated
1701+ " ]\n"
1702+ "3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
1703+ "4. replaceable (boolean, optional, default=false) Marks this transaction as BIP125 replaceable.\n"
1704+ " Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible.\n"
1705+ "\nResult:\n"
1706+ " \"psbt\": \"value\", (string) The resulting raw transaction (base64-encoded string)\n"
in
src/rpc/rawtransaction.cpp:1754
in
336f31d78doutdated
1749+ " If false, RPC will fail if any signatures are present.\n"
1750+ "3. iswitness (boolean, optional) Whether the transaction hex is a serialized witness transaction.\n"
1751+ " If iswitness is not present, heuristic tests will be used in decoding. Only has an effect if\n"
1752+ " permitsigdata is true\n"
1753+ "\nResult:\n"
1754+ " \"psbt\": \"value\", (string) The resulting raw transaction (base64-encoded string)\n"
in
src/wallet/rpcwallet.cpp:4471
in
9e4077a992outdated
4467+ const CTxIn& txin = txConst->vin[i];
4468+ PSBTInput& input = psbtx.inputs.at(i);
4469+
4470+ // If we don't know about this input, skip it and let someone else deal with it
4471+ const uint256& txhash = txin.prevout.hash;
4472+ if (pwallet->mapWallet.count(txhash)) {
instagibbs
commented at 3:38 pm on July 5, 2018:
member
Needs rebase now that #13425 is merged. (I think?)
achow101 force-pushed
on Jul 5, 2018
achow101
commented at 6:00 pm on July 5, 2018:
member
Rebased onto master after #13425 was merged. Will address comments soon.
laanwj added this to the "Blockers" column in a project
in
src/script/sign.h:103
in
dfa5afe665outdated
98+static constexpr uint8_t PSBT_OUT_REDEEMSCRIPT = 0x00;
99+static constexpr uint8_t PSBT_OUT_WITNESSSCRIPT = 0x01;
100+static constexpr uint8_t PSBT_OUT_BIP32_DERIVATION = 0x02;
101+
102+// The separator is 0x00. Reading this in means that the unserializer can interpret it
103+// as a 0 length key. which indicates that this is the separator. The separator has no value.
achow101
commented at 10:44 pm on July 5, 2018:
member
Instead of walletcreatefundedpsbt, could make a rawtransactiontopsbt or alike?
There already is a converttopsbt method. I do not think that we should make using PSBT require using raw transactions first. It should be self contained as I hope that we will move from raw transactions to PSBT entirely.
in
src/script/sign.h:175
in
8415956f70outdated
170+ hd_keypaths.emplace(pubkey, keypath);
171+}
172+
173+// Serialize HD keypaths to a stream from a map
174+template<typename Stream>
175+void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, std::vector<uint32_t>>& hd_keypaths, uint8_t type)
I’m having some trouble matching this code to the spec, with the HD keypaths shouldn’t we prefix the “value” (as in the key/value entry) with the fingerprint of the public key? I don’t see where it’s done here (and neither in ‘DeserializeHDKeypaths’).
utACK14339b0214f2976cae772ae836322d285138c353. Going to play around with it more before I give a tACK.
promag
commented at 10:23 pm on July 7, 2018:
member
utACK14339b0. I have a couple of comments but are all nits here and there.
There already is a converttopsbt method. I do not think that we should make using PSBT require using raw transactions first. It should be self contained as I hope that we will move from raw transactions to PSBT entirely.
Ok got it.
in
src/rpc/rawtransaction.cpp:1247
in
29df1b87e4outdated
That’s not what it means. The fee can be reported whenever the UTXO information for each transaction input is present in the psbt (this information is generally added by Updater roles).
It’s clearly confusing though, do you have a better way of formulating this?
in
src/rpc/rawtransaction.cpp:1612
in
29df1b87e4outdated
1618+ "Finalize the inputs of a PSBT. If the transaction is fully signed, it will produce a\n"
1619+ "network serialized transaction which can be broadcast with sendrawtransaction\n"
1620+ "Implements the Finalizer and Extractor roles.\n"
1621+ "\nArguments:\n"
1622+ "1. \"psbt\" (string) A base64 string of a PSBT\n"
1623+ "2. \"extract\" (boolean, optional, default=true) If true and the transaction is complete, \n"
something like “extract and return the complete transaction in normal network serialization instead of the PSBT.” in addition to my other suggestion in the return values section.
in
src/rpc/rawtransaction.cpp:1694
in
29df1b87e4outdated
1700+ " }\n"
1701+ " ,... More key-value pairs of the above form. For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
1702+ " accepted as second parameter.\n"
1703+ " ]\n"
1704+ "3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
1705+ "4. replaceable (boolean, optional, default=false) Marks this transaction as BIP125 replaceable.\n"
A lot of this is shared with createrawtransaction so changing this will also also cause createrawtransaction’s API to change. Having it be separate though means that there will be a lot of code duplication.
in
src/rpc/rawtransaction.cpp:1750
in
29df1b87e4outdated
1745+ "converttopsbt \"hexstring\" ( permitsigdata iswitness )\n"
1746+ "\nConverts a network serialized transaction to a PSBT. This should be used only with createrawtransaction and fundrawtransaction\n"
1747+ "createpsbt and walletcreatefundedpsbt should be used for new applications.\n"
1748+ "\nArguments:\n"
1749+ "1. \"hexstring\" (string, required) The hex string of a raw transaction\n"
1750+ "2. permitsigdata (boolean, optional) If true, any signatures in the input will be discarded.\n"
in
src/rpc/rawtransaction.cpp:1741
in
29df1b87e4outdated
1747+ "createpsbt and walletcreatefundedpsbt should be used for new applications.\n"
1748+ "\nArguments:\n"
1749+ "1. \"hexstring\" (string, required) The hex string of a raw transaction\n"
1750+ "2. permitsigdata (boolean, optional) If true, any signatures in the input will be discarded.\n"
1751+ " If false, RPC will fail if any signatures are present.\n"
1752+ "3. iswitness (boolean, optional) Whether the transaction hex is a serialized witness transaction.\n"
There really isn’t a default value for iswitness. Without it being specified, both witness and non-witness are tried. If it is specified, then if it is true, only witness is tried, and false only non-witness is tried.
Just not crazy about passing around pointers more than we have to.
instagibbs
commented at 1:35 pm on July 9, 2018:
member
Left some comments, looking good overall.
I’d also like the RPC help to be a bit more descriptive of what the calls are doing, in plain english, to avoid users having to be BIP174 experts. e.g., what does “finalizer” mean.
laanwj
commented at 2:21 pm on July 9, 2018:
member
might want to fix this warning:
0/.../bitcoin/src/wallet/rpcwallet.h:14:1: warning: class 'PartiallySignedTransaction' was previously declared as a struct [-Wmismatched-tags]
1class PartiallySignedTransaction;
2^
3/.../bitcoin/src/script/sign.h:486:8: note: previous use is here
4struct PartiallySignedTransaction
5 ^
6/.../bitcoin/src/wallet/rpcwallet.h:14:1: note: did you mean struct here?
7class PartiallySignedTransaction;
8^~~~~
9struct
101 warning generated.
in
src/rpc/rawtransaction.cpp:1612
in
14339b0214outdated
1607+ "2. \"extract\" (boolean, optional, default=true) If true and the transaction is complete, \n"
1608+ " extract and return the complete transaction in normal network serialization.\n"
1609+
1610+ "\nResult:\n"
1611+ "{\n"
1612+ " \"psbt\" : \"value\", (string) The base64-encoded partially signed transaction\n"
We should probably have a document (in doc/ or so) that explain the most common workflows (hardware wallet, coinjoin, multisig) with the relevant RPCs.
achow101 force-pushed
on Jul 9, 2018
achow101
commented at 8:14 pm on July 9, 2018:
member
might want to fix this warning
I don’t see this warning locally, but fixed anyways.
achow101 force-pushed
on Jul 9, 2018
laanwj
commented at 2:18 pm on July 10, 2018:
member
I don’t see this warning locally, but fixed anyways.
Heh, building with clang-latest-master is sometimes useful.
We should probably have a document (in doc/ or so) that explain the most common workflows (hardware wallet, coinjoin, multisig) with the relevant RPCs.
Good idea, though probably not in this PR if we want it in before the feature freeze.
in
test/functional/rpc_psbt.py:2
in
52a5f17a68outdated
SegWit is activated immediately in Regtest by default these days (nStartTime ... ALWAYS_ACTIVE ). If you change setup_clean_chain = True to False, you can leave out this generate() line completely.
Sjors
commented at 7:28 pm on July 10, 2018:
member
Lightly tested, great stuff! Though multisig remains a bit tedious and confusing.
explain the most common workflows (hardware wallet, coinjoin, multisig) with the relevant RPCs
Adding test for those would be useful, and could catch if we forgot any useful params in the RPC.
I’m missing a test case for bip32_derivs.
Bit of a privacy issue: let’s say person A and B are about to spend from a multisig address, sending everything to person A. Person A gives their address to person B, their wallet wallet creates a PSBT, but doesn’t sign it. Wallet A then calls walletprocesspsbt which signs it and spontaneously adds the master_fingerprint and bip32 path. Same issue with walletcreatefundedpsbt.
Adding bip32_derivs should probably be opt-in.
At the risk over expanding the scope too much, it would be quite useful if inputs of createpsbt can add add a redeemScript argument, as a hint for multisig addresses the wallet might not be aware of. Although see below…
Somewhat orthogonal bug(?): walletcreatefundedpsbt is unable to construct a transaction if it can’t find the relevant UTXO. E.g. if you call addmultisig for a 2 of 2 where you only control one key, and then fund it from an external wallet. Although getaddressinfo will be aware of the mutlisig, getreceivedbyaddress will claim it’s not part of the wallet. You have to import the address and rescan for this to work. It seems to me that the wallet really should care about these transactions even if it doesn’t list them.
walletprocesspsbt won’t sign a transaction if it doesn’t know about the multisig address (i.e. addmultisig was never called). This is the case even if the PSBT has sufficient information, since it could match the witness_script against its own pub keys. Might be a nice improvement for later.
walletprocesspsbt also won’t sign a transaction if addmultisig was called but it can’t find the UTXO (see above for why). However in this case it could in principle blind sign it, or at least throw a more clear error message than "complete": false.
These rescans are rather painful, so - if it’s not too late - adding a blockheight hint to BIP-174 might be really helpful. I can suggest that on the mailing list if others think it’s useful.
It would be nice if all RPC calls which can produce a complete transaction have a flag that lets you produce the hex immediately, rather than going through the finalizepsbt dance.
achow101
commented at 11:03 pm on July 10, 2018:
member
Adding test for those would be useful, and could catch if we forgot any useful params in the RPC.
There already are test cases for multisig. I have added one for coinjoin where inputs come from multiple nodes.
I’m missing a test case for bip32_derivs.
This is done in the updater tests which is a unit test (so we can add specific prevtxs).
Adding bip32_derivs should probably be opt-in.
Done
At the risk over expanding the scope too much, it would be quite useful if inputs of createpsbt can add add a redeemScript argument, as a hint for multisig addresses the wallet might not be aware of. Although see below…
While that could be useful, createpsbt does not do any updating, and I do not think it would be good to include any other data in an input before a UTXO is included for the input.
Somewhat orthogonal bug(?): walletcreatefundedpsbt is unable to construct a transaction if it can’t find the relevant UTXO. E.g. if you call addmultisig for a 2 of 2 where you only control one key, and then fund it from an external wallet. Although getaddressinfo will be aware of the mutlisig, getreceivedbyaddress will claim it’s not part of the wallet. You have to import the address and rescan for this to work. It seems to me that the wallet really should care about these transactions even if it doesn’t list them.
This is more of a problem with the wallet structure in general. I do not think that PSBT should really be doing anything about this.
These rescans are rather painful, so - if it’s not too late - adding a blockheight hint to BIP-174 might be really helpful. I can suggest that on the mailing list if others think it’s useful.
In general, I don’t think this is really useful. If you already know where to start rescanning for UTXOs, why can’t you just find the UTXO and add it yourself? There isn’t really any need to tell someone else to do it.
It would be nice if all RPC calls which can produce a complete transaction have a flag that lets you produce the hex immediately, rather than going through the finalizepsbt dance.
This was considered, but I think it is easier to follow and understand if the roles are more separated rather than integrated into one command. Instead of having many commands that can produce variable output, we will only have one command that does. The rest will have fixed, known outputs.
achow101 force-pushed
on Jul 10, 2018
achow101 force-pushed
on Jul 10, 2018
achow101 force-pushed
on Jul 10, 2018
sipa
commented at 10:24 pm on July 11, 2018:
member
Bit of a privacy issue: let’s say person A and B are about to spend from a multisig address, sending everything to person A. Person A gives their address to person B, their wallet wallet creates a PSBT, but doesn’t sign it. Wallet A then calls walletprocesspsbt which signs it and spontaneously adds the master_fingerprint and bip32 path. Same issue with walletcreatefundedpsbt.
I think it’s generally hard to maintain much privacy in PSBT. You should assume that those you share a PSBT with will learn more about you than the general public will, even if just by observing which parties add data at what time.
Somewhat orthogonal bug(?): walletcreatefundedpsbt is unable to construct a transaction if it can’t find the relevant UTXO.
That’s inevitable. If you don’t know what is being spent, you don’t know what data to add the the PSBT.
walletprocesspsbt won’t sign a transaction if it doesn’t know about the multisig address (i.e. addmultisig was never called). This is the case even if the PSBT has sufficient information, since it could match the witness_script against its own pub keys. Might be a nice improvement for later.
That sounds like a bug to me. If the PSBT actually has all the information available (UTXO, redeemscript, witnessscript), walletprocesspsbt should sign with all the keys it has.
However in this case it could in principle blind sign it, or at least throw a more clear error message than “complete”: false.
These rescans are rather painful, so - if it’s not too late - adding a blockheight hint to BIP-174 might be really helpful. I can suggest that on the mailing list if others think it’s useful.
I think that generally no normal operation should involve rescans. PSBT are for formalizing interactions between pieces of wallet software, and wallet software should already have ways to know about its own UTXOs (which may in exceptional situations mean rescan, but generally shouldn’t).
There can also be more low-level separate RPCs that permit simulating some of the functionality without having strict wallets participate. None of that needs to be part of the initial functionality in Bitcoin Core, and some of it can be separate tools even. For example:
utxoupdatepsbt (node RPC) which adds UTXO data using chainstate/mempool to a PSBT rather than from a wallet.
analyzepsbt (utility RPC, but aware of signing logic) which could report more data on PSBT than just decoding it (it could include fee, estimated vsize after signing, estimated feerate, what stage each input is towards finalizing and/or what’s missing to progress further).
joinpsbts (utility RPC) which would combine the inputs and outputs from multiple PSBTs for possible different transactions (effectively constructing a coinjoin), maintaining all utxo/script/derivation data for existing inputs.
achow101
commented at 10:36 pm on July 11, 2018:
member
walletprocesspsbt won’t sign a transaction if it doesn’t know about the multisig address (i.e. addmultisig was never called). This is the case even if the PSBT has sufficient information, since it could match the witness_script against its own pub keys. Might be a nice improvement for later.
This shouldn’t be the case as it is explicitly tested for in the test cases. A multisig address is used with keys from 3 nodes, but the multisig address is only added to one of them. One of the other nodes (without having called addmultisigaddress) is still able to sign the transaction and produce a complete, sendable transaction.
There can also be more low-level separate RPCs that permit simulating some of the functionality without having strict wallets participate
Certainly, but I think such functionality should be done in a separate PR to avoid adding more things to review in this PR which is already somewhat large.
Sjors
commented at 9:16 am on July 12, 2018:
member
In this test case node1 created the multisig and is the first to sign it. In the scenario I tested, the multisig was created by an independent wallet, so the participating wallets only have the matching public and private keys, but don’t know there’s a multisig involved.
sipa
commented at 5:38 pm on July 12, 2018:
member
In this test case node1 created the multisig and is the first to sign it. In the scenario I tested, the multisig was created by an independent wallet, so the participating wallets only have the matching public and private keys, but don’t know there’s a multisig involved.
So run walletprocesspsbt on the PSBT with the wallet that does have the information about the multisig construction? It should add it to the file, and permit the signers to use that information.
If I’m misunderstanding the scenario, can you give a script to reproduce the issue? If you’re right, this may be an issue.
Sjors
commented at 3:30 pm on July 13, 2018:
member
achow101
commented at 6:25 pm on July 13, 2018:
member
@sjors this is expected behavior due to how the wallet works. It is orthogonal to this PR and is just a side effect of the current wallet structure.
sipa
commented at 6:38 pm on July 13, 2018:
member
@Sjors So what is happening is that none of the wallets involved in your tests treat the address as “mine”, and:
As a result none know about the UTXO being spent,
As a result none can add UTXO information to the PSBT
As a result none can add script information (even those that know about the multisig, because they don’t know that it is relevant for that input).
As a result none sign (because they don’t know their key is relevant)
The solution is calling importaddress with P2WSH address on one of the nodes, then giving the PSBT to that node, then giving it to the node with the multisig information, and then giving it to all signers.
It is a highly confusing situation that adding a multisig address doesn’t automatically watch it, but it is consistent with how everything works: things are only treated as mine if (A) you know the scripts involved and have ALL the private keys or (B) the address was imported as watch-only.
Longer term this is something I want to address with my descriptors work.
Sjors
commented at 7:03 pm on July 13, 2018:
member
I see, at least we have it documented again :-)
Implement PSBT Structures and un/serialization methods per BIP 17441c607f09b
Add pubkeys and whether input was witness to SignatureData
Stores pubkeys in SignatureData and retrieves them when using GetPubKey().
Stores whether the signatures in a SignatureData are for a witness input.
12bcc64f27
Methods for interacting with PSBT structs
Added methods which move data to/from SignaturData objects to
PSBTInput and PSBTOutput objects.
Added sanity checks for PSBTs as a whole which are done immediately
after deserialization.
Added Merge methods to merge a PSBT into another one.
e9d86a43ad
Refactor transaction creation and transaction funding logic
In preparation for more create transaction and fund transcation RPCs,
refactor the transaction creation and funding logic into separate
functions.
58a8e28918
SignPSBTInput wrapper function
The SignPSBTInput function takes a PSBTInput, SignatureData, SigningProvider,
and other data necessary for signing. It fills the SignatureData with data from
the PSBTInput, retrieves the UTXO from the PSBTInput, signs and finalizes the
input if possible, and then extracts the results from the SignatureData and
puts them back into the PSBTInput.
8b5ef27937
in
src/script/sign.h:550
in
96237e8c75outdated
545+ s >> magic;
546+ if (!std::equal(magic, magic + 4, PSBT_MAGIC_BYTES)) {
547+ throw std::ios_base::failure("Invalid PSBT magic bytes");
548+ }
549+ unsigned char magic_sep;
550+ s >> magic_sep;
Good catch. I have fixed this by adding 0xff to the magic bytes so it will be checked above.
achow101 force-pushed
on Jul 13, 2018
DrahtBot
commented at 0:50 am on July 14, 2018:
member
#13359 (wallet: Directly operate with CMutableTransaction by MarcoFalke)
#13266 (refactoring: Convert DataFromTransaction to a SignatureData constructor, and privatize helpers by Empact)
#13144 (RPC: Improve error messages on RPC endpoints that use GetTransaction by jimpo)
#13098 (Skip tx-rehashing on historic blocks by MarcoFalke)
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.
in
src/rpc/rawtransaction.cpp:1739
in
3e3fb6e737outdated
1750+ "converttopsbt \"hexstring\" ( permitsigdata iswitness )\n"
1751+ "\nConverts a network serialized transaction to a PSBT. This should be used only with createrawtransaction and fundrawtransaction\n"
1752+ "createpsbt and walletcreatefundedpsbt should be used for new applications.\n"
1753+ "\nArguments:\n"
1754+ "1. \"hexstring\" (string, required) The hex string of a raw transaction\n"
1755+ "2. permitsigdata (boolean, optional, default=false) If true, any signatures in the input will be discarde and conversion.\n"
This seems wrong. With the current code, if permitsigdata is false it will try both witness and no_witness (where it should only permit non-witness, I think?). Further, when iswitness is not specified, it will only try witness.
in
src/rpc/rawtransaction.cpp:1686
in
3e3fb6e737outdated
1681+UniValue createpsbt(const JSONRPCRequest& request)
1682+{
1683+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 4)
1684+ throw std::runtime_error(
1685+ "createpsbt [{\"txid\":\"id\",\"vout\":n},...] [{\"address\":amount},{\"data\":\"hex\"},...] ( locktime ) ( replaceable )\n"
1686+ "\nCreates a transaction in the Partially Signed Transaction format. Inputs will be added if supplied inputs are not enough\n"
in
src/rpc/rawtransaction.cpp:1742
in
4afc08e472outdated
1738@@ -1755,8 +1739,9 @@ UniValue converttopsbt(const JSONRPCRequest& request)
1739 "2. permitsigdata (boolean, optional, default=false) If true, any signatures in the input will be discarde and conversion.\n"
1740 " will continue. If false, RPC will fail if any signatures are present.\n"
1741 "3. iswitness (boolean, optional) Whether the transaction hex is a serialized witness transaction.\n"
1742- " If iswitness is not present, heuristic tests will be used in decoding. Only has an effect if\n"
1743- " permitsigdata is true\n"
1744+ " If iswitness is not present, heuristic tests will be used in decoding. If true, only witness deserializaion\n"
decodepsbt takes a PSBT and decodes it to JSON
combinepsbt takes multiple PSBTs for the same tx and combines them.
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.
c27fe419ef
Create wallet RPCs for PSBT
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.
a4b06fb42e
achow101 force-pushed
on Jul 16, 2018
Tests for PSBT
Added functional tests for PSBT that test the RPCs. Also added all
of the BIP 174 test vectors (except for the updater tests) in the
functional tests.
Added a Unit test for the BIP 174 updater test vector.
020628e3a4
achow101 force-pushed
on Jul 17, 2018
sipa
commented at 1:20 am on July 17, 2018:
member
utACK020628e3a4e88e36647eaf92bac4b3552796ac6a
laanwj
commented at 6:25 pm on July 18, 2018:
member
utACK020628e3a4e88e36647eaf92bac4b3552796ac6a
laanwj merged this
on Jul 18, 2018
laanwj closed this
on Jul 18, 2018
laanwj referenced this in commit
b654723461
on Jul 18, 2018
fanquake removed this from the "Blockers" column in a project
MarcoFalke referenced this in commit
aba2e666d7
on Jul 19, 2018
meshcollider referenced this in commit
31c0006a6c
on Feb 25, 2020
sidhujag referenced this in commit
421889f107
on Feb 25, 2020
sidhujag referenced this in commit
5813be17ef
on Nov 10, 2020
UdjinM6 referenced this in commit
47f20465c3
on May 19, 2021
UdjinM6 referenced this in commit
1d240e7108
on May 19, 2021
UdjinM6 referenced this in commit
6f7b52ac63
on May 19, 2021
kittywhiskers referenced this in commit
5a4e75cdc3
on May 20, 2021
kittywhiskers referenced this in commit
dfd2a197d7
on May 20, 2021
kittywhiskers referenced this in commit
bc2f11f230
on May 20, 2021
barrystyle referenced this in commit
8e74396e6e
on May 27, 2021
barrystyle referenced this in commit
a8669d0a93
on May 27, 2021
barrystyle referenced this in commit
4a6b6f21dd
on May 31, 2021
kittywhiskers referenced this in commit
bcfec0b047
on Jun 4, 2021
kittywhiskers referenced this in commit
dbb1546f6e
on Jun 4, 2021
UdjinM6 referenced this in commit
6964099ba2
on Jun 7, 2021
barrystyle referenced this in commit
acb122e6cf
on Jun 8, 2021
barrystyle referenced this in commit
9166796714
on Jun 8, 2021
kittywhiskers referenced this in commit
2b7d4a3487
on Jun 9, 2021
kittywhiskers referenced this in commit
2799f70622
on Jul 9, 2021
kittywhiskers referenced this in commit
bf9ae7cf99
on Jul 13, 2021
kittywhiskers referenced this in commit
04f913f374
on Jul 13, 2021
kittywhiskers referenced this in commit
c00b3e942f
on Jul 13, 2021
PastaPastaPasta referenced this in commit
e98241da5d
on Jul 13, 2021
gades referenced this in commit
58d7b3b1cd
on Apr 26, 2022
gades referenced this in commit
6beff1d0b3
on Apr 30, 2022
malbit referenced this in commit
e163b6e23f
on Aug 7, 2022
This is a metadata mirror of the GitHub repository
bitcoin/bitcoin.
This site is not affiliated with GitHub.
Content is generated from a GitHub metadata backup.
generated: 2025-04-06 15:12 UTC
This site is hosted by @0xB10C More mirrored repositories can be found on mirror.b10c.me