diff --git a/codex/clock.nim b/codex/clock.nim index 2d3e5a79..f680ddec 100644 --- a/codex/clock.nim +++ b/codex/clock.nim @@ -1,6 +1,5 @@ import pkg/chronos import pkg/stew/endians2 -import pkg/stint import pkg/upraises import pkg/stint diff --git a/tests/integration/marketplacesuite.nim b/tests/integration/marketplacesuite.nim index 22423ced..9eefdccf 100644 --- a/tests/integration/marketplacesuite.nim +++ b/tests/integration/marketplacesuite.nim @@ -8,9 +8,9 @@ import ./multinodes export mp export multinodes -template marketplacesuite*(name: string, startNodes: Nodes, body: untyped) = +template marketplacesuite*(name: string, body: untyped) = - multinodesuite name, startNodes: + multinodesuite name: var marketplace {.inject, used.}: Marketplace var period: uint64 diff --git a/tests/integration/multinodes.nim b/tests/integration/multinodes.nim index c03046b7..9b05e487 100644 --- a/tests/integration/multinodes.nim +++ b/tests/integration/multinodes.nim @@ -21,7 +21,7 @@ type role*: Role node*: NodeProcess address*: ?Address - Nodes* = object + NodeConfigs* = object clients*: NodeConfig providers*: NodeConfig validators*: NodeConfig @@ -107,7 +107,7 @@ proc withLogFile*[T: Config]( startConfig.logFile = logToFile return startConfig -template multinodesuite*(name: string, startNodes: Nodes, body: untyped) = +template multinodesuite*(name: string, body: untyped) = ethersuite name: @@ -115,11 +115,13 @@ template multinodesuite*(name: string, startNodes: Nodes, body: untyped) = var bootstrap: string let starttime = now().format("yyyy-MM-dd'_'HH:mm:ss") var currentTestName = "" + var nodeConfigs: NodeConfigs - template test(namet, bodyt) = - currentTestName = namet - test namet: - bodyt + template test(tname, startNodeConfigs, tbody) = + currentTestName = tname + nodeConfigs = startNodeConfigs + test tname: + tbody proc getLogFile(role: Role, index: ?int): string = # create log file path, format: @@ -209,18 +211,18 @@ template multinodesuite*(name: string, startNodes: Nodes, body: untyped) = running.filter(proc(r: RunningNode): bool = r.role == Role.Validator) proc startHardhatNode(): NodeProcess = - var config = startNodes.hardhat + var config = nodeConfigs.hardhat return newHardhatProcess(config, Role.Hardhat) proc startClientNode(): NodeProcess = let clientIdx = clients().len - var config = startNodes.clients + var config = nodeConfigs.clients config.cliOptions.add CliOption(key: "--persistence") return newNodeProcess(clientIdx, config, Role.Client) proc startProviderNode(): NodeProcess = let providerIdx = providers().len - var config = startNodes.providers + var config = nodeConfigs.providers config.cliOptions.add CliOption(key: "--bootstrap-node", value: bootstrap) config.cliOptions.add CliOption(key: "--persistence") @@ -233,18 +235,18 @@ template multinodesuite*(name: string, startNodes: Nodes, body: untyped) = proc startValidatorNode(): NodeProcess = let validatorIdx = validators().len - var config = startNodes.validators + var config = nodeConfigs.validators config.cliOptions.add CliOption(key: "--bootstrap-node", value: bootstrap) config.cliOptions.add CliOption(key: "--validator") return newNodeProcess(validatorIdx, config, Role.Validator) setup: - if not startNodes.hardhat.isNil: + if not nodeConfigs.hardhat.isNil: let node = startHardhatNode() running.add RunningNode(role: Role.Hardhat, node: node) - for i in 0.. //_.log, +marketplacesuite "Marketplace payouts": - clients: NodeConfig() - .nodes(1) - # .debug() # uncomment to enable console log output.debug() - # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log - .withLogTopics("node", "erasure"), + test "expired request partially pays out for stored time", + NodeConfigs( + # Uncomment to start Hardhat automatically, mainly so logs can be inspected locally + # hardhat: HardhatConfig().withLogFile() - providers: NodeConfig() - .nodes(1) - # .debug() # uncomment to enable console log output - # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log - .withLogTopics( - "marketplace", - "sales", - "reservations", - "node", - "JSONRPC-HTTP-CLIENT", - "JSONRPC-WS-CLIENT", - "ethers", - "restapi", - "clock" - ) -): - test "expired request partially pays out for stored time": + clients: + NodeConfig() + .nodes(1) + # .debug() # uncomment to enable console log output.debug() + # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log + .withLogTopics("node", "erasure"), + + providers: + NodeConfig() + .nodes(1) + # .debug() # uncomment to enable console log output + # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log + .withLogTopics("marketplace", "sales", "reservations", "node", "clock"), + ): let reward = 400.u256 let duration = 100.periods let collateral = 200.u256 diff --git a/tests/integration/testproofs.nim b/tests/integration/testproofs.nim index f6a4590d..a2967528 100644 --- a/tests/integration/testproofs.nim +++ b/tests/integration/testproofs.nim @@ -12,195 +12,187 @@ export chronicles logScope: topics = "integration test proofs" -marketplacesuite "Simulate invalid proofs, 1 provider node, every proof invalid", - Nodes( + +marketplacesuite "Hosts submit regular proofs": + + test "hosts submit periodic proofs for slots they fill", NodeConfigs( # Uncomment to start Hardhat automatically, mainly so logs can be inspected locally - # hardhat: HardhatConfig() - # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log, + # hardhat: HardhatConfig().withLogFile() - clients: NodeConfig() - .nodes(1) - # .debug() # uncomment to enable console log output - # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log - .withLogTopics("node"), + clients: + NodeConfig() + .nodes(1) + # .debug() # uncomment to enable console log output + # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log + .withLogTopics("node"), - providers: NodeConfig() - .nodes(1) - .simulateProofFailuresFor(providerIdx=0, failEveryNProofs=1) - # .debug() # uncomment to enable console log output - # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log - .withLogTopics( - "marketplace", - "sales", - "reservations", - "node", - "JSONRPC-HTTP-CLIENT", - "JSONRPC-WS-CLIENT", - "ethers", - "restapi", - "clock" - ), - - validators: NodeConfig() - .nodes(1) - # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log - # .debug() # uncomment to enable console log output - .withLogTopics("validator", "initial-proving", "proving", "clock", "onchain", "ethers") + providers: + NodeConfig() + .nodes(1) + # .debug() # uncomment to enable console log output + # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log + .withLogTopics("marketplace", "sales", "reservations", "node", "clock"), ): + let client0 = clients()[0].node.client + let totalPeriods = 50 - test "slot is freed after too many invalid proofs submitted": - let client0 = clients()[0].node.client - let totalPeriods = 50 + let data = byteutils.toHex(await exampleData()) + createAvailabilities(data.len, totalPeriods.periods) - let data = byteutils.toHex(await exampleData()) - createAvailabilities(data.len, totalPeriods.periods) + let cid = client0.upload(data).get - let cid = client0.upload(data).get + let purchaseId = await client0.requestStorage(cid, duration=totalPeriods.periods) + check eventually client0.purchaseStateIs(purchaseId, "started") - let purchaseId = await client0.requestStorage(cid, duration=totalPeriods.periods) - let requestId = client0.requestId(purchaseId).get + var proofWasSubmitted = false + proc onProofSubmitted(event: ProofSubmitted) = + proofWasSubmitted = true - check eventually client0.purchaseStateIs(purchaseId, "started") + let subscription = await marketplace.subscribe(ProofSubmitted, onProofSubmitted) - var slotWasFreed = false - proc onSlotFreed(event: SlotFreed) {.gcsafe, upraises:[].} = - if event.requestId == requestId and - event.slotIndex == 0.u256: # assume only one slot, so index 0 - slotWasFreed = true + let currentPeriod = await getCurrentPeriod() + check eventuallyP(proofWasSubmitted, currentPeriod + totalPeriods.u256 + 1) - let subscription = await marketplace.subscribe(SlotFreed, onSlotFreed) + await subscription.unsubscribe() - let currentPeriod = await getCurrentPeriod() - check eventuallyP(slotWasFreed, currentPeriod + totalPeriods.u256 + 1) - await subscription.unsubscribe() -marketplacesuite "Simulate invalid proofs, 1 provider node, every 3rd proof invalid", - Nodes( - # Uncomment to start Hardhat automatically, mainly so logs can be inspected locally - # hardhat: HardhatConfig() - # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log, - - clients: NodeConfig() - .nodes(1) - # .debug() # uncomment to enable console log output - # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log - .withLogTopics("node"), - - providers: NodeConfig() - .nodes(1) - .simulateProofFailuresFor(providerIdx=0, failEveryNProofs=3) - # .debug() # uncomment to enable console log output - # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log - .withLogTopics( - "marketplace", - "sales", - "reservations", - "node", - "JSONRPC-HTTP-CLIENT", - "JSONRPC-WS-CLIENT", - "ethers", - "restapi", - "clock" - ), - - validators: NodeConfig() - .nodes(1) - # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log - .withLogTopics("validator", "initial-proving", "proving", "clock", "onchain", "ethers") - ): - - test "hosts submit periodic proofs for slots they fill": - let client0 = clients()[0].node.client - let totalPeriods = 50 - - let data = byteutils.toHex(await exampleData()) - createAvailabilities(data.len, totalPeriods.periods) - - let cid = client0.upload(data).get - - let purchaseId = await client0.requestStorage(cid, duration=totalPeriods.periods) - check eventually client0.purchaseStateIs(purchaseId, "started") - - var proofWasSubmitted = false - proc onProofSubmitted(event: ProofSubmitted) = - proofWasSubmitted = true - - let subscription = await marketplace.subscribe(ProofSubmitted, onProofSubmitted) - - let currentPeriod = await getCurrentPeriod() - check eventuallyP(proofWasSubmitted, currentPeriod + totalPeriods.u256 + 1) - - await subscription.unsubscribe() - - test "slot is not freed when not enough invalid proofs submitted": - let client0 = clients()[0].node.client - let totalPeriods = 25 - - let data = byteutils.toHex(await exampleData()) - createAvailabilities(data.len, totalPeriods.periods) - - let cid = client0.upload(data).get - - let purchaseId = await client0.requestStorage(cid, duration=totalPeriods.periods) - let requestId = client0.requestId(purchaseId).get - - check eventually client0.purchaseStateIs(purchaseId, "started") - - var slotWasFreed = false - proc onSlotFreed(event: SlotFreed) {.gcsafe, upraises:[].} = - if event.requestId == requestId and - event.slotIndex == 0.u256: # assume only one slot, so index 0 - slotWasFreed = true - - let subscription = await marketplace.subscribe(SlotFreed, onSlotFreed) - - # check not freed - let currentPeriod = await getCurrentPeriod() - check not eventuallyP(slotWasFreed, currentPeriod + totalPeriods.u256 + 1) - - await subscription.unsubscribe() - -marketplacesuite "Simulate invalid proofs", - Nodes( - # Uncomment to start Hardhat automatically, mainly so logs can be inspected locally - # hardhat: HardhatConfig() - # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log, - - clients: NodeConfig() - .nodes(1) - # .debug() # uncomment to enable console log output.debug() - # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log - .withLogTopics("node", "erasure"), - - providers: NodeConfig() - .nodes(2) - .simulateProofFailuresFor(providerIdx=0, failEveryNProofs=2) - # .debug() # uncomment to enable console log output - # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log - .withLogTopics( - "marketplace", - "sales", - "reservations", - "node", - "JSONRPC-HTTP-CLIENT", - "JSONRPC-WS-CLIENT", - "ethers", - "restapi" - ), - - validators: NodeConfig() - .nodes(1) - # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log - .withLogTopics("validator", "initial-proving", "proving") - ): +marketplacesuite "Simulate invalid proofs": # 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. - test "provider that submits invalid proofs is paid out less": + test "slot is freed after too many invalid proofs submitted", NodeConfigs( + # Uncomment to start Hardhat automatically, mainly so logs can be inspected locally + # hardhat: HardhatConfig().withLogFile() + + clients: + NodeConfig() + .nodes(1) + # .debug() # uncomment to enable console log output + # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log + .withLogTopics("node"), + + providers: + NodeConfig() + .nodes(1) + .simulateProofFailuresFor(providerIdx=0, failEveryNProofs=1) + # .debug() # uncomment to enable console log output + # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log + .withLogTopics("marketplace", "sales", "reservations", "node", "clock"), + + validators: + NodeConfig() + .nodes(1) + # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log + # .debug() # uncomment to enable console log output + .withLogTopics("validator", "clock", "onchain", "ethers") + ): + let client0 = clients()[0].node.client + let totalPeriods = 50 + + let data = byteutils.toHex(await exampleData()) + createAvailabilities(data.len, totalPeriods.periods) + + let cid = client0.upload(data).get + + let purchaseId = await client0.requestStorage(cid, duration=totalPeriods.periods) + let requestId = client0.requestId(purchaseId).get + + check eventually client0.purchaseStateIs(purchaseId, "started") + + var slotWasFreed = false + proc onSlotFreed(event: SlotFreed) {.gcsafe, upraises:[].} = + if event.requestId == requestId and + event.slotIndex == 0.u256: # assume only one slot, so index 0 + slotWasFreed = true + + let subscription = await marketplace.subscribe(SlotFreed, onSlotFreed) + + let currentPeriod = await getCurrentPeriod() + check eventuallyP(slotWasFreed, currentPeriod + totalPeriods.u256 + 1) + + await subscription.unsubscribe() + + test "slot is not freed when not enough invalid proofs submitted", NodeConfigs( + # Uncomment to start Hardhat automatically, mainly so logs can be inspected locally + # hardhat: HardhatConfig().withLogFile() + + clients: + NodeConfig() + .nodes(1) + # .debug() # uncomment to enable console log output + # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log + .withLogTopics("node"), + + providers: + NodeConfig() + .nodes(1) + .simulateProofFailuresFor(providerIdx=0, failEveryNProofs=3) + # .debug() # uncomment to enable console log output + # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log + .withLogTopics("marketplace", "sales", "reservations", "node", "clock"), + + validators: + NodeConfig() + .nodes(1) + # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log + .withLogTopics("validator", "clock", "onchain", "ethers") + ): + let client0 = clients()[0].node.client + let totalPeriods = 25 + + let data = byteutils.toHex(await exampleData()) + createAvailabilities(data.len, totalPeriods.periods) + + let cid = client0.upload(data).get + + let purchaseId = await client0.requestStorage(cid, duration=totalPeriods.periods) + let requestId = client0.requestId(purchaseId).get + + check eventually client0.purchaseStateIs(purchaseId, "started") + + var slotWasFreed = false + proc onSlotFreed(event: SlotFreed) {.gcsafe, upraises:[].} = + if event.requestId == requestId and + event.slotIndex == 0.u256: # assume only one slot, so index 0 + slotWasFreed = true + + let subscription = await marketplace.subscribe(SlotFreed, onSlotFreed) + + # check not freed + let currentPeriod = await getCurrentPeriod() + check not eventuallyP(slotWasFreed, currentPeriod + totalPeriods.u256 + 1) + + await subscription.unsubscribe() + + test "host that submits invalid proofs is paid out less", NodeConfigs( + # Uncomment to start Hardhat automatically, mainly so logs can be inspected locally + # hardhat: HardhatConfig().withLogFile() + + clients: + NodeConfig() + .nodes(1) + # .debug() # uncomment to enable console log output.debug() + # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log + .withLogTopics("node", "erasure"), + + providers: + NodeConfig() + .nodes(2) + .simulateProofFailuresFor(providerIdx=0, failEveryNProofs=2) + # .debug() # uncomment to enable console log output + # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log + .withLogTopics("marketplace", "sales", "reservations", "node", "clock"), + + validators: + NodeConfig() + .nodes(1) + # .withLogFile() # uncomment to output log file to tests/integration/logs/ //_.log + .withLogTopics("validator") + ): let client0 = clients()[0].node.client let provider0 = providers()[0] let provider1 = providers()[1]