Skip to content

Conversation

@jamesob
Copy link
Contributor

@jamesob jamesob commented May 27, 2022

Currently, we only test rule 5 of BIP-125 (replacement transactions cannot evict more than 100 transactions) by changing default mempool parameters to allow for more descendants. The current test works on a single transaction graph that has over 100 descendants.

This patch adds a test to exercise rule 5 using the default mempool parameters. The case is a little more sophisticated: instead of working on a single transaction graph, it uses a replacement transaction to "unite" several UTXOs which join independent transaction graphs. The total number of transactions in these graphs sum to more than the max allowable replacement.

I think the difference in transaction topology makes this a worthwhile testcase to have, setting aside the fact that this testcase works without having to use atypical mempool params.

See also: relevant discussion from IRC

And some little type annotation additions.
@fanquake fanquake added the Tests label May 27, 2022
@jamesob jamesob force-pushed the 2022-05-bip125-rule5-test branch from 406e8de to 9b825e7 Compare May 27, 2022 18:00
@fanquake fanquake requested a review from glozow May 28, 2022 12:16
Copy link
Member

@glozow glozow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strong Concept ACK as we don't currently have test coverage for Rule 5 with default mempool limits

@laanwj
Copy link
Member

laanwj commented May 31, 2022

Concept ACK

Copy link
Contributor

@brunoerg brunoerg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK

@jamesob jamesob force-pushed the 2022-05-bip125-rule5-test branch from 9b825e7 to fd564f3 Compare May 31, 2022 13:16
@dunxen
Copy link
Contributor

dunxen commented Jun 1, 2022

Concept ACK

@jnewbery
Copy link
Contributor

jnewbery commented Jun 1, 2022

Concept ACK. What do you think about also removing the test that uses the non-standard mempool config?

Copy link
Member

@danielabrozzoni danielabrozzoni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK

This testcase exercises rule 5 of BIP-125 (no more than 100 evictions
due to replacement) without having to test under non-default mempool
parametmers.
@jamesob jamesob force-pushed the 2022-05-bip125-rule5-test branch from fd564f3 to 687adda Compare June 2, 2022 14:19
@jamesob
Copy link
Contributor Author

jamesob commented Jun 2, 2022

Concept ACK. What do you think about also removing the test that uses the non-standard mempool config?

Personally I don't think it hurts to have the coverage - the test seems to run pretty fast - but I did think it'd be interesting to add another test case with default params that uses a different (simpler) topology, which could just be uniting >125 individual txns.

Edit: but IMO might as well just merge this and get the coverage, then think about adding more cases later.

Copy link
Contributor

@LarryRuane LarryRuane left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 687adda
I really like this new test, comments are just suggestions

return self._address

def get_utxo(self, *, txid: str = '', vout: Optional[int] = None, mark_as_spent=True):
def get_utxo(self, *, txid: str = '', vout: Optional[int] = None, mark_as_spent=True) -> dict:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR doesn't seem to require this change, does it? If not, could you mention that in the commit message? That would help reviewers.

def create_self_transfer_multi(self, *, from_node, utxos_to_spend=None, num_outputs=1, fee_per_output=1000):
def create_self_transfer_multi(
self, *, from_node,
utxos_to_spend: Optional[List[dict]] = None,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment, this doesn't seem required; could you mention that in the commit comment?

# For each root UTXO, create a package that contains the spend of that
# UTXO and `txs_per_graph` children tx.
for graph_num in range(num_tx_graphs):
root_utxos.append(wallet.get_utxo())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
root_utxos.append(wallet.get_utxo())
utxo_parent_spend = wallet.get_utxo()
root_utxos.append(utxo_parent_spend)

so that code below is simpler

optin_parent_tx = wallet.send_self_transfer_multi(
from_node=normal_node,
sequence=BIP125_SEQUENCE_NUMBER,
utxos_to_spend=[root_utxos[graph_num]],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
utxos_to_spend=[root_utxos[graph_num]],
utxos_to_spend=[utxo_parent_spend],

nit, slight readability improvement; I had to stare at the original for a while, the nested braces made me think at first it was some kind of double-nested index lookup! (Maybe it's just me.)


assert normal_node.getmempoolentry(child_tx['txid'])

num_txs_invalidated = len(root_utxos) + (num_tx_graphs * txs_per_graph)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
num_txs_invalidated = len(root_utxos) + (num_tx_graphs * txs_per_graph)
num_txs_to_invalidate = len(root_utxos) + (num_tx_graphs * txs_per_graph)

nit variable rename, they're not invalided yet

assert num_txs_invalidated > MAX_REPLACEMENT_LIMIT
else:
assert num_txs_invalidated <= MAX_REPLACEMENT_LIMIT

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe add here (but requires a change below):

            assert_equal(num_txs_to_invalidate, normal_node.getmempoolinfo()['size'])

Comment on lines +486 to +487
txid = normal_node.sendrawtransaction(tx_hex, 0)
assert normal_node.getmempoolentry(txid)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
txid = normal_node.sendrawtransaction(tx_hex, 0)
assert normal_node.getmempoolentry(txid)
# The replacement tx should have been accepted into the mempool and it
# should be the only tx in the mempool (having replaced all others).
txid = normal_node.sendrawtransaction(tx_hex, 0)
assert normal_node.getmempoolentry(txid)
assert_equal(normal_node.getmempoolinfo()['size'], 1)

nit, just to clarify what is going on (would have helped me review), however the new assertion requires a change below.

Comment on lines +489 to +492
# Clear the mempool once finished, and rescan the other nodes' wallet
# to account for the spends we've made on `normal_node`.
self.generate(normal_node, 1)
self.wallet.rescan_utxos()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indent these lines so the mempool gets cleared out at the end of each test case. Needed only if the assertions I recommended above are taken.

@jamesob
Copy link
Contributor Author

jamesob commented Jun 3, 2022

I am done making relatively minor changes to this PR. If there are problems with the correctness of the test I will fix them, but otherwise I have other things to do.

@laanwj
Copy link
Member

laanwj commented Jun 7, 2022

Code review ACK 687adda

I am done making relatively minor changes to this PR

Fair enough, opening a PR doesn't oblige you to incorporate every minor suggestion, i think it's fine like this

@laanwj laanwj merged commit e282764 into bitcoin:master Jun 7, 2022
self, *, from_node,
utxos_to_spend: Optional[List[dict]] = None,
num_outputs=1,
sequence=0,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be an array of the same length as utxos_to_spend?

(Might fix in a follow-up)

@bitcoin bitcoin locked and limited conversation to collaborators Jul 1, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.