-
Notifications
You must be signed in to change notification settings - Fork 38.7k
[tests] Split NodeConn from NodeConnCB #11712
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
ryanofsky
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This basically looks good, but I really think it's important to stop creating peer objects via callback in add_p2p_connection. The change I think you should make is here a683588 (previously described in #11182 (comment)).
Advantages of this change:
-
Simpler control flow. Tests create their own peer objects. You can see when and where they get constructed and what arguments they are constructed with. No need to pass around callbacks. There's no advantage I can see to passing around callbacks unless saving two
()characters is an advantage. -
Less coupling and repetition. TestNode no longer needs need to know anything about peer objects other than that they have connect and disconnect methods. The connect arguments (dstaddr, dstport, net="regtest", services=NODE_NETWORK, send_version=True) are defined and used one place instead of repeated 12 times in testnode, mininode, and comptool code, and in individual test case code.
-
Lets you drop second commit, reduces overall diff from 502 lines to 457 lines.
test/functional/p2p-segwit.py
Outdated
| - Submit the block over the p2p interface | ||
| - use the getbestblockhash rpc to check for acceptance.""" | ||
| if with_witness: | ||
| node.p2p.send_message(msg_witness_block(block)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "[tests] Remove rpc property from TestNode in p2p-segwit.py"
Did you mean to s/node.p2p/p2p/ here and below?
test/functional/p2p-segwit.py
Outdated
| else: | ||
| node.p2p.send_message(msg_block(block)) | ||
| p2p.sync_with_ping() | ||
| assert_equal(node.rpc.getbestblockhash() == block.hash, accepted) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "[tests] Remove rpc property from TestNode in p2p-segwit.py"
Do you want to s/node.rpc/node/ here for consistency with test_transaction_acceptance? Another alternative which would also be nice would be to pass these functions just rpc objects instead of nodes.
test/functional/p2p-segwit.py
Outdated
| self.std_node.test_transaction_acceptance(p2sh_txs[3], True, False, b'bad-witness-nonstandard') | ||
| self.test_node.test_transaction_acceptance(p2sh_txs[3], True, True) | ||
| test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[3], True, False, b'bad-witness-nonstandard') | ||
| test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_txs[3], True, True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[tests] Remove rpc property from TestNode in p2p-segwit.py
Not a comment on this PR but this whole test file is very repetitive. With a few lambdas / local helper functions it could probably be made a lot shorter and more readable.
| self.wait_until_stopped() | ||
|
|
||
| def add_p2p_connection(self, p2p_conn, **kwargs): | ||
| def add_p2p_connection(self, p2p_conn_type, **kwargs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "[tests] instantiate NodeConnCB in TestNode"
Can similary control flow and revert this whole commit, see main comment.
test/functional/example_test.py
Outdated
| # override the on_*() methods if you need custom behaviour. | ||
| class BaseNode(NodeConnCB): | ||
| def __init__(self): | ||
| def __init__(self, dstaddr, dstport, net="regtest", services=NODE_NETWORK, send_version=True): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "[tests] Make NodeConnCB a subclass of NodeConn"
Can get rid of all these default parameters repeated so many times. See main comment.
Change the helper methods to functions which take a node and a p2p connection as arguments.
6090ef4 to
f66ff10
Compare
f66ff10 to
a328ab3
Compare
|
Thanks Russ. I much prefer your suggested way of passing the constructed NodeConnCB object to TestNode. I've incorporated your change and split the PR into smaller commits to aid reviewing. |
maflcko
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK a328ab35888baaa481b5b59e41472f91e8802f8e. Going to review this week or so.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stylte-nit: Any reason for this change? I think the previous is easier to read python code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's some discussion of the differences here: https://stackoverflow.com/questions/850795/different-ways-of-clearing-lists
If there was a different reference to this array, then self.p2ps = [] wouldn't clear that array, it would just change self.p2ps to point to a new, empty array.
Practically, there's not much difference, but I think I prefer del self.p2ps[:]. I actually got this from @ryanofsky's commit - perhaps he had a specific reason to make this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, fine to keep, since it is ever-so-slightly safer and already used by this syntax in stop_node
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Main reason for suggesting this is that having multiple instances of the same list can make things confusing when you are debugging.
ryanofsky
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK a328ab35888baaa481b5b59e41472f91e8802f8e
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "[tests] Tidy up mininode"
Think you missed the readble() function above. Would be good to note that is an asyncore callback like writeable().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can actually just remove the readable() override entirely. From https://docs.python.org/3.6/library/asyncore.html#asyncore.dispatcher.readable : "The default method simply returns True, indicating that by default, all channels will be interested in read events." so this override isn't actually doing anything.
I'll update the commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "[tests] Tidy up mininode"
Seems like this method should begin with an underscore (like _log_message below), since this is part of the read handler, and not something that should be called externally. I also think a name like _got_data _on_data _handle_data _process_messages might be more descriptive since read_message suggests a method that blocks waiting for a message as opposed to a method handling incoming data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. Changed to _on_data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "[tests] Tidy up mininode"
Would change "a message" to "messages" everywhere since this can parse more than just one message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "[tests] Make NodeConnCB a subclass of NodeConn"
Maybe keep assigning nServices/messages_count/last_message/ping_counter members that don't depend on connection information in __init__ rather than peer_connect. This would mean you don't need to introduce a NodeConnCB.peer_connect method in this commit, and in the next commit it can be a shorter, more focused override. Just a suggestion, though, difference is minor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. Makes more sense. Thanks.
Add docstrings and renames some methods. Also removes the redundant NodeConn.readable() method override.
This is required since NodeConnCB will inherit from NodeConn after the next commit.
This makes NodeConnCB a subclass of NodeConn, and removes the need for the client code to know anything about the implementation details of NodeConnCB. NodeConn can now be swapped out for any other implementation of a low-level connection without changing client code.
This commit moves the logic that sends a version message on connection from NodeConn to NodeConnCB. NodeConn should not be aware of the semantics or meaning of the P2P payloads.
a328ab3 to
e9dfa9b
Compare
|
Addressed @ryanofsky's comments |
ryanofsky
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK e9dfa9b. Only changes since last review were the various things commented above.
maflcko
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK e9dfa9b
| self.wait_until_stopped() | ||
|
|
||
| def add_p2p_connection(self, p2p_conn, **kwargs): | ||
| def add_p2p_connection(self, p2p_conn, *args, **kwargs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I'd rather do the opposite and disallow passing through unnamed args here. Forcing code to be explicit should be safer and ease future review, imo.
def add_p2p_connection(self, p2p_conn, *, **kwargs)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the goal is to disallow unnamed arguments, this place to do is where the arguments are actually declared (in the peer_connect method). If you make that change here instead of there, you will be introducing an inconsistency between add_p2p_connection and peer_connect. It is better for testnode to just forward arguments on to peernode, instead making unnecessary assumptions about how it works internally and creating unnecessary differences. Forwarding *args and **kwargs is also idiomatic in python while forwarding just **kwargs is more unusual.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think @ryanofsky is right - the right place for this is in NodeConnCB.peer_connect(). Can we leave that for a future PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jnewbery Sure, future PR sounds good.
e9dfa9b [tests] Move version message sending from NodeConn to NodeConnCB (John Newbery) dad596f [tests] Make NodeConnCB a subclass of NodeConn (John Newbery) e30d404 [tests] Move only: move NodeConnCB below NodeConn (John Newbery) 4d50598 [tests] Tidy up mininode (John Newbery) f2ae6f3 [tests] Remove mininode periodic (half-hour) ping messages (John Newbery) ec59523 [tests] Remove rpc property from TestNode in p2p-segwit.py. (John Newbery) Pull request description: This is the final step in #11518, except for possibly renaming - for motivation, please see that PR. If this is merged, then migrating the test framework from asyncore to asyncio should be easier (I say should because I haven't dug too deeply into what would be required). Requesting review from @ryanofsky , since he always has good feedback on these refactor PRs, and I'd appreciate his take on this refactor. Note particularly that I've reverted the change suggested here: #11182 (comment) . The idea, as always, is to present a simple interface to the test writer. Tree-SHA512: 94dd467a13ec799b101108cf47d4dccb6f6240b601e375e3d785313333bbb389c26072a50759aca663bbf3d6c8b867b99e36ae8800ab8ea115e0496c151926ce
* [tests] Remove mininode periodic (half-hour) ping messages * [tests] Tidy up mininode Add docstrings and renames some methods. Also removes the redundant NodeConn.readable() method override. * [tests] Move only: move NodeConnCB below NodeConn This is required since NodeConnCB will inherit from NodeConn after the next commit. * [tests] Make NodeConnCB a subclass of NodeConn This makes NodeConnCB a subclass of NodeConn, and removes the need for the client code to know anything about the implementation details of NodeConnCB. NodeConn can now be swapped out for any other implementation of a low-level connection without changing client code. * [tests] Move version message sending from NodeConn to NodeConnCB This commit moves the logic that sends a version message on connection from NodeConn to NodeConnCB. NodeConn should not be aware of the semantics or meaning of the P2P payloads. * remove witness Signed-off-by: Pasta <[email protected]> * Fix 11712 Co-authored-by: John Newbery <[email protected]> Co-authored-by: UdjinM6 <[email protected]>
…#3373) * [tests] Remove mininode periodic (half-hour) ping messages * [tests] Tidy up mininode Add docstrings and renames some methods. Also removes the redundant NodeConn.readable() method override. * [tests] Move only: move NodeConnCB below NodeConn This is required since NodeConnCB will inherit from NodeConn after the next commit. * [tests] Make NodeConnCB a subclass of NodeConn This makes NodeConnCB a subclass of NodeConn, and removes the need for the client code to know anything about the implementation details of NodeConnCB. NodeConn can now be swapped out for any other implementation of a low-level connection without changing client code. * [tests] Move version message sending from NodeConn to NodeConnCB This commit moves the logic that sends a version message on connection from NodeConn to NodeConnCB. NodeConn should not be aware of the semantics or meaning of the P2P payloads. * remove witness Signed-off-by: Pasta <[email protected]> * Fix 11712 Co-authored-by: John Newbery <[email protected]> Co-authored-by: UdjinM6 <[email protected]>
This is the final step in #11518, except for possibly renaming - for motivation, please see that PR.
If this is merged, then migrating the test framework from asyncore to asyncio should be easier (I say should because I haven't dug too deeply into what would be required).
Requesting review from @ryanofsky , since he always has good feedback on these refactor PRs, and I'd appreciate his take on this refactor. Note particularly that I've reverted the change suggested here: #11182 (comment) . The idea, as always, is to present a simple interface to the test writer.