diff --git a/codex/contracts/clock.nim b/codex/contracts/clock.nim index 9102e5c2..4be75257 100644 --- a/codex/contracts/clock.nim +++ b/codex/contracts/clock.nim @@ -15,26 +15,39 @@ type provider: Provider subscription: Subscription offset: times.Duration + blockNumber: UInt256 started: bool newBlock: AsyncEvent - lastBlockTime: UInt256 proc new*(_: type OnChainClock, provider: Provider): OnChainClock = OnChainClock(provider: provider, newBlock: newAsyncEvent()) +proc update(clock: OnChainClock, blck: Block) = + if number =? blck.number and number > clock.blockNumber: + let blockTime = initTime(blck.timestamp.truncate(int64), 0) + let computerTime = getTime() + clock.offset = blockTime - computerTime + clock.blockNumber = number + trace "updated clock", blockTime=blck.timestamp, blockNumber=number, offset=clock.offset + clock.newBlock.fire() + +proc update(clock: OnChainClock) {.async.} = + try: + if latest =? (await clock.provider.getBlock(BlockTag.latest)): + clock.update(latest) + except CatchableError as error: + debug "error updating clock: ", error=error.msg + discard + method start*(clock: OnChainClock) {.async.} = if clock.started: return - proc onBlock(blck: Block) = - let blockTime = initTime(blck.timestamp.truncate(int64), 0) - let computerTime = getTime() - clock.offset = blockTime - computerTime - clock.lastBlockTime = blck.timestamp - clock.newBlock.fire() + proc onBlock(_: Block) = + # ignore block parameter; hardhat may call this with pending blocks + asyncSpawn clock.update() - if latestBlock =? (await clock.provider.getBlock(BlockTag.latest)): - onBlock(latestBlock) + await clock.update() clock.subscription = await clock.provider.subscribe(onBlock) clock.started = true @@ -47,22 +60,8 @@ method stop*(clock: OnChainClock) {.async.} = clock.started = false method now*(clock: OnChainClock): SecondsSince1970 = - when codex_use_hardhat: - # hardhat's latest block.timestamp is usually 1s behind the block timestamp - # in the newHeads event. When testing, always return the latest block. - try: - if queriedBlock =? (waitFor clock.provider.getBlock(BlockTag.latest)): - trace "using last block timestamp for clock.now", - lastBlockTimestamp = queriedBlock.timestamp.truncate(int64), - cachedBlockTimestamp = clock.lastBlockTime.truncate(int64) - return queriedBlock.timestamp.truncate(int64) - except CatchableError as e: - warn "failed to get latest block timestamp", error = e.msg - return clock.lastBlockTime.truncate(int64) - - else: - doAssert clock.started, "clock should be started before calling now()" - return toUnix(getTime() + clock.offset) + doAssert clock.started, "clock should be started before calling now()" + return toUnix(getTime() + clock.offset) method waitUntil*(clock: OnChainClock, time: SecondsSince1970) {.async.} = while (let difference = time - clock.now(); difference > 0): diff --git a/codex/contracts/market.nim b/codex/contracts/market.nim index 8f12578e..c2b89a86 100644 --- a/codex/contracts/market.nim +++ b/codex/contracts/market.nim @@ -60,7 +60,8 @@ method proofDowntime*(market: OnChainMarket): Future[uint8] {.async.} = return config.proofs.downtime method getPointer*(market: OnChainMarket, slotId: SlotId): Future[uint8] {.async.} = - return await market.contract.getPointer(slotId) + let overrides = CallOverrides(blockTag: some BlockTag.pending) + return await market.contract.getPointer(slotId, overrides) method myRequests*(market: OnChainMarket): Future[seq[RequestId]] {.async.} = return await market.contract.myRequests @@ -88,7 +89,8 @@ method getRequest(market: OnChainMarket, method requestState*(market: OnChainMarket, requestId: RequestId): Future[?RequestState] {.async.} = try: - return some await market.contract.requestState(requestId) + let overrides = CallOverrides(blockTag: some BlockTag.pending) + return some await market.contract.requestState(requestId, overrides) except ProviderError as e: if e.revertReason.contains("Unknown request"): return none RequestState @@ -96,7 +98,8 @@ method requestState*(market: OnChainMarket, method slotState*(market: OnChainMarket, slotId: SlotId): Future[SlotState] {.async.} = - return await market.contract.slotState(slotId) + let overrides = CallOverrides(blockTag: some BlockTag.pending) + return await market.contract.slotState(slotId, overrides) method getRequestEnd*(market: OnChainMarket, id: RequestId): Future[SecondsSince1970] {.async.} = @@ -140,7 +143,8 @@ method withdrawFunds(market: OnChainMarket, method isProofRequired*(market: OnChainMarket, id: SlotId): Future[bool] {.async.} = try: - return await market.contract.isProofRequired(id) + let overrides = CallOverrides(blockTag: some BlockTag.pending) + return await market.contract.isProofRequired(id, overrides) except ProviderError as e: if e.revertReason.contains("Slot is free"): return false @@ -149,14 +153,16 @@ method isProofRequired*(market: OnChainMarket, method willProofBeRequired*(market: OnChainMarket, id: SlotId): Future[bool] {.async.} = try: - return await market.contract.willProofBeRequired(id) + let overrides = CallOverrides(blockTag: some BlockTag.pending) + return await market.contract.willProofBeRequired(id, overrides) except ProviderError as e: if e.revertReason.contains("Slot is free"): return false raise e method getChallenge*(market: OnChainMarket, id: SlotId): Future[ProofChallenge] {.async.} = - return await market.contract.getChallenge(id) + let overrides = CallOverrides(blockTag: some BlockTag.pending) + return await market.contract.getChallenge(id, overrides) method submitProof*(market: OnChainMarket, id: SlotId, diff --git a/tests/contracts/testClock.nim b/tests/contracts/testClock.nim index d7b6ad34..40f7aed0 100644 --- a/tests/contracts/testClock.nim +++ b/tests/contracts/testClock.nim @@ -23,7 +23,7 @@ ethersuite "On-Chain Clock": let future = (getTime() + 42.years).toUnix discard await ethProvider.send("evm_setNextBlockTimestamp", @[%future]) discard await ethProvider.send("evm_mine") - check clock.now() == future + check eventually clock.now() == future test "can wait until a certain time is reached by the chain": let future = clock.now() + 42 # seconds diff --git a/tests/contracts/time.nim b/tests/contracts/time.nim index 05eba0b3..cd6aac1b 100644 --- a/tests/contracts/time.nim +++ b/tests/contracts/time.nim @@ -1,7 +1,7 @@ import pkg/ethers proc currentTime*(provider: Provider): Future[UInt256] {.async.} = - return (!await provider.getBlock(BlockTag.latest)).timestamp + return (!await provider.getBlock(BlockTag.pending)).timestamp proc advanceTime*(provider: JsonRpcProvider, seconds: UInt256) {.async.} = discard await provider.send("evm_increaseTime", @[%("0x" & seconds.toHex)]) diff --git a/tests/ethertest.nim b/tests/ethertest.nim index 8859f714..349aafad 100644 --- a/tests/ethertest.nim +++ b/tests/ethertest.nim @@ -18,6 +18,8 @@ template ethersuite*(name, body) = setup: ethProvider = JsonRpcProvider.new("ws://localhost:8545") snapshot = await send(ethProvider, "evm_snapshot") + # ensure that we have a recent block with a fresh timestamp + discard await send(ethProvider, "evm_mine") accounts = await ethProvider.listAccounts() teardown: diff --git a/tests/integration/multinodes.nim b/tests/integration/multinodes.nim index 58a013a1..10eff165 100644 --- a/tests/integration/multinodes.nim +++ b/tests/integration/multinodes.nim @@ -226,6 +226,8 @@ template multinodesuite*(name: string, body: untyped) = # reverted in the test teardown if nodeConfigs.hardhat.isNil: snapshot = await send(ethProvider, "evm_snapshot") + # ensure that we have a recent block with a fresh timestamp + discard await send(ethProvider, "evm_mine") accounts = await ethProvider.listAccounts() except CatchableError as e: fatal "failed to connect to hardhat", error = e.msg diff --git a/tests/integration/testmarketplace.nim b/tests/integration/testmarketplace.nim index 27e0eeab..e9973d8f 100644 --- a/tests/integration/testmarketplace.nim +++ b/tests/integration/testmarketplace.nim @@ -28,7 +28,7 @@ marketplacesuite "Marketplace payouts": let reward = 400.u256 let duration = 100.periods let collateral = 200.u256 - let expiry = 4.periods + let expiry = 10.periods let datasetSizeInBlocks = 3 let data = await RandomChunker.example(blocks=datasetSizeInBlocks) let client = clients()[0] diff --git a/tests/integration/testproofs.nim b/tests/integration/testproofs.nim index 287507d3..43363135 100644 --- a/tests/integration/testproofs.nim +++ b/tests/integration/testproofs.nim @@ -105,6 +105,7 @@ marketplacesuite "Simulate invalid proofs": let purchaseId = await client0.requestStorage( cid, + expiry=10.periods, duration=totalPeriods.periods, origDatasetSizeInBlocks=datasetSizeInBlocks) let requestId = client0.requestId(purchaseId).get @@ -161,6 +162,7 @@ marketplacesuite "Simulate invalid proofs": let purchaseId = await client0.requestStorage( cid, + expiry=10.periods, duration=totalPeriods.periods, origDatasetSizeInBlocks=datasetSizeInBlocks) let requestId = client0.requestId(purchaseId).get