rpc: add `vsize_adjusted` field to getrawtransaction output for mempool transactions
What changed, and why it matters
This commit adds a new read-only field called vsize_adjusted to the getrawtransaction RPC output, but only when the transaction is currently in the memory pool. It exposes information the node already calculates for mempool policy, so it does not change behavior, fix a bug, or introduce a vulnerability. It is a transparency/feature improvement for RPC users.
No security action required; review as normal feature/test addition.
Security signals we found
No security-relevant signals present
Additive RPC field only
Read-only data exposure from existing mempool state
Evidence from the diff
The patch extends getrawtransaction verbosity=1 to include vsize_adjusted, populated from CTxMemPool::info().vsize when the transaction is found in the mempool. This value reflects the sigop-adjusted virtual size used for mempool bytespersigop accounting. The change is additive, read-only, and guarded by existing mempool locks; it does not alter validation, policy, or consensus code.
Changed components
src/rpc/rawtransaction.cpptest/functional/mempool_sigoplimit.pyInspect captured patch +20 / −0
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 31a877b8..92e1e9c9 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -216,6 +216,7 @@ static RPCMethod getrawtransaction()
const std::vector<RPCResult> verbosity_1_block{
{RPCResult::Type::BOOL, "in_active_chain", /*optional=*/true, "Whether specified block is in the active chain or not (only present with explicit \"blockhash\" argument)"},
{RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "the block hash"},
+ {RPCResult::Type::NUM, "vsize_adjusted", /*optional=*/true, "Sigop-adjusted virtual size in bytes, present for mempool transactions."},
{RPCResult::Type::NUM, "confirmations", /*optional=*/true, "The confirmations"},
{RPCResult::Type::NUM_TIME, "blocktime", /*optional=*/true, "The block time expressed in " + UNIX_EPOCH_TIME},
{RPCResult::Type::NUM, "time", /*optional=*/true, "Same as \"blocktime\""},
@@ -333,6 +334,15 @@ static RPCMethod getrawtransaction()
LOCK(cs_main);
blockindex = chainman.m_blockman.LookupBlockIndex(hash_block); // May be nullptr for mempool transactions
}
+
+ // Add sigop-adjusted virtual size if the transaction exists in the mempool.
+ if (blockindex == nullptr && hash_block.IsNull() && node.mempool) {
+ auto info = node.mempool->info(tx->GetHash());
+ if (info.tx) {
+ result.pushKV("vsize_adjusted", info.vsize);
+ }
+ }
+
if (verbosity == 1) {
TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate());
return result;
diff --git a/test/functional/mempool_sigoplimit.py b/test/functional/mempool_sigoplimit.py
index 1ade8469..16e83aab 100755
--- a/test/functional/mempool_sigoplimit.py
+++ b/test/functional/mempool_sigoplimit.py
@@ -151,6 +151,16 @@ class BytesPerSigOpTest(BitcoinTestFramework):
assert_equal(entry_parent['descendantcount'], 2)
assert_equal(entry_parent['descendantsize'], parent_tx.get_vsize() + sigop_equivalent_vsize)
+ tx_hex = tx.serialize().hex()
+ txid = tx.txid_hex
+ self.log.info(f"Pushing padded tx {txid} into mempool for getrawtransaction sigopsize field check")
+ self.nodes[0].sendrawtransaction(hexstring=tx_hex, maxburnamount='1.0')
+ # Fetch with verbosity=1 and assert sigopsize is present and correct
+ raw = self.nodes[0].getrawtransaction(txid, 1)
+ sigop_equivalent_vsize = ceil(num_sigops * bytes_per_sigop / WITNESS_SCALE_FACTOR)
+ assert_equal(raw['vsize_adjusted'], sigop_equivalent_vsize)
+ assert_greater_than(raw['vsize_adjusted'], raw['vsize'])
+
def test_sigops_package(self):
self.log.info("Test a overly-large sigops-vbyte hits package limits")
# Make a 2-transaction package which fails vbyte checks even though
Why this scored 19/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.