WIP simulation integration test

Committing so latest work can be rebased.
This commit is contained in:
Eric Mastro 2023-04-14 19:41:22 +10:00
parent 90fee8eebb
commit 81bf77375d
No known key found for this signature in database
4 changed files with 216 additions and 10 deletions

View File

@ -3,6 +3,7 @@ import pkg/contractabi
import pkg/nimcrypto import pkg/nimcrypto
import pkg/ethers/fields import pkg/ethers/fields
import pkg/questionable/results import pkg/questionable/results
import pkg/stew/byteutils
export contractabi export contractabi
@ -63,6 +64,15 @@ func toArray*(id: RequestId | SlotId | Nonce): array[32, byte] =
proc `$`*(id: RequestId | SlotId | Nonce): string = proc `$`*(id: RequestId | SlotId | Nonce): string =
id.toArray.toHex id.toArray.toHex
proc fromHex*(T: type RequestId, hex: string): T =
T array[32, byte].fromHex(hex)
proc fromHex*(T: type SlotId, hex: string): T =
T array[32, byte].fromHex(hex)
proc fromHex*(T: type Nonce, hex: string): T =
T array[32, byte].fromHex(hex)
func fromTuple(_: type StorageRequest, tupl: tuple): StorageRequest = func fromTuple(_: type StorageRequest, tupl: tuple): StorageRequest =
StorageRequest( StorageRequest(
client: tupl[0], client: tupl[0],

View File

@ -60,4 +60,5 @@ func `%`*(purchase: Purchase): JsonNode =
"state": (purchase.state as PurchaseState).?description |? "none", "state": (purchase.state as PurchaseState).?description |? "none",
"error": purchase.error.?msg, "error": purchase.error.?msg,
"request": purchase.request, "request": purchase.request,
"requestId": purchase.requestId
} }

View File

@ -1,4 +1,4 @@
import std/os import std/sequtils
import codex/contracts/marketplace import codex/contracts/marketplace
import codex/contracts/deployment import codex/contracts/deployment
import codex/periods import codex/periods
@ -96,18 +96,131 @@ twonodessuite "Proving integration test", debug1=false, debug2=false:
await subscription.unsubscribe() await subscription.unsubscribe()
stopValidator(validator) stopValidator(validator)
invalidproofsuite "Simulate invalid proofs", debugClient=false, debugProvider=false:
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
proc startValidator: NodeProcess =
let datadir = getTempDir() / "CodexValidator"
startNode([
"--data-dir=" & datadir,
"--api-port=8180",
"--disc-port=8190",
"--validator",
"--eth-account=" & $accounts[2]
], debug = true)
proc stopValidator(node: NodeProcess) =
node.stop()
removeDir(getTempDir() / "CodexValidator")
setup:
let deployment = Deployment.init()
marketplace = Marketplace.new(!deployment.address(Marketplace), provider)
period = (await marketplace.config()).proofs.period.truncate(uint64)
await provider.getSigner(accounts[0]).mint()
await provider.getSigner(accounts[1]).mint()
await provider.getSigner(accounts[1]).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()
teardown:
await subscription.unsubscribe()
validator.stopValidator()
proc waitUntilPurchaseIsStarted(proofProbability: uint64 = 3,
duration: uint64 = 100 * period,
expiry: uint64 = 30) {.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
discard storageProvider.postAvailability(
size=0xFFFFF,
duration=duration,
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=duration,
proofProbability=proofProbability,
reward=400
)
check eventually client.getPurchase(purchase){"state"} == %"started"
let requestId = RequestId.fromHex client.getPurchase(purchase){"requestId"}.getStr
slotId = slotId(requestId, 0.u256)
proc advanceToNextPeriod() {.async.} =
await provider.advanceTime(period.u256)
proc waitForProvingRounds(rounds: Positive) {.async.} =
var rnds = rounds - 1 # proof round runs prior to advancing
missed += await marketplace.missingProofs(slotId)
while rnds > 0:
await advanceToNextPeriod()
rnds -= 1
proc invalid(proofs: seq[seq[byte]]): uint =
proofs.count(@[]).uint
test "simulates invalid proof every N proofs": test "simulates invalid proof every N proofs":
# TODO: waiting on validation work to be completed before these tests are possible # TODO: waiting on validation work to be completed before these tests are possible
# 1. instantiate node manually (startNode) with --simulate-failed-proofs=3 # 1. instantiate node manually (startNode) with --simulate-failed-proofs=3
# 2. check that the number of expected proofs are missed # 2. check that the number of expected proofs are missed
check 1 == 1 let failEveryNProofs = 3
let totalProofs = 6
let expectedInvalid = totalProofs div failEveryNProofs
let expectedValid = totalProofs - expectedInvalid
startProviderNode(failEveryNProofs.uint)
test "does not simulate invalid proof when --simulate-failed-proofs is 0": await waitUntilPurchaseIsStarted(proofProbability=1)
# 1. instantiate node manually (startNode) with --simulate-failed-proofs=0 await waitForProvingRounds(totalProofs)
# 2. check that the number of expected missed proofs is 0
check 1 == 1
test "does not simulate invalid proof when chainId is 1": check eventually submitted.len == expectedValid
# 1. instantiate node manually (startNode) with --simulate-failed-proofs=3 check missed.truncate(int) == expectedInvalid
# 2. check that the number of expected missed proofs is 0
check 1 == 1
# 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()
# check 1 == 1
# test "does not simulate invalid proof when --simulate-failed-proofs is 0":
# # 1. instantiate node manually (startNode) with --simulate-failed-proofs=0
# # 2. check that the number of expected missed proofs is 0
# check 1 == 1
# test "does not simulate invalid proof when chainId is 1":
# # 1. instantiate node manually (startNode) with --simulate-failed-proofs=3
# # 2. check that the number of expected missed proofs is 0
# check 1 == 1

View File

@ -60,3 +60,85 @@ template twonodessuite*(name: string, debug1, debug2: bool, body) =
removeDir(dataDir2) removeDir(dataDir2)
body 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