-
Notifications
You must be signed in to change notification settings - Fork 719
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
Use waiting for blocks instead epochs, when waiting for new UTXOs #5843
Use waiting for blocks instead epochs, when waiting for new UTXOs #5843
Conversation
fb26618
to
ba4aae4
Compare
a142218
to
bd3e138
Compare
if currentEpoch > timeout | ||
then pure Nothing | ||
else do | ||
H.threadDelay 10_000 |
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.
@palas why we were using 10ms polling interval?
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.
Feel free to change it. My reasoning was, computers do more than 10^9 operations per second so doing 100 polls per second seems that it is not a lot of processing wasted waiting (less than 0.00001%), and at the same time the latency is almost imperceptible for humans (100th of a second)
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.
Nice work. I am approving but I would like this comment addressed before merging: #5843 (comment)
watchEpochStateUpdate epochStateView (EpochInterval maxBound) $ \(_, _, BlockNo blockNumber) -> | ||
pure $ | ||
if blockNumber >= startingBlockNumber + numberOfBlocks | ||
then Just blockNumber |
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.
Not for this PR but we might want to consider a sum type to make it clear that Nothing
means we will recurse.
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.
@@ -75,3 +80,27 @@ runInBackground act = void . H.evalM $ allocate (H.async act) cleanUp | |||
|
|||
decodeEraUTxO :: (IsShelleyBasedEra era, MonadTest m) => ShelleyBasedEra era -> Aeson.Value -> m (UTxO era) | |||
decodeEraUTxO _ = H.jsonErrorFail . Aeson.fromJSON | |||
|
|||
-- TODO upstream to hedgehog-extras | |||
waitForJustM |
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.
findLargestUtxoWithAddress
should recurse until an input is found or we should expose a separate function that does this.
I want to discourage "helper" functions like that that allow us introduce additional threadDelay
's.
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.
Do you mean, to make a waiting and looping an implementation detail? But then functions like findLargestUtxoWithAddress
would require a timeout value as an input additionally - which complicates things a bit. How do you find the correct timeout value?
After considering it for a while I think we should also measure time differently - in blocks, slots, and epochs instead.
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.
After considering it for a while I think we should also measure time differently - in blocks, slots, and epochs instead.
Agreed. In this instance we can wait 2/3 blocks which should be enough time for the tx input to become available. The point is we need to continue to stay away from threadDelay
as much as possible or move it to "lower level" functions.
Edit: k
blocks would be better for small k
. However we can actually enforce this at the foldEpochState
level which will eliminate test flakiness due to rollbacks.
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.
You can't really get rid of threadDelay
s because we're using polling in waiting.
@@ -203,13 +201,14 @@ activityChangeProposalTest execConfig epochStateView ceo work prefix | |||
|
|||
void $ waitForEpochs epochStateView minWait |
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.
Add a TODO
here to explain why we are waiting.
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.
Added a comments with explanation. Why TODO? What's left to do here?
] | ||
assertNewEpochState epochStateView sbe maxWait lens expected = withFrozenCallStack $ do | ||
mStateView <- watchEpochStateUpdate epochStateView maxWait (const checkEpochState) | ||
when (isNothing mStateView) $ do |
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.
watchEpochStateUpdate
returns Nothing
when the timeout has been exceeded (i.e the value of interest is not present in the ledger state). It's like we are checking "one last time here" which I'm not sure makes sense or is slightly misleading. Even more reason to not return a Maybe
but instead a sum type that clearly says the value hasn't been found within the max wait period.
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.
Technically, the epoch state could change between watchEpochStateUpdate
and getFromEpochStateForEra
, so we could see different values. We're logging observed value so we need to call that function anyway - so doing check again won't hurt.
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 highlights that actually a product type isomorphic to (Bool, a)
would be the best suited for our watching functions. We could return the current value and conditionally break the loop.
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.
Technically, the epoch state could change between watchEpochStateUpdate and getFromEpochStateForEra, so we could see different values. We're logging observed value so we need to call that function anyway - so doing check again won't hurt.
Add a comment making this clear.
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.
added
d213753
to
b4e6c9c
Compare
Co-authored-by: Pablo Lamela <[email protected]> Review remarks part 1
b4e6c9c
to
fcd06be
Compare
Description
This PR provides new functions allowing to extract slot number and block number from epoch state view, and waiting for new blocks. This cuts down the test execution time a bit. Waiting for an epoch in a plutus test takes ~70s, where one block wait is around 20s.
Checklist
See Runnings tests for more details
CHANGELOG.md
for affected package.cabal
files are updatedhlint
. See.github/workflows/check-hlint.yml
to get thehlint
versionstylish-haskell
. See.github/workflows/stylish-haskell.yml
to get thestylish-haskell
versionghc-8.10.7
andghc-9.2.7
Note on CI
If your PR is from a fork, the necessary CI jobs won't trigger automatically for security reasons.
You will need to get someone with write privileges. Please contact IOG node developers to do this
for you.