From 2cf892c467a9553f85bd596ed02966960403da66 Mon Sep 17 00:00:00 2001 From: markspanbroek Date: Wed, 7 Feb 2024 07:50:35 +0100 Subject: [PATCH] Smart contracts update: Groth16Proof instead of bytes (#683) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Smart contracts update: Groth16Proof instead of bytes * Use dummy verifier for now, until we can create ZK proofs * Fix tests: submit proof only when slot is filled * Submit dummy proofs for now * More detailed log when proof submission failed * Use dummy verifier for integration tests For now at least * Fix mistake in blanket renaming to ethProvider * Update to latest codex-contracts-eth * feat: zkey-hash from chain * Fix zkeyHash --------- Co-authored-by: Adam Uhlíř --- codex/contracts/config.nim | 4 ++- codex/contracts/deployment.nim | 5 ++- codex/contracts/market.nim | 11 +++++-- codex/contracts/marketplace.nim | 6 ++-- codex/contracts/proofs.nim | 33 +++++++++++++++++++ codex/market.nim | 11 +++++-- codex/node.nim | 11 +++++-- codex/sales/salescontext.nim | 2 +- codex/sales/states/filling.nim | 2 +- codex/sales/states/proving.nim | 3 +- codex/sales/states/provingsimulated.nim | 2 +- tests/codex/helpers/mockmarket.nim | 15 +++++---- tests/codex/sales/states/testfilled.nim | 2 +- .../codex/sales/states/testinitialproving.nim | 6 ++-- tests/codex/sales/states/testproving.nim | 10 +++--- .../sales/states/testsimulatedproving.nim | 11 +++---- tests/codex/sales/testsales.nim | 16 ++++----- tests/codex/testvalidation.nim | 11 ++++--- tests/contracts/deployment.nim | 12 +++++-- tests/contracts/testContracts.nim | 5 +-- tests/contracts/testDeployment.nim | 4 +-- tests/contracts/testMarket.nim | 22 ++++++------- tests/examples.nim | 21 +++++++++--- tests/integration/multinodes.nim | 14 ++++---- tests/integration/testproofs.nim | 11 +++++-- vendor/codex-contracts-eth | 2 +- 26 files changed, 164 insertions(+), 88 deletions(-) create mode 100644 codex/contracts/proofs.nim diff --git a/codex/contracts/config.nim b/codex/contracts/config.nim index d97c7786..fd6a1fa8 100644 --- a/codex/contracts/config.nim +++ b/codex/contracts/config.nim @@ -17,13 +17,15 @@ type period*: UInt256 # proofs requirements are calculated per period (in seconds) timeout*: UInt256 # mark proofs as missing before the timeout (in seconds) downtime*: uint8 # ignore this much recent blocks for proof requirements + zkeyHash*: string # hash of the zkey file which is linked to the verifier func fromTuple(_: type ProofConfig, tupl: tuple): ProofConfig = ProofConfig( period: tupl[0], timeout: tupl[1], - downtime: tupl[2] + downtime: tupl[2], + zkeyHash: tupl[3] ) func fromTuple(_: type CollateralConfig, tupl: tuple): CollateralConfig = diff --git a/codex/contracts/deployment.nim b/codex/contracts/deployment.nim index 46591100..70cecd03 100644 --- a/codex/contracts/deployment.nim +++ b/codex/contracts/deployment.nim @@ -14,7 +14,10 @@ type Deployment* = ref object const knownAddresses = { # Hardhat localhost network "31337": { - "Marketplace": Address.init("0x59b670e9fA9D0A427751Af201D676719a970857b") + # TODO: This is currently the address of the marketplace with a dummy + # verifier. Replace with "0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44" once we + # can generate actual Groth16 ZK proofs + "Marketplace": Address.init("0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f"), }.toTable, # Taiko Alpha-3 Testnet "167005": { diff --git a/codex/contracts/market.nim b/codex/contracts/market.nim index 51b3577b..8f12578e 100644 --- a/codex/contracts/market.nim +++ b/codex/contracts/market.nim @@ -8,6 +8,7 @@ import pkg/questionable import ../logutils import ../market import ./marketplace +import ./proofs export market @@ -38,6 +39,10 @@ proc approveFunds(market: OnChainMarket, amount: UInt256) {.async.} = discard await token.increaseAllowance(market.contract.address(), amount).confirm(1) +method getZkeyHash*(market: OnChainMarket): Future[?string] {.async.} = + let config = await market.contract.config() + return some config.proofs.zkeyHash + method getSigner*(market: OnChainMarket): Future[Address] {.async.} = return await market.signer.getAddress() @@ -120,7 +125,7 @@ method getActiveSlot*(market: OnChainMarket, method fillSlot(market: OnChainMarket, requestId: RequestId, slotIndex: UInt256, - proof: seq[byte], + proof: Groth16Proof, collateral: UInt256) {.async.} = await market.approveFunds(collateral) await market.contract.fillSlot(requestId, slotIndex, proof) @@ -155,7 +160,7 @@ method getChallenge*(market: OnChainMarket, id: SlotId): Future[ProofChallenge] method submitProof*(market: OnChainMarket, id: SlotId, - proof: seq[byte]) {.async.} = + proof: Groth16Proof) {.async.} = await market.contract.submitProof(id, proof) method markProofAsMissing*(market: OnChainMarket, @@ -272,7 +277,7 @@ method subscribeProofSubmission*(market: OnChainMarket, callback: OnProofSubmitted): Future[MarketSubscription] {.async.} = proc onEvent(event: ProofSubmitted) {.upraises: [].} = - callback(event.id, event.proof) + callback(event.id) let subscription = await market.contract.subscribe(ProofSubmitted, onEvent) return OnChainMarketSubscription(eventSubscription: subscription) diff --git a/codex/contracts/marketplace.nim b/codex/contracts/marketplace.nim index 721e5ce5..805681fe 100644 --- a/codex/contracts/marketplace.nim +++ b/codex/contracts/marketplace.nim @@ -5,6 +5,7 @@ import pkg/stint import pkg/chronos import ../clock import ./requests +import ./proofs import ./config export stint @@ -33,7 +34,6 @@ type requestId* {.indexed.}: RequestId ProofSubmitted* = object of Event id*: SlotId - proof*: seq[byte] proc config*(marketplace: Marketplace): MarketplaceConfig {.contract, view.} @@ -43,7 +43,7 @@ proc slashPercentage*(marketplace: Marketplace): UInt256 {.contract, view.} proc minCollateralThreshold*(marketplace: Marketplace): UInt256 {.contract, view.} proc requestStorage*(marketplace: Marketplace, request: StorageRequest) {.contract.} -proc fillSlot*(marketplace: Marketplace, requestId: RequestId, slotIndex: UInt256, proof: seq[byte]) {.contract.} +proc fillSlot*(marketplace: Marketplace, requestId: RequestId, slotIndex: UInt256, proof: Groth16Proof) {.contract.} proc withdrawFunds*(marketplace: Marketplace, requestId: RequestId) {.contract.} proc freeSlot*(marketplace: Marketplace, id: SlotId) {.contract.} proc getRequest*(marketplace: Marketplace, id: RequestId): StorageRequest {.contract, view.} @@ -65,5 +65,5 @@ proc willProofBeRequired*(marketplace: Marketplace, id: SlotId): bool {.contract proc getChallenge*(marketplace: Marketplace, id: SlotId): array[32, byte] {.contract, view.} proc getPointer*(marketplace: Marketplace, id: SlotId): uint8 {.contract, view.} -proc submitProof*(marketplace: Marketplace, id: SlotId, proof: seq[byte]) {.contract.} +proc submitProof*(marketplace: Marketplace, id: SlotId, proof: Groth16Proof) {.contract.} proc markProofAsMissing*(marketplace: Marketplace, id: SlotId, period: UInt256) {.contract.} diff --git a/codex/contracts/proofs.nim b/codex/contracts/proofs.nim new file mode 100644 index 00000000..3b84a2e7 --- /dev/null +++ b/codex/contracts/proofs.nim @@ -0,0 +1,33 @@ +import pkg/stint +import pkg/contractabi +import pkg/ethers/fields + +type + Groth16Proof* = object + a*: G1Point + b*: G2Point + c*: G1Point + G1Point* = object + x*: UInt256 + y*: UInt256 + G2Point* = object + x*: array[2, UInt256] + y*: array[2, UInt256] + +func solidityType*(_: type G1Point): string = + solidityType(G1Point.fieldTypes) + +func solidityType*(_: type G2Point): string = + solidityType(G2Point.fieldTypes) + +func solidityType*(_: type Groth16Proof): string = + solidityType(Groth16Proof.fieldTypes) + +func encode*(encoder: var AbiEncoder, point: G1Point) = + encoder.write(point.fieldValues) + +func encode*(encoder: var AbiEncoder, point: G2Point) = + encoder.write(point.fieldValues) + +func encode*(encoder: var AbiEncoder, proof: Groth16Proof) = + encoder.write(proof.fieldValues) diff --git a/codex/market.nim b/codex/market.nim index bf78ddeb..acb0cfe3 100644 --- a/codex/market.nim +++ b/codex/market.nim @@ -3,12 +3,14 @@ import pkg/upraises import pkg/questionable import pkg/ethers/erc20 import ./contracts/requests +import ./contracts/proofs import ./clock import ./periods export chronos export questionable export requests +export proofs export SecondsSince1970 export periods @@ -23,13 +25,16 @@ type OnSlotFreed* = proc(requestId: RequestId, slotIndex: UInt256) {.gcsafe, upraises: [].} OnRequestCancelled* = proc(requestId: RequestId) {.gcsafe, upraises:[].} OnRequestFailed* = proc(requestId: RequestId) {.gcsafe, upraises:[].} - OnProofSubmitted* = proc(id: SlotId, proof: seq[byte]) {.gcsafe, upraises:[].} + OnProofSubmitted* = proc(id: SlotId) {.gcsafe, upraises:[].} PastStorageRequest* = object requestId*: RequestId ask*: StorageAsk expiry*: UInt256 ProofChallenge* = array[32, byte] +method getZkeyHash*(market: Market): Future[?string] {.base, async.} = + raiseAssert("not implemented") + method getSigner*(market: Market): Future[Address] {.base, async.} = raiseAssert("not implemented") @@ -91,7 +96,7 @@ method getActiveSlot*( method fillSlot*(market: Market, requestId: RequestId, slotIndex: UInt256, - proof: seq[byte], + proof: Groth16Proof, collateral: UInt256) {.base, async.} = raiseAssert("not implemented") @@ -120,7 +125,7 @@ method getChallenge*(market: Market, id: SlotId): Future[ProofChallenge] {.base, method submitProof*(market: Market, id: SlotId, - proof: seq[byte]) {.base, async.} = + proof: Groth16Proof) {.base, async.} = raiseAssert("not implemented") method markProofAsMissing*(market: Market, diff --git a/codex/node.nim b/codex/node.nim index e3c6baca..e86ab821 100644 --- a/codex/node.nim +++ b/codex/node.nim @@ -549,7 +549,7 @@ proc onStore( proc onProve( self: CodexNodeRef, slot: Slot, - challenge: ProofChallenge): Future[?!seq[byte]] {.async.} = + challenge: ProofChallenge): Future[?!Groth16Proof] {.async.} = ## Generats a proof for a given slot and challenge ## @@ -585,7 +585,12 @@ proc onProve( return failure(err) # Todo: send proofInput to circuit. Get proof. (Profit, repeat.) - success(@[42'u8]) + + # For now: dummy proof that is not all zero's, so that it is accepted by the + # dummy verifier: + var proof = Groth16Proof.default + proof.a.x = 42.u256 + success(proof) proc onExpiryUpdate( self: CodexNodeRef, @@ -635,7 +640,7 @@ proc start*(self: CodexNodeRef) {.async.} = self.onClear(request, slotIndex) hostContracts.sales.onProve = - proc(slot: Slot, challenge: ProofChallenge): Future[?!seq[byte]] = + proc(slot: Slot, challenge: ProofChallenge): Future[?!Groth16Proof] = # TODO: generate proof self.onProve(slot, challenge) diff --git a/codex/sales/salescontext.nim b/codex/sales/salescontext.nim index 0c209db7..199aa5fb 100644 --- a/codex/sales/salescontext.nim +++ b/codex/sales/salescontext.nim @@ -27,7 +27,7 @@ type OnStore* = proc(request: StorageRequest, slot: UInt256, blocksCb: BlocksCb): Future[?!void] {.gcsafe, upraises: [].} - OnProve* = proc(slot: Slot, challenge: ProofChallenge): Future[?!seq[byte]] {.gcsafe, upraises: [].} + OnProve* = proc(slot: Slot, challenge: ProofChallenge): Future[?!Groth16Proof] {.gcsafe, upraises: [].} OnExpiryUpdate* = proc(rootCid: string, expiry: SecondsSince1970): Future[?!void] {.gcsafe, upraises: [].} OnClear* = proc(request: StorageRequest, slotIndex: UInt256) {.gcsafe, upraises: [].} diff --git a/codex/sales/states/filling.nim b/codex/sales/states/filling.nim index b6646733..73db9fcb 100644 --- a/codex/sales/states/filling.nim +++ b/codex/sales/states/filling.nim @@ -12,7 +12,7 @@ logScope: type SaleFilling* = ref object of ErrorHandlingState - proof*: seq[byte] + proof*: Groth16Proof method `$`*(state: SaleFilling): string = "SaleFilling" diff --git a/codex/sales/states/proving.nim b/codex/sales/states/proving.nim index 047e5f4a..e3d80f1a 100644 --- a/codex/sales/states/proving.nim +++ b/codex/sales/states/proving.nim @@ -2,6 +2,7 @@ import std/options import pkg/questionable/results import ../../clock import ../../logutils +import ../../utils/exceptions import ../statemachine import ../salesagent import ../salescontext @@ -35,7 +36,7 @@ method prove*( debug "Submitting proof", currentPeriod = currentPeriod, slotId = slot.id await market.submitProof(slot.id, proof) except CatchableError as e: - error "Submitting proof failed", msg = e.msg + error "Submitting proof failed", msg = e.msgDetail proc proveLoop( state: SaleProving, diff --git a/codex/sales/states/provingsimulated.nim b/codex/sales/states/provingsimulated.nim index 78ce5ee5..9c77e85a 100644 --- a/codex/sales/states/provingsimulated.nim +++ b/codex/sales/states/provingsimulated.nim @@ -31,7 +31,7 @@ when codex_enable_proof_failures: try: warn "Submitting INVALID proof", period = currentPeriod, slotId = slot.id - await market.submitProof(slot.id, newSeq[byte](0)) + await market.submitProof(slot.id, Groth16Proof.default) except ProviderError as e: if not e.revertReason.contains("Invalid proof"): onSubmitProofError(e, currentPeriod, slot.id) diff --git a/tests/codex/helpers/mockmarket.nim b/tests/codex/helpers/mockmarket.nim index f0d8e967..db84b208 100644 --- a/tests/codex/helpers/mockmarket.nim +++ b/tests/codex/helpers/mockmarket.nim @@ -6,6 +6,7 @@ import std/sugar import pkg/questionable import pkg/codex/market import pkg/codex/contracts/requests +import pkg/codex/contracts/proofs import pkg/codex/contracts/config import ../examples @@ -24,6 +25,7 @@ type fulfilled*: seq[Fulfillment] filled*: seq[MockSlot] freed*: seq[SlotId] + submitted*: seq[Groth16Proof] markedAsMissingProofs*: seq[SlotId] canBeMarkedAsMissing: HashSet[SlotId] withdrawn*: seq[RequestId] @@ -36,13 +38,13 @@ type config*: MarketplaceConfig Fulfillment* = object requestId*: RequestId - proof*: seq[byte] + proof*: Groth16Proof host*: Address MockSlot* = object requestId*: RequestId host*: Address slotIndex*: UInt256 - proof*: seq[byte] + proof*: Groth16Proof Subscriptions = object onRequest: seq[RequestSubscription] onFulfillment: seq[FulfillmentSubscription] @@ -215,7 +217,7 @@ proc emitRequestFailed*(market: MockMarket, requestId: RequestId) = proc fillSlot*(market: MockMarket, requestId: RequestId, slotIndex: UInt256, - proof: seq[byte], + proof: Groth16Proof, host: Address) = let slot = MockSlot( requestId: requestId, @@ -230,7 +232,7 @@ proc fillSlot*(market: MockMarket, method fillSlot*(market: MockMarket, requestId: RequestId, slotIndex: UInt256, - proof: seq[byte], + proof: Groth16Proof, collateral: UInt256) {.async.} = market.fillSlot(requestId, slotIndex, proof, market.signer) @@ -273,9 +275,10 @@ method getChallenge*(mock: MockMarket, id: SlotId): Future[ProofChallenge] {.asy proc setProofEnd*(mock: MockMarket, id: SlotId, proofEnd: UInt256) = mock.proofEnds[id] = proofEnd -method submitProof*(mock: MockMarket, id: SlotId, proof: seq[byte]) {.async.} = +method submitProof*(mock: MockMarket, id: SlotId, proof: Groth16Proof) {.async.} = + mock.submitted.add(proof) for subscription in mock.subscriptions.onProofSubmitted: - subscription.callback(id, proof) + subscription.callback(id) method markProofAsMissing*(market: MockMarket, id: SlotId, diff --git a/tests/codex/sales/states/testfilled.nim b/tests/codex/sales/states/testfilled.nim index 1e5e292f..e8a16e10 100644 --- a/tests/codex/sales/states/testfilled.nim +++ b/tests/codex/sales/states/testfilled.nim @@ -31,7 +31,7 @@ checksuite "sales state 'filled'": slot = MockSlot(requestId: request.id, host: Address.example, slotIndex: slotIndex, - proof: @[]) + proof: Groth16Proof.default) market.requestEnds[request.id] = 321 onExpiryUpdatePassedExpiry = -1 diff --git a/tests/codex/sales/states/testinitialproving.nim b/tests/codex/sales/states/testinitialproving.nim index a47406a2..0659edd3 100644 --- a/tests/codex/sales/states/testinitialproving.nim +++ b/tests/codex/sales/states/testinitialproving.nim @@ -16,7 +16,7 @@ import ../../helpers import ../../helpers/mockmarket asyncchecksuite "sales state 'initialproving'": - let proof = exampleProof() + let proof = Groth16Proof.example let request = StorageRequest.example let slotIndex = (request.ask.slots div 2).u256 let market = MockMarket.new() @@ -26,7 +26,7 @@ asyncchecksuite "sales state 'initialproving'": var receivedChallenge: ProofChallenge setup: - let onProve = proc (slot: Slot, challenge: ProofChallenge): Future[?!seq[byte]] {.async.} = + let onProve = proc (slot: Slot, challenge: ProofChallenge): Future[?!Groth16Proof] {.async.} = receivedChallenge = challenge return success(proof) let context = SalesContext( @@ -60,7 +60,7 @@ asyncchecksuite "sales state 'initialproving'": check receivedChallenge == market.proofChallenge test "switches to errored state when onProve callback fails": - let onProveFailed: OnProve = proc(slot: Slot, challenge: ProofChallenge): Future[?!seq[byte]] {.async.} = + let onProveFailed: OnProve = proc(slot: Slot, challenge: ProofChallenge): Future[?!Groth16Proof] {.async.} = return failure("oh no!") let proofFailedContext = SalesContext( diff --git a/tests/codex/sales/states/testproving.nim b/tests/codex/sales/states/testproving.nim index a14d3975..57966da7 100644 --- a/tests/codex/sales/states/testproving.nim +++ b/tests/codex/sales/states/testproving.nim @@ -18,7 +18,7 @@ asyncchecksuite "sales state 'proving'": let slot = Slot.example let request = slot.request - let proof = exampleProof() + let proof = Groth16Proof.example var market: MockMarket var clock: MockClock @@ -29,7 +29,7 @@ asyncchecksuite "sales state 'proving'": setup: clock = MockClock.new() market = MockMarket.new() - let onProve = proc (slot: Slot, challenge: ProofChallenge): Future[?!seq[byte]] {.async.} = + let onProve = proc (slot: Slot, challenge: ProofChallenge): Future[?!Groth16Proof] {.async.} = receivedChallenge = challenge return success(proof) let context = SalesContext(market: market, clock: clock, onProve: onProve.some) @@ -53,11 +53,9 @@ asyncchecksuite "sales state 'proving'": test "submits proofs": var receivedIds: seq[SlotId] - var receivedProofs: seq[seq[byte]] - proc onProofSubmission(id: SlotId, proof: seq[byte]) = + proc onProofSubmission(id: SlotId) = receivedIds.add(id) - receivedProofs.add(proof) let subscription = await market.subscribeProofSubmission(onProofSubmission) market.slotState[slot.id] = SlotState.Filled @@ -67,7 +65,7 @@ asyncchecksuite "sales state 'proving'": market.setProofRequired(slot.id, true) await market.advanceToNextPeriod() - check eventually receivedIds == @[slot.id] and receivedProofs == @[proof] + check eventually receivedIds == @[slot.id] await future.cancelAndWait() await subscription.unsubscribe() diff --git a/tests/codex/sales/states/testsimulatedproving.nim b/tests/codex/sales/states/testsimulatedproving.nim index e9efa617..4fde8ada 100644 --- a/tests/codex/sales/states/testsimulatedproving.nim +++ b/tests/codex/sales/states/testsimulatedproving.nim @@ -19,7 +19,7 @@ asyncchecksuite "sales state 'simulated-proving'": let slot = Slot.example let request = slot.request - let proof = exampleProof() + let proof = Groth16Proof.example let failEveryNProofs = 3 let totalProofs = 6 @@ -29,14 +29,12 @@ asyncchecksuite "sales state 'simulated-proving'": var state: SaleProvingSimulated var proofSubmitted: Future[void] = newFuture[void]("proofSubmitted") - var submitted: seq[seq[byte]] var subscription: Subscription setup: clock = MockClock.new() - proc onProofSubmission(id: SlotId, proof: seq[byte]) = - submitted.add(proof) + proc onProofSubmission(id: SlotId) = proofSubmitted.complete() proofSubmitted = newFuture[void]("proofSubmitted") @@ -45,7 +43,7 @@ asyncchecksuite "sales state 'simulated-proving'": market.setProofRequired(slot.id, true) subscription = await market.subscribeProofSubmission(onProofSubmission) - let onProve = proc (slot: Slot, challenge: ProofChallenge): Future[?!seq[byte]] {.async.} = + let onProve = proc (slot: Slot, challenge: ProofChallenge): Future[?!Groth16Proof] {.async.} = return success(proof) let context = SalesContext(market: market, clock: clock, onProve: onProve.some) agent = newSalesAgent(context, @@ -79,9 +77,10 @@ asyncchecksuite "sales state 'simulated-proving'": test "submits invalid proof every 3 proofs": let future = state.run(agent) + let invalid = Groth16Proof.default await market.waitForProvingRounds(totalProofs) - check submitted == @[proof, proof, @[], proof, proof, @[]] + check market.submitted == @[proof, proof, invalid, proof, proof, invalid] await future.cancelAndWait() diff --git a/tests/codex/sales/testsales.nim b/tests/codex/sales/testsales.nim index 5af97538..5f98e853 100644 --- a/tests/codex/sales/testsales.nim +++ b/tests/codex/sales/testsales.nim @@ -21,7 +21,7 @@ import ../helpers/always import ../examples asyncchecksuite "Sales - start": - let proof = exampleProof() + let proof = Groth16Proof.example var request: StorageRequest var sales: Sales @@ -64,7 +64,7 @@ asyncchecksuite "Sales - start": return success() queue = sales.context.slotQueue - sales.onProve = proc(slot: Slot, challenge: ProofChallenge): Future[?!seq[byte]] {.async.} = + sales.onProve = proc(slot: Slot, challenge: ProofChallenge): Future[?!Groth16Proof] {.async.} = return success(proof) itemsProcessed = @[] request.expiry = ((await clock.now()) + 42).u256 @@ -112,7 +112,7 @@ asyncchecksuite "Sales - start": check sales.agents.any(agent => agent.data.requestId == request.id and agent.data.slotIndex == 1.u256) asyncchecksuite "Sales": - let proof = exampleProof() + let proof = Groth16Proof.example var availability: Availability var request: StorageRequest @@ -167,7 +167,7 @@ asyncchecksuite "Sales": return success() queue = sales.context.slotQueue - sales.onProve = proc(slot: Slot, challenge: ProofChallenge): Future[?!seq[byte]] {.async.} = + sales.onProve = proc(slot: Slot, challenge: ProofChallenge): Future[?!Groth16Proof] {.async.} = return success(proof) await sales.start() itemsProcessed = @[] @@ -369,7 +369,7 @@ asyncchecksuite "Sales": test "handles errors during state run": var saleFailed = false - sales.onProve = proc(slot: Slot, challenge: ProofChallenge): Future[?!seq[byte]] {.async.} = + sales.onProve = proc(slot: Slot, challenge: ProofChallenge): Future[?!Groth16Proof] {.async.} = # raise exception so machine.onError is called raise newException(ValueError, "some error") @@ -394,10 +394,10 @@ asyncchecksuite "Sales": test "generates proof of storage": var provingRequest: StorageRequest var provingSlot: UInt256 - sales.onProve = proc(slot: Slot, challenge: ProofChallenge): Future[?!seq[byte]] {.async.} = + sales.onProve = proc(slot: Slot, challenge: ProofChallenge): Future[?!Groth16Proof] {.async.} = provingRequest = slot.request provingSlot = slot.slotIndex - return success(exampleProof()) + return success(Groth16Proof.example) createAvailability() await market.requestStorage(request) check eventually provingRequest == request @@ -427,7 +427,7 @@ asyncchecksuite "Sales": test "calls onClear when storage becomes available again": # fail the proof intentionally to trigger `agent.finish(success=false)`, # which then calls the onClear callback - sales.onProve = proc(slot: Slot, challenge: ProofChallenge): Future[?!seq[byte]] {.async.} = + sales.onProve = proc(slot: Slot, challenge: ProofChallenge): Future[?!Groth16Proof] {.async.} = raise newException(IOError, "proof failed") var clearedRequest: StorageRequest var clearedSlotIndex: UInt256 diff --git a/tests/codex/testvalidation.nim b/tests/codex/testvalidation.nim index 6786ecb0..df12f4cf 100644 --- a/tests/codex/testvalidation.nim +++ b/tests/codex/testvalidation.nim @@ -14,6 +14,7 @@ asyncchecksuite "validation": let timeout = 5 let maxSlots = 100 let slot = Slot.example + let proof = Groth16Proof.example let collateral = slot.request.ask.collateral var validation: Validation @@ -41,25 +42,25 @@ asyncchecksuite "validation": check validation.slots.len == 0 test "when a slot is filled on chain, it is added to the list": - await market.fillSlot(slot.request.id, slot.slotIndex, @[], collateral) + await market.fillSlot(slot.request.id, slot.slotIndex, proof, collateral) check validation.slots == @[slot.id] for state in [SlotState.Finished, SlotState.Failed]: test "when slot state changes, it is removed from the list": - await market.fillSlot(slot.request.id, slot.slotIndex, @[], collateral) + await market.fillSlot(slot.request.id, slot.slotIndex, proof, collateral) market.slotState[slot.id] = state advanceToNextPeriod() check eventually validation.slots.len == 0 test "when a proof is missed, it is marked as missing": - await market.fillSlot(slot.request.id, slot.slotIndex, @[], collateral) + await market.fillSlot(slot.request.id, slot.slotIndex, proof, collateral) market.setCanProofBeMarkedAsMissing(slot.id, true) advanceToNextPeriod() await sleepAsync(1.millis) check market.markedAsMissingProofs.contains(slot.id) test "when a proof can not be marked as missing, it will not be marked": - await market.fillSlot(slot.request.id, slot.slotIndex, @[], collateral) + await market.fillSlot(slot.request.id, slot.slotIndex, proof, collateral) market.setCanProofBeMarkedAsMissing(slot.id, false) advanceToNextPeriod() await sleepAsync(1.millis) @@ -68,5 +69,5 @@ asyncchecksuite "validation": test "it does not monitor more than the maximum number of slots": for _ in 0.. LogLevel.TRACE or enabledLogLevel == LogLevel.NONE): echo "" @@ -115,12 +115,12 @@ template multinodesuite*(name: string, "--bootstrap-node=" & bootstrap, "--persistence", "--simulate-proof-failures=" & $failEveryNProofs], - debugNodes.ethProvider) + debugNodes.provider) let restClient = newCodexClient(index) running.add RunningNode.new(Role.Provider, node, restClient, datadir, account) - if debugNodes.ethProvider: - debug "started new ethProvider node and codex client", + if debugNodes.provider: + debug "started new provider node and codex client", restApiPort = 8080 + index, discPort = 8090 + index, account proc startValidatorNode() = diff --git a/tests/integration/testproofs.nim b/tests/integration/testproofs.nim index 0af0572a..a3440f99 100644 --- a/tests/integration/testproofs.nim +++ b/tests/integration/testproofs.nim @@ -12,6 +12,11 @@ import ./multinodes logScope: topics = "test proofs" +# TODO: This is currently the address of the marketplace with a dummy +# verifier. Use real marketplace address once we can generate actual +# Groth16 ZK proofs. +let marketplaceAddress = Marketplace.address(dummyVerifier = true) + twonodessuite "Proving integration test", debug1=false, debug2=false: let validatorDir = getTempDir() / "CodexValidator" @@ -22,7 +27,7 @@ twonodessuite "Proving integration test", debug1=false, debug2=false: client.getPurchase(id).option.?state == some state setup: - marketplace = Marketplace.new(Marketplace.address, ethProvider) + marketplace = Marketplace.new(marketplaceAddress, ethProvider) period = (await marketplace.config()).proofs.period.truncate(uint64) # Our Hardhat configuration does use automine, which means that time tracked by `ethProvider.currentTime()` is not @@ -110,7 +115,7 @@ twonodessuite "Proving integration test", debug1=false, debug2=false: multinodesuite "Simulate invalid proofs", StartNodes.init(clients=1'u, providers=0'u, validators=1'u), - DebugNodes.init(client=false, ethProvider=false, validator=false): + DebugNodes.init(client=false, provider=false, validator=false): proc purchaseStateIs(client: CodexClient, id: PurchaseId, state: string): bool = client.getPurchase(id).option.?state == some state @@ -120,7 +125,7 @@ multinodesuite "Simulate invalid proofs", var slotId: SlotId setup: - marketplace = Marketplace.new(Marketplace.address, ethProvider) + marketplace = Marketplace.new(marketplaceAddress, ethProvider) let config = await marketplace.config() period = config.proofs.period.truncate(uint64) slotId = SlotId(array[32, byte].default) # ensure we aren't reusing from prev test diff --git a/vendor/codex-contracts-eth b/vendor/codex-contracts-eth index b5f33992..6c9f797f 160000 --- a/vendor/codex-contracts-eth +++ b/vendor/codex-contracts-eth @@ -1 +1 @@ -Subproject commit b5f33992b67df3733042a7d912c854700e8c863c +Subproject commit 6c9f797f408608958714024b9055fcc330e3842f