refactor: [rpc] Remove confusing and brittle integral casts (take 2)
What changed, and why it matters
This commit is a code cleanup in Bitcoin Core's RPC (remote procedure call) output code. It removes explicit type casts when adding numeric values to JSON responses, relying on the underlying types instead. There is no direct evidence this fixes a security vulnerability; it is presented by the author as a refactoring to make the code less confusing and brittle.
No immediate security action required. Treat as routine refactoring. If reviewing for risk, verify that the underlying C++ types for each field are correctly and consistently serialized by UniValue::pushKV overloads, and that no unintended signed/unsigned or width changes affect downstream consumers.
Security signals we found
No security-relevant keywords in commit title or message
No explicit bug fix, bounds check, or validation added
Changes are cosmetic/type-cast removals across RPC JSON serialization
No CVE, advisory, or security disclosure referenced in commit materials
Evidence from the diff
The change removes C-style and static_cast conversions to int64_t, uint64_t, int32_t, int, bool, etc. when pushing numeric fields into UniValue JSON objects across RPC, REST, and wallet RPC code. The affected fields include locktime, vout, sequence, output index, coin height, txoutset transactions, version bits required, mapped AS, address time, memory stats, PSBT version, command duration, ancestor counts/sizes/fees, and wallet receive time. The commit title and message describe it as a refactor to remove ‘confusing and brittle integral casts’. No behavior change is asserted, and the diff does not show any bounds checks, input validation, or memory safety fixes.
Changed components
src/core_io.cppsrc/rest.cppsrc/rpc/blockchain.cppsrc/rpc/mining.cppsrc/rpc/net.cppsrc/rpc/node.cppsrc/rpc/rawtransaction.cppsrc/rpc/server.cppsrc/wallet/rpc/coins.cppsrc/wallet/rpc/transactions.cppInspect captured patch +24 / −24
diff --git a/src/core_io.cpp b/src/core_io.cpp
index a4b726cd..90eb65cd 100644
--- a/src/core_io.cpp
+++ b/src/core_io.cpp
@@ -439,7 +439,7 @@ void TxToUniv(const CTransaction& tx, const uint256& block_hash, UniValue& entry
entry.pushKV("size", tx.ComputeTotalSize());
entry.pushKV("vsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR);
entry.pushKV("weight", GetTransactionWeight(tx));
- entry.pushKV("locktime", (int64_t)tx.nLockTime);
+ entry.pushKV("locktime", tx.nLockTime);
UniValue vin{UniValue::VARR};
vin.reserve(tx.vin.size());
@@ -457,7 +457,7 @@ void TxToUniv(const CTransaction& tx, const uint256& block_hash, UniValue& entry
in.pushKV("coinbase", HexStr(txin.scriptSig));
} else {
in.pushKV("txid", txin.prevout.hash.GetHex());
- in.pushKV("vout", (int64_t)txin.prevout.n);
+ in.pushKV("vout", txin.prevout.n);
UniValue o(UniValue::VOBJ);
o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true));
o.pushKV("hex", HexStr(txin.scriptSig));
@@ -482,14 +482,14 @@ void TxToUniv(const CTransaction& tx, const uint256& block_hash, UniValue& entry
ScriptToUniv(prev_txout.scriptPubKey, /*out=*/o_script_pub_key, /*include_hex=*/true, /*include_address=*/true);
UniValue p(UniValue::VOBJ);
- p.pushKV("generated", bool(prev_coin.fCoinBase));
- p.pushKV("height", uint64_t(prev_coin.nHeight));
+ p.pushKV("generated", static_cast<bool>(prev_coin.fCoinBase));
+ p.pushKV("height", prev_coin.nHeight);
p.pushKV("value", ValueFromAmount(prev_txout.nValue));
p.pushKV("scriptPubKey", std::move(o_script_pub_key));
in.pushKV("prevout", std::move(p));
}
}
- in.pushKV("sequence", (int64_t)txin.nSequence);
+ in.pushKV("sequence", txin.nSequence);
vin.push_back(std::move(in));
}
entry.pushKV("vin", std::move(vin));
@@ -502,7 +502,7 @@ void TxToUniv(const CTransaction& tx, const uint256& block_hash, UniValue& entry
UniValue out(UniValue::VOBJ);
out.pushKV("value", ValueFromAmount(txout.nValue));
- out.pushKV("n", (int64_t)i);
+ out.pushKV("n", i);
UniValue o(UniValue::VOBJ);
ScriptToUniv(txout.scriptPubKey, /*out=*/o, /*include_hex=*/true, /*include_address=*/true);
diff --git a/src/rest.cpp b/src/rest.cpp
index b91b229a..21d1f692 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -1065,7 +1065,7 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::
UniValue utxos(UniValue::VARR);
for (const CCoin& coin : outs) {
UniValue utxo(UniValue::VOBJ);
- utxo.pushKV("height", (int32_t)coin.nHeight);
+ utxo.pushKV("height", coin.nHeight);
utxo.pushKV("value", ValueFromAmount(coin.out.nValue));
// include the script in a json output
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index a883570f..0cc1eb87 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1097,7 +1097,7 @@ static RPCHelpMan gettxoutsetinfo()
CHECK_NONFATAL(stats.total_amount.has_value());
ret.pushKV("total_amount", ValueFromAmount(stats.total_amount.value()));
if (!stats.index_used) {
- ret.pushKV("transactions", static_cast<int64_t>(stats.nTransactions));
+ ret.pushKV("transactions", stats.nTransactions);
ret.pushKV("disk_size", stats.nDiskSize);
} else {
CCoinsStats prev_stats{};
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index d0efa84f..ee80b903 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -983,7 +983,7 @@ static RPCHelpMan getblocktemplate()
result.pushKV("version", block.nVersion);
result.pushKV("rules", std::move(aRules));
result.pushKV("vbavailable", std::move(vbavailable));
- result.pushKV("vbrequired", int(0));
+ result.pushKV("vbrequired", 0);
result.pushKV("previousblockhash", block.hashPrevBlock.GetHex());
result.pushKV("transactions", std::move(transactions));
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index c6359c37..5c54e207 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -235,7 +235,7 @@ static RPCHelpMan getpeerinfo()
}
obj.pushKV("network", GetNetworkName(stats.m_network));
if (stats.m_mapped_as != 0) {
- obj.pushKV("mapped_as", uint64_t(stats.m_mapped_as));
+ obj.pushKV("mapped_as", stats.m_mapped_as);
}
ServiceFlags services{statestats.their_services};
obj.pushKV("services", strprintf("%016x", services));
@@ -958,7 +958,7 @@ static RPCHelpMan getnodeaddresses()
for (const CAddress& addr : vAddr) {
UniValue obj(UniValue::VOBJ);
- obj.pushKV("time", int64_t{TicksSinceEpoch<std::chrono::seconds>(addr.nTime)});
+ obj.pushKV("time", TicksSinceEpoch<std::chrono::seconds>(addr.nTime));
obj.pushKV("services", static_cast<std::underlying_type_t<decltype(addr.nServices)>>(addr.nServices));
obj.pushKV("address", addr.ToStringAddr());
obj.pushKV("port", addr.GetPort());
@@ -1127,7 +1127,7 @@ UniValue AddrmanEntryToJSON(const AddrInfo& info, const CConnman& connman)
}
ret.pushKV("port", info.GetPort());
ret.pushKV("services", static_cast<std::underlying_type_t<decltype(info.nServices)>>(info.nServices));
- ret.pushKV("time", int64_t{TicksSinceEpoch<std::chrono::seconds>(info.nTime)});
+ ret.pushKV("time", TicksSinceEpoch<std::chrono::seconds>(info.nTime));
ret.pushKV("network", GetNetworkName(info.GetNetClass()));
ret.pushKV("source", info.source.ToStringAddr());
ret.pushKV("source_network", GetNetworkName(info.source.GetNetClass()));
diff --git a/src/rpc/node.cpp b/src/rpc/node.cpp
index c922b27f..93d860d4 100644
--- a/src/rpc/node.cpp
+++ b/src/rpc/node.cpp
@@ -113,12 +113,12 @@ static UniValue RPCLockedMemoryInfo()
{
LockedPool::Stats stats = LockedPoolManager::Instance().stats();
UniValue obj(UniValue::VOBJ);
- obj.pushKV("used", uint64_t(stats.used));
- obj.pushKV("free", uint64_t(stats.free));
- obj.pushKV("total", uint64_t(stats.total));
- obj.pushKV("locked", uint64_t(stats.locked));
- obj.pushKV("chunks_used", uint64_t(stats.chunks_used));
- obj.pushKV("chunks_free", uint64_t(stats.chunks_free));
+ obj.pushKV("used", stats.used);
+ obj.pushKV("free", stats.free);
+ obj.pushKV("total", stats.total);
+ obj.pushKV("locked", stats.locked);
+ obj.pushKV("chunks_used", stats.chunks_used);
+ obj.pushKV("chunks_free", stats.chunks_free);
return obj;
}
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 0604aa94..5885422b 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -1092,7 +1092,7 @@ static RPCHelpMan decodepsbt()
result.pushKV("global_xpubs", std::move(global_xpubs));
// PSBT version
- result.pushKV("psbt_version", static_cast<uint64_t>(psbtx.GetVersion()));
+ result.pushKV("psbt_version", psbtx.GetVersion());
// Proprietary
UniValue proprietary(UniValue::VARR);
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 01fb815a..cddd62f4 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -219,7 +219,7 @@ static RPCHelpMan getrpcinfo()
for (const RPCCommandExecutionInfo& info : g_rpc_server_info.active_commands) {
UniValue entry(UniValue::VOBJ);
entry.pushKV("method", info.method);
- entry.pushKV("duration", int64_t{Ticks<std::chrono::microseconds>(SteadyClock::now() - info.start)});
+ entry.pushKV("duration", Ticks<std::chrono::microseconds>(SteadyClock::now() - info.start));
active_commands.push_back(std::move(entry));
}
diff --git a/src/wallet/rpc/coins.cpp b/src/wallet/rpc/coins.cpp
index e4fb3843..5dc3391d 100644
--- a/src/wallet/rpc/coins.cpp
+++ b/src/wallet/rpc/coins.cpp
@@ -667,9 +667,9 @@ RPCHelpMan listunspent()
CAmount ancestor_fees;
pwallet->chain().getTransactionAncestry(out.outpoint.hash, ancestor_count, descendant_count, &ancestor_size, &ancestor_fees);
if (ancestor_count) {
- entry.pushKV("ancestorcount", uint64_t(ancestor_count));
- entry.pushKV("ancestorsize", uint64_t(ancestor_size));
- entry.pushKV("ancestorfees", uint64_t(ancestor_fees));
+ entry.pushKV("ancestorcount", ancestor_count);
+ entry.pushKV("ancestorsize", ancestor_size);
+ entry.pushKV("ancestorfees", ancestor_fees);
}
}
entry.pushKV("spendable", true); // Any coins we list are always spendable
diff --git a/src/wallet/rpc/transactions.cpp b/src/wallet/rpc/transactions.cpp
index 6fe96458..34ebdea7 100644
--- a/src/wallet/rpc/transactions.cpp
+++ b/src/wallet/rpc/transactions.cpp
@@ -47,7 +47,7 @@ static void WalletTxToJSON(const CWallet& wallet, const CWalletTx& wtx, UniValue
mempool_conflicts.push_back(mempool_conflict.GetHex());
entry.pushKV("mempoolconflicts", std::move(mempool_conflicts));
entry.pushKV("time", wtx.GetTxTime());
- entry.pushKV("timereceived", int64_t{wtx.nTimeReceived});
+ entry.pushKV("timereceived", wtx.nTimeReceived);
// Add opt-in RBF status
std::string rbfStatus = "no";
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.