aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/release-notes-16525.md9
-rw-r--r--src/core_write.cpp4
-rw-r--r--src/rpc/rawtransaction.cpp8
-rwxr-xr-xtest/functional/rpc_rawtransaction.py3
4 files changed, 18 insertions, 6 deletions
diff --git a/doc/release-notes-16525.md b/doc/release-notes-16525.md
new file mode 100644
index 0000000000..220cb78de4
--- /dev/null
+++ b/doc/release-notes-16525.md
@@ -0,0 +1,9 @@
+RPC changes
+-----------
+
+Exposed transaction version numbers are now treated as unsigned 32-bit integers
+instead of signed 32-bit integers. This matches their treatment in consensus
+logic. Versions greater than 2 continue to be non-standard (matching previous
+behavior of smaller than 1 or greater than 2 being non-standard). Note that
+this includes the joinpsbt command, which combines partially-signed
+transactions by selecting the highest version number.
diff --git a/src/core_write.cpp b/src/core_write.cpp
index 69b62df901..34cfeecc6f 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -179,7 +179,9 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
{
entry.pushKV("txid", tx.GetHash().GetHex());
entry.pushKV("hash", tx.GetWitnessHash().GetHex());
- entry.pushKV("version", tx.nVersion);
+ // Transaction version is actually unsigned in consensus checks, just signed in memory,
+ // so cast to unsigned before giving it to the user.
+ entry.pushKV("version", static_cast<int64_t>(static_cast<uint32_t>(tx.nVersion)));
entry.pushKV("size", (int)::GetSerializeSize(tx, PROTOCOL_VERSION));
entry.pushKV("vsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR);
entry.pushKV("weight", GetTransactionWeight(tx));
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 7b1da6fdcd..0bc3e0fe9f 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -1632,7 +1632,7 @@ UniValue joinpsbts(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, "At least two PSBTs are required to join PSBTs.");
}
- int32_t best_version = 1;
+ uint32_t best_version = 1;
uint32_t best_locktime = 0xffffffff;
for (unsigned int i = 0; i < txs.size(); ++i) {
PartiallySignedTransaction psbtx;
@@ -1642,8 +1642,8 @@ UniValue joinpsbts(const JSONRPCRequest& request)
}
psbtxs.push_back(psbtx);
// Choose the highest version number
- if (psbtx.tx->nVersion > best_version) {
- best_version = psbtx.tx->nVersion;
+ if (static_cast<uint32_t>(psbtx.tx->nVersion) > best_version) {
+ best_version = static_cast<uint32_t>(psbtx.tx->nVersion);
}
// Choose the lowest lock time
if (psbtx.tx->nLockTime < best_locktime) {
@@ -1654,7 +1654,7 @@ UniValue joinpsbts(const JSONRPCRequest& request)
// Create a blank psbt where everything will be added
PartiallySignedTransaction merged_psbt;
merged_psbt.tx = CMutableTransaction();
- merged_psbt.tx->nVersion = best_version;
+ merged_psbt.tx->nVersion = static_cast<int32_t>(best_version);
merged_psbt.tx->nLockTime = best_locktime;
// Merge
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index 14cad3d1b8..23b5e647d6 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -424,11 +424,12 @@ class RawTransactionsTest(BitcoinTestFramework):
####################################
# Test the minimum transaction version number that fits in a signed 32-bit integer.
+ # As transaction version is unsigned, this should convert to its unsigned equivalent.
tx = CTransaction()
tx.nVersion = -0x80000000
rawtx = ToHex(tx)
decrawtx = self.nodes[0].decoderawtransaction(rawtx)
- assert_equal(decrawtx['version'], -0x80000000)
+ assert_equal(decrawtx['version'], 0x80000000)
# Test the maximum transaction version number that fits in a signed 32-bit integer.
tx = CTransaction()