[contracts] Add Clock that synchronizes time with EVM
This commit is contained in:
parent
ce38a38849
commit
fa84861d86
|
@ -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
|
|
@ -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()
|
|
@ -3,5 +3,6 @@ import ./contracts/testContracts
|
||||||
import ./contracts/testMarket
|
import ./contracts/testMarket
|
||||||
import ./contracts/testProofs
|
import ./contracts/testProofs
|
||||||
import ./contracts/testInteractions
|
import ./contracts/testInteractions
|
||||||
|
import ./contracts/testClock
|
||||||
|
|
||||||
{.warning[UnusedImport]:off.}
|
{.warning[UnusedImport]:off.}
|
||||||
|
|
Loading…
Reference in New Issue