From 9671aa08c2a7eb0af75ad3016585872c5b781f75 Mon Sep 17 00:00:00 2001 From: Ava Chow Date: Mon, 16 Mar 2026 14:05:39 -0700 Subject: [PATCH] psbt: add tx input and output fields in PSBTInput and PSBTOutput PSBTInput should be aware of the previous txid, output index, and sequence numbers for inputs, extracting them from the global unsigned tx. PSBTOutput should be aware of the output amount and script, extracting them from the global unsigned tx. This prepares for PSBTv2 where these fields are serialized. --- src/psbt.cpp | 10 ++++++++-- src/psbt.h | 24 ++++++++++++++++++------ src/rpc/rawtransaction.cpp | 18 ++---------------- src/test/fuzz/deserialize.cpp | 4 ++-- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/psbt.cpp b/src/psbt.cpp index 416eae11d1f..29f16e73c87 100644 --- a/src/psbt.cpp +++ b/src/psbt.cpp @@ -15,8 +15,14 @@ using common::PSBTError; PartiallySignedTransaction::PartiallySignedTransaction(const CMutableTransaction& tx) : tx(tx) { - inputs.resize(tx.vin.size(), PSBTInput(GetVersion())); - outputs.resize(tx.vout.size(), PSBTOutput(GetVersion())); + inputs.reserve(tx.vin.size()); + for (const CTxIn& input : tx.vin) { + inputs.emplace_back(GetVersion(), input.prevout.hash, input.prevout.n, input.nSequence); + } + outputs.reserve(tx.vout.size()); + for (const CTxOut& output : tx.vout) { + outputs.emplace_back(GetVersion(), output.nValue, output.scriptPubKey); + } } bool PartiallySignedTransaction::IsNull() const diff --git a/src/psbt.h b/src/psbt.h index 4272cd3a807..dcf0d6bd1a5 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -280,6 +280,10 @@ public: std::map> hash160_preimages; std::map> hash256_preimages; + Txid prev_txid; + uint32_t prev_out; + std::optional sequence; + // Taproot fields std::vector m_tap_key_sig; std::map, std::vector> m_tap_script_sigs; @@ -304,8 +308,11 @@ public: void FromSignatureData(const SignatureData& sigdata); void Merge(const PSBTInput& input); uint32_t GetVersion() const { return m_psbt_version; } - explicit PSBTInput(uint32_t psbt_version) - : m_psbt_version(psbt_version) + explicit PSBTInput(uint32_t psbt_version, const Txid& prev_txid, uint32_t prev_out, std::optional sequence = std::nullopt) + : m_psbt_version(psbt_version), + prev_txid(prev_txid), + prev_out(prev_out), + sequence(sequence) { assert(m_psbt_version == 0); } @@ -816,13 +823,18 @@ public: std::map, std::vector> unknown; std::set m_proprietary; + CAmount amount; + CScript script; + bool IsNull() const; void FillSignatureData(SignatureData& sigdata) const; void FromSignatureData(const SignatureData& sigdata); void Merge(const PSBTOutput& output); uint32_t GetVersion() const { return m_psbt_version; } - explicit PSBTOutput(uint32_t psbt_version) - : m_psbt_version(psbt_version) + explicit PSBTOutput(uint32_t psbt_version, CAmount amount, const CScript& script) + : m_psbt_version(psbt_version), + amount(amount), + script(script) { assert(m_psbt_version == 0); } @@ -1264,7 +1276,7 @@ public: // Read input data unsigned int i = 0; while (!s.empty() && i < tx->vin.size()) { - PSBTInput input(psbt_ver); + PSBTInput input(psbt_ver, tx->vin[i].prevout.hash, tx->vin[i].prevout.n, tx->vin[i].nSequence); s >> input; inputs.push_back(input); @@ -1287,7 +1299,7 @@ public: // Read output data i = 0; while (!s.empty() && i < tx->vout.size()) { - PSBTOutput output(psbt_ver); + PSBTOutput output(psbt_ver, tx->vout[i].nValue, tx->vout[i].scriptPubKey); s >> output; outputs.push_back(output); ++i; diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 67067110648..517a02bf39d 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1649,14 +1649,7 @@ static RPCMethod createpsbt() CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf, self.Arg("version")); // Make a blank psbt - PartiallySignedTransaction psbtx; - psbtx.tx = rawTx; - for (unsigned int i = 0; i < rawTx.vin.size(); ++i) { - psbtx.inputs.emplace_back(0); - } - for (unsigned int i = 0; i < rawTx.vout.size(); ++i) { - psbtx.outputs.emplace_back(0); - } + PartiallySignedTransaction psbtx(rawTx); // Serialize the PSBT DataStream ssTx{}; @@ -1717,14 +1710,7 @@ static RPCMethod converttopsbt() } // Make a blank psbt - PartiallySignedTransaction psbtx; - psbtx.tx = tx; - for (unsigned int i = 0; i < tx.vin.size(); ++i) { - psbtx.inputs.emplace_back(0); - } - for (unsigned int i = 0; i < tx.vout.size(); ++i) { - psbtx.outputs.emplace_back(0); - } + PartiallySignedTransaction psbtx(tx); // Serialize the PSBT DataStream ssTx{}; diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp index b3f35baa0fc..15150c4a444 100644 --- a/src/test/fuzz/deserialize.cpp +++ b/src/test/fuzz/deserialize.cpp @@ -192,11 +192,11 @@ FUZZ_TARGET_DESERIALIZE(prefilled_transaction_deserialize, { DeserializeFromFuzzingInput(buffer, prefilled_transaction); }) FUZZ_TARGET_DESERIALIZE(psbt_input_deserialize, { - PSBTInput psbt_input(0); + PSBTInput psbt_input(0, Txid{}, 0); DeserializeFromFuzzingInput(buffer, psbt_input); }) FUZZ_TARGET_DESERIALIZE(psbt_output_deserialize, { - PSBTOutput psbt_output(0); + PSBTOutput psbt_output(0, 0, CScript()); DeserializeFromFuzzingInput(buffer, psbt_output); }) FUZZ_TARGET_DESERIALIZE(block_deserialize, {