multinode test setup for invalid proof submission tests
# Conflicts: # codex/contracts/market.nim # codex/validation.nim # tests/integration/testproofs.nim
This commit is contained in:
parent
664a1b190c
commit
78fa4dd3a3
|
@ -4,6 +4,7 @@ import pkg/ethers
|
|||
import pkg/ethers/testing
|
||||
import pkg/upraises
|
||||
import pkg/questionable
|
||||
import pkg/chronicles
|
||||
import ../market
|
||||
import ./marketplace
|
||||
|
||||
|
|
|
@ -7,6 +7,9 @@ import ../clock
|
|||
|
||||
export sets
|
||||
|
||||
logScope:
|
||||
topics = "proving"
|
||||
|
||||
type
|
||||
Proving* = ref object of RootObj
|
||||
market*: Market
|
||||
|
@ -31,7 +34,7 @@ proc `onProve=`*(proving: Proving, callback: OnProve) =
|
|||
func add*(proving: Proving, slot: Slot) =
|
||||
proving.slots.incl(slot)
|
||||
|
||||
proc getCurrentPeriod(proving: Proving): Future[Period] {.async.} =
|
||||
proc getCurrentPeriod*(proving: Proving): Future[Period] {.async.} =
|
||||
let periodicity = await proving.market.periodicity()
|
||||
return periodicity.periodOf(proving.clock.now().u256)
|
||||
|
||||
|
@ -48,10 +51,14 @@ proc removeEndedContracts(proving: Proving) {.async.} =
|
|||
proving.slots.excl(ended)
|
||||
|
||||
method prove*(proving: Proving, slot: Slot) {.base, async.} =
|
||||
logScope:
|
||||
currentPeriod = await proving.getCurrentPeriod()
|
||||
|
||||
without onProve =? proving.onProve:
|
||||
raiseAssert "onProve callback not set"
|
||||
try:
|
||||
let proof = await onProve(slot)
|
||||
debug "submitting proof"
|
||||
await proving.market.submitProof(slot.id, proof)
|
||||
except CatchableError as e:
|
||||
error "Submitting proof failed", msg = e.msg
|
||||
|
|
|
@ -11,6 +11,9 @@ type
|
|||
failEveryNProofs: uint
|
||||
proofCount: uint
|
||||
|
||||
logScope:
|
||||
topics = "simulated proving"
|
||||
|
||||
func new*(_: type SimulatedProving,
|
||||
market: Market,
|
||||
clock: Clock,
|
||||
|
@ -27,21 +30,23 @@ method init(proving: SimulatedProving) {.async.} =
|
|||
"--eth-provider."
|
||||
proving.failEveryNProofs = 0'u
|
||||
|
||||
proc onSubmitProofError(error: ref CatchableError) =
|
||||
error "Submitting invalid proof failed", msg = error.msg
|
||||
proc onSubmitProofError(error: ref CatchableError, period: UInt256) =
|
||||
error "Submitting invalid proof failed", period, msg = error.msg
|
||||
|
||||
method prove(proving: SimulatedProving, slot: Slot) {.async.} =
|
||||
let period = await proving.getCurrentPeriod()
|
||||
proving.proofCount += 1
|
||||
if proving.failEveryNProofs > 0'u and
|
||||
proving.proofCount mod proving.failEveryNProofs == 0'u:
|
||||
proving.proofCount = 0
|
||||
try:
|
||||
debug "submitting INVALID proof"
|
||||
await proving.market.submitProof(slot.id, newSeq[byte](0))
|
||||
except ProviderError as e:
|
||||
if not e.revertReason.contains("Invalid proof"):
|
||||
onSubmitProofError(e)
|
||||
onSubmitProofError(e, period)
|
||||
except CatchableError as e:
|
||||
onSubmitProofError(e)
|
||||
onSubmitProofError(e, period)
|
||||
else:
|
||||
await procCall Proving(proving).prove(slot)
|
||||
|
||||
|
|
|
@ -62,14 +62,18 @@ proc removeSlotsThatHaveEnded(validation: Validation) {.async.} =
|
|||
proc markProofAsMissing(validation: Validation,
|
||||
slotId: SlotId,
|
||||
period: Period) {.async.} =
|
||||
logScope:
|
||||
currentPeriod = validation.getCurrentPeriod()
|
||||
|
||||
try:
|
||||
if await validation.market.canProofBeMarkedAsMissing(slotId, period):
|
||||
trace "Marking proof as missing", slotId = $slotId, period = period
|
||||
trace "Marking proof as missing", slotId = $slotId, periodProofMissed = period
|
||||
await validation.market.markProofAsMissing(slotId, period)
|
||||
else: trace "Proof not missing", checkedPeriod = period
|
||||
except CancelledError:
|
||||
raise
|
||||
except CatchableError as e:
|
||||
debug "Marking proof as missing failed", msg = e.msg
|
||||
error "Marking proof as missing failed", msg = e.msg
|
||||
|
||||
proc markProofsAsMissing(validation: Validation) {.async.} =
|
||||
for slotId in validation.slots:
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
import std/os
|
||||
import std/macros
|
||||
import std/json
|
||||
import std/httpclient
|
||||
import pkg/chronicles
|
||||
import ../ethertest
|
||||
import ./codexclient
|
||||
import ./nodes
|
||||
|
||||
export ethertest
|
||||
export codexclient
|
||||
export nodes
|
||||
|
||||
template multinodesuite*(name: string,
|
||||
startNodes: StartNodes, debugNodes: DebugNodes, body: untyped) =
|
||||
|
||||
if (debugNodes.client or debugNodes.provider) and
|
||||
(enabledLogLevel > LogLevel.DEBUG or
|
||||
enabledLogLevel == LogLevel.NONE):
|
||||
echo ""
|
||||
echo "More test debug logging is available by running the tests with " &
|
||||
"'-d:chronicles_log_level=DEBUG " &
|
||||
"-d:chronicles_default_output_device=stdout " &
|
||||
"-d:chronicles_sinks=textlines'"
|
||||
echo ""
|
||||
|
||||
ethersuite name:
|
||||
|
||||
var running: seq[RunningNode]
|
||||
var bootstrap: string
|
||||
|
||||
proc newNodeProcess(index: int,
|
||||
addlOptions: seq[string],
|
||||
debug: bool): (NodeProcess, string, Address) =
|
||||
|
||||
if index > accounts.len - 1:
|
||||
raiseAssert("Cannot start node at index " & $index &
|
||||
", not enough eth accounts.")
|
||||
|
||||
let datadir = getTempDir() / "Codex" & $index
|
||||
var options = @[
|
||||
"--api-port=" & $(8080 + index),
|
||||
"--data-dir=" & datadir,
|
||||
"--nat=127.0.0.1",
|
||||
"--disc-ip=127.0.0.1",
|
||||
"--disc-port=" & $(8090 + index),
|
||||
"--eth-account=" & $accounts[index]]
|
||||
.concat(addlOptions)
|
||||
if debug: options.add "--log-level=INFO;DEBUG: " & debugNodes.topics
|
||||
let node = startNode(options, debug = debug)
|
||||
(node, datadir, accounts[index])
|
||||
|
||||
proc newCodexClient(index: int): CodexClient =
|
||||
CodexClient.new("http://localhost:" & $(8080 + index) & "/api/codex/v1")
|
||||
|
||||
proc startClientNode() =
|
||||
let index = running.len
|
||||
let (node, datadir, account) = newNodeProcess(
|
||||
index, @["--persistence"], debugNodes.client)
|
||||
let restClient = newCodexClient(index)
|
||||
running.add RunningNode.new(Role.Client, node, restClient, datadir,
|
||||
account)
|
||||
if debugNodes.client:
|
||||
debug "started new client node and codex client",
|
||||
restApiPort = 8080 + index, discPort = 8090 + index, account
|
||||
|
||||
proc startProviderNode(failEveryNProofs: uint = 0) =
|
||||
let index = running.len
|
||||
let (node, datadir, account) = newNodeProcess(index, @[
|
||||
"--bootstrap-node=" & bootstrap,
|
||||
"--persistence",
|
||||
"--simulate-proof-failures=" & $failEveryNProofs],
|
||||
debugNodes.provider)
|
||||
let restClient = newCodexClient(index)
|
||||
running.add RunningNode.new(Role.Provider, node, restClient, datadir,
|
||||
account)
|
||||
if debugNodes.provider:
|
||||
debug "started new provider node and codex client",
|
||||
restApiPort = 8080 + index, discPort = 8090 + index, account
|
||||
|
||||
proc startValidatorNode() =
|
||||
let index = running.len
|
||||
let (node, datadir, account) = newNodeProcess(index, @[
|
||||
"--bootstrap-node=" & bootstrap,
|
||||
"--validator"],
|
||||
debugNodes.validator)
|
||||
let restClient = newCodexClient(index)
|
||||
running.add RunningNode.new(Role.Validator, node, restClient, datadir,
|
||||
account)
|
||||
if debugNodes.validator:
|
||||
debug "started new validator node and codex client",
|
||||
restApiPort = 8080 + index, discPort = 8090 + index, account
|
||||
|
||||
proc clients(): seq[RunningNode] =
|
||||
running.filter(proc(r: RunningNode): bool = r.role == Role.Client)
|
||||
|
||||
proc providers(): seq[RunningNode] =
|
||||
running.filter(proc(r: RunningNode): bool = r.role == Role.Provider)
|
||||
|
||||
proc validators(): seq[RunningNode] =
|
||||
running.filter(proc(r: RunningNode): bool = r.role == Role.Validator)
|
||||
|
||||
setup:
|
||||
for i in 0..<startNodes.clients:
|
||||
startClientNode()
|
||||
if i == 0:
|
||||
bootstrap = running[0].restClient.info()["spr"].getStr()
|
||||
|
||||
for i in 0..<startNodes.providers:
|
||||
startProviderNode()
|
||||
|
||||
for i in 0..<startNodes.validators:
|
||||
startValidatorNode()
|
||||
|
||||
teardown:
|
||||
for r in running:
|
||||
r.restClient.close()
|
||||
r.node.stop()
|
||||
removeDir(r.datadir)
|
||||
running = @[]
|
||||
|
||||
body
|
|
@ -2,14 +2,58 @@ import std/osproc
|
|||
import std/os
|
||||
import std/streams
|
||||
import std/strutils
|
||||
import pkg/ethers
|
||||
import ./codexclient
|
||||
|
||||
const workingDir = currentSourcePath() / ".." / ".." / ".."
|
||||
const executable = "build" / "codex"
|
||||
|
||||
type NodeProcess* = ref object
|
||||
process: Process
|
||||
arguments: seq[string]
|
||||
debug: bool
|
||||
type
|
||||
NodeProcess* = ref object
|
||||
process: Process
|
||||
arguments: seq[string]
|
||||
debug: bool
|
||||
Role* = enum
|
||||
Client,
|
||||
Provider,
|
||||
Validator
|
||||
RunningNode* = ref object
|
||||
role*: Role
|
||||
node*: NodeProcess
|
||||
restClient*: CodexClient
|
||||
datadir*: string
|
||||
ethAccount*: Address
|
||||
StartNodes* = object
|
||||
clients*: uint
|
||||
providers*: uint
|
||||
validators*: uint
|
||||
DebugNodes* = object
|
||||
client*: bool
|
||||
provider*: bool
|
||||
validator*: bool
|
||||
topics*: string
|
||||
|
||||
proc new*(_: type RunningNode,
|
||||
role: Role,
|
||||
node: NodeProcess,
|
||||
restClient: CodexClient,
|
||||
datadir: string,
|
||||
ethAccount: Address): RunningNode =
|
||||
RunningNode(role: role,
|
||||
node: node,
|
||||
restClient: restClient,
|
||||
datadir: datadir,
|
||||
ethAccount: ethAccount)
|
||||
|
||||
proc init*(_: type StartNodes,
|
||||
clients, providers, validators: uint): StartNodes =
|
||||
StartNodes(clients: clients, providers: providers, validators: validators)
|
||||
|
||||
proc init*(_: type DebugNodes,
|
||||
client, provider, validator: bool,
|
||||
topics: string = "validation,proving"): DebugNodes =
|
||||
DebugNodes(client: client, provider: provider, validator: validator,
|
||||
topics: topics)
|
||||
|
||||
proc start(node: NodeProcess) =
|
||||
if node.debug:
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import std/sequtils
|
||||
import std/os
|
||||
from std/times import getTime, toUnix
|
||||
import pkg/chronicles
|
||||
import codex/contracts/marketplace
|
||||
import codex/contracts/deployment
|
||||
import codex/periods
|
||||
|
@ -6,6 +9,10 @@ import ../contracts/time
|
|||
import ../contracts/deployment
|
||||
import ../codex/helpers/eventually
|
||||
import ./twonodes
|
||||
import ./multinodes
|
||||
|
||||
logScope:
|
||||
topics = "test proofs"
|
||||
|
||||
twonodessuite "Proving integration test", debug1=false, debug2=false:
|
||||
|
||||
|
@ -96,7 +103,9 @@ twonodessuite "Proving integration test", debug1=false, debug2=false:
|
|||
await subscription.unsubscribe()
|
||||
stopValidator(validator)
|
||||
|
||||
invalidproofsuite "Simulate invalid proofs", debugClient=false, debugProvider=false:
|
||||
multinodesuite "Simulate invalid proofs",
|
||||
StartNodes.init(clients=1'u, providers=0'u, validators=1'u),
|
||||
DebugNodes.init(client=false, provider=false, validator=false):
|
||||
|
||||
var marketplace: Marketplace
|
||||
var period: uint64
|
||||
|
@ -106,46 +115,41 @@ invalidproofsuite "Simulate invalid proofs", debugClient=false, debugProvider=fa
|
|||
var missed: UInt256
|
||||
var slotId: SlotId
|
||||
var validator: NodeProcess
|
||||
|
||||
|
||||
proc startValidator: NodeProcess =
|
||||
startNode([
|
||||
"--data-dir=" & validatorDir,
|
||||
"--api-port=8180",
|
||||
"--disc-port=8190",
|
||||
"--validator",
|
||||
"--eth-account=" & $accounts[2]
|
||||
], debug = false)
|
||||
|
||||
proc stopValidator(node: NodeProcess) =
|
||||
node.stop()
|
||||
removeDir(validatorDir)
|
||||
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)
|
||||
period = (await marketplace.config()).proofs.period.truncate(uint64)
|
||||
let config = await marketplace.config()
|
||||
period = config.proofs.period.truncate(uint64)
|
||||
periodDowntime = config.proofs.downtime
|
||||
await provider.getSigner(accounts[0]).mint()
|
||||
await provider.getSigner(accounts[1]).mint()
|
||||
await provider.getSigner(accounts[1]).deposit()
|
||||
await provider.getSigner(accounts[2]).mint()
|
||||
await provider.getSigner(accounts[2]).deposit()
|
||||
proofSubmitted = newFuture[void]("proofSubmitted")
|
||||
proc onProofSubmitted(event: ProofSubmitted) =
|
||||
debugEcho ">>> proof submitted: ", event.proof
|
||||
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)
|
||||
validator = startValidator()
|
||||
slotId = SlotId(array[32, byte].default) # ensure we aren't reusing from prev test
|
||||
downtime = @[]
|
||||
periodicity = Periodicity(seconds: period.u256)
|
||||
|
||||
teardown:
|
||||
await subscription.unsubscribe()
|
||||
validator.stopValidator()
|
||||
|
||||
proc waitUntilPurchaseIsStarted(proofProbability: uint64 = 3,
|
||||
duration: uint64 = 100 * period,
|
||||
expiry: uint64 = 30) {.async.} =
|
||||
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")
|
||||
|
@ -153,9 +157,15 @@ invalidproofsuite "Simulate invalid proofs", debugClient=false, debugProvider=fa
|
|||
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=duration,
|
||||
duration=dur,
|
||||
minPrice=300
|
||||
)
|
||||
let cid = client.upload("some file contents " & $ getTime().toUnix)
|
||||
|
@ -163,56 +173,152 @@ invalidproofsuite "Simulate invalid proofs", debugClient=false, debugProvider=fa
|
|||
let purchase = client.requestStorage(
|
||||
cid,
|
||||
expiry=expiry,
|
||||
duration=duration,
|
||||
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 advanceToNextPeriod {.async.} =
|
||||
let periodicity = Periodicity(seconds: period.u256)
|
||||
let currentPeriod = periodicity.periodOf(await provider.currentTime())
|
||||
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 advanceToNextPeriod() {.async.} =
|
||||
await provider.advanceTime(period.u256)
|
||||
proc advanceToCurrentPeriodEnd {.async.} =
|
||||
let currentPeriod = await getCurrentPeriod()
|
||||
let endOfPeriod = periodicity.periodEnd(currentPeriod)
|
||||
await provider.advanceTimeTo(endOfPeriod)
|
||||
|
||||
proc waitForProvingRounds(rounds: Positive) {.async.} =
|
||||
var rnds = rounds - 1 # proof round runs prior to advancing
|
||||
missed += await marketplace.missingProofs(slotId)
|
||||
proc recordDowntime() {.async.} =
|
||||
let currentPeriod = await getCurrentPeriod()
|
||||
let isInDowntime = await inDowntime()
|
||||
downtime.add (currentPeriod, isInDowntime)
|
||||
debug "downtime recorded", currentPeriod, isInDowntime
|
||||
|
||||
while rnds > 0:
|
||||
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()
|
||||
rnds -= 1
|
||||
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
|
||||
|
||||
proc invalid(proofs: seq[seq[byte]]): uint =
|
||||
proofs.count(@[]).uint
|
||||
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..<periods:
|
||||
p += 1.u256
|
||||
invalid.add (p, false)
|
||||
return invalid
|
||||
|
||||
test "simulates invalid proof every N proofs":
|
||||
# TODO: waiting on validation work to be completed before these tests are possible
|
||||
# 1. instantiate node manually (startNode) with --simulate-failed-proofs=3
|
||||
# 2. check that the number of expected proofs are missed
|
||||
let failEveryNProofs = 3
|
||||
let totalProofs = 6
|
||||
let expectedInvalid = totalProofs div failEveryNProofs
|
||||
let expectedValid = totalProofs - expectedInvalid
|
||||
startProviderNode(failEveryNProofs.uint)
|
||||
for j in 0..<(periods div failEveryNProofs.int):
|
||||
for i in 0..<failEveryNProofs - 1'u:
|
||||
p += 1.u256
|
||||
invalid.add (p, false)
|
||||
p += 1.u256
|
||||
invalid.add (p, true)
|
||||
# add remaining falses
|
||||
for k in 0..<(periods mod failEveryNProofs.int):
|
||||
p += 1.u256
|
||||
invalid.add (p, false)
|
||||
# var proofs = false.repeat(failEveryNProofs - 1)
|
||||
# proofs.add true
|
||||
# proofs = proofs.cycle(periods div failEveryNProofs.int)
|
||||
# .concat(false.repeat(periods mod failEveryNProofs.int)) # leftover falses
|
||||
# return proofs
|
||||
return invalid
|
||||
|
||||
await waitUntilPurchaseIsStarted(proofProbability=1)
|
||||
await waitForProvingRounds(totalProofs)
|
||||
proc expectedMissed(startPeriod: Period, failEveryNProofs: uint, periods: Positive): int =
|
||||
# Intersects a seq of expected invalid proofs (true = invalid proof) with
|
||||
# a seq of bools indicating a period was in pointer downtime (true = period
|
||||
# was in pointer downtime).
|
||||
# We can only expect an invalid proof to have been submitted if the slot
|
||||
# was accepting proofs in that period, meaning it cannot be in downtime.
|
||||
# eg failEveryNProofs = 3, periods = 2, the invalid proofs seq will be:
|
||||
# @[false, false, true, false, false, true]
|
||||
# If we hit downtime in the second half of running our test, the
|
||||
# downtime seq might be @[false, false, false, true, true, true]
|
||||
# When these two are intersected such that invalid is true and downtime is false,
|
||||
# the result would be @[false, false, false, false, false, true], or 1 total
|
||||
# invalid proof that should be marked as missed.
|
||||
let invalid = expectedInvalid(startPeriod, failEveryNProofs, periods)
|
||||
var expectedMissed = 0
|
||||
for i in 0..<invalid.len:
|
||||
let (invalidPeriod, isInvalidProof) = invalid[i]
|
||||
for j in 0..<downtime.len:
|
||||
let (downtimePeriod, isDowntime) = downtime[j]
|
||||
if invalidPeriod == downtimePeriod:
|
||||
if isInvalidProof and not isDowntime:
|
||||
inc expectedMissed
|
||||
break
|
||||
# if invalid[i] == true and downtime[i] == false:
|
||||
# expectedMissed += 1
|
||||
|
||||
check eventually submitted.len == expectedValid
|
||||
check missed.truncate(int) == expectedInvalid
|
||||
debug "expectedMissed invalid / downtime", invalid, downtime, expectedMissed
|
||||
return expectedMissed
|
||||
|
||||
test "simulates invalid proof for every proofs":
|
||||
let failEveryNProofs = 1'u
|
||||
let totalProofs = 12
|
||||
startProviderNode(failEveryNProofs)
|
||||
|
||||
# await waitUntilPurchaseIsStarted(proofProbability=1)
|
||||
# var proofWasSubmitted = false
|
||||
# proc onProofSubmitted(event: ProofSubmitted) =
|
||||
# proofWasSubmitted = true
|
||||
# let subscription = await marketplace.subscribe(ProofSubmitted, onProofSubmitted)
|
||||
# await provider.advanceTime(period.u256)
|
||||
# check eventually proofWasSubmitted
|
||||
# await subscription.unsubscribe()
|
||||
let startPeriod = await waitUntilPurchaseIsStarted(duration=totalProofs.uint * period,
|
||||
failEveryNProofs = failEveryNProofs)
|
||||
await waitUntilSlotNoLongerFilled()
|
||||
|
||||
# check 1 == 1
|
||||
check missed.truncate(int) == expectedMissed(startPeriod, failEveryNProofs, totalProofs)
|
||||
|
||||
# test "simulates invalid proof every N proofs":
|
||||
# let failEveryNProofs = 3'u
|
||||
# let totalProofs = 12
|
||||
# startProviderNode(failEveryNProofs)
|
||||
|
||||
# await waitUntilPurchaseIsStarted(duration=totalProofs.uint * period,
|
||||
# failEveryNProofs = failEveryNProofs)
|
||||
# await waitUntilSlotNoLongerFilled()
|
||||
|
||||
# check missed.truncate(int) == expectedMissed(failEveryNProofs, totalProofs)
|
||||
|
||||
# test "does not simulate invalid proofs when --simulate-failed-proofs is 0":
|
||||
# let failEveryNProofs = 0'u
|
||||
# let totalProofs = 12
|
||||
# startProviderNode(failEveryNProofs)
|
||||
|
||||
# await waitUntilPurchaseIsStarted(duration=totalProofs.uint * period,
|
||||
# failEveryNProofs = failEveryNProofs)
|
||||
# await waitUntilSlotNoLongerFilled()
|
||||
|
||||
# check missed.truncate(int) == expectedMissed(failEveryNProofs, totalProofs)
|
||||
|
||||
# test "does not simulate invalid proof when --simulate-failed-proofs is 0":
|
||||
# # 1. instantiate node manually (startNode) with --simulate-failed-proofs=0
|
||||
|
|
|
@ -77,85 +77,3 @@ template twonodessuite*(name: string, debug1, debug2: string, body) =
|
|||
removeDir(dataDir2)
|
||||
|
||||
body
|
||||
|
||||
type
|
||||
Role = enum
|
||||
Client,
|
||||
Provider
|
||||
RunningNode* = ref object
|
||||
role: Role
|
||||
node: NodeProcess
|
||||
restClient: CodexClient
|
||||
datadir: string
|
||||
|
||||
template invalidproofsuite*(name: string, debugClient, debugProvider: bool, body) =
|
||||
|
||||
|
||||
|
||||
ethersuite name:
|
||||
|
||||
var running: seq[RunningNode]
|
||||
var bootstrap: string
|
||||
|
||||
proc newNodeProcess(index: int,
|
||||
addlOptions: seq[string],
|
||||
debug: bool): (NodeProcess, string) =
|
||||
|
||||
let datadir = getTempDir() / "Codex" & $index
|
||||
let node = startNode(@[
|
||||
"--api-port=" & $(8080 + index),
|
||||
"--data-dir=" & datadir,
|
||||
"--nat=127.0.0.1",
|
||||
"--disc-ip=127.0.0.1",
|
||||
"--disc-port=" & $(8090 + index),
|
||||
"--persistence",
|
||||
"--eth-account=" & $accounts[index]
|
||||
].concat(addlOptions), debug = debug)
|
||||
debugEcho "started new codex node listening with rest api listening on port ", 8080 + index
|
||||
(node, datadir)
|
||||
|
||||
proc newCodexClient(index: int): CodexClient =
|
||||
debugEcho "started new rest client talking to port ", 8080 + index
|
||||
CodexClient.new("http://localhost:" & $(8080 + index) & "/api/codex/v1")
|
||||
|
||||
proc startClientNode() =
|
||||
let index = running.len
|
||||
let (node, datadir) = newNodeProcess(index, @[], debugClient)
|
||||
let restClient = newCodexClient(index)
|
||||
running.add RunningNode(role: Role.Client,
|
||||
node: node,
|
||||
restClient: restClient,
|
||||
datadir: datadir)
|
||||
debugEcho "started client node, index ", index
|
||||
|
||||
proc startProviderNode(failEveryNProofs: uint) =
|
||||
let index = running.len
|
||||
let (node, datadir) = newNodeProcess(index, @[
|
||||
"--bootstrap-node=" & bootstrap,
|
||||
"--simulate-proof-failures=" & $failEveryNProofs],
|
||||
debugProvider)
|
||||
let restClient = newCodexClient(index)
|
||||
running.add RunningNode(role: Role.Provider,
|
||||
node: node,
|
||||
restClient: restClient,
|
||||
datadir: datadir)
|
||||
debugEcho "started provider node, index ", index
|
||||
|
||||
proc clients(): seq[RunningNode] =
|
||||
running.filter(proc(r: RunningNode): bool = r.role == Role.Client)
|
||||
|
||||
proc providers(): seq[RunningNode] =
|
||||
running.filter(proc(r: RunningNode): bool = r.role == Role.Provider)
|
||||
|
||||
setup:
|
||||
startClientNode()
|
||||
|
||||
bootstrap = running[0].restClient.info()["spr"].getStr()
|
||||
|
||||
teardown:
|
||||
for r in running:
|
||||
r.restClient.close()
|
||||
r.node.stop()
|
||||
removeDir(r.datadir)
|
||||
|
||||
body
|
||||
|
|
Loading…
Reference in New Issue