From 9cf46b6a3f483281e94404d1a987d0f7386fe63d Mon Sep 17 00:00:00 2001 From: glozow Date: Fri, 5 May 2023 19:25:46 +0100 Subject: [PATCH] [rpc] add vsize_bip141 for non-sigop-adjusted vsize Add a result for users who are expecting BIP141 vsize without sigop adjustment. --- src/rpc/mempool.cpp | 7 +++++++ test/functional/mempool_accept.py | 15 ++++++++++----- test/functional/mempool_sigoplimit.py | 4 +++- test/functional/p2p_segwit.py | 2 ++ test/functional/rpc_packages.py | 1 + 5 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp index 85c648a8cfccb..8e9c9234bafbe 100644 --- a/src/rpc/mempool.cpp +++ b/src/rpc/mempool.cpp @@ -131,6 +131,8 @@ static RPCHelpMan testmempoolaccept() {RPCResult::Type::BOOL, "allowed", /*optional=*/true, "Whether this tx would be accepted to the mempool and pass client-specified maxfeerate. " "If not present, the tx was not fully validated due to a failure in another tx in the list."}, {RPCResult::Type::NUM, "vsize", /*optional=*/true, "Maximum of sigop-adjusted size (-bytespersigop) and virtual transaction size as defined in BIP 141."}, + {RPCResult::Type::NUM, "vsize_bip141", /*optional=*/true, "Virtual transaction size as defined in BIP 141.\n" + "This is different from actual serialized size for witness transactions as witness data is discounted (only present when 'allowed' is true)."}, {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees (only present if 'allowed' is true)", { {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT}, @@ -223,6 +225,7 @@ static RPCHelpMan testmempoolaccept() // These can be used to calculate the feerate. result_inner.pushKV("allowed", true); result_inner.pushKV("vsize", virtual_size); + result_inner.pushKV("vsize_bip141", GetVirtualTransactionSize(*tx, 0, 0)); UniValue fees(UniValue::VOBJ); fees.pushKV("base", ValueFromAmount(fee)); fees.pushKV("effective-feerate", ValueFromAmount(tx_result.m_effective_feerate.value().GetFeePerK())); @@ -253,6 +256,7 @@ static std::vector MempoolEntryDescription() { return { RPCResult{RPCResult::Type::NUM, "vsize", "maximum of sigop-adjusted size (-bytespersigop) and virtual transaction size as defined in BIP 141."}, + RPCResult{RPCResult::Type::NUM, "vsize_bip141", "virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted."}, RPCResult{RPCResult::Type::NUM, "weight", "transaction weight as defined in BIP 141."}, RPCResult{RPCResult::Type::NUM_TIME, "time", "local time transaction entered pool in seconds since 1 Jan 1970 GMT"}, RPCResult{RPCResult::Type::NUM, "height", "block height when transaction entered pool"}, @@ -282,6 +286,7 @@ static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPool AssertLockHeld(pool.cs); info.pushKV("vsize", (int)e.GetTxSize()); + info.pushKV("vsize_bip141", GetVirtualTransactionSize(e.GetTx(), 0, 0)); info.pushKV("weight", (int)e.GetTxWeight()); info.pushKV("time", count_seconds(e.GetTime())); info.pushKV("height", (int)e.GetHeight()); @@ -841,6 +846,7 @@ static RPCHelpMan submitpackage() {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"}, {RPCResult::Type::STR_HEX, "other-wtxid", /*optional=*/true, "The wtxid of a different transaction with the same txid but different witness found in the mempool. This means the submitted transaction was ignored."}, {RPCResult::Type::NUM, "vsize", "Maximum of sigop-adjusted size (-bytespersigop) and virtual transaction size as defined in BIP 141."}, + {RPCResult::Type::NUM, "vsize_bip141", "Virtual transaction size as defined in BIP 141."}, {RPCResult::Type::OBJ, "fees", "Transaction fees", { {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT}, {RPCResult::Type::STR_AMOUNT, "effective-feerate", /*optional=*/true, "if the transaction was not already in the mempool, the effective feerate in " + CURRENCY_UNIT + " per KvB. For example, the package feerate and/or feerate with modified fees from prioritisetransaction."}, @@ -939,6 +945,7 @@ static RPCHelpMan submitpackage() if (it->second.m_result_type == MempoolAcceptResult::ResultType::VALID || it->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY) { result_inner.pushKV("vsize", int64_t{it->second.m_vsize.value()}); + result_inner.pushKV("vsize_bip141", GetVirtualTransactionSize(*tx, 0, 0)); UniValue fees(UniValue::VOBJ); fees.pushKV("base", ValueFromAmount(it->second.m_base_fees.value())); if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) { diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py index 8f3aec96a72d9..ffafa320494a9 100755 --- a/test/functional/mempool_accept.py +++ b/test/functional/mempool_accept.py @@ -103,7 +103,8 @@ def run_test(self): raw_tx_0 = tx.serialize().hex() txid_0 = tx.rehash() self.check_mempool_result( - result_expected=[{'txid': txid_0, 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': fee}}], + result_expected=[{'txid': txid_0, 'allowed': True, 'vsize': tx.get_vsize(), + 'vsize_bip141': tx.get_vsize(), 'fees': {'base': fee}}], rawtxs=[raw_tx_0], ) @@ -118,7 +119,8 @@ def run_test(self): tx = tx_from_hex(raw_tx_final) fee_expected = Decimal('50.0') - output_amount self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': fee_expected}}], + result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), + 'vsize_bip141': tx.get_vsize(), 'fees': {'base': fee_expected}}], rawtxs=[tx.serialize().hex()], maxfeerate=0, ) @@ -140,7 +142,8 @@ def run_test(self): raw_tx_0 = tx.serialize().hex() txid_0 = tx.rehash() self.check_mempool_result( - result_expected=[{'txid': txid_0, 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': (2 * fee)}}], + result_expected=[{'txid': txid_0, 'allowed': True, 'vsize': tx.get_vsize(), + 'vsize_bip141': tx.get_vsize(), 'fees': {'base': (2 * fee)}}], rawtxs=[raw_tx_0], ) @@ -197,7 +200,8 @@ def run_test(self): raw_tx_reference = tx.serialize().hex() # Reference tx should be valid on itself self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), 'fees': { 'base': Decimal('0.1') - Decimal('0.05')}}], + result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), + 'vsize_bip141': tx.get_vsize(), 'fees': { 'base': Decimal('0.1') - Decimal('0.05')}}], rawtxs=[tx.serialize().hex()], maxfeerate=0, ) @@ -367,7 +371,8 @@ def run_test(self): tx.vout[0] = CTxOut(COIN - 1000, DUMMY_MIN_OP_RETURN_SCRIPT) assert_equal(len(tx.serialize_without_witness()), MIN_STANDARD_TX_NONWITNESS_SIZE) self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), 'fees': { 'base': Decimal('0.00001000')}}], + result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), + 'vsize_bip141': tx.get_vsize(), 'fees': { 'base': Decimal('0.00001000')}}], rawtxs=[tx.serialize().hex()], maxfeerate=0, ) diff --git a/test/functional/mempool_sigoplimit.py b/test/functional/mempool_sigoplimit.py index 962b2b19bd8ef..66725cc54fe2f 100755 --- a/test/functional/mempool_sigoplimit.py +++ b/test/functional/mempool_sigoplimit.py @@ -97,7 +97,8 @@ def test_sigops_limit(self, bytes_per_sigop, num_sigops): tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'X'*(256+vsize_to_pad+1)]) res = self.nodes[0].testmempoolaccept([tx.serialize().hex()])[0] assert_equal(res['allowed'], True) - assert_equal(res['vsize'], sigop_equivalent_vsize+1) + assert_equal(res['vsize'], sigop_equivalent_vsize + 1) + assert_equal(res['vsize_bip141'], tx.get_vsize()) # decrease the tx's vsize to be right below the sigop-limit equivalent size # => tx's vsize in mempool should stick at the sigop-limit equivalent @@ -107,6 +108,7 @@ def test_sigops_limit(self, bytes_per_sigop, num_sigops): res = self.nodes[0].testmempoolaccept([tx.serialize().hex()])[0] assert_equal(res['allowed'], True) assert_equal(res['vsize'], sigop_equivalent_vsize) + assert_equal(res['vsize_bip141'], tx.get_vsize()) # check that the ancestor and descendant size calculations in the mempool # also use the same max(sigop_equivalent_vsize, serialized_vsize) logic diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index 1e7bc95a63ec9..6edf8eb5a22c3 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -631,6 +631,7 @@ def test_standardness_v0(self): 'wtxid': tx3.getwtxid(), 'allowed': True, 'vsize': tx3.get_vsize(), + 'vsize_bip141': tx3.get_vsize(), 'fees': { 'base': Decimal('0.00001000'), }, @@ -650,6 +651,7 @@ def test_standardness_v0(self): 'wtxid': tx3.getwtxid(), 'allowed': True, 'vsize': tx3.get_vsize(), + 'vsize_bip141': tx3.get_vsize(), 'fees': { 'base': Decimal('0.00011000'), }, diff --git a/test/functional/rpc_packages.py b/test/functional/rpc_packages.py index ae1a498e28abd..86911b3610e30 100755 --- a/test/functional/rpc_packages.py +++ b/test/functional/rpc_packages.py @@ -312,6 +312,7 @@ def test_submit_child_with_parents(self, num_parents, partial_submit): tx_result = submitpackage_result["tx-results"][wtxid] assert_equal(tx_result["txid"], tx.rehash()) assert_equal(tx_result["vsize"], tx.get_vsize()) + assert_equal(tx_result["vsize_bip141"], tx.get_vsize()) assert_equal(tx_result["fees"]["base"], DEFAULT_FEE) if wtxid not in presubmitted_wtxids: assert_fee_amount(DEFAULT_FEE, tx.get_vsize(), tx_result["fees"]["effective-feerate"])