[contracts] Add Clock that synchronizes time with EVM

This commit is contained in:
Mark Spanbroek 2022-05-16 15:38:52 +02:00 committed by markspanbroek
parent ce38a38849
commit fa84861d86
3 changed files with 89 additions and 0 deletions

View File

@ -0,0 +1,40 @@
import std/times
import pkg/ethers
import pkg/chronos
import pkg/stint
type
Clock* = ref object
provider: Provider
subscription: Subscription
offset: int64
started: bool
SecondsSince1970* = int64
proc new*(_: type Clock, provider: Provider): Clock =
Clock(provider: provider)
proc start*(clock: Clock) {.async.} =
if clock.started:
return
clock.started = true
proc onBlock(blck: Block) {.gcsafe, upraises:[].} =
let blockTime = blck.timestamp.truncate(int64)
let computerTime = getTime().toUnix
clock.offset = blockTime - computerTime
onBlock(!await clock.provider.getBlock(BlockTag.latest))
clock.subscription = await clock.provider.subscribe(onBlock)
proc stop*(clock: Clock) {.async.} =
if not clock.started:
return
clock.started = false
await clock.subscription.unsubscribe()
proc now*(clock: Clock): SecondsSince1970 =
doAssert clock.started, "clock should be started before calling now()"
getTime().toUnix + clock.offset

View File

@ -0,0 +1,48 @@
import std/times
import pkg/chronos
import dagger/contracts/clock
import ../ethertest
ethersuite "Clock":
var clock: Clock
setup:
clock = Clock.new(provider)
await clock.start()
teardown:
await clock.stop()
test "returns the current time of the EVM":
let latestBlock = (!await provider.getBlock(BlockTag.latest))
let timestamp = latestBlock.timestamp.truncate(int64)
check clock.now() == timestamp
test "updates time with timestamp of new blocks":
let future = (getTime() + 42.years).toUnix
discard await provider.send("evm_setNextBlockTimestamp", @[%future])
discard await provider.send("evm_mine")
check clock.now() == future
test "updates time using wall-clock in-between blocks":
let past = clock.now()
await sleepAsync(chronos.seconds(1))
check clock.now() == past + 1
test "raises when not started":
expect AssertionError:
discard Clock.new(provider).now()
test "raises when stopped":
await clock.stop()
expect AssertionError:
discard clock.now()
test "handles starting multiple times":
await clock.start()
await clock.start()
test "handles stopping multiple times":
await clock.stop()
await clock.stop()

View File

@ -3,5 +3,6 @@ import ./contracts/testContracts
import ./contracts/testMarket
import ./contracts/testProofs
import ./contracts/testInteractions
import ./contracts/testClock
{.warning[UnusedImport]:off.}