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",
|
"chronicles >= 0.7.2",
|
||||||
"chronos >= 2.5.2",
|
"chronos >= 2.5.2",
|
||||||
"confutils",
|
"confutils",
|
||||||
"ethers >= 0.1.3 & < 0.2.0",
|
"ethers >= 0.1.4 & < 0.2.0",
|
||||||
"libbacktrace",
|
"libbacktrace",
|
||||||
"libp2p",
|
"libp2p",
|
||||||
"metrics",
|
"metrics",
|
||||||
|
|
|
@ -3,11 +3,11 @@ import contracts/offers
|
||||||
import contracts/storage
|
import contracts/storage
|
||||||
import contracts/deployment
|
import contracts/deployment
|
||||||
import contracts/market
|
import contracts/market
|
||||||
import contracts/prooftiming
|
import contracts/proofs
|
||||||
|
|
||||||
export requests
|
export requests
|
||||||
export offers
|
export offers
|
||||||
export storage
|
export storage
|
||||||
export deployment
|
export deployment
|
||||||
export market
|
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
|
OfferSelected* = object of Event
|
||||||
offerId*: Id
|
offerId*: Id
|
||||||
requestId* {.indexed.}: Id
|
requestId* {.indexed.}: Id
|
||||||
|
ProofSubmitted* = object of Event
|
||||||
|
id*: Id
|
||||||
|
proof*: seq[byte]
|
||||||
|
|
||||||
proc collateralAmount*(storage: Storage): UInt256 {.contract, view.}
|
proc collateralAmount*(storage: Storage): UInt256 {.contract, view.}
|
||||||
proc slashMisses*(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 getChallenge*(storage: Storage, id: Id): array[32, byte] {.contract, view.}
|
||||||
proc getPointer*(storage: Storage, id: Id): uint8 {.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.}
|
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 std/times
|
||||||
import pkg/upraises
|
import pkg/upraises
|
||||||
import pkg/questionable
|
import pkg/questionable
|
||||||
import ./por/timing/prooftiming
|
import ./por/timing/proofs
|
||||||
|
|
||||||
export sets
|
export sets
|
||||||
export prooftiming
|
export proofs
|
||||||
|
|
||||||
type
|
type
|
||||||
Proving* = ref object
|
Proving* = ref object
|
||||||
timing: ProofTiming
|
proofs: Proofs
|
||||||
stopped: bool
|
stopped: bool
|
||||||
contracts*: HashSet[ContractId]
|
contracts*: HashSet[ContractId]
|
||||||
onProofRequired: ?OnProofRequired
|
onProofRequired: ?OnProofRequired
|
||||||
OnProofRequired* = proc (id: ContractId) {.gcsafe, upraises:[].}
|
OnProofRequired* = proc (id: ContractId) {.gcsafe, upraises:[].}
|
||||||
|
|
||||||
func new*(_: type Proving, timing: ProofTiming): Proving =
|
func new*(_: type Proving, proofs: Proofs): Proving =
|
||||||
Proving(timing: timing)
|
Proving(proofs: proofs)
|
||||||
|
|
||||||
proc `onProofRequired=`*(proving: Proving, callback: OnProofRequired) =
|
proc `onProofRequired=`*(proving: Proving, callback: OnProofRequired) =
|
||||||
proving.onProofRequired = some callback
|
proving.onProofRequired = some callback
|
||||||
|
@ -28,23 +28,31 @@ proc removeEndedContracts(proving: Proving) {.async.} =
|
||||||
let now = getTime().toUnix().u256
|
let now = getTime().toUnix().u256
|
||||||
var ended: HashSet[ContractId]
|
var ended: HashSet[ContractId]
|
||||||
for id in proving.contracts:
|
for id in proving.contracts:
|
||||||
if now >= (await proving.timing.getProofEnd(id)):
|
if now >= (await proving.proofs.getProofEnd(id)):
|
||||||
ended.incl(id)
|
ended.incl(id)
|
||||||
proving.contracts.excl(ended)
|
proving.contracts.excl(ended)
|
||||||
|
|
||||||
proc run(proving: Proving) {.async.} =
|
proc run(proving: Proving) {.async.} =
|
||||||
while not proving.stopped:
|
while not proving.stopped:
|
||||||
let currentPeriod = await proving.timing.getCurrentPeriod()
|
let currentPeriod = await proving.proofs.getCurrentPeriod()
|
||||||
await proving.removeEndedContracts()
|
await proving.removeEndedContracts()
|
||||||
for id in proving.contracts:
|
for id in proving.contracts:
|
||||||
if (await proving.timing.isProofRequired(id)) or
|
if (await proving.proofs.isProofRequired(id)) or
|
||||||
(await proving.timing.willProofBeRequired(id)):
|
(await proving.proofs.willProofBeRequired(id)):
|
||||||
if callback =? proving.onProofRequired:
|
if callback =? proving.onProofRequired:
|
||||||
callback(id)
|
callback(id)
|
||||||
await proving.timing.waitUntilPeriod(currentPeriod + 1)
|
await proving.proofs.waitUntilPeriod(currentPeriod + 1)
|
||||||
|
|
||||||
proc start*(proving: Proving) =
|
proc start*(proving: Proving) =
|
||||||
asyncSpawn proving.run()
|
asyncSpawn proving.run()
|
||||||
|
|
||||||
proc stop*(proving: Proving) =
|
proc stop*(proving: Proving) =
|
||||||
proving.stopped = true
|
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
|
check proofEnd > 0
|
||||||
|
|
||||||
test "accept storage proofs":
|
test "accept storage proofs":
|
||||||
|
let proof = seq[byte].example
|
||||||
switchAccount(host)
|
switchAccount(host)
|
||||||
await storage.startContract(id)
|
await storage.startContract(id)
|
||||||
await waitUntilProofRequired(id)
|
await waitUntilProofRequired(id)
|
||||||
await storage.submitProof(id, true)
|
await storage.submitProof(id, proof)
|
||||||
|
|
||||||
test "can mark missing proofs":
|
test "can mark missing proofs":
|
||||||
switchAccount(host)
|
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/asynctest
|
||||||
import pkg/chronos
|
import pkg/chronos
|
||||||
import pkg/dagger/proving
|
import pkg/dagger/proving
|
||||||
import ./helpers/mockprooftiming
|
import ./helpers/mockproofs
|
||||||
import ./examples
|
import ./examples
|
||||||
|
|
||||||
suite "Proving":
|
suite "Proving":
|
||||||
|
|
||||||
var proving: Proving
|
var proving: Proving
|
||||||
var timing: MockProofTiming
|
var proofs: MockProofs
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
timing = MockProofTiming.new()
|
proofs = MockProofs.new()
|
||||||
proving = Proving.new(timing)
|
proving = Proving.new(proofs)
|
||||||
proving.start()
|
proving.start()
|
||||||
|
|
||||||
teardown:
|
teardown:
|
||||||
proving.stop()
|
proving.stop()
|
||||||
|
|
||||||
proc advanceToNextPeriod(timing: MockProofTiming) {.async.} =
|
proc advanceToNextPeriod(proofs: MockProofs) {.async.} =
|
||||||
let current = await timing.getCurrentPeriod()
|
let current = await proofs.getCurrentPeriod()
|
||||||
timing.advanceToPeriod(current + 1)
|
proofs.advanceToPeriod(current + 1)
|
||||||
await sleepAsync(1.milliseconds)
|
await sleepAsync(1.milliseconds)
|
||||||
|
|
||||||
test "maintains a list of contract ids to watch":
|
test "maintains a list of contract ids to watch":
|
||||||
|
@ -45,8 +45,8 @@ suite "Proving":
|
||||||
proc onProofRequired(id: ContractId) =
|
proc onProofRequired(id: ContractId) =
|
||||||
called = true
|
called = true
|
||||||
proving.onProofRequired = onProofRequired
|
proving.onProofRequired = onProofRequired
|
||||||
timing.setProofRequired(id, true)
|
proofs.setProofRequired(id, true)
|
||||||
await timing.advanceToNextPeriod()
|
await proofs.advanceToNextPeriod()
|
||||||
check called
|
check called
|
||||||
|
|
||||||
test "callback receives id of contract for which proof is required":
|
test "callback receives id of contract for which proof is required":
|
||||||
|
@ -57,12 +57,12 @@ suite "Proving":
|
||||||
proc onProofRequired(id: ContractId) =
|
proc onProofRequired(id: ContractId) =
|
||||||
callbackIds.add(id)
|
callbackIds.add(id)
|
||||||
proving.onProofRequired = onProofRequired
|
proving.onProofRequired = onProofRequired
|
||||||
timing.setProofRequired(id1, true)
|
proofs.setProofRequired(id1, true)
|
||||||
await timing.advanceToNextPeriod()
|
await proofs.advanceToNextPeriod()
|
||||||
check callbackIds == @[id1]
|
check callbackIds == @[id1]
|
||||||
timing.setProofRequired(id1, false)
|
proofs.setProofRequired(id1, false)
|
||||||
timing.setProofRequired(id2, true)
|
proofs.setProofRequired(id2, true)
|
||||||
await timing.advanceToNextPeriod()
|
await proofs.advanceToNextPeriod()
|
||||||
check callbackIds == @[id1, id2]
|
check callbackIds == @[id1, id2]
|
||||||
|
|
||||||
test "invokes callback when proof is about to be required":
|
test "invokes callback when proof is about to be required":
|
||||||
|
@ -72,20 +72,45 @@ suite "Proving":
|
||||||
proc onProofRequired(id: ContractId) =
|
proc onProofRequired(id: ContractId) =
|
||||||
called = true
|
called = true
|
||||||
proving.onProofRequired = onProofRequired
|
proving.onProofRequired = onProofRequired
|
||||||
timing.setProofRequired(id, false)
|
proofs.setProofRequired(id, false)
|
||||||
timing.setProofToBeRequired(id, true)
|
proofs.setProofToBeRequired(id, true)
|
||||||
await timing.advanceToNextPeriod()
|
await proofs.advanceToNextPeriod()
|
||||||
check called
|
check called
|
||||||
|
|
||||||
test "stops watching when contract has ended":
|
test "stops watching when contract has ended":
|
||||||
let id = ContractId.example
|
let id = ContractId.example
|
||||||
proving.add(id)
|
proving.add(id)
|
||||||
timing.setProofEnd(id, getTime().toUnix().u256)
|
proofs.setProofEnd(id, getTime().toUnix().u256)
|
||||||
await timing.advanceToNextPeriod()
|
await proofs.advanceToNextPeriod()
|
||||||
var called: bool
|
var called: bool
|
||||||
proc onProofRequired(id: ContractId) =
|
proc onProofRequired(id: ContractId) =
|
||||||
called = true
|
called = true
|
||||||
proving.onProofRequired = onProofRequired
|
proving.onProofRequired = onProofRequired
|
||||||
timing.setProofRequired(id, true)
|
proofs.setProofRequired(id, true)
|
||||||
await timing.advanceToNextPeriod()
|
await proofs.advanceToNextPeriod()
|
||||||
check not called
|
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/random
|
||||||
|
import std/sequtils
|
||||||
import pkg/stint
|
import pkg/stint
|
||||||
|
|
||||||
proc example*[T: SomeInteger](_: type T): T =
|
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:
|
for item in result.mitems:
|
||||||
item = T.example
|
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 =
|
proc example*(_: type UInt256): UInt256 =
|
||||||
UInt256.fromBytes(array[32, byte].example)
|
UInt256.fromBytes(array[32, byte].example)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import ./contracts/testCollateral
|
import ./contracts/testCollateral
|
||||||
import ./contracts/testContracts
|
import ./contracts/testContracts
|
||||||
import ./contracts/testMarket
|
import ./contracts/testMarket
|
||||||
import ./contracts/testProofTiming
|
import ./contracts/testProofs
|
||||||
|
|
||||||
{.warning[UnusedImport]:off.}
|
{.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