Skip to content

Conversation

sipa
Copy link
Member

@sipa sipa commented Sep 27, 2020

The fact that net_processing uses a mix of mockable tand non-mockable time functions made it hard to write functional tests for #19988.

I'm opening this as a separate PR as I believe it's independently useful. In some ways this doesn't go quite as far as it could, as there are now several data structures that could be converted to std::chrono types as well now. I haven't done that here, but I'm happy to reconsider that.

@sipa sipa force-pushed the 202009_mockable_netproc branch from 1576f76 to 155a4de Compare September 27, 2020 22:17
@DrahtBot DrahtBot added the P2P label Sep 27, 2020
@sipa sipa force-pushed the 202009_mockable_netproc branch from 155a4de to 1281d7d Compare September 28, 2020 00:29
@bitcoin bitcoin deleted a comment Sep 28, 2020
@DrahtBot
Copy link
Contributor

DrahtBot commented Sep 28, 2020

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

Copy link
Member

@maflcko maflcko 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, but I don't like that this patch makes the code more fragile.

@naumenkogs
Copy link
Member

Concept ACK

@sipa sipa force-pushed the 202009_mockable_netproc branch from 1281d7d to e5c0223 Compare September 28, 2020 06:55
@practicalswift
Copy link
Contributor

Concept ACK

Copy link
Contributor

@ajtowns ajtowns left a comment

Choose a reason for hiding this comment

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

ACK e5c0223

Checked conversion from GetTime() to count_microsecounds(GetTime<>()) and that variables that are now mockable are only compared with mockable times.


self.test_tx_requests()
# Run each test against new bitcoind instances, as setting mocktimes has long-term effects on when
# the next trickle relay event happens.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure it's a good idea to link mockable time to network delays in general -- if you bump the mocktime by a hours/days that shouldn't risk triggering "hey this peer hasn't said anything for ages, let's disconnect" conditions, and equally if you backdate the mocktime for some reason, that shouldn't cause network tasks to say "oh, we decided we don't need to do anything until time t, which is apparently years away" and effectively hang. Having to tweak tests feels a bit like a canary...

My intuition for this was we have two sorts of delays -- short ones (<30s) that just prevent us busy looping when there's nothing to actually do and don't generally need to be precisely controlled, and long ones (minutes/hours/days) that are human visible and that we'll obviously need mocktime to test because minutes/hours/days is effectively forever.

