Smart contracts update: Groth16Proof instead of bytes (#683)
* 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íř <adam@uhlir.dev>
This commit is contained in:
parent
403b9baf9f
commit
2cf892c467
|
@ -17,13 +17,15 @@ type
|
||||||
period*: UInt256 # proofs requirements are calculated per period (in seconds)
|
period*: UInt256 # proofs requirements are calculated per period (in seconds)
|
||||||
timeout*: UInt256 # mark proofs as missing before the timeout (in seconds)
|
timeout*: UInt256 # mark proofs as missing before the timeout (in seconds)
|
||||||
downtime*: uint8 # ignore this much recent blocks for proof requirements
|
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 =
|
func fromTuple(_: type ProofConfig, tupl: tuple): ProofConfig =
|
||||||
ProofConfig(
|
ProofConfig(
|
||||||
period: tupl[0],
|
period: tupl[0],
|
||||||
timeout: tupl[1],
|
timeout: tupl[1],
|
||||||
downtime: tupl[2]
|
downtime: tupl[2],
|
||||||
|
zkeyHash: tupl[3]
|
||||||
)
|
)
|
||||||
|
|
||||||
func fromTuple(_: type CollateralConfig, tupl: tuple): CollateralConfig =
|
func fromTuple(_: type CollateralConfig, tupl: tuple): CollateralConfig =
|
||||||
|
|
|
@ -14,7 +14,10 @@ type Deployment* = ref object
|
||||||
const knownAddresses = {
|
const knownAddresses = {
|
||||||
# Hardhat localhost network
|
# Hardhat localhost network
|
||||||
"31337": {
|
"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,
|
}.toTable,
|
||||||
# Taiko Alpha-3 Testnet
|
# Taiko Alpha-3 Testnet
|
||||||
"167005": {
|
"167005": {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import pkg/questionable
|
||||||
import ../logutils
|
import ../logutils
|
||||||
import ../market
|
import ../market
|
||||||
import ./marketplace
|
import ./marketplace
|
||||||
|
import ./proofs
|
||||||
|
|
||||||
export market
|
export market
|
||||||
|
|
||||||
|
@ -38,6 +39,10 @@ proc approveFunds(market: OnChainMarket, amount: UInt256) {.async.} =
|
||||||
|
|
||||||
discard await token.increaseAllowance(market.contract.address(), amount).confirm(1)
|
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.} =
|
method getSigner*(market: OnChainMarket): Future[Address] {.async.} =
|
||||||
return await market.signer.getAddress()
|
return await market.signer.getAddress()
|
||||||
|
|
||||||
|
@ -120,7 +125,7 @@ method getActiveSlot*(market: OnChainMarket,
|
||||||
method fillSlot(market: OnChainMarket,
|
method fillSlot(market: OnChainMarket,
|
||||||
requestId: RequestId,
|
requestId: RequestId,
|
||||||
slotIndex: UInt256,
|
slotIndex: UInt256,
|
||||||
proof: seq[byte],
|
proof: Groth16Proof,
|
||||||
collateral: UInt256) {.async.} =
|
collateral: UInt256) {.async.} =
|
||||||
await market.approveFunds(collateral)
|
await market.approveFunds(collateral)
|
||||||
await market.contract.fillSlot(requestId, slotIndex, proof)
|
await market.contract.fillSlot(requestId, slotIndex, proof)
|
||||||
|
@ -155,7 +160,7 @@ method getChallenge*(market: OnChainMarket, id: SlotId): Future[ProofChallenge]
|
||||||
|
|
||||||
method submitProof*(market: OnChainMarket,
|
method submitProof*(market: OnChainMarket,
|
||||||
id: SlotId,
|
id: SlotId,
|
||||||
proof: seq[byte]) {.async.} =
|
proof: Groth16Proof) {.async.} =
|
||||||
await market.contract.submitProof(id, proof)
|
await market.contract.submitProof(id, proof)
|
||||||
|
|
||||||
method markProofAsMissing*(market: OnChainMarket,
|
method markProofAsMissing*(market: OnChainMarket,
|
||||||
|
@ -272,7 +277,7 @@ method subscribeProofSubmission*(market: OnChainMarket,
|
||||||
callback: OnProofSubmitted):
|
callback: OnProofSubmitted):
|
||||||
Future[MarketSubscription] {.async.} =
|
Future[MarketSubscription] {.async.} =
|
||||||
proc onEvent(event: ProofSubmitted) {.upraises: [].} =
|
proc onEvent(event: ProofSubmitted) {.upraises: [].} =
|
||||||
callback(event.id, event.proof)
|
callback(event.id)
|
||||||
let subscription = await market.contract.subscribe(ProofSubmitted, onEvent)
|
let subscription = await market.contract.subscribe(ProofSubmitted, onEvent)
|
||||||
return OnChainMarketSubscription(eventSubscription: subscription)
|
return OnChainMarketSubscription(eventSubscription: subscription)
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import pkg/stint
|
||||||
import pkg/chronos
|
import pkg/chronos
|
||||||
import ../clock
|
import ../clock
|
||||||
import ./requests
|
import ./requests
|
||||||
|
import ./proofs
|
||||||
import ./config
|
import ./config
|
||||||
|
|
||||||
export stint
|
export stint
|
||||||
|
@ -33,7 +34,6 @@ type
|
||||||
requestId* {.indexed.}: RequestId
|
requestId* {.indexed.}: RequestId
|
||||||
ProofSubmitted* = object of Event
|
ProofSubmitted* = object of Event
|
||||||
id*: SlotId
|
id*: SlotId
|
||||||
proof*: seq[byte]
|
|
||||||
|
|
||||||
|
|
||||||
proc config*(marketplace: Marketplace): MarketplaceConfig {.contract, view.}
|
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 minCollateralThreshold*(marketplace: Marketplace): UInt256 {.contract, view.}
|
||||||
|
|
||||||
proc requestStorage*(marketplace: Marketplace, request: StorageRequest) {.contract.}
|
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 withdrawFunds*(marketplace: Marketplace, requestId: RequestId) {.contract.}
|
||||||
proc freeSlot*(marketplace: Marketplace, id: SlotId) {.contract.}
|
proc freeSlot*(marketplace: Marketplace, id: SlotId) {.contract.}
|
||||||
proc getRequest*(marketplace: Marketplace, id: RequestId): StorageRequest {.contract, view.}
|
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 getChallenge*(marketplace: Marketplace, id: SlotId): array[32, byte] {.contract, view.}
|
||||||
proc getPointer*(marketplace: Marketplace, id: SlotId): uint8 {.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.}
|
proc markProofAsMissing*(marketplace: Marketplace, id: SlotId, period: UInt256) {.contract.}
|
||||||
|
|
|
@ -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)
|
|
@ -3,12 +3,14 @@ import pkg/upraises
|
||||||
import pkg/questionable
|
import pkg/questionable
|
||||||
import pkg/ethers/erc20
|
import pkg/ethers/erc20
|
||||||
import ./contracts/requests
|
import ./contracts/requests
|
||||||
|
import ./contracts/proofs
|
||||||
import ./clock
|
import ./clock
|
||||||
import ./periods
|
import ./periods
|
||||||
|
|
||||||
export chronos
|
export chronos
|
||||||
export questionable
|
export questionable
|
||||||
export requests
|
export requests
|
||||||
|
export proofs
|
||||||
export SecondsSince1970
|
export SecondsSince1970
|
||||||
export periods
|
export periods
|
||||||
|
|
||||||
|
@ -23,13 +25,16 @@ type
|
||||||
OnSlotFreed* = proc(requestId: RequestId, slotIndex: UInt256) {.gcsafe, upraises: [].}
|
OnSlotFreed* = proc(requestId: RequestId, slotIndex: UInt256) {.gcsafe, upraises: [].}
|
||||||
OnRequestCancelled* = proc(requestId: RequestId) {.gcsafe, upraises:[].}
|
OnRequestCancelled* = proc(requestId: RequestId) {.gcsafe, upraises:[].}
|
||||||
OnRequestFailed* = 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
|
PastStorageRequest* = object
|
||||||
requestId*: RequestId
|
requestId*: RequestId
|
||||||
ask*: StorageAsk
|
ask*: StorageAsk
|
||||||
expiry*: UInt256
|
expiry*: UInt256
|
||||||
ProofChallenge* = array[32, byte]
|
ProofChallenge* = array[32, byte]
|
||||||
|
|
||||||
|
method getZkeyHash*(market: Market): Future[?string] {.base, async.} =
|
||||||
|
raiseAssert("not implemented")
|
||||||
|
|
||||||
method getSigner*(market: Market): Future[Address] {.base, async.} =
|
method getSigner*(market: Market): Future[Address] {.base, async.} =
|
||||||
raiseAssert("not implemented")
|
raiseAssert("not implemented")
|
||||||
|
|
||||||
|
@ -91,7 +96,7 @@ method getActiveSlot*(
|
||||||
method fillSlot*(market: Market,
|
method fillSlot*(market: Market,
|
||||||
requestId: RequestId,
|
requestId: RequestId,
|
||||||
slotIndex: UInt256,
|
slotIndex: UInt256,
|
||||||
proof: seq[byte],
|
proof: Groth16Proof,
|
||||||
collateral: UInt256) {.base, async.} =
|
collateral: UInt256) {.base, async.} =
|
||||||
raiseAssert("not implemented")
|
raiseAssert("not implemented")
|
||||||
|
|
||||||
|
@ -120,7 +125,7 @@ method getChallenge*(market: Market, id: SlotId): Future[ProofChallenge] {.base,
|
||||||
|
|
||||||
method submitProof*(market: Market,
|
method submitProof*(market: Market,
|
||||||
id: SlotId,
|
id: SlotId,
|
||||||
proof: seq[byte]) {.base, async.} =
|
proof: Groth16Proof) {.base, async.} =
|
||||||
raiseAssert("not implemented")
|
raiseAssert("not implemented")
|
||||||
|
|
||||||
method markProofAsMissing*(market: Market,
|
method markProofAsMissing*(market: Market,
|
||||||
|
|
|
@ -549,7 +549,7 @@ proc onStore(
|
||||||
proc onProve(
|
proc onProve(
|
||||||
self: CodexNodeRef,
|
self: CodexNodeRef,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
challenge: ProofChallenge): Future[?!seq[byte]] {.async.} =
|
challenge: ProofChallenge): Future[?!Groth16Proof] {.async.} =
|
||||||
## Generats a proof for a given slot and challenge
|
## Generats a proof for a given slot and challenge
|
||||||
##
|
##
|
||||||
|
|
||||||
|
@ -585,7 +585,12 @@ proc onProve(
|
||||||
return failure(err)
|
return failure(err)
|
||||||
|
|
||||||
# Todo: send proofInput to circuit. Get proof. (Profit, repeat.)
|
# 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(
|
proc onExpiryUpdate(
|
||||||
self: CodexNodeRef,
|
self: CodexNodeRef,
|
||||||
|
@ -635,7 +640,7 @@ proc start*(self: CodexNodeRef) {.async.} =
|
||||||
self.onClear(request, slotIndex)
|
self.onClear(request, slotIndex)
|
||||||
|
|
||||||
hostContracts.sales.onProve =
|
hostContracts.sales.onProve =
|
||||||
proc(slot: Slot, challenge: ProofChallenge): Future[?!seq[byte]] =
|
proc(slot: Slot, challenge: ProofChallenge): Future[?!Groth16Proof] =
|
||||||
# TODO: generate proof
|
# TODO: generate proof
|
||||||
self.onProve(slot, challenge)
|
self.onProve(slot, challenge)
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ type
|
||||||
OnStore* = proc(request: StorageRequest,
|
OnStore* = proc(request: StorageRequest,
|
||||||
slot: UInt256,
|
slot: UInt256,
|
||||||
blocksCb: BlocksCb): Future[?!void] {.gcsafe, upraises: [].}
|
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: [].}
|
OnExpiryUpdate* = proc(rootCid: string, expiry: SecondsSince1970): Future[?!void] {.gcsafe, upraises: [].}
|
||||||
OnClear* = proc(request: StorageRequest,
|
OnClear* = proc(request: StorageRequest,
|
||||||
slotIndex: UInt256) {.gcsafe, upraises: [].}
|
slotIndex: UInt256) {.gcsafe, upraises: [].}
|
||||||
|
|
|
@ -12,7 +12,7 @@ logScope:
|
||||||
|
|
||||||
type
|
type
|
||||||
SaleFilling* = ref object of ErrorHandlingState
|
SaleFilling* = ref object of ErrorHandlingState
|
||||||
proof*: seq[byte]
|
proof*: Groth16Proof
|
||||||
|
|
||||||
method `$`*(state: SaleFilling): string = "SaleFilling"
|
method `$`*(state: SaleFilling): string = "SaleFilling"
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import std/options
|
||||||
import pkg/questionable/results
|
import pkg/questionable/results
|
||||||
import ../../clock
|
import ../../clock
|
||||||
import ../../logutils
|
import ../../logutils
|
||||||
|
import ../../utils/exceptions
|
||||||
import ../statemachine
|
import ../statemachine
|
||||||
import ../salesagent
|
import ../salesagent
|
||||||
import ../salescontext
|
import ../salescontext
|
||||||
|
@ -35,7 +36,7 @@ method prove*(
|
||||||
debug "Submitting proof", currentPeriod = currentPeriod, slotId = slot.id
|
debug "Submitting proof", currentPeriod = currentPeriod, slotId = slot.id
|
||||||
await market.submitProof(slot.id, proof)
|
await market.submitProof(slot.id, proof)
|
||||||
except CatchableError as e:
|
except CatchableError as e:
|
||||||
error "Submitting proof failed", msg = e.msg
|
error "Submitting proof failed", msg = e.msgDetail
|
||||||
|
|
||||||
proc proveLoop(
|
proc proveLoop(
|
||||||
state: SaleProving,
|
state: SaleProving,
|
||||||
|
|
|
@ -31,7 +31,7 @@ when codex_enable_proof_failures:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
warn "Submitting INVALID proof", period = currentPeriod, slotId = slot.id
|
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:
|
except ProviderError as e:
|
||||||
if not e.revertReason.contains("Invalid proof"):
|
if not e.revertReason.contains("Invalid proof"):
|
||||||
onSubmitProofError(e, currentPeriod, slot.id)
|
onSubmitProofError(e, currentPeriod, slot.id)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import std/sugar
|
||||||
import pkg/questionable
|
import pkg/questionable
|
||||||
import pkg/codex/market
|
import pkg/codex/market
|
||||||
import pkg/codex/contracts/requests
|
import pkg/codex/contracts/requests
|
||||||
|
import pkg/codex/contracts/proofs
|
||||||
import pkg/codex/contracts/config
|
import pkg/codex/contracts/config
|
||||||
import ../examples
|
import ../examples
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@ type
|
||||||
fulfilled*: seq[Fulfillment]
|
fulfilled*: seq[Fulfillment]
|
||||||
filled*: seq[MockSlot]
|
filled*: seq[MockSlot]
|
||||||
freed*: seq[SlotId]
|
freed*: seq[SlotId]
|
||||||
|
submitted*: seq[Groth16Proof]
|
||||||
markedAsMissingProofs*: seq[SlotId]
|
markedAsMissingProofs*: seq[SlotId]
|
||||||
canBeMarkedAsMissing: HashSet[SlotId]
|
canBeMarkedAsMissing: HashSet[SlotId]
|
||||||
withdrawn*: seq[RequestId]
|
withdrawn*: seq[RequestId]
|
||||||
|
@ -36,13 +38,13 @@ type
|
||||||
config*: MarketplaceConfig
|
config*: MarketplaceConfig
|
||||||
Fulfillment* = object
|
Fulfillment* = object
|
||||||
requestId*: RequestId
|
requestId*: RequestId
|
||||||
proof*: seq[byte]
|
proof*: Groth16Proof
|
||||||
host*: Address
|
host*: Address
|
||||||
MockSlot* = object
|
MockSlot* = object
|
||||||
requestId*: RequestId
|
requestId*: RequestId
|
||||||
host*: Address
|
host*: Address
|
||||||
slotIndex*: UInt256
|
slotIndex*: UInt256
|
||||||
proof*: seq[byte]
|
proof*: Groth16Proof
|
||||||
Subscriptions = object
|
Subscriptions = object
|
||||||
onRequest: seq[RequestSubscription]
|
onRequest: seq[RequestSubscription]
|
||||||
onFulfillment: seq[FulfillmentSubscription]
|
onFulfillment: seq[FulfillmentSubscription]
|
||||||
|
@ -215,7 +217,7 @@ proc emitRequestFailed*(market: MockMarket, requestId: RequestId) =
|
||||||
proc fillSlot*(market: MockMarket,
|
proc fillSlot*(market: MockMarket,
|
||||||
requestId: RequestId,
|
requestId: RequestId,
|
||||||
slotIndex: UInt256,
|
slotIndex: UInt256,
|
||||||
proof: seq[byte],
|
proof: Groth16Proof,
|
||||||
host: Address) =
|
host: Address) =
|
||||||
let slot = MockSlot(
|
let slot = MockSlot(
|
||||||
requestId: requestId,
|
requestId: requestId,
|
||||||
|
@ -230,7 +232,7 @@ proc fillSlot*(market: MockMarket,
|
||||||
method fillSlot*(market: MockMarket,
|
method fillSlot*(market: MockMarket,
|
||||||
requestId: RequestId,
|
requestId: RequestId,
|
||||||
slotIndex: UInt256,
|
slotIndex: UInt256,
|
||||||
proof: seq[byte],
|
proof: Groth16Proof,
|
||||||
collateral: UInt256) {.async.} =
|
collateral: UInt256) {.async.} =
|
||||||
market.fillSlot(requestId, slotIndex, proof, market.signer)
|
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) =
|
proc setProofEnd*(mock: MockMarket, id: SlotId, proofEnd: UInt256) =
|
||||||
mock.proofEnds[id] = proofEnd
|
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:
|
for subscription in mock.subscriptions.onProofSubmitted:
|
||||||
subscription.callback(id, proof)
|
subscription.callback(id)
|
||||||
|
|
||||||
method markProofAsMissing*(market: MockMarket,
|
method markProofAsMissing*(market: MockMarket,
|
||||||
id: SlotId,
|
id: SlotId,
|
||||||
|
|
|
@ -31,7 +31,7 @@ checksuite "sales state 'filled'":
|
||||||
slot = MockSlot(requestId: request.id,
|
slot = MockSlot(requestId: request.id,
|
||||||
host: Address.example,
|
host: Address.example,
|
||||||
slotIndex: slotIndex,
|
slotIndex: slotIndex,
|
||||||
proof: @[])
|
proof: Groth16Proof.default)
|
||||||
|
|
||||||
market.requestEnds[request.id] = 321
|
market.requestEnds[request.id] = 321
|
||||||
onExpiryUpdatePassedExpiry = -1
|
onExpiryUpdatePassedExpiry = -1
|
||||||
|
|
|
@ -16,7 +16,7 @@ import ../../helpers
|
||||||
import ../../helpers/mockmarket
|
import ../../helpers/mockmarket
|
||||||
|
|
||||||
asyncchecksuite "sales state 'initialproving'":
|
asyncchecksuite "sales state 'initialproving'":
|
||||||
let proof = exampleProof()
|
let proof = Groth16Proof.example
|
||||||
let request = StorageRequest.example
|
let request = StorageRequest.example
|
||||||
let slotIndex = (request.ask.slots div 2).u256
|
let slotIndex = (request.ask.slots div 2).u256
|
||||||
let market = MockMarket.new()
|
let market = MockMarket.new()
|
||||||
|
@ -26,7 +26,7 @@ asyncchecksuite "sales state 'initialproving'":
|
||||||
var receivedChallenge: ProofChallenge
|
var receivedChallenge: ProofChallenge
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
let onProve = proc (slot: Slot, challenge: ProofChallenge): Future[?!seq[byte]] {.async.} =
|
let onProve = proc (slot: Slot, challenge: ProofChallenge): Future[?!Groth16Proof] {.async.} =
|
||||||
receivedChallenge = challenge
|
receivedChallenge = challenge
|
||||||
return success(proof)
|
return success(proof)
|
||||||
let context = SalesContext(
|
let context = SalesContext(
|
||||||
|
@ -60,7 +60,7 @@ asyncchecksuite "sales state 'initialproving'":
|
||||||
check receivedChallenge == market.proofChallenge
|
check receivedChallenge == market.proofChallenge
|
||||||
|
|
||||||
test "switches to errored state when onProve callback fails":
|
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!")
|
return failure("oh no!")
|
||||||
|
|
||||||
let proofFailedContext = SalesContext(
|
let proofFailedContext = SalesContext(
|
||||||
|
|
|
@ -18,7 +18,7 @@ asyncchecksuite "sales state 'proving'":
|
||||||
|
|
||||||
let slot = Slot.example
|
let slot = Slot.example
|
||||||
let request = slot.request
|
let request = slot.request
|
||||||
let proof = exampleProof()
|
let proof = Groth16Proof.example
|
||||||
|
|
||||||
var market: MockMarket
|
var market: MockMarket
|
||||||
var clock: MockClock
|
var clock: MockClock
|
||||||
|
@ -29,7 +29,7 @@ asyncchecksuite "sales state 'proving'":
|
||||||
setup:
|
setup:
|
||||||
clock = MockClock.new()
|
clock = MockClock.new()
|
||||||
market = MockMarket.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
|
receivedChallenge = challenge
|
||||||
return success(proof)
|
return success(proof)
|
||||||
let context = SalesContext(market: market, clock: clock, onProve: onProve.some)
|
let context = SalesContext(market: market, clock: clock, onProve: onProve.some)
|
||||||
|
@ -53,11 +53,9 @@ asyncchecksuite "sales state 'proving'":
|
||||||
|
|
||||||
test "submits proofs":
|
test "submits proofs":
|
||||||
var receivedIds: seq[SlotId]
|
var receivedIds: seq[SlotId]
|
||||||
var receivedProofs: seq[seq[byte]]
|
|
||||||
|
|
||||||
proc onProofSubmission(id: SlotId, proof: seq[byte]) =
|
proc onProofSubmission(id: SlotId) =
|
||||||
receivedIds.add(id)
|
receivedIds.add(id)
|
||||||
receivedProofs.add(proof)
|
|
||||||
|
|
||||||
let subscription = await market.subscribeProofSubmission(onProofSubmission)
|
let subscription = await market.subscribeProofSubmission(onProofSubmission)
|
||||||
market.slotState[slot.id] = SlotState.Filled
|
market.slotState[slot.id] = SlotState.Filled
|
||||||
|
@ -67,7 +65,7 @@ asyncchecksuite "sales state 'proving'":
|
||||||
market.setProofRequired(slot.id, true)
|
market.setProofRequired(slot.id, true)
|
||||||
await market.advanceToNextPeriod()
|
await market.advanceToNextPeriod()
|
||||||
|
|
||||||
check eventually receivedIds == @[slot.id] and receivedProofs == @[proof]
|
check eventually receivedIds == @[slot.id]
|
||||||
|
|
||||||
await future.cancelAndWait()
|
await future.cancelAndWait()
|
||||||
await subscription.unsubscribe()
|
await subscription.unsubscribe()
|
||||||
|
|
|
@ -19,7 +19,7 @@ asyncchecksuite "sales state 'simulated-proving'":
|
||||||
|
|
||||||
let slot = Slot.example
|
let slot = Slot.example
|
||||||
let request = slot.request
|
let request = slot.request
|
||||||
let proof = exampleProof()
|
let proof = Groth16Proof.example
|
||||||
let failEveryNProofs = 3
|
let failEveryNProofs = 3
|
||||||
let totalProofs = 6
|
let totalProofs = 6
|
||||||
|
|
||||||
|
@ -29,14 +29,12 @@ asyncchecksuite "sales state 'simulated-proving'":
|
||||||
var state: SaleProvingSimulated
|
var state: SaleProvingSimulated
|
||||||
|
|
||||||
var proofSubmitted: Future[void] = newFuture[void]("proofSubmitted")
|
var proofSubmitted: Future[void] = newFuture[void]("proofSubmitted")
|
||||||
var submitted: seq[seq[byte]]
|
|
||||||
var subscription: Subscription
|
var subscription: Subscription
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
clock = MockClock.new()
|
clock = MockClock.new()
|
||||||
|
|
||||||
proc onProofSubmission(id: SlotId, proof: seq[byte]) =
|
proc onProofSubmission(id: SlotId) =
|
||||||
submitted.add(proof)
|
|
||||||
proofSubmitted.complete()
|
proofSubmitted.complete()
|
||||||
proofSubmitted = newFuture[void]("proofSubmitted")
|
proofSubmitted = newFuture[void]("proofSubmitted")
|
||||||
|
|
||||||
|
@ -45,7 +43,7 @@ asyncchecksuite "sales state 'simulated-proving'":
|
||||||
market.setProofRequired(slot.id, true)
|
market.setProofRequired(slot.id, true)
|
||||||
subscription = await market.subscribeProofSubmission(onProofSubmission)
|
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)
|
return success(proof)
|
||||||
let context = SalesContext(market: market, clock: clock, onProve: onProve.some)
|
let context = SalesContext(market: market, clock: clock, onProve: onProve.some)
|
||||||
agent = newSalesAgent(context,
|
agent = newSalesAgent(context,
|
||||||
|
@ -79,9 +77,10 @@ asyncchecksuite "sales state 'simulated-proving'":
|
||||||
|
|
||||||
test "submits invalid proof every 3 proofs":
|
test "submits invalid proof every 3 proofs":
|
||||||
let future = state.run(agent)
|
let future = state.run(agent)
|
||||||
|
let invalid = Groth16Proof.default
|
||||||
|
|
||||||
await market.waitForProvingRounds(totalProofs)
|
await market.waitForProvingRounds(totalProofs)
|
||||||
check submitted == @[proof, proof, @[], proof, proof, @[]]
|
check market.submitted == @[proof, proof, invalid, proof, proof, invalid]
|
||||||
|
|
||||||
await future.cancelAndWait()
|
await future.cancelAndWait()
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ import ../helpers/always
|
||||||
import ../examples
|
import ../examples
|
||||||
|
|
||||||
asyncchecksuite "Sales - start":
|
asyncchecksuite "Sales - start":
|
||||||
let proof = exampleProof()
|
let proof = Groth16Proof.example
|
||||||
|
|
||||||
var request: StorageRequest
|
var request: StorageRequest
|
||||||
var sales: Sales
|
var sales: Sales
|
||||||
|
@ -64,7 +64,7 @@ asyncchecksuite "Sales - start":
|
||||||
return success()
|
return success()
|
||||||
|
|
||||||
queue = sales.context.slotQueue
|
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)
|
return success(proof)
|
||||||
itemsProcessed = @[]
|
itemsProcessed = @[]
|
||||||
request.expiry = ((await clock.now()) + 42).u256
|
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)
|
check sales.agents.any(agent => agent.data.requestId == request.id and agent.data.slotIndex == 1.u256)
|
||||||
|
|
||||||
asyncchecksuite "Sales":
|
asyncchecksuite "Sales":
|
||||||
let proof = exampleProof()
|
let proof = Groth16Proof.example
|
||||||
|
|
||||||
var availability: Availability
|
var availability: Availability
|
||||||
var request: StorageRequest
|
var request: StorageRequest
|
||||||
|
@ -167,7 +167,7 @@ asyncchecksuite "Sales":
|
||||||
return success()
|
return success()
|
||||||
|
|
||||||
queue = sales.context.slotQueue
|
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)
|
return success(proof)
|
||||||
await sales.start()
|
await sales.start()
|
||||||
itemsProcessed = @[]
|
itemsProcessed = @[]
|
||||||
|
@ -369,7 +369,7 @@ asyncchecksuite "Sales":
|
||||||
|
|
||||||
test "handles errors during state run":
|
test "handles errors during state run":
|
||||||
var saleFailed = false
|
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 exception so machine.onError is called
|
||||||
raise newException(ValueError, "some error")
|
raise newException(ValueError, "some error")
|
||||||
|
|
||||||
|
@ -394,10 +394,10 @@ asyncchecksuite "Sales":
|
||||||
test "generates proof of storage":
|
test "generates proof of storage":
|
||||||
var provingRequest: StorageRequest
|
var provingRequest: StorageRequest
|
||||||
var provingSlot: UInt256
|
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
|
provingRequest = slot.request
|
||||||
provingSlot = slot.slotIndex
|
provingSlot = slot.slotIndex
|
||||||
return success(exampleProof())
|
return success(Groth16Proof.example)
|
||||||
createAvailability()
|
createAvailability()
|
||||||
await market.requestStorage(request)
|
await market.requestStorage(request)
|
||||||
check eventually provingRequest == request
|
check eventually provingRequest == request
|
||||||
|
@ -427,7 +427,7 @@ asyncchecksuite "Sales":
|
||||||
test "calls onClear when storage becomes available again":
|
test "calls onClear when storage becomes available again":
|
||||||
# fail the proof intentionally to trigger `agent.finish(success=false)`,
|
# fail the proof intentionally to trigger `agent.finish(success=false)`,
|
||||||
# which then calls the onClear callback
|
# 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")
|
raise newException(IOError, "proof failed")
|
||||||
var clearedRequest: StorageRequest
|
var clearedRequest: StorageRequest
|
||||||
var clearedSlotIndex: UInt256
|
var clearedSlotIndex: UInt256
|
||||||
|
|
|
@ -14,6 +14,7 @@ asyncchecksuite "validation":
|
||||||
let timeout = 5
|
let timeout = 5
|
||||||
let maxSlots = 100
|
let maxSlots = 100
|
||||||
let slot = Slot.example
|
let slot = Slot.example
|
||||||
|
let proof = Groth16Proof.example
|
||||||
let collateral = slot.request.ask.collateral
|
let collateral = slot.request.ask.collateral
|
||||||
|
|
||||||
var validation: Validation
|
var validation: Validation
|
||||||
|
@ -41,25 +42,25 @@ asyncchecksuite "validation":
|
||||||
check validation.slots.len == 0
|
check validation.slots.len == 0
|
||||||
|
|
||||||
test "when a slot is filled on chain, it is added to the list":
|
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]
|
check validation.slots == @[slot.id]
|
||||||
|
|
||||||
for state in [SlotState.Finished, SlotState.Failed]:
|
for state in [SlotState.Finished, SlotState.Failed]:
|
||||||
test "when slot state changes, it is removed from the list":
|
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
|
market.slotState[slot.id] = state
|
||||||
advanceToNextPeriod()
|
advanceToNextPeriod()
|
||||||
check eventually validation.slots.len == 0
|
check eventually validation.slots.len == 0
|
||||||
|
|
||||||
test "when a proof is missed, it is marked as missing":
|
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)
|
market.setCanProofBeMarkedAsMissing(slot.id, true)
|
||||||
advanceToNextPeriod()
|
advanceToNextPeriod()
|
||||||
await sleepAsync(1.millis)
|
await sleepAsync(1.millis)
|
||||||
check market.markedAsMissingProofs.contains(slot.id)
|
check market.markedAsMissingProofs.contains(slot.id)
|
||||||
|
|
||||||
test "when a proof can not be marked as missing, it will not be marked":
|
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)
|
market.setCanProofBeMarkedAsMissing(slot.id, false)
|
||||||
advanceToNextPeriod()
|
advanceToNextPeriod()
|
||||||
await sleepAsync(1.millis)
|
await sleepAsync(1.millis)
|
||||||
|
@ -68,5 +69,5 @@ asyncchecksuite "validation":
|
||||||
test "it does not monitor more than the maximum number of slots":
|
test "it does not monitor more than the maximum number of slots":
|
||||||
for _ in 0..<maxSlots + 1:
|
for _ in 0..<maxSlots + 1:
|
||||||
let slot = Slot.example
|
let slot = Slot.example
|
||||||
await market.fillSlot(slot.request.id, slot.slotIndex, @[], collateral)
|
await market.fillSlot(slot.request.id, slot.slotIndex, proof, collateral)
|
||||||
check validation.slots.len == maxSlots
|
check validation.slots.len == maxSlots
|
||||||
|
|
|
@ -3,15 +3,21 @@ import std/options
|
||||||
import pkg/ethers
|
import pkg/ethers
|
||||||
import pkg/codex/contracts/marketplace
|
import pkg/codex/contracts/marketplace
|
||||||
|
|
||||||
const hardhatMarketAddress = Address.init("0x59b670e9fA9D0A427751Af201D676719a970857b").get()
|
const hardhatMarketAddress =
|
||||||
|
Address.init("0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44").get()
|
||||||
|
const hardhatMarketWithDummyVerifier =
|
||||||
|
Address.init("0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f").get()
|
||||||
const marketAddressEnvName = "CODEX_MARKET_ADDRESS"
|
const marketAddressEnvName = "CODEX_MARKET_ADDRESS"
|
||||||
|
|
||||||
proc address*(_: type Marketplace): Address =
|
proc address*(_: type Marketplace, dummyVerifier = false): Address =
|
||||||
if existsEnv(marketAddressEnvName):
|
if existsEnv(marketAddressEnvName):
|
||||||
without address =? Address.init(getEnv(marketAddressEnvName)):
|
without address =? Address.init(getEnv(marketAddressEnvName)):
|
||||||
raiseAssert "Invalid env. variable marketplace contract address"
|
raiseAssert "Invalid env. variable marketplace contract address"
|
||||||
|
|
||||||
return address
|
return address
|
||||||
|
|
||||||
hardhatMarketAddress
|
if dummyVerifier:
|
||||||
|
hardhatMarketWithDummyVerifier
|
||||||
|
else:
|
||||||
|
hardhatMarketAddress
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import ./time
|
||||||
import ./deployment
|
import ./deployment
|
||||||
|
|
||||||
ethersuite "Marketplace contracts":
|
ethersuite "Marketplace contracts":
|
||||||
let proof = exampleProof()
|
let proof = Groth16Proof.example
|
||||||
|
|
||||||
var client, host: Signer
|
var client, host: Signer
|
||||||
var marketplace: Marketplace
|
var marketplace: Marketplace
|
||||||
|
@ -25,7 +25,8 @@ ethersuite "Marketplace contracts":
|
||||||
client = ethProvider.getSigner(accounts[0])
|
client = ethProvider.getSigner(accounts[0])
|
||||||
host = ethProvider.getSigner(accounts[1])
|
host = ethProvider.getSigner(accounts[1])
|
||||||
|
|
||||||
marketplace = Marketplace.new(Marketplace.address, ethProvider.getSigner())
|
let address = Marketplace.address(dummyVerifier = true)
|
||||||
|
marketplace = Marketplace.new(address, ethProvider.getSigner())
|
||||||
|
|
||||||
let tokenAddress = await marketplace.token()
|
let tokenAddress = await marketplace.token()
|
||||||
token = Erc20Token.new(tokenAddress, ethProvider.getSigner())
|
token = Erc20Token.new(tokenAddress, ethProvider.getSigner())
|
||||||
|
|
|
@ -31,11 +31,11 @@ asyncchecksuite "Deployment":
|
||||||
|
|
||||||
test "uses chainId hardcoded values as fallback":
|
test "uses chainId hardcoded values as fallback":
|
||||||
let deployment = Deployment.new(provider, configFactory())
|
let deployment = Deployment.new(provider, configFactory())
|
||||||
provider.chainId = 31337.u256
|
provider.chainId = 167005.u256
|
||||||
|
|
||||||
let address = await deployment.address(Marketplace)
|
let address = await deployment.address(Marketplace)
|
||||||
check address.isSome
|
check address.isSome
|
||||||
check $(!address) == "0x59b670e9fa9d0a427751af201d676719a970857b"
|
check $(!address) == "0x948cf9291b77bd7ad84781b9047129addf1b894f"
|
||||||
|
|
||||||
test "return none for unknown networks":
|
test "return none for unknown networks":
|
||||||
let deployment = Deployment.new(provider, configFactory())
|
let deployment = Deployment.new(provider, configFactory())
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import std/options
|
import std/options
|
||||||
import pkg/chronos
|
import pkg/chronos
|
||||||
import pkg/stew/byteutils
|
|
||||||
import codex/contracts
|
import codex/contracts
|
||||||
import ../ethertest
|
import ../ethertest
|
||||||
import ./examples
|
import ./examples
|
||||||
|
@ -8,7 +7,7 @@ import ./time
|
||||||
import ./deployment
|
import ./deployment
|
||||||
|
|
||||||
ethersuite "On-Chain Market":
|
ethersuite "On-Chain Market":
|
||||||
let proof = exampleProof()
|
let proof = Groth16Proof.example
|
||||||
|
|
||||||
var market: OnChainMarket
|
var market: OnChainMarket
|
||||||
var marketplace: Marketplace
|
var marketplace: Marketplace
|
||||||
|
@ -17,7 +16,8 @@ ethersuite "On-Chain Market":
|
||||||
var periodicity: Periodicity
|
var periodicity: Periodicity
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
marketplace = Marketplace.new(Marketplace.address, ethProvider.getSigner())
|
let address = Marketplace.address(dummyVerifier = true)
|
||||||
|
marketplace = Marketplace.new(address, ethProvider.getSigner())
|
||||||
let config = await marketplace.config()
|
let config = await marketplace.config()
|
||||||
|
|
||||||
market = OnChainMarket.new(marketplace)
|
market = OnChainMarket.new(marketplace)
|
||||||
|
@ -111,6 +111,9 @@ ethersuite "On-Chain Market":
|
||||||
check (await market.willProofBeRequired(slotId(request.id, slotIndex))) == false
|
check (await market.willProofBeRequired(slotId(request.id, slotIndex))) == false
|
||||||
|
|
||||||
test "submits proofs":
|
test "submits proofs":
|
||||||
|
await market.requestStorage(request)
|
||||||
|
await market.fillSlot(request.id, slotIndex, proof, request.ask.collateral)
|
||||||
|
await advanceToNextPeriod()
|
||||||
await market.submitProof(slotId(request.id, slotIndex), proof)
|
await market.submitProof(slotId(request.id, slotIndex), proof)
|
||||||
|
|
||||||
test "marks a proof as missing":
|
test "marks a proof as missing":
|
||||||
|
@ -260,20 +263,15 @@ ethersuite "On-Chain Market":
|
||||||
await subscription.unsubscribe()
|
await subscription.unsubscribe()
|
||||||
|
|
||||||
test "supports proof submission subscriptions":
|
test "supports proof submission subscriptions":
|
||||||
|
await market.requestStorage(request)
|
||||||
|
await market.fillSlot(request.id, slotIndex, proof, request.ask.collateral)
|
||||||
|
await advanceToNextPeriod()
|
||||||
var receivedIds: seq[SlotId]
|
var receivedIds: seq[SlotId]
|
||||||
var receivedProofs: seq[seq[byte]]
|
proc onProofSubmission(id: SlotId) =
|
||||||
|
|
||||||
proc onProofSubmission(id: SlotId, proof: seq[byte]) =
|
|
||||||
receivedIds.add(id)
|
receivedIds.add(id)
|
||||||
receivedProofs.add(proof)
|
|
||||||
|
|
||||||
let subscription = await market.subscribeProofSubmission(onProofSubmission)
|
let subscription = await market.subscribeProofSubmission(onProofSubmission)
|
||||||
|
|
||||||
await market.submitProof(slotId(request.id, slotIndex), proof)
|
await market.submitProof(slotId(request.id, slotIndex), proof)
|
||||||
|
|
||||||
check receivedIds == @[slotId(request.id, slotIndex)]
|
check receivedIds == @[slotId(request.id, slotIndex)]
|
||||||
check receivedProofs == @[proof]
|
|
||||||
|
|
||||||
await subscription.unsubscribe()
|
await subscription.unsubscribe()
|
||||||
|
|
||||||
test "request is none when unknown":
|
test "request is none when unknown":
|
||||||
|
|
|
@ -4,6 +4,7 @@ import std/times
|
||||||
import std/typetraits
|
import std/typetraits
|
||||||
|
|
||||||
import pkg/codex/contracts/requests
|
import pkg/codex/contracts/requests
|
||||||
|
import pkg/codex/contracts/proofs
|
||||||
import pkg/codex/sales/slotqueue
|
import pkg/codex/sales/slotqueue
|
||||||
import pkg/codex/stores
|
import pkg/codex/stores
|
||||||
|
|
||||||
|
@ -62,8 +63,18 @@ proc example*(_: type SlotQueueItem): SlotQueueItem =
|
||||||
let slot = Slot.example
|
let slot = Slot.example
|
||||||
SlotQueueItem.init(request, slot.slotIndex.truncate(uint16))
|
SlotQueueItem.init(request, slot.slotIndex.truncate(uint16))
|
||||||
|
|
||||||
proc exampleProof*(): seq[byte] =
|
proc example(_: type G1Point): G1Point =
|
||||||
var proof: seq[byte]
|
G1Point(x: UInt256.example, y: UInt256.example)
|
||||||
while proof.len == 0:
|
|
||||||
proof = seq[byte].example
|
proc example(_: type G2Point): G2Point =
|
||||||
return proof
|
G2Point(
|
||||||
|
x: [UInt256.example, UInt256.example],
|
||||||
|
y: [UInt256.example, UInt256.example]
|
||||||
|
)
|
||||||
|
|
||||||
|
proc example*(_: type Groth16Proof): Groth16Proof =
|
||||||
|
Groth16Proof(
|
||||||
|
a: G1Point.example,
|
||||||
|
b: G2Point.example,
|
||||||
|
c: G1Point.example
|
||||||
|
)
|
||||||
|
|
|
@ -23,7 +23,7 @@ type
|
||||||
validators*: uint
|
validators*: uint
|
||||||
DebugNodes* = object
|
DebugNodes* = object
|
||||||
client*: bool
|
client*: bool
|
||||||
ethProvider*: bool
|
provider*: bool
|
||||||
validator*: bool
|
validator*: bool
|
||||||
topics*: string
|
topics*: string
|
||||||
Role* {.pure.} = enum
|
Role* {.pure.} = enum
|
||||||
|
@ -48,15 +48,15 @@ proc init*(_: type StartNodes,
|
||||||
StartNodes(clients: clients, providers: providers, validators: validators)
|
StartNodes(clients: clients, providers: providers, validators: validators)
|
||||||
|
|
||||||
proc init*(_: type DebugNodes,
|
proc init*(_: type DebugNodes,
|
||||||
client, ethProvider, validator: bool,
|
client, provider, validator: bool,
|
||||||
topics: string = "validator,proving,market"): DebugNodes =
|
topics: string = "validator,proving,market"): DebugNodes =
|
||||||
DebugNodes(client: client, ethProvider: ethProvider, validator: validator,
|
DebugNodes(client: client, provider: provider, validator: validator,
|
||||||
topics: topics)
|
topics: topics)
|
||||||
|
|
||||||
template multinodesuite*(name: string,
|
template multinodesuite*(name: string,
|
||||||
startNodes: StartNodes, debugNodes: DebugNodes, body: untyped) =
|
startNodes: StartNodes, debugNodes: DebugNodes, body: untyped) =
|
||||||
|
|
||||||
if (debugNodes.client or debugNodes.ethProvider) and
|
if (debugNodes.client or debugNodes.provider) and
|
||||||
(enabledLogLevel > LogLevel.TRACE or
|
(enabledLogLevel > LogLevel.TRACE or
|
||||||
enabledLogLevel == LogLevel.NONE):
|
enabledLogLevel == LogLevel.NONE):
|
||||||
echo ""
|
echo ""
|
||||||
|
@ -115,12 +115,12 @@ template multinodesuite*(name: string,
|
||||||
"--bootstrap-node=" & bootstrap,
|
"--bootstrap-node=" & bootstrap,
|
||||||
"--persistence",
|
"--persistence",
|
||||||
"--simulate-proof-failures=" & $failEveryNProofs],
|
"--simulate-proof-failures=" & $failEveryNProofs],
|
||||||
debugNodes.ethProvider)
|
debugNodes.provider)
|
||||||
let restClient = newCodexClient(index)
|
let restClient = newCodexClient(index)
|
||||||
running.add RunningNode.new(Role.Provider, node, restClient, datadir,
|
running.add RunningNode.new(Role.Provider, node, restClient, datadir,
|
||||||
account)
|
account)
|
||||||
if debugNodes.ethProvider:
|
if debugNodes.provider:
|
||||||
debug "started new ethProvider node and codex client",
|
debug "started new provider node and codex client",
|
||||||
restApiPort = 8080 + index, discPort = 8090 + index, account
|
restApiPort = 8080 + index, discPort = 8090 + index, account
|
||||||
|
|
||||||
proc startValidatorNode() =
|
proc startValidatorNode() =
|
||||||
|
|
|
@ -12,6 +12,11 @@ import ./multinodes
|
||||||
logScope:
|
logScope:
|
||||||
topics = "test proofs"
|
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:
|
twonodessuite "Proving integration test", debug1=false, debug2=false:
|
||||||
let validatorDir = getTempDir() / "CodexValidator"
|
let validatorDir = getTempDir() / "CodexValidator"
|
||||||
|
|
||||||
|
@ -22,7 +27,7 @@ twonodessuite "Proving integration test", debug1=false, debug2=false:
|
||||||
client.getPurchase(id).option.?state == some state
|
client.getPurchase(id).option.?state == some state
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
marketplace = Marketplace.new(Marketplace.address, ethProvider)
|
marketplace = Marketplace.new(marketplaceAddress, ethProvider)
|
||||||
period = (await marketplace.config()).proofs.period.truncate(uint64)
|
period = (await marketplace.config()).proofs.period.truncate(uint64)
|
||||||
|
|
||||||
# Our Hardhat configuration does use automine, which means that time tracked by `ethProvider.currentTime()` is not
|
# 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",
|
multinodesuite "Simulate invalid proofs",
|
||||||
StartNodes.init(clients=1'u, providers=0'u, validators=1'u),
|
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 =
|
proc purchaseStateIs(client: CodexClient, id: PurchaseId, state: string): bool =
|
||||||
client.getPurchase(id).option.?state == some state
|
client.getPurchase(id).option.?state == some state
|
||||||
|
@ -120,7 +125,7 @@ multinodesuite "Simulate invalid proofs",
|
||||||
var slotId: SlotId
|
var slotId: SlotId
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
marketplace = Marketplace.new(Marketplace.address, ethProvider)
|
marketplace = Marketplace.new(marketplaceAddress, ethProvider)
|
||||||
let config = await marketplace.config()
|
let config = await marketplace.config()
|
||||||
period = config.proofs.period.truncate(uint64)
|
period = config.proofs.period.truncate(uint64)
|
||||||
slotId = SlotId(array[32, byte].default) # ensure we aren't reusing from prev test
|
slotId = SlotId(array[32, byte].default) # ensure we aren't reusing from prev test
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit b5f33992b67df3733042a7d912c854700e8c863c
|
Subproject commit 6c9f797f408608958714024b9055fcc330e3842f
|
Loading…
Reference in New Issue