diff --git a/codex/clock.nim b/codex/clock.nim index b9ed4595..d4c678aa 100644 --- a/codex/clock.nim +++ b/codex/clock.nim @@ -14,9 +14,6 @@ type method now*(clock: Clock): SecondsSince1970 {.base, upraises: [].} = raiseAssert "not implemented" -method lastBlockTimestamp*(clock: Clock): Future[UInt256] {.base, async.} = - raiseAssert "not implemented" - method waitUntil*(clock: Clock, time: SecondsSince1970) {.base, async.} = raiseAssert "not implemented" diff --git a/codex/contracts/clock.nim b/codex/contracts/clock.nim index 763dc579..35c7f9af 100644 --- a/codex/contracts/clock.nim +++ b/codex/contracts/clock.nim @@ -10,13 +10,12 @@ logScope: topics = "contracts clock" type - LastBlockUnknownError* = object of CatchableError OnChainClock* = ref object of Clock provider: Provider subscription: Subscription - offset: times.Duration started: bool newBlock: AsyncEvent + lastBlockTime: UInt256 proc new*(_: type OnChainClock, provider: Provider): OnChainClock = OnChainClock(provider: provider, newBlock: newAsyncEvent()) @@ -27,9 +26,7 @@ method start*(clock: OnChainClock) {.async.} = clock.started = true proc onBlock(blck: Block) {.upraises:[].} = - let blockTime = initTime(blck.timestamp.truncate(int64), 0) - let computerTime = getTime() - clock.offset = blockTime - computerTime + clock.lastBlockTime = blck.timestamp clock.newBlock.fire() if latestBlock =? (await clock.provider.getBlock(BlockTag.latest)): @@ -45,16 +42,17 @@ method stop*(clock: OnChainClock) {.async.} = await clock.subscription.unsubscribe() method now*(clock: OnChainClock): SecondsSince1970 = - doAssert clock.started, "clock should be started before calling now()" - toUnix(getTime() + clock.offset) - -method lastBlockTimestamp*(clock: OnChainClock): Future[UInt256] {.async.} = - without blk =? await clock.provider.getBlock(BlockTag.latest): - raise newException(LastBlockUnknownError, "failed to get last block") - - return blk.timestamp + try: + if queriedBlock =? (waitFor clock.provider.getBlock(BlockTag.latest)): + if queriedBlock.timestamp != clock.lastBlockTime: + trace "queried block and event block are not in sync", + queriedBlockLessThanEventBlock = queriedBlock.timestamp < clock.lastBlockTime + return queriedBlock.timestamp.truncate(int64) + except CatchableError as e: + warn "failed to get latest block timestamp" + return clock.lastBlockTime.truncate(int64) method waitUntil*(clock: OnChainClock, time: SecondsSince1970) {.async.} = - while (let difference = time - (await clock.lastBlockTimestamp).truncate(int64); difference > 0): + while (let difference = time - clock.now(); difference > 0): clock.newBlock.clear() discard await clock.newBlock.wait().withTimeout(chronos.seconds(difference)) diff --git a/codex/contracts/market.nim b/codex/contracts/market.nim index 6beaa923..8f340a76 100644 --- a/codex/contracts/market.nim +++ b/codex/contracts/market.nim @@ -58,10 +58,6 @@ method proofDowntime*(market: OnChainMarket): Future[uint8] {.async.} = method getPointer*(market: OnChainMarket, slotId: SlotId): Future[uint8] {.async.} = return await market.contract.getPointer(slotId) -method currentBlockchainTime*(market: OnChainMarket): Future[UInt256] {.async.} = - let provider = market.contract.provider - return (!await provider.getBlock(BlockTag.latest)).timestamp - method myRequests*(market: OnChainMarket): Future[seq[RequestId]] {.async.} = return await market.contract.myRequests diff --git a/codex/contracts/marketplace.nim b/codex/contracts/marketplace.nim index f8951b7b..c675e9ac 100644 --- a/codex/contracts/marketplace.nim +++ b/codex/contracts/marketplace.nim @@ -64,7 +64,6 @@ proc isProofRequired*(marketplace: Marketplace, id: SlotId): bool {.contract, vi proc willProofBeRequired*(marketplace: Marketplace, id: SlotId): bool {.contract, view.} proc getChallenge*(marketplace: Marketplace, id: SlotId): array[32, byte] {.contract, view.} proc getPointer*(marketplace: Marketplace, id: SlotId): uint8 {.contract, view.} -proc inDowntime*(marketplace: Marketplace, id: SlotId): bool {.contract, view.} proc submitProof*(marketplace: Marketplace, id: SlotId, proof: seq[byte]) {.contract.} proc markProofAsMissing*(marketplace: Marketplace, id: SlotId, period: UInt256) {.contract.} diff --git a/codex/sales/salesagent.nim b/codex/sales/salesagent.nim index ab12c8b0..b189650d 100644 --- a/codex/sales/salesagent.nim +++ b/codex/sales/salesagent.nim @@ -60,7 +60,6 @@ proc retrieveRequestState*(agent: SalesAgent): Future[?RequestState] {.async.} = return await market.requestState(data.requestId) func state*(agent: SalesAgent): ?string = - debugEcho "[salesagent] getting state..." proc description(state: State): string = $state agent.query(description) diff --git a/codex/sales/states/proving.nim b/codex/sales/states/proving.nim index ef65bf52..a086aac1 100644 --- a/codex/sales/states/proving.nim +++ b/codex/sales/states/proving.nim @@ -57,13 +57,10 @@ proc proveLoop( proc getCurrentPeriod(): Future[Period] {.async.} = let periodicity = await market.periodicity() - let blockchainNow = await clock.lastBlockTimestamp - return periodicity.periodOf(blockchainNow) - # return periodicity.periodOf(clock.now().u256) + return periodicity.periodOf(clock.now().u256) proc waitUntilPeriod(period: Period) {.async.} = let periodicity = await market.periodicity() - debug "waiting until time", time = periodicity.periodStart(period).truncate(int64) await clock.waitUntil(periodicity.periodStart(period).truncate(int64)) while true: diff --git a/codex/utils/asyncstatemachine.nim b/codex/utils/asyncstatemachine.nim index acfdde18..27d09b64 100644 --- a/codex/utils/asyncstatemachine.nim +++ b/codex/utils/asyncstatemachine.nim @@ -34,7 +34,6 @@ proc transition(_: type Event, previous, next: State): Event = return some next proc query*[T](machine: Machine, query: Query[T]): ?T = - if not machine.state.isNil: debugEcho "machine state: ", $machine.state if machine.state.isNil: none T else: diff --git a/codex/validation.nim b/codex/validation.nim index 31e0efed..168595ee 100644 --- a/codex/validation.nim +++ b/codex/validation.nim @@ -37,9 +37,7 @@ proc slots*(validation: Validation): seq[SlotId] = validation.slots.toSeq proc getCurrentPeriod(validation: Validation): Future[UInt256] {.async.} = - let currentTime = await validation.clock.lastBlockTimestamp - return validation.periodicity.periodOf(currentTime) - # return validation.periodicity.periodOf(validation.clock.now().u256) + return validation.periodicity.periodOf(validation.clock.now().u256) proc waitUntilNextPeriod(validation: Validation) {.async.} = let period = await validation.getCurrentPeriod() diff --git a/tests/codex/helpers/mockclock.nim b/tests/codex/helpers/mockclock.nim index 8e19205a..d5e164a1 100644 --- a/tests/codex/helpers/mockclock.nim +++ b/tests/codex/helpers/mockclock.nim @@ -1,5 +1,6 @@ import std/times import pkg/chronos +import pkg/stint import codex/clock export clock @@ -35,9 +36,6 @@ proc advance*(clock: MockClock, seconds: int64) = method now*(clock: MockClock): SecondsSince1970 = clock.time -method lastBlockTimestamp*(clock: MockClock): Future[UInt256] {.base, async.} = - return clock.now.u256 - method waitUntil*(clock: MockClock, time: SecondsSince1970) {.async.} = if time > clock.now(): let future = newFuture[void]() diff --git a/tests/contracts/testClock.nim b/tests/contracts/testClock.nim index 7f691eaf..47adbf50 100644 --- a/tests/contracts/testClock.nim +++ b/tests/contracts/testClock.nim @@ -1,55 +1,37 @@ import std/times import pkg/chronos import codex/contracts/clock +import codex/utils/json import ../ethertest ethersuite "On-Chain Clock": var clock: OnChainClock setup: - clock = OnChainClock.new(provider) + clock = OnChainClock.new(ethProvider) await clock.start() teardown: await clock.stop() test "returns the current time of the EVM": - let latestBlock = (!await provider.getBlock(BlockTag.latest)) + let latestBlock = (!await ethProvider.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") + discard await ethProvider.send("evm_setNextBlockTimestamp", @[%future]) + discard await ethProvider.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 - 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") + discard await ethProvider.send("evm_setNextBlockTimestamp", @[%future]) + discard await ethProvider.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() - - test "raises when stopped": - await clock.stop() - expect AssertionDefect: - discard clock.now() - test "handles starting multiple times": await clock.start() await clock.start() diff --git a/tests/contracts/testContracts.nim b/tests/contracts/testContracts.nim index 8dfa54f2..08cc9202 100644 --- a/tests/contracts/testContracts.nim +++ b/tests/contracts/testContracts.nim @@ -23,13 +23,13 @@ ethersuite "Marketplace contracts": token = token.connect(account) setup: - client = provider.getSigner(accounts[0]) - host = provider.getSigner(accounts[1]) + client = ethProvider.getSigner(accounts[0]) + host = ethProvider.getSigner(accounts[1]) - marketplace = Marketplace.new(Marketplace.address, provider.getSigner()) + marketplace = Marketplace.new(Marketplace.address, ethProvider.getSigner()) let tokenAddress = await marketplace.token() - token = Erc20Token.new(tokenAddress, provider.getSigner()) + token = Erc20Token.new(tokenAddress, ethProvider.getSigner()) let config = await marketplace.config() periodicity = Periodicity(seconds: config.proofs.period) @@ -46,13 +46,13 @@ ethersuite "Marketplace contracts": slotId = request.slotId(0.u256) proc waitUntilProofRequired(slotId: SlotId) {.async.} = - let currentPeriod = periodicity.periodOf(await provider.currentTime()) - await provider.advanceTimeTo(periodicity.periodEnd(currentPeriod)) + let currentPeriod = periodicity.periodOf(await ethProvider.currentTime()) + await ethProvider.advanceTimeTo(periodicity.periodEnd(currentPeriod) + 1) while not ( (await marketplace.isProofRequired(slotId)) and (await marketplace.getPointer(slotId)) < 250 ): - await provider.advanceTime(periodicity.seconds) + await ethProvider.advanceTime(periodicity.seconds) proc startContract() {.async.} = for slotIndex in 1.. multinodesuite > marketplacesuite > test + var ethProvider {.inject, used.}: JsonRpcProvider var accounts {.inject, used.}: seq[Address] var snapshot: JsonNode setup: - provider = JsonRpcProvider.new("ws://localhost:8545") - snapshot = await send(provider, "evm_snapshot") - accounts = await provider.listAccounts() + ethProvider = JsonRpcProvider.new("ws://localhost:8545") + snapshot = await send(ethProvider, "evm_snapshot") + accounts = await ethProvider.listAccounts() teardown: - discard await send(provider, "evm_revert", @[snapshot]) + discard await send(ethProvider, "evm_revert", @[snapshot]) body diff --git a/tests/integration/marketplacesuite.nim b/tests/integration/marketplacesuite.nim index f72e4b2a..27e40561 100644 --- a/tests/integration/marketplacesuite.nim +++ b/tests/integration/marketplacesuite.nim @@ -58,7 +58,6 @@ template marketplacesuite*(name: string, startNodes: Nodes, body: untyped) = nodes = providers().len, tolerance = 0): Future[PurchaseId] {.async.} = - # let cid = client.upload(byteutils.toHex(data)).get let expiry = (await ethProvider.currentTime()) + expiry.u256 # avoid timing issues by filling the slot at the start of the next period @@ -85,12 +84,8 @@ template marketplacesuite*(name: string, startNodes: Nodes, body: untyped) = period = config.proofs.period.truncate(uint64) periodicity = Periodicity(seconds: period.u256) - - discard await ethProvider.send("evm_setIntervalMining", @[%1000]) - - # Our Hardhat configuration does use automine, which means that time tracked by `provider.currentTime()` is not # advanced until blocks are mined and that happens only when transaction is submitted. # As we use in tests provider.currentTime() which uses block timestamp this can lead to synchronization issues. diff --git a/tests/integration/multinodes.nim b/tests/integration/multinodes.nim index d1eb17cb..1cbd12a2 100644 --- a/tests/integration/multinodes.nim +++ b/tests/integration/multinodes.nim @@ -89,23 +89,6 @@ proc debug*(config: NodeConfig, enabled = true): NodeConfig = startConfig.debugEnabled = enabled return startConfig -# proc withLogFile*( -# config: NodeConfig, -# file: bool | string -# ): NodeConfig = - -# var startConfig = config -# when file is bool: -# if not file: startConfig.logFile = none string -# else: startConfig.logFile = -# some currentSourcePath.parentDir() / "codex" & $index & ".log" -# else: -# if file.len <= 0: -# raise newException(ValueError, "file path length must be > 0") -# startConfig.logFile = some file - -# return startConfig - proc withLogTopics*( config: NodeConfig, topics: varargs[string] @@ -135,10 +118,7 @@ proc withLogFile*( template multinodesuite*(name: string, startNodes: Nodes, body: untyped) = - asyncchecksuite name: - - var ethProvider {.inject, used.}: JsonRpcProvider - var accounts {.inject, used.}: seq[Address] + ethersuite name: var running: seq[RunningNode] var bootstrap: string @@ -258,10 +238,6 @@ template multinodesuite*(name: string, startNodes: Nodes, body: untyped) = let node = startHardhatNode() running.add RunningNode(role: Role.Hardhat, node: node) - echo "Connecting to hardhat on ws://localhost:8545..." - ethProvider = JsonRpcProvider.new("ws://localhost:8545") - accounts = await ethProvider.listAccounts() - for i in 0..