Subscribe to proof submissions (#83)
* Update dagger-contracts * [proving] rename ProofTiming -> Proofs * Update nim-ethers to 0.1.4 * [proving] Subscribe to proof submissions * [proving] support proof submission through the Proving abstraction
This commit is contained in:
parent
4d681102e5
commit
b88561e090
|
@ -13,7 +13,7 @@ requires "nim >= 1.2.0",
|
|||
"chronicles >= 0.7.2",
|
||||
"chronos >= 2.5.2",
|
||||
"confutils",
|
||||
"ethers >= 0.1.3 & < 0.2.0",
|
||||
"ethers >= 0.1.4 & < 0.2.0",
|
||||
"libbacktrace",
|
||||
"libp2p",
|
||||
"metrics",
|
||||
|
|
|
@ -3,11 +3,11 @@ import contracts/offers
|
|||
import contracts/storage
|
||||
import contracts/deployment
|
||||
import contracts/market
|
||||
import contracts/prooftiming
|
||||
import contracts/proofs
|
||||
|
||||
export requests
|
||||
export offers
|
||||
export storage
|
||||
export deployment
|
||||
export market
|
||||
export prooftiming
|
||||
export proofs
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
import pkg/ethers
|
||||
import ../por/timing/proofs
|
||||
import ./storage
|
||||
|
||||
export proofs
|
||||
|
||||
type
|
||||
OnChainProofs* = ref object of Proofs
|
||||
storage: Storage
|
||||
pollInterval*: Duration
|
||||
ProofsSubscription = proofs.Subscription
|
||||
EventSubscription = ethers.Subscription
|
||||
OnChainProofsSubscription = ref object of ProofsSubscription
|
||||
eventSubscription: EventSubscription
|
||||
|
||||
const DefaultPollInterval = 3.seconds
|
||||
|
||||
proc new*(_: type OnChainProofs, storage: Storage): OnChainProofs =
|
||||
OnChainProofs(storage: storage, pollInterval: DefaultPollInterval)
|
||||
|
||||
method periodicity*(proofs: OnChainProofs): Future[Periodicity] {.async.} =
|
||||
let period = await proofs.storage.proofPeriod()
|
||||
return Periodicity(seconds: period)
|
||||
|
||||
method getCurrentPeriod*(proofs: OnChainProofs): Future[Period] {.async.} =
|
||||
let periodicity = await proofs.periodicity()
|
||||
let blk = !await proofs.storage.provider.getBlock(BlockTag.latest)
|
||||
return periodicity.periodOf(blk.timestamp)
|
||||
|
||||
method waitUntilPeriod*(proofs: OnChainProofs,
|
||||
period: Period) {.async.} =
|
||||
while (await proofs.getCurrentPeriod()) < period:
|
||||
await sleepAsync(proofs.pollInterval)
|
||||
|
||||
method isProofRequired*(proofs: OnChainProofs,
|
||||
id: ContractId): Future[bool] {.async.} =
|
||||
return await proofs.storage.isProofRequired(id)
|
||||
|
||||
method willProofBeRequired*(proofs: OnChainProofs,
|
||||
id: ContractId): Future[bool] {.async.} =
|
||||
return await proofs.storage.willProofBeRequired(id)
|
||||
|
||||
method getProofEnd*(proofs: OnChainProofs,
|
||||
id: ContractId): Future[UInt256] {.async.} =
|
||||
return await proofs.storage.proofEnd(id)
|
||||
|
||||
method submitProof*(proofs: OnChainProofs,
|
||||
id: ContractId,
|
||||
proof: seq[byte]) {.async.} =
|
||||
await proofs.storage.submitProof(id, proof)
|
||||
|
||||
method subscribeProofSubmission*(proofs: OnChainProofs,
|
||||
callback: OnProofSubmitted):
|
||||
Future[ProofsSubscription] {.async.} =
|
||||
proc onEvent(event: ProofSubmitted) {.upraises: [].} =
|
||||
callback(event.id, event.proof)
|
||||
let subscription = await proofs.storage.subscribe(ProofSubmitted, onEvent)
|
||||
return OnChainProofsSubscription(eventSubscription: subscription)
|
||||
|
||||
method unsubscribe*(subscription: OnChainProofsSubscription) {.async, upraises:[].} =
|
||||
await subscription.eventSubscription.unsubscribe()
|
|
@ -1,40 +0,0 @@
|
|||
import ../por/timing/prooftiming
|
||||
import ./storage
|
||||
|
||||
export prooftiming
|
||||
|
||||
type
|
||||
OnChainProofTiming* = ref object of ProofTiming
|
||||
storage: Storage
|
||||
pollInterval*: Duration
|
||||
|
||||
const DefaultPollInterval = 3.seconds
|
||||
|
||||
proc new*(_: type OnChainProofTiming, storage: Storage): OnChainProofTiming =
|
||||
OnChainProofTiming(storage: storage, pollInterval: DefaultPollInterval)
|
||||
|
||||
method periodicity*(timing: OnChainProofTiming): Future[Periodicity] {.async.} =
|
||||
let period = await timing.storage.proofPeriod()
|
||||
return Periodicity(seconds: period)
|
||||
|
||||
method getCurrentPeriod*(timing: OnChainProofTiming): Future[Period] {.async.} =
|
||||
let periodicity = await timing.periodicity()
|
||||
let blk = !await timing.storage.provider.getBlock(BlockTag.latest)
|
||||
return periodicity.periodOf(blk.timestamp)
|
||||
|
||||
method waitUntilPeriod*(timing: OnChainProofTiming,
|
||||
period: Period) {.async.} =
|
||||
while (await timing.getCurrentPeriod()) < period:
|
||||
await sleepAsync(timing.pollInterval)
|
||||
|
||||
method isProofRequired*(timing: OnChainProofTiming,
|
||||
id: ContractId): Future[bool] {.async.} =
|
||||
return await timing.storage.isProofRequired(id)
|
||||
|
||||
method willProofBeRequired*(timing: OnChainProofTiming,
|
||||
id: ContractId): Future[bool] {.async.} =
|
||||
return await timing.storage.willProofBeRequired(id)
|
||||
|
||||
method getProofEnd*(timing: OnChainProofTiming,
|
||||
id: ContractId): Future[UInt256] {.async.} =
|
||||
return await timing.storage.proofEnd(id)
|
|
@ -21,6 +21,9 @@ type
|
|||
OfferSelected* = object of Event
|
||||
offerId*: Id
|
||||
requestId* {.indexed.}: Id
|
||||
ProofSubmitted* = object of Event
|
||||
id*: Id
|
||||
proof*: seq[byte]
|
||||
|
||||
proc collateralAmount*(storage: Storage): UInt256 {.contract, view.}
|
||||
proc slashMisses*(storage: Storage): UInt256 {.contract, view.}
|
||||
|
@ -47,5 +50,5 @@ proc willProofBeRequired*(storage: Storage, id: Id): bool {.contract, view.}
|
|||
proc getChallenge*(storage: Storage, id: Id): array[32, byte] {.contract, view.}
|
||||
proc getPointer*(storage: Storage, id: Id): uint8 {.contract, view.}
|
||||
|
||||
proc submitProof*(storage: Storage, id: Id, proof: bool) {.contract.}
|
||||
proc submitProof*(storage: Storage, id: Id, proof: seq[byte]) {.contract.}
|
||||
proc markProofAsMissing*(storage: Storage, id: Id, period: UInt256) {.contract.}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
import pkg/chronos
|
||||
import pkg/stint
|
||||
import pkg/upraises
|
||||
import ./periods
|
||||
|
||||
export chronos
|
||||
export stint
|
||||
export periods
|
||||
|
||||
type
|
||||
Proofs* = ref object of RootObj
|
||||
Subscription* = ref object of RootObj
|
||||
OnProofSubmitted* = proc(id: ContractId, proof: seq[byte]) {.gcsafe, upraises:[].}
|
||||
ContractId* = array[32, byte]
|
||||
|
||||
method periodicity*(proofs: Proofs):
|
||||
Future[Periodicity] {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method getCurrentPeriod*(proofs: Proofs):
|
||||
Future[Period] {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method waitUntilPeriod*(proofs: Proofs,
|
||||
period: Period) {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method isProofRequired*(proofs: Proofs,
|
||||
id: ContractId): Future[bool] {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method willProofBeRequired*(proofs: Proofs,
|
||||
id: ContractId): Future[bool] {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method getProofEnd*(proofs: Proofs,
|
||||
id: ContractId): Future[UInt256] {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method submitProof*(proofs: Proofs,
|
||||
id: ContractId,
|
||||
proof: seq[byte]) {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method subscribeProofSubmission*(proofs: Proofs,
|
||||
callback: OnProofSubmitted):
|
||||
Future[Subscription] {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method unsubscribe*(subscription: Subscription) {.base, async, upraises:[].} =
|
||||
raiseAssert("not implemented")
|
|
@ -1,35 +0,0 @@
|
|||
import pkg/chronos
|
||||
import pkg/stint
|
||||
import ./periods
|
||||
|
||||
export chronos
|
||||
export stint
|
||||
export periods
|
||||
|
||||
type
|
||||
ProofTiming* = ref object of RootObj
|
||||
ContractId* = array[32, byte]
|
||||
|
||||
method periodicity*(proofTiming: ProofTiming):
|
||||
Future[Periodicity] {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method getCurrentPeriod*(proofTiming: ProofTiming):
|
||||
Future[Period] {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method waitUntilPeriod*(proofTiming: ProofTiming,
|
||||
period: Period) {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method isProofRequired*(proofTiming: ProofTiming,
|
||||
id: ContractId): Future[bool] {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method willProofBeRequired*(proofTiming: ProofTiming,
|
||||
id: ContractId): Future[bool] {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method getProofEnd*(proofTiming: ProofTiming,
|
||||
id: ContractId): Future[UInt256] {.base, async.} =
|
||||
raiseAssert("not implemented")
|
|
@ -2,21 +2,21 @@ import std/sets
|
|||
import std/times
|
||||
import pkg/upraises
|
||||
import pkg/questionable
|
||||
import ./por/timing/prooftiming
|
||||
import ./por/timing/proofs
|
||||
|
||||
export sets
|
||||
export prooftiming
|
||||
export proofs
|
||||
|
||||
type
|
||||
Proving* = ref object
|
||||
timing: ProofTiming
|
||||
proofs: Proofs
|
||||
stopped: bool
|
||||
contracts*: HashSet[ContractId]
|
||||
onProofRequired: ?OnProofRequired
|
||||
OnProofRequired* = proc (id: ContractId) {.gcsafe, upraises:[].}
|
||||
|
||||
func new*(_: type Proving, timing: ProofTiming): Proving =
|
||||
Proving(timing: timing)
|
||||
func new*(_: type Proving, proofs: Proofs): Proving =
|
||||
Proving(proofs: proofs)
|
||||
|
||||
proc `onProofRequired=`*(proving: Proving, callback: OnProofRequired) =
|
||||
proving.onProofRequired = some callback
|
||||
|
@ -28,23 +28,31 @@ proc removeEndedContracts(proving: Proving) {.async.} =
|
|||
let now = getTime().toUnix().u256
|
||||
var ended: HashSet[ContractId]
|
||||
for id in proving.contracts:
|
||||
if now >= (await proving.timing.getProofEnd(id)):
|
||||
if now >= (await proving.proofs.getProofEnd(id)):
|
||||
ended.incl(id)
|
||||
proving.contracts.excl(ended)
|
||||
|
||||
proc run(proving: Proving) {.async.} =
|
||||
while not proving.stopped:
|
||||
let currentPeriod = await proving.timing.getCurrentPeriod()
|
||||
let currentPeriod = await proving.proofs.getCurrentPeriod()
|
||||
await proving.removeEndedContracts()
|
||||
for id in proving.contracts:
|
||||
if (await proving.timing.isProofRequired(id)) or
|
||||
(await proving.timing.willProofBeRequired(id)):
|
||||
if (await proving.proofs.isProofRequired(id)) or
|
||||
(await proving.proofs.willProofBeRequired(id)):
|
||||
if callback =? proving.onProofRequired:
|
||||
callback(id)
|
||||
await proving.timing.waitUntilPeriod(currentPeriod + 1)
|
||||
await proving.proofs.waitUntilPeriod(currentPeriod + 1)
|
||||
|
||||
proc start*(proving: Proving) =
|
||||
asyncSpawn proving.run()
|
||||
|
||||
proc stop*(proving: Proving) =
|
||||
proving.stopped = true
|
||||
|
||||
proc submitProof*(proving: Proving, id: ContractId, proof: seq[byte]) {.async.} =
|
||||
await proving.proofs.submitProof(id, proof)
|
||||
|
||||
proc subscribeProofSubmission*(proving: Proving,
|
||||
callback: OnProofSubmitted):
|
||||
Future[Subscription] =
|
||||
proving.proofs.subscribeProofSubmission(callback)
|
||||
|
|
|
@ -71,10 +71,11 @@ ethersuite "Storage contracts":
|
|||
check proofEnd > 0
|
||||
|
||||
test "accept storage proofs":
|
||||
let proof = seq[byte].example
|
||||
switchAccount(host)
|
||||
await storage.startContract(id)
|
||||
await waitUntilProofRequired(id)
|
||||
await storage.submitProof(id, true)
|
||||
await storage.submitProof(id, proof)
|
||||
|
||||
test "can mark missing proofs":
|
||||
switchAccount(host)
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
import ./ethertest
|
||||
import dagger/contracts
|
||||
import ./examples
|
||||
import ./time
|
||||
|
||||
ethersuite "On-Chain Proof Timing":
|
||||
|
||||
var timing: OnChainProofTiming
|
||||
var storage: Storage
|
||||
|
||||
setup:
|
||||
let deployment = deployment()
|
||||
storage = Storage.new(!deployment.address(Storage), provider)
|
||||
timing = OnChainProofTiming.new(storage)
|
||||
|
||||
test "can retrieve proof periodicity":
|
||||
let periodicity = await timing.periodicity()
|
||||
let periodLength = await storage.proofPeriod()
|
||||
check periodicity.seconds == periodLength
|
||||
|
||||
test "supports waiting until next period":
|
||||
let periodicity = await timing.periodicity()
|
||||
let currentPeriod = await timing.getCurrentPeriod()
|
||||
|
||||
let pollInterval = 200.milliseconds
|
||||
timing.pollInterval = pollInterval
|
||||
|
||||
proc waitForPoll {.async.} =
|
||||
await sleepAsync(pollInterval * 2)
|
||||
|
||||
let future = timing.waitUntilPeriod(currentPeriod + 1)
|
||||
|
||||
check not future.completed
|
||||
|
||||
await provider.advanceTimeTo(periodicity.periodEnd(currentPeriod))
|
||||
await waitForPoll()
|
||||
|
||||
check future.completed
|
||||
|
||||
test "supports checking whether proof is required now":
|
||||
check (await timing.isProofRequired(ContractId.example)) == false
|
||||
|
||||
test "supports checking whether proof is required soon":
|
||||
check (await timing.willProofBeRequired(ContractId.example)) == false
|
||||
|
||||
test "retrieves proof end time":
|
||||
check (await timing.getProofEnd(ContractId.example)) == 0.u256
|
|
@ -0,0 +1,70 @@
|
|||
import ./ethertest
|
||||
import dagger/contracts
|
||||
import ./examples
|
||||
import ./time
|
||||
|
||||
ethersuite "On-Chain Proofs":
|
||||
|
||||
let contractId = ContractId.example
|
||||
let proof = seq[byte].example
|
||||
|
||||
var proofs: OnChainProofs
|
||||
var storage: Storage
|
||||
|
||||
setup:
|
||||
let deployment = deployment()
|
||||
storage = Storage.new(!deployment.address(Storage), provider.getSigner())
|
||||
proofs = OnChainProofs.new(storage)
|
||||
|
||||
test "can retrieve proof periodicity":
|
||||
let periodicity = await proofs.periodicity()
|
||||
let periodLength = await storage.proofPeriod()
|
||||
check periodicity.seconds == periodLength
|
||||
|
||||
test "supports waiting until next period":
|
||||
let periodicity = await proofs.periodicity()
|
||||
let currentPeriod = await proofs.getCurrentPeriod()
|
||||
|
||||
let pollInterval = 200.milliseconds
|
||||
proofs.pollInterval = pollInterval
|
||||
|
||||
proc waitForPoll {.async.} =
|
||||
await sleepAsync(pollInterval * 2)
|
||||
|
||||
let future = proofs.waitUntilPeriod(currentPeriod + 1)
|
||||
|
||||
check not future.completed
|
||||
|
||||
await provider.advanceTimeTo(periodicity.periodEnd(currentPeriod))
|
||||
await waitForPoll()
|
||||
|
||||
check future.completed
|
||||
|
||||
test "supports checking whether proof is required now":
|
||||
check (await proofs.isProofRequired(contractId)) == false
|
||||
|
||||
test "supports checking whether proof is required soon":
|
||||
check (await proofs.willProofBeRequired(contractId)) == false
|
||||
|
||||
test "retrieves proof end time":
|
||||
check (await proofs.getProofEnd(contractId)) == 0.u256
|
||||
|
||||
test "submits proofs":
|
||||
await proofs.submitProof(contractId, proof)
|
||||
|
||||
test "supports proof submission subscriptions":
|
||||
var receivedIds: seq[ContractId]
|
||||
var receivedProofs: seq[seq[byte]]
|
||||
|
||||
proc onProofSubmission(id: ContractId, proof: seq[byte]) =
|
||||
receivedIds.add(id)
|
||||
receivedProofs.add(proof)
|
||||
|
||||
let subscription = await proofs.subscribeProofSubmission(onProofSubmission)
|
||||
|
||||
await proofs.submitProof(contractId, proof)
|
||||
|
||||
check receivedIds == @[contractId]
|
||||
check receivedProofs == @[proof]
|
||||
|
||||
await subscription.unsubscribe()
|
|
@ -0,0 +1,94 @@
|
|||
import std/sets
|
||||
import std/tables
|
||||
import std/sequtils
|
||||
import pkg/upraises
|
||||
import pkg/dagger/por/timing/proofs
|
||||
|
||||
type
|
||||
MockProofs* = ref object of Proofs
|
||||
periodicity: Periodicity
|
||||
currentPeriod: Period
|
||||
waiting: Table[Period, seq[Future[void]]]
|
||||
proofsRequired: HashSet[ContractId]
|
||||
proofsToBeRequired: HashSet[ContractId]
|
||||
proofEnds: Table[ContractId, UInt256]
|
||||
subscriptions: seq[MockSubscription]
|
||||
MockSubscription* = ref object of Subscription
|
||||
proofs: MockProofs
|
||||
callback: OnProofSubmitted
|
||||
|
||||
const DefaultPeriodLength = 10.u256
|
||||
|
||||
func new*(_: type MockProofs): MockProofs =
|
||||
MockProofs(periodicity: Periodicity(seconds: DefaultPeriodLength))
|
||||
|
||||
func setPeriodicity*(mock: MockProofs, periodicity: Periodicity) =
|
||||
mock.periodicity = periodicity
|
||||
|
||||
method periodicity*(mock: MockProofs): Future[Periodicity] {.async.} =
|
||||
return mock.periodicity
|
||||
|
||||
proc setProofRequired*(mock: MockProofs, id: ContractId, required: bool) =
|
||||
if required:
|
||||
mock.proofsRequired.incl(id)
|
||||
else:
|
||||
mock.proofsRequired.excl(id)
|
||||
|
||||
method isProofRequired*(mock: MockProofs,
|
||||
id: ContractId): Future[bool] {.async.} =
|
||||
return mock.proofsRequired.contains(id)
|
||||
|
||||
proc setProofToBeRequired*(mock: MockProofs, id: ContractId, required: bool) =
|
||||
if required:
|
||||
mock.proofsToBeRequired.incl(id)
|
||||
else:
|
||||
mock.proofsToBeRequired.excl(id)
|
||||
|
||||
method willProofBeRequired*(mock: MockProofs,
|
||||
id: ContractId): Future[bool] {.async.} =
|
||||
return mock.proofsToBeRequired.contains(id)
|
||||
|
||||
proc setProofEnd*(mock: MockProofs, id: ContractId, proofEnd: UInt256) =
|
||||
mock.proofEnds[id] = proofEnd
|
||||
|
||||
method getProofEnd*(mock: MockProofs,
|
||||
id: ContractId): Future[UInt256] {.async.} =
|
||||
if mock.proofEnds.hasKey(id):
|
||||
return mock.proofEnds[id]
|
||||
else:
|
||||
return UInt256.high
|
||||
|
||||
proc advanceToPeriod*(mock: MockProofs, period: Period) =
|
||||
doAssert period >= mock.currentPeriod
|
||||
for key in mock.waiting.keys:
|
||||
if key <= period:
|
||||
for future in mock.waiting[key]:
|
||||
future.complete()
|
||||
mock.waiting[key] = @[]
|
||||
|
||||
method getCurrentPeriod*(mock: MockProofs): Future[Period] {.async.} =
|
||||
return mock.currentPeriod
|
||||
|
||||
method waitUntilPeriod*(mock: MockProofs, period: Period) {.async.} =
|
||||
if period > mock.currentPeriod:
|
||||
let future = Future[void]()
|
||||
if not mock.waiting.hasKey(period):
|
||||
mock.waiting[period] = @[]
|
||||
mock.waiting[period].add(future)
|
||||
await future
|
||||
|
||||
method submitProof*(mock: MockProofs,
|
||||
id: ContractId,
|
||||
proof: seq[byte]) {.async.} =
|
||||
for subscription in mock.subscriptions:
|
||||
subscription.callback(id, proof)
|
||||
|
||||
method subscribeProofSubmission*(mock: MockProofs,
|
||||
callback: OnProofSubmitted):
|
||||
Future[Subscription] {.async.} =
|
||||
let subscription = MockSubscription(proofs: mock, callback: callback)
|
||||
mock.subscriptions.add(subscription)
|
||||
return subscription
|
||||
|
||||
method unsubscribe*(subscription: MockSubscription) {.async, upraises:[].} =
|
||||
subscription.proofs.subscriptions.keepItIf(it != subscription)
|
|
@ -1,72 +0,0 @@
|
|||
import std/sets
|
||||
import std/tables
|
||||
import pkg/dagger/por/timing/prooftiming
|
||||
|
||||
type
|
||||
MockProofTiming* = ref object of ProofTiming
|
||||
periodicity: Periodicity
|
||||
currentPeriod: Period
|
||||
waiting: Table[Period, seq[Future[void]]]
|
||||
proofsRequired: HashSet[ContractId]
|
||||
proofsToBeRequired: HashSet[ContractId]
|
||||
proofEnds: Table[ContractId, UInt256]
|
||||
|
||||
const DefaultPeriodLength = 10.u256
|
||||
|
||||
func new*(_: type MockProofTiming): MockProofTiming =
|
||||
MockProofTiming(periodicity: Periodicity(seconds: DefaultPeriodLength))
|
||||
|
||||
func setPeriodicity*(mock: MockProofTiming, periodicity: Periodicity) =
|
||||
mock.periodicity = periodicity
|
||||
|
||||
method periodicity*(mock: MockProofTiming): Future[Periodicity] {.async.} =
|
||||
return mock.periodicity
|
||||
|
||||
proc setProofRequired*(mock: MockProofTiming, id: ContractId, required: bool) =
|
||||
if required:
|
||||
mock.proofsRequired.incl(id)
|
||||
else:
|
||||
mock.proofsRequired.excl(id)
|
||||
|
||||
method isProofRequired*(mock: MockProofTiming,
|
||||
id: ContractId): Future[bool] {.async.} =
|
||||
return mock.proofsRequired.contains(id)
|
||||
|
||||
proc setProofToBeRequired*(mock: MockProofTiming, id: ContractId, required: bool) =
|
||||
if required:
|
||||
mock.proofsToBeRequired.incl(id)
|
||||
else:
|
||||
mock.proofsToBeRequired.excl(id)
|
||||
|
||||
method willProofBeRequired*(mock: MockProofTiming,
|
||||
id: ContractId): Future[bool] {.async.} =
|
||||
return mock.proofsToBeRequired.contains(id)
|
||||
|
||||
proc setProofEnd*(mock: MockProofTiming, id: ContractId, proofEnd: UInt256) =
|
||||
mock.proofEnds[id] = proofEnd
|
||||
|
||||
method getProofEnd*(mock: MockProofTiming,
|
||||
id: ContractId): Future[UInt256] {.async.} =
|
||||
if mock.proofEnds.hasKey(id):
|
||||
return mock.proofEnds[id]
|
||||
else:
|
||||
return UInt256.high
|
||||
|
||||
proc advanceToPeriod*(mock: MockProofTiming, period: Period) =
|
||||
doAssert period >= mock.currentPeriod
|
||||
for key in mock.waiting.keys:
|
||||
if key <= period:
|
||||
for future in mock.waiting[key]:
|
||||
future.complete()
|
||||
mock.waiting[key] = @[]
|
||||
|
||||
method getCurrentPeriod*(mock: MockProofTiming): Future[Period] {.async.} =
|
||||
return mock.currentPeriod
|
||||
|
||||
method waitUntilPeriod*(mock: MockProofTiming, period: Period) {.async.} =
|
||||
if period > mock.currentPeriod:
|
||||
let future = Future[void]()
|
||||
if not mock.waiting.hasKey(period):
|
||||
mock.waiting[period] = @[]
|
||||
mock.waiting[period].add(future)
|
||||
await future
|
|
@ -2,25 +2,25 @@ from std/times import getTime, toUnix
|
|||
import pkg/asynctest
|
||||
import pkg/chronos
|
||||
import pkg/dagger/proving
|
||||
import ./helpers/mockprooftiming
|
||||
import ./helpers/mockproofs
|
||||
import ./examples
|
||||
|
||||
suite "Proving":
|
||||
|
||||
var proving: Proving
|
||||
var timing: MockProofTiming
|
||||
var proofs: MockProofs
|
||||
|
||||
setup:
|
||||
timing = MockProofTiming.new()
|
||||
proving = Proving.new(timing)
|
||||
proofs = MockProofs.new()
|
||||
proving = Proving.new(proofs)
|
||||
proving.start()
|
||||
|
||||
teardown:
|
||||
proving.stop()
|
||||
|
||||
proc advanceToNextPeriod(timing: MockProofTiming) {.async.} =
|
||||
let current = await timing.getCurrentPeriod()
|
||||
timing.advanceToPeriod(current + 1)
|
||||
proc advanceToNextPeriod(proofs: MockProofs) {.async.} =
|
||||
let current = await proofs.getCurrentPeriod()
|
||||
proofs.advanceToPeriod(current + 1)
|
||||
await sleepAsync(1.milliseconds)
|
||||
|
||||
test "maintains a list of contract ids to watch":
|
||||
|
@ -45,8 +45,8 @@ suite "Proving":
|
|||
proc onProofRequired(id: ContractId) =
|
||||
called = true
|
||||
proving.onProofRequired = onProofRequired
|
||||
timing.setProofRequired(id, true)
|
||||
await timing.advanceToNextPeriod()
|
||||
proofs.setProofRequired(id, true)
|
||||
await proofs.advanceToNextPeriod()
|
||||
check called
|
||||
|
||||
test "callback receives id of contract for which proof is required":
|
||||
|
@ -57,12 +57,12 @@ suite "Proving":
|
|||
proc onProofRequired(id: ContractId) =
|
||||
callbackIds.add(id)
|
||||
proving.onProofRequired = onProofRequired
|
||||
timing.setProofRequired(id1, true)
|
||||
await timing.advanceToNextPeriod()
|
||||
proofs.setProofRequired(id1, true)
|
||||
await proofs.advanceToNextPeriod()
|
||||
check callbackIds == @[id1]
|
||||
timing.setProofRequired(id1, false)
|
||||
timing.setProofRequired(id2, true)
|
||||
await timing.advanceToNextPeriod()
|
||||
proofs.setProofRequired(id1, false)
|
||||
proofs.setProofRequired(id2, true)
|
||||
await proofs.advanceToNextPeriod()
|
||||
check callbackIds == @[id1, id2]
|
||||
|
||||
test "invokes callback when proof is about to be required":
|
||||
|
@ -72,20 +72,45 @@ suite "Proving":
|
|||
proc onProofRequired(id: ContractId) =
|
||||
called = true
|
||||
proving.onProofRequired = onProofRequired
|
||||
timing.setProofRequired(id, false)
|
||||
timing.setProofToBeRequired(id, true)
|
||||
await timing.advanceToNextPeriod()
|
||||
proofs.setProofRequired(id, false)
|
||||
proofs.setProofToBeRequired(id, true)
|
||||
await proofs.advanceToNextPeriod()
|
||||
check called
|
||||
|
||||
test "stops watching when contract has ended":
|
||||
let id = ContractId.example
|
||||
proving.add(id)
|
||||
timing.setProofEnd(id, getTime().toUnix().u256)
|
||||
await timing.advanceToNextPeriod()
|
||||
proofs.setProofEnd(id, getTime().toUnix().u256)
|
||||
await proofs.advanceToNextPeriod()
|
||||
var called: bool
|
||||
proc onProofRequired(id: ContractId) =
|
||||
called = true
|
||||
proving.onProofRequired = onProofRequired
|
||||
timing.setProofRequired(id, true)
|
||||
await timing.advanceToNextPeriod()
|
||||
proofs.setProofRequired(id, true)
|
||||
await proofs.advanceToNextPeriod()
|
||||
check not called
|
||||
|
||||
test "submits proofs":
|
||||
let id = ContractId.example
|
||||
let proof = seq[byte].example
|
||||
await proving.submitProof(id, proof)
|
||||
|
||||
test "supports proof submission subscriptions":
|
||||
let id = ContractId.example
|
||||
let proof = seq[byte].example
|
||||
|
||||
var receivedIds: seq[ContractId]
|
||||
var receivedProofs: seq[seq[byte]]
|
||||
|
||||
proc onProofSubmission(id: ContractId, proof: seq[byte]) =
|
||||
receivedIds.add(id)
|
||||
receivedProofs.add(proof)
|
||||
|
||||
let subscription = await proving.subscribeProofSubmission(onProofSubmission)
|
||||
|
||||
await proving.submitProof(id, proof)
|
||||
|
||||
check receivedIds == @[id]
|
||||
check receivedProofs == @[proof]
|
||||
|
||||
await subscription.unsubscribe()
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import std/random
|
||||
import std/sequtils
|
||||
import pkg/stint
|
||||
|
||||
proc example*[T: SomeInteger](_: type T): T =
|
||||
|
@ -8,5 +9,9 @@ proc example*[T,N](_: type array[N, T]): array[N, T] =
|
|||
for item in result.mitems:
|
||||
item = T.example
|
||||
|
||||
proc example*[T](_: type seq[T]): seq[T] =
|
||||
let length = uint8.example.int
|
||||
newSeqWith(length, T.example)
|
||||
|
||||
proc example*(_: type UInt256): UInt256 =
|
||||
UInt256.fromBytes(array[32, byte].example)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import ./contracts/testCollateral
|
||||
import ./contracts/testContracts
|
||||
import ./contracts/testMarket
|
||||
import ./contracts/testProofTiming
|
||||
import ./contracts/testProofs
|
||||
|
||||
{.warning[UnusedImport]:off.}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 6aa2894521faa53a9896e800caf713499b33c318
|
||||
Subproject commit 2bf01da728317fd1f3ae8424785f31b53eb4013f
|
|
@ -1 +1 @@
|
|||
Subproject commit 0d9a25ec0ab9c4b807664a357c7ec31006986cae
|
||||
Subproject commit b111c27b619fc1d81fb1c6942372824a18a71960
|
|
@ -1 +1 @@
|
|||
Subproject commit ac74b91f11bb8511ab9e7cc3075f0267415c3006
|
||||
Subproject commit a0dca2674d07b34c293ca318fa8ca30e123c13ca
|
Loading…
Reference in New Issue