From 3235847473e36070cbe9b0e9deacdd8d8d9428fe Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 2 Oct 2019 15:49:33 -0400 Subject: [PATCH 01/15] Types are compact size uints --- src/psbt.h | 41 +++++++++++++++++++---------------- src/script/sign.h | 2 +- src/serialize.h | 13 +++++++++++ src/test/fuzz/script_sign.cpp | 4 ++-- 4 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/psbt.h b/src/psbt.h index 21daa050e..a752e99e7 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -69,52 +69,52 @@ struct PSBTInput inline void Serialize(Stream& s) const { // Write the utxo if (non_witness_utxo) { - SerializeToVector(s, PSBT_IN_NON_WITNESS_UTXO); + SerializeToVector(s, CompactSizeWriter(PSBT_IN_NON_WITNESS_UTXO)); OverrideStream os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS); SerializeToVector(os, non_witness_utxo); } if (!witness_utxo.IsNull()) { - SerializeToVector(s, PSBT_IN_WITNESS_UTXO); + SerializeToVector(s, CompactSizeWriter(PSBT_IN_WITNESS_UTXO)); SerializeToVector(s, witness_utxo); } if (final_script_sig.empty() && final_script_witness.IsNull()) { // Write any partial signatures for (auto sig_pair : partial_sigs) { - SerializeToVector(s, PSBT_IN_PARTIAL_SIG, Span{sig_pair.second.first}); + SerializeToVector(s, CompactSizeWriter(PSBT_IN_PARTIAL_SIG), Span{sig_pair.second.first}); s << sig_pair.second.second; } // Write the sighash type if (sighash_type != std::nullopt) { - SerializeToVector(s, PSBT_IN_SIGHASH); + SerializeToVector(s, CompactSizeWriter(PSBT_IN_SIGHASH)); SerializeToVector(s, *sighash_type); } // Write the redeem script if (!redeem_script.empty()) { - SerializeToVector(s, PSBT_IN_REDEEMSCRIPT); + SerializeToVector(s, CompactSizeWriter(PSBT_IN_REDEEMSCRIPT)); s << redeem_script; } // Write the witness script if (!witness_script.empty()) { - SerializeToVector(s, PSBT_IN_WITNESSSCRIPT); + SerializeToVector(s, CompactSizeWriter(PSBT_IN_WITNESSSCRIPT)); s << witness_script; } // Write any hd keypaths - SerializeHDKeypaths(s, hd_keypaths, PSBT_IN_BIP32_DERIVATION); + SerializeHDKeypaths(s, hd_keypaths, CompactSizeWriter(PSBT_IN_BIP32_DERIVATION)); } // Write script sig if (!final_script_sig.empty()) { - SerializeToVector(s, PSBT_IN_SCRIPTSIG); + SerializeToVector(s, CompactSizeWriter(PSBT_IN_SCRIPTSIG)); s << final_script_sig; } // write script witness if (!final_script_witness.IsNull()) { - SerializeToVector(s, PSBT_IN_SCRIPTWITNESS); + SerializeToVector(s, CompactSizeWriter(PSBT_IN_SCRIPTWITNESS)); SerializeToVector(s, final_script_witness.stack); } @@ -147,8 +147,9 @@ struct PSBTInput break; } - // First byte of key is the type - unsigned char type = key[0]; + // Type is compact size uint at beginning of key + SpanReader skey(s.GetType(), s.GetVersion(), key); + uint64_t type = ReadCompactSize(skey); // Do stuff based on type switch(type) { @@ -292,18 +293,18 @@ struct PSBTOutput inline void Serialize(Stream& s) const { // Write the redeem script if (!redeem_script.empty()) { - SerializeToVector(s, PSBT_OUT_REDEEMSCRIPT); + SerializeToVector(s, CompactSizeWriter(PSBT_OUT_REDEEMSCRIPT)); s << redeem_script; } // Write the witness script if (!witness_script.empty()) { - SerializeToVector(s, PSBT_OUT_WITNESSSCRIPT); + SerializeToVector(s, CompactSizeWriter(PSBT_OUT_WITNESSSCRIPT)); s << witness_script; } // Write any hd keypaths - SerializeHDKeypaths(s, hd_keypaths, PSBT_OUT_BIP32_DERIVATION); + SerializeHDKeypaths(s, hd_keypaths, CompactSizeWriter(PSBT_OUT_BIP32_DERIVATION)); // Write unknown things for (auto& entry : unknown) { @@ -334,8 +335,9 @@ struct PSBTOutput break; } - // First byte of key is the type - unsigned char type = key[0]; + // Type is compact size uint at beginning of key + SpanReader skey(s.GetType(), s.GetVersion(), key); + uint64_t type = ReadCompactSize(skey); // Do stuff based on type switch(type) { @@ -422,7 +424,7 @@ struct PartiallySignedTransaction s << PSBT_MAGIC_BYTES; // unsigned tx flag - SerializeToVector(s, PSBT_GLOBAL_UNSIGNED_TX); + SerializeToVector(s, CompactSizeWriter(PSBT_GLOBAL_UNSIGNED_TX)); // Write serialized tx to a stream OverrideStream os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS); @@ -474,8 +476,9 @@ struct PartiallySignedTransaction break; } - // First byte of key is the type - unsigned char type = key[0]; + // Type is compact size uint at beginning of key + SpanReader skey(s.GetType(), s.GetVersion(), key); + uint64_t type = ReadCompactSize(skey); // Do stuff based on type switch(type) { diff --git a/src/script/sign.h b/src/script/sign.h index 50525af33..622147cd9 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -143,7 +143,7 @@ void DeserializeHDKeypaths(Stream& s, const std::vector& key, std // Serialize HD keypaths to a stream from a map template -void SerializeHDKeypaths(Stream& s, const std::map& hd_keypaths, uint8_t type) +void SerializeHDKeypaths(Stream& s, const std::map& hd_keypaths, CompactSizeWriter type) { for (auto keypath_pair : hd_keypaths) { if (!keypath_pair.first.IsValid()) { diff --git a/src/serialize.h b/src/serialize.h index edf10440c..873361fe9 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -527,6 +527,19 @@ struct CompactSizeFormatter } }; +class CompactSizeWriter +{ +protected: + uint64_t n; +public: + explicit CompactSizeWriter(uint64_t n_in) : n(n_in) { } + + template + void Serialize(Stream &s) const { + WriteCompactSize(s, n); + } +}; + template struct LimitedStringFormatter { diff --git a/src/test/fuzz/script_sign.cpp b/src/test/fuzz/script_sign.cpp index 79380bd9c..205f6c806 100644 --- a/src/test/fuzz/script_sign.cpp +++ b/src/test/fuzz/script_sign.cpp @@ -43,7 +43,7 @@ FUZZ_TARGET_INIT(script_sign, initialize_script_sign) } catch (const std::ios_base::failure&) { } CDataStream serialized{SER_NETWORK, PROTOCOL_VERSION}; - SerializeHDKeypaths(serialized, hd_keypaths, fuzzed_data_provider.ConsumeIntegral()); + SerializeHDKeypaths(serialized, hd_keypaths, CompactSizeWriter(fuzzed_data_provider.ConsumeIntegral())); } { @@ -61,7 +61,7 @@ FUZZ_TARGET_INIT(script_sign, initialize_script_sign) } CDataStream serialized{SER_NETWORK, PROTOCOL_VERSION}; try { - SerializeHDKeypaths(serialized, hd_keypaths, fuzzed_data_provider.ConsumeIntegral()); + SerializeHDKeypaths(serialized, hd_keypaths, CompactSizeWriter(fuzzed_data_provider.ConsumeIntegral())); } catch (const std::ios_base::failure&) { } std::map deserialized_hd_keypaths; From c3eb416b882522dffa4254b52d2da5b53c970efe Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 2 Oct 2019 16:11:34 -0400 Subject: [PATCH 02/15] Implement PSBT versions --- src/psbt.h | 26 ++++++++++++++++++++++++++ test/functional/data/rpc_psbt.json | 4 +++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/psbt.h b/src/psbt.h index a752e99e7..834af2621 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -20,6 +20,7 @@ static constexpr uint8_t PSBT_MAGIC_BYTES[5] = {'p', 's', 'b', 't', 0xff}; // Global types static constexpr uint8_t PSBT_GLOBAL_UNSIGNED_TX = 0x00; +static constexpr uint8_t PSBT_GLOBAL_VERSION = 0xFB; // Input types static constexpr uint8_t PSBT_IN_NON_WITNESS_UTXO = 0x00; @@ -45,6 +46,9 @@ static constexpr uint8_t PSBT_SEPARATOR = 0x00; // to prevent reading a stream indefinitely and running out of memory. const std::streamsize MAX_FILE_SIZE_PSBT = 100000000; // 100 MiB +// PSBT version number +static constexpr uint32_t PSBT_HIGHEST_VERSION = 0; + /** A structure for PSBTs which contain per-input information */ struct PSBTInput { @@ -398,6 +402,7 @@ struct PartiallySignedTransaction std::vector inputs; std::vector outputs; std::map, std::vector> unknown; + std::optional m_version; bool IsNull() const; @@ -430,6 +435,12 @@ struct PartiallySignedTransaction OverrideStream os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS); SerializeToVector(os, *tx); + // PSBT version + if (m_version != std::nullopt && *m_version > 0) { + SerializeToVector(s, CompactSizeWriter(PSBT_GLOBAL_VERSION)); + SerializeToVector(s, *m_version); + } + // Write the unknown things for (auto& entry : unknown) { s << entry.first; @@ -502,6 +513,21 @@ struct PartiallySignedTransaction } break; } + case PSBT_GLOBAL_VERSION: + { + if (m_version) { + throw std::ios_base::failure("Duplicate Key, version already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Global version key is more than one byte type"); + } + uint32_t v; + UnserializeFromVector(s, v); + m_version = v; + if (*m_version > PSBT_HIGHEST_VERSION) { + throw std::ios_base::failure("Unsupported version number"); + } + break; + } // Unknown stuff default: { if (unknown.count(key) > 0) { diff --git a/test/functional/data/rpc_psbt.json b/test/functional/data/rpc_psbt.json index 0f6cd97fd..ddec4e65e 100644 --- a/test/functional/data/rpc_psbt.json +++ b/test/functional/data/rpc_psbt.json @@ -19,6 +19,7 @@ "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", @@ -34,7 +35,8 @@ "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" ], "creator" : [ { From df84fa99c5a52e4688e240c585f7d22b20401906 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Mon, 4 Jan 2021 17:21:29 -0500 Subject: [PATCH 03/15] Add GetVersion helper to PSBT --- src/psbt.cpp | 8 ++++++++ src/psbt.h | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/psbt.cpp b/src/psbt.cpp index 658576680..f3ecbd63d 100644 --- a/src/psbt.cpp +++ b/src/psbt.cpp @@ -401,3 +401,11 @@ bool DecodeRawPSBT(PartiallySignedTransaction& psbt, const std::string& tx_data, } return true; } + +uint32_t PartiallySignedTransaction::GetVersion() const +{ + if (m_version != std::nullopt) { + return *m_version; + } + return 0; +} diff --git a/src/psbt.h b/src/psbt.h index 834af2621..46cfaf5f9 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -405,6 +405,7 @@ struct PartiallySignedTransaction std::optional m_version; bool IsNull() const; + uint32_t GetVersion() const; /** Merge psbt into this. The two psbts must have the same underlying CTransaction (i.e. the * same actual Bitcoin transaction.) Returns true if the merge succeeded, false otherwise. */ @@ -436,7 +437,7 @@ struct PartiallySignedTransaction SerializeToVector(os, *tx); // PSBT version - if (m_version != std::nullopt && *m_version > 0) { + if (GetVersion() > 0) { SerializeToVector(s, CompactSizeWriter(PSBT_GLOBAL_VERSION)); SerializeToVector(s, *m_version); } From 10ba0b593d3c9bc03e36d52344237be6e89c443f Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Mon, 25 Jan 2021 16:49:44 -0500 Subject: [PATCH 04/15] Output psbt version in decodepsbt --- src/rpc/rawtransaction.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 78c159621..253ff3746 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1075,6 +1075,7 @@ static RPCHelpMan decodepsbt() { {RPCResult::Type::ELISION, "", "The layout is the same as the output of decoderawtransaction."}, }}, + {RPCResult::Type::NUM, "psbt_version", "The PSBT version number. Not to be confused with the unsigned transaction version"}, {RPCResult::Type::OBJ_DYN, "unknown", "The unknown global fields", { {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, @@ -1194,6 +1195,9 @@ static RPCHelpMan decodepsbt() TxToUniv(CTransaction(*psbtx.tx), uint256(), tx_univ, false); result.pushKV("tx", tx_univ); + // PSBT version + result.pushKV("psbt_version", static_cast(psbtx.GetVersion())); + // Unknown data UniValue unknowns(UniValue::VOBJ); for (auto entry : psbtx.unknown) { From aebe758e54802ead664a3c8b694fe0b447e01724 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 2 Oct 2019 16:45:56 -0400 Subject: [PATCH 05/15] Implement PSBT proprietary type --- src/psbt.h | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/src/psbt.h b/src/psbt.h index 46cfaf5f9..9390b38ee 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -21,6 +21,7 @@ static constexpr uint8_t PSBT_MAGIC_BYTES[5] = {'p', 's', 'b', 't', 0xff}; // Global types static constexpr uint8_t PSBT_GLOBAL_UNSIGNED_TX = 0x00; static constexpr uint8_t PSBT_GLOBAL_VERSION = 0xFB; +static constexpr uint8_t PSBT_GLOBAL_PROPRIETARY = 0xFC; // Input types static constexpr uint8_t PSBT_IN_NON_WITNESS_UTXO = 0x00; @@ -32,11 +33,13 @@ static constexpr uint8_t PSBT_IN_WITNESSSCRIPT = 0x05; static constexpr uint8_t PSBT_IN_BIP32_DERIVATION = 0x06; static constexpr uint8_t PSBT_IN_SCRIPTSIG = 0x07; static constexpr uint8_t PSBT_IN_SCRIPTWITNESS = 0x08; +static constexpr uint8_t PSBT_IN_PROPRIETARY = 0xFC; // Output types static constexpr uint8_t PSBT_OUT_REDEEMSCRIPT = 0x00; static constexpr uint8_t PSBT_OUT_WITNESSSCRIPT = 0x01; static constexpr uint8_t PSBT_OUT_BIP32_DERIVATION = 0x02; +static constexpr uint8_t PSBT_OUT_PROPRIETARY = 0xFC; // The separator is 0x00. Reading this in means that the unserializer can interpret it // as a 0 length key which indicates that this is the separator. The separator has no value. @@ -49,6 +52,22 @@ const std::streamsize MAX_FILE_SIZE_PSBT = 100000000; // 100 MiB // PSBT version number static constexpr uint32_t PSBT_HIGHEST_VERSION = 0; +/** A structure for PSBT proprietary types */ +struct PSBTProprietary +{ + uint64_t subtype; + std::vector identifier; + std::vector key; + std::vector value; + + bool operator<(const PSBTProprietary &b) const { + return key < b.key; + } + bool operator==(const PSBTProprietary &b) const { + return key == b.key; + } +}; + /** A structure for PSBTs which contain per-input information */ struct PSBTInput { @@ -61,6 +80,7 @@ struct PSBTInput std::map hd_keypaths; std::map partial_sigs; std::map, std::vector> unknown; + std::set m_proprietary; std::optional sighash_type; bool IsNull() const; @@ -122,6 +142,12 @@ struct PSBTInput SerializeToVector(s, final_script_witness.stack); } + // Write proprietary things + for (const auto& entry : m_proprietary) { + s << entry.key; + s << entry.value; + } + // Write unknown things for (auto& entry : unknown) { s << entry.first; @@ -255,6 +281,20 @@ struct PSBTInput UnserializeFromVector(s, final_script_witness.stack); break; } + case PSBT_IN_PROPRIETARY: + { + PSBTProprietary this_prop; + skey >> this_prop.identifier; + this_prop.subtype = ReadCompactSize(skey); + this_prop.key = key; + + if (m_proprietary.count(this_prop) > 0) { + throw std::ios_base::failure("Duplicate Key, proprietary key already found"); + } + s >> this_prop.value; + m_proprietary.insert(this_prop); + break; + } // Unknown stuff default: if (unknown.count(key) > 0) { @@ -286,6 +326,7 @@ struct PSBTOutput CScript witness_script; std::map hd_keypaths; std::map, std::vector> unknown; + std::set m_proprietary; bool IsNull() const; void FillSignatureData(SignatureData& sigdata) const; @@ -310,6 +351,12 @@ struct PSBTOutput // Write any hd keypaths SerializeHDKeypaths(s, hd_keypaths, CompactSizeWriter(PSBT_OUT_BIP32_DERIVATION)); + // Write proprietary things + for (const auto& entry : m_proprietary) { + s << entry.key; + s << entry.value; + } + // Write unknown things for (auto& entry : unknown) { s << entry.first; @@ -370,6 +417,20 @@ struct PSBTOutput DeserializeHDKeypaths(s, key, hd_keypaths); break; } + case PSBT_OUT_PROPRIETARY: + { + PSBTProprietary this_prop; + skey >> this_prop.identifier; + this_prop.subtype = ReadCompactSize(skey); + this_prop.key = key; + + if (m_proprietary.count(this_prop) > 0) { + throw std::ios_base::failure("Duplicate Key, proprietary key already found"); + } + s >> this_prop.value; + m_proprietary.insert(this_prop); + break; + } // Unknown stuff default: { if (unknown.count(key) > 0) { @@ -403,6 +464,7 @@ struct PartiallySignedTransaction std::vector outputs; std::map, std::vector> unknown; std::optional m_version; + std::set m_proprietary; bool IsNull() const; uint32_t GetVersion() const; @@ -442,6 +504,12 @@ struct PartiallySignedTransaction SerializeToVector(s, *m_version); } + // Write proprietary things + for (const auto& entry : m_proprietary) { + s << entry.key; + s << entry.value; + } + // Write the unknown things for (auto& entry : unknown) { s << entry.first; @@ -529,6 +597,20 @@ struct PartiallySignedTransaction } break; } + case PSBT_GLOBAL_PROPRIETARY: + { + PSBTProprietary this_prop; + skey >> this_prop.identifier; + this_prop.subtype = ReadCompactSize(skey); + this_prop.key = key; + + if (m_proprietary.count(this_prop) > 0) { + throw std::ios_base::failure("Duplicate Key, proprietary key already found"); + } + s >> this_prop.value; + m_proprietary.insert(this_prop); + break; + } // Unknown stuff default: { if (unknown.count(key) > 0) { From a4cf8101746039ec8be234d899bdaf848548598e Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 2 Oct 2019 16:58:20 -0400 Subject: [PATCH 06/15] Output proprietary type info in decodepsbt --- src/rpc/rawtransaction.cpp | 70 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 253ff3746..4502776a0 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1076,6 +1076,16 @@ static RPCHelpMan decodepsbt() {RPCResult::Type::ELISION, "", "The layout is the same as the output of decoderawtransaction."}, }}, {RPCResult::Type::NUM, "psbt_version", "The PSBT version number. Not to be confused with the unsigned transaction version"}, + {RPCResult::Type::ARR, "proprietary", "The global proprietary map", + { + {RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR_HEX, "identifier", "The hex string for the proprietary identifier"}, + {RPCResult::Type::NUM, "subtype", "The number for the subtype"}, + {RPCResult::Type::STR_HEX, "key", "The hex for the key"}, + {RPCResult::Type::STR_HEX, "value", "The hex for the value"}, + }}, + }}, {RPCResult::Type::OBJ_DYN, "unknown", "The unknown global fields", { {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, @@ -1138,6 +1148,16 @@ static RPCHelpMan decodepsbt() { {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, }}, + {RPCResult::Type::ARR, "proprietary", "The input proprietary map", + { + {RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR_HEX, "identifier", "The hex string for the proprietary identifier"}, + {RPCResult::Type::NUM, "subtype", "The number for the subtype"}, + {RPCResult::Type::STR_HEX, "key", "The hex for the key"}, + {RPCResult::Type::STR_HEX, "value", "The hex for the value"}, + }}, + }}, }}, }}, {RPCResult::Type::ARR, "outputs", "", @@ -1169,6 +1189,16 @@ static RPCHelpMan decodepsbt() { {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, }}, + {RPCResult::Type::ARR, "proprietary", "The output proprietary map", + { + {RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR_HEX, "identifier", "The hex string for the proprietary identifier"}, + {RPCResult::Type::NUM, "subtype", "The number for the subtype"}, + {RPCResult::Type::STR_HEX, "key", "The hex for the key"}, + {RPCResult::Type::STR_HEX, "value", "The hex for the value"}, + }}, + }}, }}, }}, {RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The transaction fee paid if all UTXOs slots in the PSBT have been filled."}, @@ -1198,6 +1228,18 @@ static RPCHelpMan decodepsbt() // PSBT version result.pushKV("psbt_version", static_cast(psbtx.GetVersion())); + // Proprietary + UniValue proprietary(UniValue::VARR); + for (const auto& entry : psbtx.m_proprietary) { + UniValue this_prop(UniValue::VOBJ); + this_prop.pushKV("identifier", HexStr(entry.identifier)); + this_prop.pushKV("subtype", entry.subtype); + this_prop.pushKV("key", HexStr(entry.key)); + this_prop.pushKV("value", HexStr(entry.value)); + proprietary.push_back(this_prop); + } + result.pushKV("proprietary", proprietary); + // Unknown data UniValue unknowns(UniValue::VOBJ); for (auto entry : psbtx.unknown) { @@ -1304,6 +1346,20 @@ static RPCHelpMan decodepsbt() in.pushKV("final_scriptwitness", txinwitness); } + // Proprietary + if (!input.m_proprietary.empty()) { + UniValue proprietary(UniValue::VARR); + for (const auto& entry : input.m_proprietary) { + UniValue this_prop(UniValue::VOBJ); + this_prop.pushKV("identifier", HexStr(entry.identifier)); + this_prop.pushKV("subtype", entry.subtype); + this_prop.pushKV("key", HexStr(entry.key)); + this_prop.pushKV("value", HexStr(entry.value)); + proprietary.push_back(this_prop); + } + in.pushKV("proprietary", proprietary); + } + // Unknown data if (input.unknown.size() > 0) { UniValue unknowns(UniValue::VOBJ); @@ -1348,6 +1404,20 @@ static RPCHelpMan decodepsbt() out.pushKV("bip32_derivs", keypaths); } + // Proprietary + if (!output.m_proprietary.empty()) { + UniValue proprietary(UniValue::VARR); + for (const auto& entry : output.m_proprietary) { + UniValue this_prop(UniValue::VOBJ); + this_prop.pushKV("identifier", HexStr(entry.identifier)); + this_prop.pushKV("subtype", entry.subtype); + this_prop.pushKV("key", HexStr(entry.key)); + this_prop.pushKV("value", HexStr(entry.value)); + proprietary.push_back(this_prop); + } + out.pushKV("proprietary", proprietary); + } + // Unknown data if (output.unknown.size() > 0) { UniValue unknowns(UniValue::VOBJ); From 94065cc6c5a087a5657519202a4ca08db7c1d861 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 2 Oct 2019 19:28:52 -0400 Subject: [PATCH 07/15] Test for proprietary field --- test/functional/data/rpc_psbt.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/functional/data/rpc_psbt.json b/test/functional/data/rpc_psbt.json index ddec4e65e..9c7284d40 100644 --- a/test/functional/data/rpc_psbt.json +++ b/test/functional/data/rpc_psbt.json @@ -36,7 +36,8 @@ "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" ], "creator" : [ { From 5fdaf6a2adbf99c4ab2c2863fba35a0baa559fb5 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 25 Jul 2019 11:26:20 -0400 Subject: [PATCH 08/15] moveonly: Move (Un)Serialize(To/From)Vector, (De)SerializeHDKeypaths to psbt module SerializeToVector, UnserializeFromVector, DeserializeHDKeypaths, and SerializeHDKeypaths were in sign.h where PSBT was originally implemented. Since all of the PSBT serialization has moved to its own file, these functions should follow. --- src/psbt.h | 77 +++++++++++++++++++++++++++++++++++ src/script/sign.cpp | 1 + src/script/sign.h | 76 ---------------------------------- src/script/signingprovider.h | 3 +- src/test/fuzz/script_sign.cpp | 1 + 5 files changed, 80 insertions(+), 78 deletions(-) diff --git a/src/psbt.h b/src/psbt.h index 9390b38ee..36a3d2ca1 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -10,8 +10,11 @@ #include #include #include +#include