From 3879ec8e3a2cd7d5697456a90779113e652a7db2 Mon Sep 17 00:00:00 2001 From: markspanbroek Date: Thu, 13 Jul 2023 11:19:45 +0200 Subject: [PATCH] [clock] waitUntil() completes immediately when block arrives (#475) Previously it could take up to one second to complete the future. This messed with the timings in the integration tests and made them less predictable. --- codex/clock.nim | 5 ++--- codex/contracts/clock.nim | 9 ++++++++- tests/contracts/testClock.nim | 12 ++++++++++++ tests/integration/testproofs.nim | 6 +++--- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/codex/clock.nim b/codex/clock.nim index 069c4d28..88df94da 100644 --- a/codex/clock.nim +++ b/codex/clock.nim @@ -10,9 +10,8 @@ type method now*(clock: Clock): SecondsSince1970 {.base, upraises: [].} = raiseAssert "not implemented" -method waitUntil*(clock: Clock, time: SecondsSince1970) {.base,async.} = - while clock.now() < time: - await sleepAsync(1.seconds) +method waitUntil*(clock: Clock, time: SecondsSince1970) {.base, async.} = + raiseAssert "not implemented" proc withTimeout*(future: Future[void], clock: Clock, diff --git a/codex/contracts/clock.nim b/codex/contracts/clock.nim index ed8e5ef7..d7136573 100644 --- a/codex/contracts/clock.nim +++ b/codex/contracts/clock.nim @@ -12,9 +12,10 @@ type subscription: Subscription offset: times.Duration started: bool + newBlock: AsyncEvent proc new*(_: type OnChainClock, provider: Provider): OnChainClock = - OnChainClock(provider: provider) + OnChainClock(provider: provider, newBlock: newAsyncEvent()) proc start*(clock: OnChainClock) {.async.} = if clock.started: @@ -25,6 +26,7 @@ proc start*(clock: OnChainClock) {.async.} = let blockTime = initTime(blck.timestamp.truncate(int64), 0) let computerTime = getTime() clock.offset = blockTime - computerTime + clock.newBlock.fire() if latestBlock =? (await clock.provider.getBlock(BlockTag.latest)): await onBlock(latestBlock) @@ -41,3 +43,8 @@ proc stop*(clock: OnChainClock) {.async.} = method now*(clock: OnChainClock): SecondsSince1970 = doAssert clock.started, "clock should be started before calling now()" toUnix(getTime() + clock.offset) + +method waitUntil*(clock: OnChainClock, time: SecondsSince1970) {.async.} = + while (let difference = time - clock.now(); difference > 0): + clock.newBlock.clear() + discard await clock.newBlock.wait().withTimeout(chronos.seconds(difference)) diff --git a/tests/contracts/testClock.nim b/tests/contracts/testClock.nim index 742e5ad3..7f691eaf 100644 --- a/tests/contracts/testClock.nim +++ b/tests/contracts/testClock.nim @@ -29,6 +29,18 @@ ethersuite "On-Chain Clock": await sleepAsync(chronos.seconds(1)) check clock.now() > past + test "can wait until a certain time is reached by the chain": + let future = clock.now() + 42 # seconds + let waiting = clock.waitUntil(future) + discard await provider.send("evm_setNextBlockTimestamp", @[%future]) + discard await provider.send("evm_mine") + check await waiting.withTimeout(chronos.milliseconds(100)) + + test "can wait until a certain time is reached by the wall-clock": + let future = clock.now() + 1 # seconds + let waiting = clock.waitUntil(future) + check await waiting.withTimeout(chronos.seconds(2)) + test "raises when not started": expect AssertionDefect: discard OnChainClock.new(provider).now() diff --git a/tests/integration/testproofs.nim b/tests/integration/testproofs.nim index 66924ea0..dcbe311e 100644 --- a/tests/integration/testproofs.nim +++ b/tests/integration/testproofs.nim @@ -94,7 +94,7 @@ twonodessuite "Proving integration test", debug1=false, debug2=false: break else: await advanceToNextPeriod() - await sleepAsync(1.seconds) + await sleepAsync(100.milliseconds) check slotWasFreed @@ -186,7 +186,7 @@ multinodesuite "Simulate invalid proofs", break else: await advanceToNextPeriod() - await sleepAsync(1.seconds) + await sleepAsync(100.milliseconds) check slotWasFreed @@ -210,7 +210,7 @@ multinodesuite "Simulate invalid proofs", break else: await advanceToNextPeriod() - await sleepAsync(1.seconds) + await sleepAsync(100.milliseconds) check not slotWasFreed