WIP simulation integration test
Committing so latest work can be rebased.
This commit is contained in:
parent
90fee8eebb
commit
81bf77375d
|
@ -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],
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue