From 28896c29fe77197f7636fa2fcdd373acbc63fffe Mon Sep 17 00:00:00 2001 From: Eric Mastro Date: Mon, 24 Apr 2023 19:37:19 +1000 Subject: [PATCH] make integration test very loose Accurate integration tests counting the exact number of expected missed proofs has proved elusive to tackle due to trying to emulate whether or not the validator should be able to mark missing proofs or not. As a workaround for the time being, loose tests are now being used that ensure a slot is freed after enough proofs are missed (due to being invalid). --- tests/integration/testproofs.nim | 257 +++++++++---------------------- 1 file changed, 72 insertions(+), 185 deletions(-) diff --git a/tests/integration/testproofs.nim b/tests/integration/testproofs.nim index 1cec1b13..d5b8aef8 100644 --- a/tests/integration/testproofs.nim +++ b/tests/integration/testproofs.nim @@ -109,85 +109,24 @@ multinodesuite "Simulate invalid proofs", var marketplace: Marketplace var period: uint64 - var proofSubmitted: Future[void] - var subscription: Subscription - var submitted: seq[seq[byte]] - var missed: UInt256 var slotId: SlotId - var validator: NodeProcess - let validatorDir = getTempDir() / "CodexValidator" - var periodDowntime: uint8 - var downtime: seq[(Period, bool)] - var periodicity: Periodicity setup: let deployment = Deployment.init() marketplace = Marketplace.new(!deployment.address(Marketplace), provider) let config = await marketplace.config() period = config.proofs.period.truncate(uint64) - periodDowntime = config.proofs.downtime - proofSubmitted = newFuture[void]("proofSubmitted") - proc onProofSubmitted(event: ProofSubmitted) = - submitted.add(event.proof) - proofSubmitted.complete() - proofSubmitted = newFuture[void]("proofSubmitted") - subscription = await marketplace.subscribe(ProofSubmitted, onProofSubmitted) - missed = 0.u256 slotId = SlotId(array[32, byte].default) # ensure we aren't reusing from prev test - downtime = @[] - periodicity = Periodicity(seconds: period.u256) # 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. await provider.advanceTime(1.u256) - teardown: - await subscription.unsubscribe() - - proc getCurrentPeriod(): Future[Period] {.async.} = - return periodicity.periodOf(await provider.currentTime()) - - proc waitUntilPurchaseIsStarted(proofProbability: uint64 = 1, - duration: uint64 = 12 * period, - expiry: uint64 = 4 * period, - failEveryNProofs: uint): Future[Period] {.async.} = - - if clients().len < 1 or providers().len < 1: - raiseAssert("must start at least one client and one provider") - - let client = clients()[0].restClient - let storageProvider = providers()[0].restClient - - # The last period is the period in which the slot is freed, and therefore - # proofs cannot be submitted. That means that the duration must go an - # additional period longer to allow for invalid proofs to be submitted in - # the second to last period and counted as missed in the last period. - let dur = duration + (1 * period) - - discard storageProvider.postAvailability( - size=0xFFFFF, - duration=dur, - minPrice=300 - ) - let cid = client.upload("some file contents " & $ getTime().toUnix) - let expiry = (await provider.currentTime()) + expiry.u256 - let purchase = client.requestStorage( - cid, - expiry=expiry, - duration=dur, - proofProbability=proofProbability, - reward=400 - ) - check eventually client.getPurchase(purchase){"state"} == %"started" - debug "purchase state", state = client.getPurchase(purchase){"state"} - let requestId = RequestId.fromHex client.getPurchase(purchase){"requestId"}.getStr - slotId = slotId(requestId, 0.u256) - return await getCurrentPeriod() - - proc inDowntime: Future[bool] {.async.} = - var periodPointer = await marketplace.getPointer(slotId) - return periodPointer < periodDowntime + proc periods(p: Ordinal | uint): uint64 = + when p is uint: + p * period + else: p.uint * period proc advanceToNextPeriod {.async.} = let periodicity = Periodicity(seconds: period.u256) @@ -195,139 +134,87 @@ multinodesuite "Simulate invalid proofs", let endOfPeriod = periodicity.periodEnd(currentPeriod) await provider.advanceTimeTo(endOfPeriod + 1) - proc advanceToNextPeriodStart {.async.} = - let currentPeriod = await getCurrentPeriod() - let startOfPeriod = periodicity.periodEnd(currentPeriod + 1) - await provider.advanceTimeTo(startOfPeriod) + proc waitUntilPurchaseIsStarted(proofProbability: uint64 = 1, + duration: uint64 = 12.periods, + expiry: uint64 = 4.periods) {.async.} = + if clients().len < 1 or providers().len < 1: + raiseAssert("must start at least one client and one provider") - proc advanceToCurrentPeriodEnd {.async.} = - let currentPeriod = await getCurrentPeriod() - let endOfPeriod = periodicity.periodEnd(currentPeriod) - await provider.advanceTimeTo(endOfPeriod) + let client = clients()[0].restClient + let storageProvider = providers()[0].restClient - proc recordDowntime() {.async.} = - let currentPeriod = await getCurrentPeriod() - let isInDowntime = await inDowntime() - downtime.add (currentPeriod, isInDowntime) - debug "downtime recorded", currentPeriod, isInDowntime + discard storageProvider.postAvailability( + size=0xFFFFF, + duration=duration, + minPrice=300, + maxCollateral=200 + ) + let cid = client.upload("some file contents " & $ getTime().toUnix) + let expiry = (await provider.currentTime()) + expiry.u256 + # avoid timing issues by filling the slot at the start of the next period + await advanceToNextPeriod() + let purchase = client.requestStorage( + cid, + expiry=expiry, + duration=duration, + proofProbability=proofProbability, + collateral=100, + reward=400 + ) + check eventually client.getPurchase(purchase){"state"} == %"started" + let requestId = RequestId.fromHex client.getPurchase(purchase){"requestId"}.getStr + slotId = slotId(requestId, 0.u256) - proc waitUntilSlotNoLongerFilled() {.async.} = - var i = 0 - # await recordDowntime() - # await advanceToNextPeriodStart() - while (await marketplace.slotState(slotId)) == SlotState.Filled: - let currentPeriod = await getCurrentPeriod() - # await advanceToCurrentPeriodEnd() - await advanceToNextPeriod() - debug "--------------- PERIOD START ---------------", currentPeriod - await recordDowntime() - # debug "--------------- PERIOD END ---------------", currentPeriod - await sleepAsync(1.seconds) # let validation happen - debug "Checked previous period for missed proofs", missedProofs = $(await marketplace.missingProofs(slotId)) - i += 1 - # downtime.del downtime.len - 1 # remove last downtime as it is an additional proving round adding to duration for checking proofs, and we are offset by one as we are checking previous periods - missed = await marketplace.missingProofs(slotId) - debug "Total missed proofs", missed + # TODO: these are very loose tests in that they are not testing EXACTLY how + # proofs were marked as missed by the validator. These tests should be + # tightened so that they are showing, as an integration test, that specific + # proofs are being marked as missed by the validator. - proc expectedInvalid(startPeriod: Period, - failEveryNProofs: uint, - periods: Positive): seq[(Period, bool)] = - # Create a seq of bools where each bool represents a proving round. - # If true, an invalid proof should have been sent. - var p = startPeriod + 1.u256 - var invalid: seq[(Period, bool)] = @[] - if failEveryNProofs == 0: - for i in 0..