But maybe we've really got two different sorts of mocking that we want to do -- "set the time to X" and it stays there until we're ready to set it to some different time "Y" (what we've got now), and "everything that was going to happen in the next 5 minutes, get it done now" (something more like what the mockscheduler rpc does)? You could implement the latter by bumping the system clock (rather than replacing it), and only allowing the bump amount to increase.

I suspect at a minimum we'd want to switch to the std::chrono::time_point abstraction and use different clocks so that we could tell these cases apart by type, but that doesn't seem like a good thing to dive into immediately before feature freeze. (I had a sketch I was working on a while back at https://github.com/ajtowns/bitcoin/commits/201908-systime fwiw)

And mocktime is only relevant for regtest, so the downsides of this approach are pretty limited (presumably to just these test case changes)

Copy link
Member Author

@sipa sipa Oct 7, 2020

Choose a reason for hiding this comment

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

I think we'll indeed a number of timers for different purposes, eventually:

  • System time (possibly adjusted by peer data), for use in block and wallet transaction timestamps (as they have an absolute UNIX epoch as reference ).
  • Steady time, mockable, for timing application level events (tx relay, pinging, addr rebroadcast, ...).
  • Steady time, for avoiding busy looping (like select() timeout, message handler 100ms delay, ...).

The last one indeed I think shouldn't be mockable, but things like ping timeouts I think should be. It just becomes too complicated when multiple clocks are mixed within one layer of the code - even if it means using a mockable clock for some delays that are in practice very short.

As for dealing with the fact that making small delays mockable complicates testing, I think the best solution is a "add X to mock time offset, but keep the clock running", if that's what you meant.

Copy link
Member

@maflcko maflcko Oct 8, 2020

Choose a reason for hiding this comment

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

I disagree that system time (used for blocks and wallet txs) should not be mockable. For example, sometimes we want to create a deterministic blockchain, so the block times need to be fixed. I know it is possible to use the python block generator, but I don't see a strong reason to disallow system time to be mocked.

Edit: So it is also important to be able to say "set time to a constant" instead of just "add offset, but keep clock running".

Copy link
Contributor

Choose a reason for hiding this comment

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

I think the idea was to have two ways of mocking -- fix the system time to X (and prevent it from advancing, so time goes t, t+1, t+2, t+3, X, X, X, X), or bump the system time by D (so time goes t, t+1, t+2, t+3, t+D+3, t+D+4, t+D+5).

@jnewbery
Copy link
Contributor

jnewbery commented Oct 7, 2020

ACK e5c0223

@sipa sipa force-pushed the 202009_mockable_netproc branch from e5c0223 to d7fad16 Compare October 7, 2020 23:24
@sipa sipa force-pushed the 202009_mockable_netproc branch from d7fad16 to 93fca5f Compare October 8, 2020 02:13
Copy link
Member

@maflcko maflcko left a comment

Choose a reason for hiding this comment

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

ACK 93fca5f 🐎

Show signature and timestamp

Signature:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

ACK 93fca5fbd84ff793625f1c2bd469cfee68aa07f1 🐎
-----BEGIN PGP SIGNATURE-----

iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p
pUg9lwv9Hr28B7UGDp2zRH285YsHrhEiqoQTWbSpuL9dQPRWTAD4ygHN9qW4TbZt
DOsuHRZOAjFBinWH/gYIUUW3F8WvIchHMgNY+p4+IkNbYIAMruDmMvbDTldUq0Hu
n9QzyB6Oz2OW9p8hMFJTbPB+8rVwMwA4H8ZwooghiKNszd/sFVFi5j5Pxgd6XlFi
MDkYpUmS3wQt1Kb2ya4SyOVPdlGQpje9ASjqCNSDz+CJOoJ9fFRZ+txEgn5lgTKI
o/oPoNVd2ZIQamx79+1y4kzLmkBBxbxP96ulC6l1UCMA9kKzX1m6yafSgN4Lc3Wo
01G5qBGawYXtWb48LPQGEYhVVIM0AcukRvpMA1TBpXkVPKDtvO/8/QEqkMZRnmaI
C10s9QP3TNuGhkIY4AUwVQkFmQEbWaePNVVdMd/ee3WO1N2VKuiH/+9/zxpMq9cf
tuoffg+0Y2MhRxVFjey23gjDoea+OQjo2KfRApyhELaqejX48k9A3oUbwW7NrUYb
IznFTsZW
=b0jx
-----END PGP SIGNATURE-----

Timestamp of file with hash 03cb2a91902242d76811cd547cea6874233f1f46c555bd142069e3cbfa6b48fc -

@sipa sipa force-pushed the 202009_mockable_netproc branch from 44b17b2 to b6834e3 Compare October 8, 2020 08:05
@maflcko
Copy link
Member

maflcko commented Oct 8, 2020

ACK b6834e3 🌶

Show signature and timestamp

Signature:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

ACK b6834e312a 🌶
-----BEGIN PGP SIGNATURE-----

iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p
pUiqVAwAkgjqSWeoLAE5Eej6vdWXcdAqJlztAhCbdlyCZJJRd/Wu34rtBvHC0fwW
UsmVfevPkIL4ejJqUsII+h2QidQv8Ie//EiX+9HtdeQIbpX0AgWJd6mb5jdS8NJw
sXwpFfL+x+3H8weUk7mxlIvPtYLZm1VsrlhWR6QW1HG0wL3o9/MVNho3c78lOjxL
nQz//fbX6hCLD067gE2ujx7wJsBzbux8jn57oifZq2KPK+6ENmVy8s63u7qDocRw
Gc7xpBp2KmnRlfX0Juik8QjNOGOIuNBytRhuZwaLNWKupQT3ItxGWvI8jk7G8mov
cKL6csUlRx7iM0z3bHjzZRabbOp8lT29chErWaB6mprVpmC0QJMEw/+JkW6NARnd
LNpniw8ttC6Y4Nyci0DCQsDLzyQ942I6tGTWV+gR7XqHMC3DRd5/zCJsP/zhkrXT
Aac9tNB45brc8Vl534j+og+pZ7oxSKug6IUwmImavdqRjl0rq/+RsTdFr7Vk9IeG
2MJK2Tjc
=pOLL
-----END PGP SIGNATURE-----

Timestamp of file with hash df57ab8fe3ed162f8bb109f94ab3daf5cb2dd502b92b384bc065c8b7c69084eb -

@jnewbery
Copy link
Contributor

jnewbery commented Oct 8, 2020

utACK b6834e3

@fanquake fanquake requested a review from ajtowns October 8, 2020 09:28
@naumenkogs
Copy link
Member

utACK b6834e3

I agree with the comments by @ajtowns, but I guess it can only introduce problems on regtest? And since this PR is necessary for #19988, I think it's fine, that can be fixed later.

@@ -582,7 +582,7 @@ static bool MarkBlockAsReceived(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs
}
if (state->vBlocksInFlight.begin() == itInFlight->second.second) {
// First block on the queue was received, update the start download time for the next one
state->nDownloadingSince = std::max(state->nDownloadingSince, GetTimeMicros());
state->nDownloadingSince = std::max(state->nDownloadingSince, count_microseconds(GetTime<std::chrono::microseconds>()));
Copy link
Contributor

Choose a reason for hiding this comment

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

seems like a backwards step turning neat code into lengthy code - why not use a function for this or change GetTimeMicros() itself?

Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request May 18, 2021
Summary:
```
The fact that net_processing uses a mix of mockable tand non-mockable
time functions made it hard to write functional tests for #19988.

I'm opening this as a separate PR as I believe it's independently
useful. In some ways this doesn't go quite as far as it could, as there
are now several data structures that could be converted to std::chrono
types as well now. I haven't done that here, but I'm happy to reconsider
that.
```

Backport of [[bitcoin/bitcoin#20027 | core#20027]].

Test Plan:
  ninja all check-all

Reviewers: #bitcoin_abc, deadalnix

Reviewed By: #bitcoin_abc, deadalnix

Differential Revision: https://reviews.bitcoinabc.org/D9542
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Aug 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants