mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-06 14:19:59 -05:00
Merge #20916: rpc: Return wtxid from testmempoolaccept
fa0aa87071
rpc: Return wtxid from testmempoolaccept (MarcoFalke) Pull request description: It would be nice if `testmempoolaccept` returned the unique wtxid directly to avoid a costly `decoderawtransaction` roundtrip ACKs for top commit: mjdietzx: utACKfa0aa87071
stackman27: utACK [`fa0aa87`](fa0aa87071
) glozow: cr ACKfa0aa87071
Tree-SHA512: 05dbaf46d93e47e9eedb725c2f57175e6d4e1722da0531fe4f80e74fc2518911da87634f25f61fa2bc8d87a3017e82fd0684b09a0a9706d71deed970035c2e7a
This commit is contained in:
commit
32e59fc371
7 changed files with 48 additions and 10 deletions
|
@ -894,6 +894,7 @@ static RPCHelpMan testmempoolaccept()
|
||||||
{RPCResult::Type::OBJ, "", "",
|
{RPCResult::Type::OBJ, "", "",
|
||||||
{
|
{
|
||||||
{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
|
{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
|
||||||
|
{RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},
|
||||||
{RPCResult::Type::BOOL, "allowed", "If the mempool allows this tx to be inserted"},
|
{RPCResult::Type::BOOL, "allowed", "If the mempool allows this tx to be inserted"},
|
||||||
{RPCResult::Type::NUM, "vsize", "Virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted (only present when 'allowed' is true)"},
|
{RPCResult::Type::NUM, "vsize", "Virtual transaction size as defined in BIP 141. 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", "Transaction fees (only present if 'allowed' is true)",
|
{RPCResult::Type::OBJ, "fees", "Transaction fees (only present if 'allowed' is true)",
|
||||||
|
@ -930,7 +931,6 @@ static RPCHelpMan testmempoolaccept()
|
||||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
|
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
|
||||||
}
|
}
|
||||||
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
|
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
|
||||||
const uint256& tx_hash = tx->GetHash();
|
|
||||||
|
|
||||||
const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ?
|
const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ?
|
||||||
DEFAULT_MAX_RAW_TX_FEE_RATE :
|
DEFAULT_MAX_RAW_TX_FEE_RATE :
|
||||||
|
@ -942,7 +942,8 @@ static RPCHelpMan testmempoolaccept()
|
||||||
|
|
||||||
UniValue result(UniValue::VARR);
|
UniValue result(UniValue::VARR);
|
||||||
UniValue result_0(UniValue::VOBJ);
|
UniValue result_0(UniValue::VOBJ);
|
||||||
result_0.pushKV("txid", tx_hash.GetHex());
|
result_0.pushKV("txid", tx->GetHash().GetHex());
|
||||||
|
result_0.pushKV("wtxid", tx->GetWitnessHash().GetHex());
|
||||||
|
|
||||||
TxValidationState state;
|
TxValidationState state;
|
||||||
bool test_accept_res;
|
bool test_accept_res;
|
||||||
|
|
|
@ -126,8 +126,13 @@ class BIP65Test(BitcoinTestFramework):
|
||||||
# First we show that this tx is valid except for CLTV by getting it
|
# First we show that this tx is valid except for CLTV by getting it
|
||||||
# rejected from the mempool for exactly that reason.
|
# rejected from the mempool for exactly that reason.
|
||||||
assert_equal(
|
assert_equal(
|
||||||
[{'txid': spendtx.hash, 'allowed': False, 'reject-reason': 'non-mandatory-script-verify-flag (Negative locktime)'}],
|
[{
|
||||||
self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0)
|
'txid': spendtx.hash,
|
||||||
|
'wtxid': spendtx.getwtxid(),
|
||||||
|
'allowed': False,
|
||||||
|
'reject-reason': 'non-mandatory-script-verify-flag (Negative locktime)',
|
||||||
|
}],
|
||||||
|
self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Now we verify that a block with this transaction is also invalid.
|
# Now we verify that a block with this transaction is also invalid.
|
||||||
|
|
|
@ -112,8 +112,13 @@ class BIP66Test(BitcoinTestFramework):
|
||||||
# First we show that this tx is valid except for DERSIG by getting it
|
# First we show that this tx is valid except for DERSIG by getting it
|
||||||
# rejected from the mempool for exactly that reason.
|
# rejected from the mempool for exactly that reason.
|
||||||
assert_equal(
|
assert_equal(
|
||||||
[{'txid': spendtx.hash, 'allowed': False, 'reject-reason': 'non-mandatory-script-verify-flag (Non-canonical DER signature)'}],
|
[{
|
||||||
self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0)
|
'txid': spendtx.hash,
|
||||||
|
'wtxid': spendtx.getwtxid(),
|
||||||
|
'allowed': False,
|
||||||
|
'reject-reason': 'non-mandatory-script-verify-flag (Non-canonical DER signature)',
|
||||||
|
}],
|
||||||
|
self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Now we verify that a block with this transaction is also invalid.
|
# Now we verify that a block with this transaction is also invalid.
|
||||||
|
|
|
@ -51,6 +51,8 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||||
def check_mempool_result(self, result_expected, *args, **kwargs):
|
def check_mempool_result(self, result_expected, *args, **kwargs):
|
||||||
"""Wrapper to check result of testmempoolaccept on node_0's mempool"""
|
"""Wrapper to check result of testmempoolaccept on node_0's mempool"""
|
||||||
result_test = self.nodes[0].testmempoolaccept(*args, **kwargs)
|
result_test = self.nodes[0].testmempoolaccept(*args, **kwargs)
|
||||||
|
for r in result_test:
|
||||||
|
r.pop('wtxid') # Skip check for now
|
||||||
assert_equal(result_expected, result_test)
|
assert_equal(result_expected, result_test)
|
||||||
assert_equal(self.nodes[0].getmempoolinfo()['size'], self.mempool_size) # Must not change mempool state
|
assert_equal(self.nodes[0].getmempoolinfo()['size'], self.mempool_size) # Must not change mempool state
|
||||||
|
|
||||||
|
|
|
@ -686,13 +686,35 @@ class SegWitTest(BitcoinTestFramework):
|
||||||
if not self.segwit_active:
|
if not self.segwit_active:
|
||||||
# Just check mempool acceptance, but don't add the transaction to the mempool, since witness is disallowed
|
# Just check mempool acceptance, but don't add the transaction to the mempool, since witness is disallowed
|
||||||
# in blocks and the tx is impossible to mine right now.
|
# in blocks and the tx is impossible to mine right now.
|
||||||
assert_equal(self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]), [{'txid': tx3.hash, 'allowed': True, 'vsize': tx3.get_vsize(), 'fees': { 'base': Decimal('0.00001000')}}])
|
assert_equal(
|
||||||
|
self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]),
|
||||||
|
[{
|
||||||
|
'txid': tx3.hash,
|
||||||
|
'wtxid': tx3.getwtxid(),
|
||||||
|
'allowed': True,
|
||||||
|
'vsize': tx3.get_vsize(),
|
||||||
|
'fees': {
|
||||||
|
'base': Decimal('0.00001000'),
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
)
|
||||||
# Create the same output as tx3, but by replacing tx
|
# Create the same output as tx3, but by replacing tx
|
||||||
tx3_out = tx3.vout[0]
|
tx3_out = tx3.vout[0]
|
||||||
tx3 = tx
|
tx3 = tx
|
||||||
tx3.vout = [tx3_out]
|
tx3.vout = [tx3_out]
|
||||||
tx3.rehash()
|
tx3.rehash()
|
||||||
assert_equal(self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]), [{'txid': tx3.hash, 'allowed': True, 'vsize': tx3.get_vsize(), 'fees': { 'base': Decimal('0.00011000')}}])
|
assert_equal(
|
||||||
|
self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]),
|
||||||
|
[{
|
||||||
|
'txid': tx3.hash,
|
||||||
|
'wtxid': tx3.getwtxid(),
|
||||||
|
'allowed': True,
|
||||||
|
'vsize': tx3.get_vsize(),
|
||||||
|
'fees': {
|
||||||
|
'base': Decimal('0.00011000'),
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
)
|
||||||
test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=True)
|
test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=True)
|
||||||
|
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
|
|
|
@ -564,6 +564,9 @@ class CTransaction:
|
||||||
def serialize(self):
|
def serialize(self):
|
||||||
return self.serialize_with_witness()
|
return self.serialize_with_witness()
|
||||||
|
|
||||||
|
def getwtxid(self):
|
||||||
|
return hash256(self.serialize())[::-1].hex()
|
||||||
|
|
||||||
# Recalculate the txid (transaction hash without witness)
|
# Recalculate the txid (transaction hash without witness)
|
||||||
def rehash(self):
|
def rehash(self):
|
||||||
self.sha256 = None
|
self.sha256 = None
|
||||||
|
@ -579,7 +582,7 @@ class CTransaction:
|
||||||
|
|
||||||
if self.sha256 is None:
|
if self.sha256 is None:
|
||||||
self.sha256 = uint256_from_str(hash256(self.serialize_without_witness()))
|
self.sha256 = uint256_from_str(hash256(self.serialize_without_witness()))
|
||||||
self.hash = encode(hash256(self.serialize_without_witness())[::-1], 'hex_codec').decode('ascii')
|
self.hash = hash256(self.serialize_without_witness())[::-1].hex()
|
||||||
|
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
self.calc_sha256()
|
self.calc_sha256()
|
||||||
|
|
|
@ -76,4 +76,4 @@ class MiniWallet:
|
||||||
from_node.sendrawtransaction(tx_hex)
|
from_node.sendrawtransaction(tx_hex)
|
||||||
assert_equal(tx_info['vsize'], vsize)
|
assert_equal(tx_info['vsize'], vsize)
|
||||||
assert_equal(tx_info['fees']['base'], fee)
|
assert_equal(tx_info['fees']['base'], fee)
|
||||||
return {'txid': tx_info['txid'], 'wtxid': from_node.decoderawtransaction(tx_hex)['hash'], 'hex': tx_hex}
|
return {'txid': tx_info['txid'], 'wtxid': tx_info['wtxid'], 'hex': tx_hex}
|
||||||
|
|
Loading…
Add table
Reference in a new issue