mirror of
https://github.com/logos-storage/logos-storage-nim.git
synced 2026-05-05 19:09:28 +00:00
contracts: introduce types for time and tokens
fixes bugs with slotqueue and repostore, where expiry duration was misinterpreted as expiry timestamp
This commit is contained in:
parent
46ca467449
commit
ea3b9916b2
@ -1,7 +1,6 @@
|
||||
import pkg/chronos
|
||||
import pkg/stew/endians2
|
||||
import pkg/upraises
|
||||
import pkg/stint
|
||||
|
||||
type
|
||||
Clock* = ref object of RootObj
|
||||
@ -42,6 +41,3 @@ proc toSecondsSince1970*(bytes: seq[byte]): SecondsSince1970 =
|
||||
|
||||
proc toSecondsSince1970*(num: uint64): SecondsSince1970 =
|
||||
cast[int64](num)
|
||||
|
||||
proc toSecondsSince1970*(bigint: StUint[40]): SecondsSince1970 =
|
||||
bigint.truncate(int64)
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import pkg/contractabi
|
||||
import pkg/ethers/contracts/fields
|
||||
import pkg/questionable/results
|
||||
import ./requests
|
||||
|
||||
export contractabi
|
||||
|
||||
@ -11,7 +12,7 @@ type
|
||||
collateral*: CollateralConfig
|
||||
proofs*: ProofConfig
|
||||
reservations*: SlotReservationsConfig
|
||||
requestDurationLimit*: StUint[40]
|
||||
requestDurationLimit*: StorageDuration
|
||||
|
||||
CollateralConfig* = object
|
||||
repairRewardPercentage*: uint8
|
||||
@ -22,8 +23,8 @@ type
|
||||
# percentage of the slashed amount going to the validators
|
||||
|
||||
ProofConfig* = object
|
||||
period*: StUint[40] # proofs requirements are calculated per period (in seconds)
|
||||
timeout*: StUint[40] # mark proofs as missing before the timeout (in seconds)
|
||||
period*: StorageDuration # proofs requirements are calculated per period (in seconds)
|
||||
timeout*: StorageDuration # mark proofs as missing before the timeout (in seconds)
|
||||
downtime*: uint8 # ignore this much recent blocks for proof requirements
|
||||
downtimeProduct*: uint8
|
||||
zkeyHash*: string # hash of the zkey file which is linked to the verifier
|
||||
|
||||
@ -89,7 +89,7 @@ template withAllowanceLock*(market: OnChainMarket, body: untyped) =
|
||||
raise newException(Defect, error.msg, error)
|
||||
|
||||
proc approveFunds(
|
||||
market: OnChainMarket, amount: UInt256
|
||||
market: OnChainMarket, amount: Tokens
|
||||
) {.async: (raises: [CancelledError, MarketError]).} =
|
||||
debug "Approving tokens", amount
|
||||
convertEthersError("Failed to approve funds"):
|
||||
@ -99,7 +99,7 @@ proc approveFunds(
|
||||
let spender = market.contract.address
|
||||
market.withAllowanceLock:
|
||||
let allowance = await token.allowance(owner, spender)
|
||||
discard await token.approve(spender, allowance + amount).confirm(1)
|
||||
discard await token.approve(spender, allowance + amount.u256).confirm(1)
|
||||
|
||||
method getSigner*(
|
||||
market: OnChainMarket
|
||||
@ -112,16 +112,16 @@ method zkeyHash*(market: OnChainMarket): string =
|
||||
|
||||
method periodicity*(market: OnChainMarket): Periodicity =
|
||||
let period = market.configuration.proofs.period
|
||||
return Periodicity(seconds: period.u64)
|
||||
return Periodicity(seconds: period)
|
||||
|
||||
method proofTimeout*(market: OnChainMarket): uint64 =
|
||||
return market.configuration.proofs.timeout.u64
|
||||
method proofTimeout*(market: OnChainMarket): StorageDuration =
|
||||
return market.configuration.proofs.timeout
|
||||
|
||||
method repairRewardPercentage*(market: OnChainMarket): uint8 =
|
||||
return market.configuration.collateral.repairRewardPercentage
|
||||
|
||||
method requestDurationLimit*(market: OnChainMarket): uint64 =
|
||||
return market.configuration.requestDurationLimit.u64
|
||||
method requestDurationLimit*(market: OnChainMarket): StorageDuration =
|
||||
return market.configuration.requestDurationLimit
|
||||
|
||||
method proofDowntime*(market: OnChainMarket): uint8 =
|
||||
return market.configuration.proofs.downtime
|
||||
@ -147,7 +147,7 @@ method requestStorage(
|
||||
) {.async: (raises: [CancelledError, MarketError]).} =
|
||||
convertEthersError("Failed to request storage"):
|
||||
debug "Requesting storage"
|
||||
await market.approveFunds(request.totalPrice().stuint(256))
|
||||
await market.approveFunds(request.totalPrice())
|
||||
discard await market.contract.requestStorage(request).confirm(1)
|
||||
|
||||
method getRequest*(
|
||||
@ -188,13 +188,13 @@ method slotState*(
|
||||
|
||||
method getRequestEnd*(
|
||||
market: OnChainMarket, id: RequestId
|
||||
): Future[SecondsSince1970] {.async.} =
|
||||
): Future[StorageTimestamp] {.async.} =
|
||||
convertEthersError("Failed to get request end"):
|
||||
return await market.contract.requestEnd(id)
|
||||
|
||||
method requestExpiresAt*(
|
||||
market: OnChainMarket, id: RequestId
|
||||
): Future[SecondsSince1970] {.async.} =
|
||||
): Future[StorageTimestamp] {.async.} =
|
||||
convertEthersError("Failed to get request expiry"):
|
||||
return await market.contract.requestExpiry(id)
|
||||
|
||||
@ -211,7 +211,7 @@ method getHost(
|
||||
|
||||
method currentCollateral*(
|
||||
market: OnChainMarket, slotId: SlotId
|
||||
): Future[UInt128] {.async: (raises: [MarketError, CancelledError]).} =
|
||||
): Future[Tokens] {.async: (raises: [MarketError, CancelledError]).} =
|
||||
convertEthersError("Failed to get slot's current collateral"):
|
||||
return await market.contract.currentCollateral(slotId)
|
||||
|
||||
@ -227,7 +227,7 @@ method fillSlot(
|
||||
requestId: RequestId,
|
||||
slotIndex: uint64,
|
||||
proof: Groth16Proof,
|
||||
collateral: UInt128,
|
||||
collateral: Tokens,
|
||||
) {.async: (raises: [CancelledError, MarketError]).} =
|
||||
convertEthersError("Failed to fill slot"):
|
||||
logScope:
|
||||
@ -235,7 +235,7 @@ method fillSlot(
|
||||
slotIndex
|
||||
|
||||
try:
|
||||
await market.approveFunds(collateral.stuint(256))
|
||||
await market.approveFunds(collateral)
|
||||
|
||||
# Add 10% to gas estimate to deal with different evm code flow when we
|
||||
# happen to be the last one to fill a slot in this request
|
||||
@ -306,7 +306,7 @@ method submitProof*(
|
||||
discard await market.contract.submitProof(id, proof).confirm(1)
|
||||
|
||||
method markProofAsMissing*(
|
||||
market: OnChainMarket, id: SlotId, period: Period
|
||||
market: OnChainMarket, id: SlotId, period: ProofPeriod
|
||||
) {.async: (raises: [CancelledError, MarketError]).} =
|
||||
convertEthersError("Failed to mark proof as missing"):
|
||||
# Add 10% to gas estimate to deal with different evm code flow when we
|
||||
@ -314,16 +314,16 @@ method markProofAsMissing*(
|
||||
let gas = await market.contract.estimateGas.markProofAsMissing(id, period)
|
||||
let overrides = TransactionOverrides(gasLimit: some (gas * 110) div 100)
|
||||
|
||||
discard await market.contract.markProofAsMissing(id, period.stuint(40), overrides).confirm(1)
|
||||
discard await market.contract.markProofAsMissing(id, period, overrides).confirm(1)
|
||||
|
||||
method canProofBeMarkedAsMissing*(
|
||||
market: OnChainMarket, id: SlotId, period: Period
|
||||
market: OnChainMarket, id: SlotId, period: ProofPeriod
|
||||
): Future[bool] {.async.} =
|
||||
let provider = market.contract.provider
|
||||
let contractWithoutSigner = market.contract.connect(provider)
|
||||
let overrides = CallOverrides(blockTag: some BlockTag.pending)
|
||||
try:
|
||||
discard await contractWithoutSigner.markProofAsMissing(id, period.stuint(40), overrides)
|
||||
discard await contractWithoutSigner.markProofAsMissing(id, period, overrides)
|
||||
return true
|
||||
except EthersError as e:
|
||||
trace "Proof cannot be marked as missing", msg = e.msg
|
||||
@ -361,7 +361,7 @@ method subscribeRequests*(
|
||||
error "There was an error in Request subscription", msg = eventErr.msg
|
||||
return
|
||||
|
||||
callback(event.requestId, event.ask, event.expiry.truncate(uint64))
|
||||
callback(event.requestId, event.ask, event.expiry)
|
||||
|
||||
convertEthersError("Failed to subscribe to StorageRequested events"):
|
||||
let subscription = await market.contract.subscribe(StorageRequested, onEvent)
|
||||
|
||||
@ -58,7 +58,7 @@ proc configuration*(marketplace: Marketplace): MarketplaceConfig {.contract, vie
|
||||
proc token*(marketplace: Marketplace): Address {.contract, view.}
|
||||
proc currentCollateral*(
|
||||
marketplace: Marketplace, id: SlotId
|
||||
): UInt128 {.contract, view.}
|
||||
): Tokens {.contract, view.}
|
||||
|
||||
proc requestStorage*(
|
||||
marketplace: Marketplace, request: StorageRequest
|
||||
@ -131,11 +131,11 @@ proc requestState*(
|
||||
proc slotState*(marketplace: Marketplace, slotId: SlotId): SlotState {.contract, view.}
|
||||
proc requestEnd*(
|
||||
marketplace: Marketplace, requestId: RequestId
|
||||
): SecondsSince1970 {.contract, view.}
|
||||
): StorageTimestamp {.contract, view.}
|
||||
|
||||
proc requestExpiry*(
|
||||
marketplace: Marketplace, requestId: RequestId
|
||||
): SecondsSince1970 {.contract, view.}
|
||||
): StorageTimestamp {.contract, view.}
|
||||
|
||||
proc missingProofs*(marketplace: Marketplace, id: SlotId): UInt256 {.contract, view.}
|
||||
proc isProofRequired*(marketplace: Marketplace, id: SlotId): bool {.contract, view.}
|
||||
@ -155,7 +155,7 @@ proc submitProof*(
|
||||
.}
|
||||
|
||||
proc markProofAsMissing*(
|
||||
marketplace: Marketplace, id: SlotId, period: StUint[40]
|
||||
marketplace: Marketplace, id: SlotId, period: ProofPeriod
|
||||
): Confirmable {.
|
||||
contract,
|
||||
errors: [
|
||||
|
||||
18
codex/contracts/periods.nim
Normal file
18
codex/contracts/periods.nim
Normal file
@ -0,0 +1,18 @@
|
||||
import ../clock
|
||||
import ./requests
|
||||
|
||||
type
|
||||
Periodicity* = object
|
||||
seconds*: StorageDuration
|
||||
|
||||
func periodOf*(periodicity: Periodicity, timestamp: StorageTimestamp): ProofPeriod =
|
||||
ProofPeriod.init(timestamp.u40 div periodicity.seconds.u40)
|
||||
|
||||
func periodOf*(periodicity: Periodicity, timestamp: SecondsSince1970): ProofPeriod =
|
||||
periodicity.periodOf(StorageTimestamp.init(timestamp))
|
||||
|
||||
func periodStart*(periodicity: Periodicity, period: ProofPeriod): StorageTimestamp =
|
||||
StorageTimestamp.init(period.u40 * periodicity.seconds.u40)
|
||||
|
||||
func periodEnd*(periodicity: Periodicity, period: ProofPeriod): StorageTimestamp =
|
||||
periodicity.periodStart(period + 1'u8)
|
||||
@ -10,8 +10,12 @@ import pkg/libp2p/[cid, multicodec]
|
||||
import ../logutils
|
||||
import ../utils/json
|
||||
from ../errors import mapFailure
|
||||
import ./timestamps
|
||||
import ./tokens
|
||||
|
||||
export contractabi
|
||||
export timestamps
|
||||
export tokens
|
||||
|
||||
type
|
||||
StorageRequest* = object
|
||||
@ -24,7 +28,7 @@ type
|
||||
StorageAsk* = object
|
||||
proofProbability* {.serialize.}: UInt256
|
||||
pricePerBytePerSecond* {.serialize.}: TokensPerSecond
|
||||
collateralPerByte* {.serialize.}: UInt128
|
||||
collateralPerByte* {.serialize.}: Tokens
|
||||
slots* {.serialize.}: uint64
|
||||
slotSize* {.serialize.}: uint64
|
||||
duration* {.serialize.}: StorageDuration
|
||||
@ -56,9 +60,6 @@ type
|
||||
Cancelled
|
||||
Repair
|
||||
|
||||
StorageDuration* = StUint[40]
|
||||
TokensPerSecond* = StUint[96]
|
||||
|
||||
proc `==`*(x, y: Nonce): bool {.borrow.}
|
||||
proc `==`*(x, y: RequestId): bool {.borrow.}
|
||||
proc `==`*(x, y: SlotId): bool {.borrow.}
|
||||
@ -69,9 +70,6 @@ proc hash*(x: Address): Hash {.borrow.}
|
||||
func toArray*(id: RequestId | SlotId | Nonce): array[32, byte] =
|
||||
array[32, byte](id)
|
||||
|
||||
func u64*(uint40: StUint[40]): uint64 =
|
||||
uint40.truncate(uint64)
|
||||
|
||||
proc `$`*(id: RequestId | SlotId | Nonce): string =
|
||||
id.toArray.toHex
|
||||
|
||||
@ -139,12 +137,6 @@ func solidityType*(_: type StorageAsk): string =
|
||||
func solidityType*(_: type StorageRequest): string =
|
||||
solidityType(StorageRequest.fieldTypes)
|
||||
|
||||
func solidityType*(_: type StUint[40]): string =
|
||||
"uint40"
|
||||
|
||||
func solidityType*(_: type StUint[96]): string =
|
||||
"uint96"
|
||||
|
||||
# Note: it seems to be ok to ignore the vbuffer offset for now
|
||||
func encode*(encoder: var AbiEncoder, cid: Cid) =
|
||||
encoder.write(cid.data.buffer)
|
||||
@ -199,19 +191,19 @@ func id*(slot: Slot): SlotId =
|
||||
slotId(slot.request, slot.slotIndex)
|
||||
|
||||
func pricePerSlotPerSecond*(ask: StorageAsk): TokensPerSecond =
|
||||
ask.pricePerBytePerSecond * ask.slotSize.to(TokensPerSecond)
|
||||
ask.pricePerBytePerSecond * ask.slotSize
|
||||
|
||||
func pricePerSlot*(ask: StorageAsk): UInt128 =
|
||||
ask.duration.stuint(128) * ask.pricePerSlotPerSecond.stuint(128)
|
||||
func pricePerSlot*(ask: StorageAsk): Tokens =
|
||||
ask.pricePerSlotPerSecond * ask.duration
|
||||
|
||||
func totalPrice*(ask: StorageAsk): UInt128 =
|
||||
ask.slots.stuint(128) * ask.pricePerSlot
|
||||
func totalPrice*(ask: StorageAsk): Tokens =
|
||||
ask.pricePerSlot * ask.slots
|
||||
|
||||
func totalPrice*(request: StorageRequest): UInt128 =
|
||||
func totalPrice*(request: StorageRequest): Tokens =
|
||||
request.ask.totalPrice
|
||||
|
||||
func collateralPerSlot*(ask: StorageAsk): UInt128 =
|
||||
ask.collateralPerByte * ask.slotSize.stuint(128)
|
||||
func collateralPerSlot*(ask: StorageAsk): Tokens =
|
||||
ask.collateralPerByte * ask.slotSize
|
||||
|
||||
func size*(ask: StorageAsk): uint64 =
|
||||
ask.slots * ask.slotSize
|
||||
|
||||
168
codex/contracts/timestamps.nim
Normal file
168
codex/contracts/timestamps.nim
Normal file
@ -0,0 +1,168 @@
|
||||
import pkg/stint
|
||||
import pkg/contractabi
|
||||
import ../utils/json
|
||||
from ../clock import SecondsSince1970
|
||||
|
||||
type
|
||||
StorageTimestamp* = object
|
||||
value: StUint[40]
|
||||
StorageDuration* = object
|
||||
value: StUint[40]
|
||||
ProofPeriod* = object
|
||||
value: StUint[40]
|
||||
|
||||
func u40*(duration: StorageDuration): StUint[40] =
|
||||
duration.value
|
||||
|
||||
func u40*(duration: StorageTimestamp): StUint[40] =
|
||||
duration.value
|
||||
|
||||
func u40*(period: ProofPeriod): StUint[40] =
|
||||
period.value
|
||||
|
||||
func u64*(duration: StorageDuration): uint64 =
|
||||
duration.value.truncate(uint64)
|
||||
|
||||
func u64*(timestamp: StorageTimestamp): uint64 =
|
||||
timestamp.value.truncate(uint64)
|
||||
|
||||
func u64*(period: ProofPeriod): uint64 =
|
||||
period.value.truncate(uint64)
|
||||
|
||||
func u256*(timestamp: StorageTimestamp): UInt256 =
|
||||
timestamp.value.stuint(256)
|
||||
|
||||
func u256*(duration: StorageDuration): UInt256 =
|
||||
duration.value.stuint(256)
|
||||
|
||||
proc toSecondsSince1970*(timestamp: StorageTimestamp): SecondsSince1970 =
|
||||
timestamp.value.truncate(int64)
|
||||
|
||||
func `'StorageDuration`*(value: static string): StorageDuration =
|
||||
const parsed = parse(value, StUint[40])
|
||||
StorageDuration(value: parsed)
|
||||
|
||||
func `'StorageTimestamp`*(value: static string): StorageTimestamp =
|
||||
const parsed =parse(value, StUint[40])
|
||||
StorageTimestamp(value: parsed)
|
||||
|
||||
func init*(_: type StorageDuration, value: StUint[40]): StorageDuration =
|
||||
StorageDuration(value: value)
|
||||
|
||||
func init*(_: type StorageDuration, value: uint32 | uint16 | uint8): StorageDuration =
|
||||
StorageDuration.init(value.stuint(40))
|
||||
|
||||
func init*(_: type StorageTimestamp, value: StUint[40]): StorageTimestamp =
|
||||
StorageTimestamp(value: value)
|
||||
|
||||
func init*(_: type StorageTimestamp, value: uint32 | uint16 | uint8): StorageTimestamp =
|
||||
StorageTimestamp.init(value.stuint(40))
|
||||
|
||||
func init*(_: type StorageTimestamp, value: SecondsSince1970): StorageTimestamp =
|
||||
# The maximum timestamp is 2^40-1 seconds after 1970, which is the year 36,835
|
||||
const maximum = StUint[40].high.truncate(SecondsSince1970)
|
||||
if value > maximum:
|
||||
# make sure that we don't wrap around to a time in the past
|
||||
return StorageTimestamp.init(maximum.stuint(40))
|
||||
StorageTimestamp.init(value.stuint(40))
|
||||
|
||||
func init*(_: type ProofPeriod, value: StUint[40]): ProofPeriod =
|
||||
ProofPeriod(value: value)
|
||||
|
||||
func `*`*(a: StorageDuration, b: uint32 | uint16 | uint8): StorageDuration =
|
||||
StorageDuration.init(a.value * b.stuint(40))
|
||||
|
||||
func `+`*(a: StorageTimestamp, b: StorageDuration): StorageTimestamp =
|
||||
StorageTimestamp(value: a.value + b.value)
|
||||
|
||||
func `+`*(a: StorageTimestamp, b: uint32 | uint16 | uint8): StorageTimestamp =
|
||||
StorageTimestamp(value: a.value + b.stuint(40))
|
||||
|
||||
func `+`*(a: StorageDuration, b: StorageDuration): StorageDuration =
|
||||
StorageDuration(value: a.value + b.value)
|
||||
|
||||
func `+`*(a: StorageDuration, b: uint32 | uint16 | uint8): StorageDuration =
|
||||
StorageDuration(value: a.value + b.stuint(40))
|
||||
|
||||
func `+`*(a: ProofPeriod, b: uint32 | uint16 | uint8): ProofPeriod =
|
||||
ProofPeriod(value: a.value + b.stuint(40))
|
||||
|
||||
func `-`*(a: StorageTimestamp, b: uint32 | uint16 | uint8): StorageTimestamp =
|
||||
StorageTimestamp(value: a.value - b.stuint(40))
|
||||
|
||||
func `-`*(a: StorageDuration, b: StorageDuration): StorageDuration =
|
||||
StorageDuration(value: a.value - b.value)
|
||||
|
||||
func `-`*(a: StorageDuration, b: uint32 | uint16 | uint8): StorageDuration =
|
||||
StorageDuration(value: a.value - b.stuint(40))
|
||||
|
||||
func `-`*(a: ProofPeriod, b: uint32 | uint16 | uint8): ProofPeriod =
|
||||
ProofPeriod(value: a.value - b.stuint(40))
|
||||
|
||||
func `+=`*(a: var StorageTimestamp, b: StorageDuration): StorageTimestamp =
|
||||
a.value += b.value
|
||||
|
||||
func `+=`*[T: StorageDuration | StorageTimestamp](a: var T, b: T) =
|
||||
a.value += b.value
|
||||
|
||||
func `-=`*[T: StorageDuration | StorageTimestamp](a: var T, b: T) =
|
||||
a.value -= b.value
|
||||
|
||||
func `<`*(a, b: StorageDuration | StorageTimestamp): bool =
|
||||
a.value < b.value
|
||||
|
||||
func `>`*(a, b: StorageDuration | StorageTimestamp): bool =
|
||||
a.value > b.value
|
||||
|
||||
func `<=`*(a, b: StorageDuration | StorageTimestamp): bool =
|
||||
a.value <= b.value
|
||||
|
||||
func `>=`*(a, b: StorageDuration | StorageTimestamp): bool =
|
||||
a.value >= b.value
|
||||
|
||||
func until*(earlier, later: StorageTimestamp): StorageDuration =
|
||||
doAssert earlier <= later
|
||||
StorageDuration.init(later.u40 - earlier.u40)
|
||||
|
||||
func solidityType*(_: type StorageDuration): string =
|
||||
"uint40"
|
||||
|
||||
func solidityType*(_: type StorageTimestamp): string =
|
||||
"uint40"
|
||||
|
||||
func solidityType*(_: type ProofPeriod): string =
|
||||
"uint40"
|
||||
|
||||
func encode*(encoder: var AbiEncoder, timestamp: StorageDuration) =
|
||||
encoder.write(timestamp.value)
|
||||
|
||||
func encode*(encoder: var AbiEncoder, timestamp: StorageTimestamp) =
|
||||
encoder.write(timestamp.value)
|
||||
|
||||
func encode*(encoder: var AbiEncoder, period: ProofPeriod) =
|
||||
encoder.write(period.value)
|
||||
|
||||
func decode*(decoder: var AbiDecoder, T: type StorageDuration): ?!T =
|
||||
let value = ?decoder.read(T.value)
|
||||
success T(value: value)
|
||||
|
||||
func decode*(decoder: var AbiDecoder, T: type StorageTimestamp): ?!T =
|
||||
let value = ?decoder.read(T.value)
|
||||
success T(value: value)
|
||||
|
||||
func decode*(decoder: var AbiDecoder, T: type ProofPeriod): ?!T =
|
||||
let value = ?decoder.read(T.value)
|
||||
success T(value: value)
|
||||
|
||||
func `%`*(value: StorageDuration | StorageTimestamp | ProofPeriod): JsonNode =
|
||||
%value.value
|
||||
|
||||
func fromJson*(_: type StorageDuration, json: JsonNode): ?!StorageDuration =
|
||||
success StorageDuration(value: ? StUint[40].fromJson(json))
|
||||
|
||||
func fromJson*(_: type StorageTimestamp, json: JsonNode): ?!StorageTimestamp =
|
||||
success StorageTimestamp(value: ? StUint[40].fromJson(json))
|
||||
|
||||
func fromJson*(_: type ProofPeriod, json: JsonNode): ?!ProofPeriod =
|
||||
success ProofPeriod(value: ? StUint[40].fromJson(json))
|
||||
|
||||
108
codex/contracts/tokens.nim
Normal file
108
codex/contracts/tokens.nim
Normal file
@ -0,0 +1,108 @@
|
||||
import pkg/stint
|
||||
import pkg/contractabi
|
||||
import ../utils/json
|
||||
import ./timestamps
|
||||
|
||||
type
|
||||
TokensPerSecond* = object
|
||||
value: StUint[96]
|
||||
Tokens* = object
|
||||
value: StUint[128]
|
||||
|
||||
func u256*(tokensPerSecond: TokensPerSecond): UInt256 =
|
||||
tokensPerSecond.value.stuint(256)
|
||||
|
||||
func u256*(tokens: Tokens): UInt256 =
|
||||
tokens.value.stuint(256)
|
||||
|
||||
func `'TokensPerSecond`*(value: static string): TokensPerSecond =
|
||||
const parsed = parse(value, StUint[96])
|
||||
TokensPerSecond(value: parsed)
|
||||
|
||||
func `'Tokens`*(value: static string): Tokens =
|
||||
const parsed = parse(value, UInt128)
|
||||
Tokens(value: parsed)
|
||||
|
||||
func init*(_: type TokensPerSecond, value: StUint[96]): TokensPerSecond =
|
||||
TokensPerSecond(value: value)
|
||||
|
||||
func init*(_: type TokensPerSecond, value: SomeUnsignedInt): TokensPerSecond =
|
||||
TokensPerSecond.init(value.stuint(96))
|
||||
|
||||
func init*(_: type Tokens, value: UInt128): Tokens =
|
||||
Tokens(value: value)
|
||||
|
||||
func init*(_: type Tokens, value: SomeUnsignedInt): Tokens =
|
||||
Tokens.init(value.stuint(128))
|
||||
|
||||
func `*`*(a: TokensPerSecond, b: SomeUnsignedInt): TokensPerSecond =
|
||||
TokensPerSecond(value: a.value * b.stuint(96))
|
||||
|
||||
func `*`*(a: TokensPerSecond, b: StorageDuration): Tokens =
|
||||
Tokens(value: a.value.stuint(128) * b.u40.stuint(128))
|
||||
|
||||
func `*`*(a: Tokens, b: SomeUnsignedInt): Tokens =
|
||||
Tokens(value: a.value * b.stuint(128))
|
||||
|
||||
func `div`*(a: Tokens, b: SomeUnsignedInt): Tokens =
|
||||
Tokens(value: a.value div b.stuint(128))
|
||||
|
||||
func `+`*(a, b: Tokens): Tokens =
|
||||
Tokens(value: a.value + b.value)
|
||||
|
||||
func `+`*(a: Tokens, b: SomeUnsignedInt): Tokens =
|
||||
Tokens(value: a.value + b.u128)
|
||||
|
||||
func `+`*(a: TokensPerSecond, b: SomeUnsignedInt): TokensPerSecond =
|
||||
TokensPerSecond(value: a.value + b.stuint(96))
|
||||
|
||||
func `-`*(a, b: Tokens): Tokens =
|
||||
Tokens(value: a.value - b.value)
|
||||
|
||||
func `+=`*[T: Tokens | TokensPerSecond](a: var T, b: T) =
|
||||
a.value += b.value
|
||||
|
||||
func `-=`*[T: Tokens | TokensPerSecond](a: var T, b: T) =
|
||||
a.value -= b.value
|
||||
|
||||
func `<`*(a, b: Tokens | TokensPerSecond): bool =
|
||||
a.value < b.value
|
||||
|
||||
func `>`*(a, b: Tokens | TokensPerSecond): bool =
|
||||
a.value > b.value
|
||||
|
||||
func `<=`*(a, b: Tokens | TokensPerSecond): bool =
|
||||
a.value <= b.value
|
||||
|
||||
func `>=`*(a, b: Tokens | TokensPerSecond): bool =
|
||||
a.value >= b.value
|
||||
|
||||
func solidityType*(_: type TokensPerSecond): string =
|
||||
"uint96"
|
||||
|
||||
func solidityType*(_: type Tokens): string =
|
||||
"uint128"
|
||||
|
||||
func encode*(encoder: var AbiEncoder, tokensPerSecond: TokensPerSecond) =
|
||||
encoder.write(tokensPerSecond.value)
|
||||
|
||||
func encode*(encoder: var AbiEncoder, tokens: Tokens) =
|
||||
encoder.write(tokens.value)
|
||||
|
||||
func decode*(decoder: var AbiDecoder, T: type TokensPerSecond): ?!T =
|
||||
let value = ?decoder.read(T.value)
|
||||
success T(value: value)
|
||||
|
||||
func decode*(decoder: var AbiDecoder, T: type Tokens): ?!T =
|
||||
let value = ?decoder.read(T.value)
|
||||
success T(value: value)
|
||||
|
||||
func `%`*(value: TokensPerSecond | Tokens): JsonNode =
|
||||
%value.value
|
||||
|
||||
func fromJson*(_: type TokensPerSecond, json: JsonNode): ?!TokensPerSecond =
|
||||
success TokensPerSecond(value: ? StUint[96].fromJson(json))
|
||||
|
||||
func fromJson*(_: type Tokens, json: JsonNode): ?!Tokens =
|
||||
success Tokens(value: ? UInt128.fromJson(json))
|
||||
|
||||
@ -4,9 +4,9 @@ import pkg/questionable
|
||||
import pkg/ethers/erc20
|
||||
import ./contracts/requests
|
||||
import ./contracts/proofs
|
||||
import ./contracts/periods
|
||||
import ./clock
|
||||
import ./errors
|
||||
import ./periods
|
||||
|
||||
export chronos
|
||||
export questionable
|
||||
@ -22,7 +22,7 @@ type
|
||||
SlotReservationNotAllowedError* = object of MarketError
|
||||
Subscription* = ref object of RootObj
|
||||
OnRequest* =
|
||||
proc(id: RequestId, ask: StorageAsk, expiry: uint64) {.gcsafe, upraises: [].}
|
||||
proc(id: RequestId, ask: StorageAsk, expiry: StorageTimestamp) {.gcsafe, upraises: [].}
|
||||
OnFulfillment* = proc(requestId: RequestId) {.gcsafe, upraises: [].}
|
||||
OnSlotFilled* = proc(requestId: RequestId, slotIndex: uint64) {.gcsafe, upraises: [].}
|
||||
OnSlotFreed* = proc(requestId: RequestId, slotIndex: uint64) {.gcsafe, upraises: [].}
|
||||
@ -37,7 +37,7 @@ type
|
||||
StorageRequested* = object of MarketplaceEvent
|
||||
requestId*: RequestId
|
||||
ask*: StorageAsk
|
||||
expiry*: StorageDuration
|
||||
expiry*: StorageTimestamp
|
||||
|
||||
SlotFilled* = object of MarketplaceEvent
|
||||
requestId* {.indexed.}: RequestId
|
||||
@ -65,16 +65,19 @@ method getSigner*(
|
||||
): Future[Address] {.base, async: (raises: [CancelledError, MarketError]).} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method zkeyHash*(market: Market): string {.base, gcsafe, raises:[].} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method periodicity*(market: Market): Periodicity {.base, gcsafe, raises:[].} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method proofTimeout*(market: Market): uint64 {.base, gcsafe, raises:[].} =
|
||||
method proofTimeout*(market: Market): StorageDuration {.base, gcsafe, raises:[].} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method repairRewardPercentage*(market: Market): uint8 {.base, gcsafe, raises:[].} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method requestDurationLimit*(market: Market): uint64 {.base, gcsafe, raises:[].} =
|
||||
method requestDurationLimit*(market: Market): StorageDuration {.base, gcsafe, raises:[].} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method proofDowntime*(market: Market): uint8 {.base, gcsafe, raises: [].} =
|
||||
@ -115,12 +118,12 @@ method slotState*(
|
||||
|
||||
method getRequestEnd*(
|
||||
market: Market, id: RequestId
|
||||
): Future[SecondsSince1970] {.base, async.} =
|
||||
): Future[StorageTimestamp] {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method requestExpiresAt*(
|
||||
market: Market, id: RequestId
|
||||
): Future[SecondsSince1970] {.base, async.} =
|
||||
): Future[StorageTimestamp] {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method getHost*(
|
||||
@ -130,7 +133,7 @@ method getHost*(
|
||||
|
||||
method currentCollateral*(
|
||||
market: Market, slotId: SlotId
|
||||
): Future[UInt128] {.base, async: (raises: [MarketError, CancelledError]).} =
|
||||
): Future[Tokens] {.base, async: (raises: [MarketError, CancelledError]).} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method getActiveSlot*(market: Market, slotId: SlotId): Future[?Slot] {.base, async.} =
|
||||
@ -141,7 +144,7 @@ method fillSlot*(
|
||||
requestId: RequestId,
|
||||
slotIndex: uint64,
|
||||
proof: Groth16Proof,
|
||||
collateral: UInt128,
|
||||
collateral: Tokens,
|
||||
) {.base, async: (raises: [CancelledError, MarketError]).} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
@ -177,12 +180,12 @@ method submitProof*(
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method markProofAsMissing*(
|
||||
market: Market, id: SlotId, period: Period
|
||||
market: Market, id: SlotId, period: ProofPeriod
|
||||
) {.base, async: (raises: [CancelledError, MarketError]).} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method canProofBeMarkedAsMissing*(
|
||||
market: Market, id: SlotId, period: Period
|
||||
market: Market, id: SlotId, period: ProofPeriod
|
||||
): Future[bool] {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
|
||||
@ -494,7 +494,7 @@ proc setupRequest(
|
||||
nodes: uint,
|
||||
tolerance: uint,
|
||||
pricePerBytePerSecond: TokensPerSecond,
|
||||
collateralPerByte: UInt128,
|
||||
collateralPerByte: Tokens,
|
||||
expiry: StorageDuration,
|
||||
): Future[?!StorageRequest] {.async.} =
|
||||
## Setup slots for a given dataset
|
||||
@ -575,7 +575,7 @@ proc requestStorage*(
|
||||
nodes: uint,
|
||||
tolerance: uint,
|
||||
pricePerBytePerSecond: TokensPerSecond,
|
||||
collateralPerByte: UInt128,
|
||||
collateralPerByte: Tokens,
|
||||
expiry: StorageDuration,
|
||||
): Future[?!PurchaseId] {.async.} =
|
||||
## Initiate a request for storage sequence, this might
|
||||
@ -614,6 +614,7 @@ proc requestStorage*(
|
||||
proc onStore(
|
||||
self: CodexNodeRef,
|
||||
request: StorageRequest,
|
||||
expiry: StorageTimestamp,
|
||||
slotIdx: uint64,
|
||||
blocksCb: BlocksCb,
|
||||
isRepairing: bool = false,
|
||||
@ -642,8 +643,6 @@ proc onStore(
|
||||
trace "Unable to create slots builder", err = err.msg
|
||||
return failure(err)
|
||||
|
||||
let expiry = request.expiry
|
||||
|
||||
if slotIdx > manifest.slotRoots.high.uint64:
|
||||
trace "Slot index not in manifest", slotIdx
|
||||
return failure(newException(CodexError, "Slot index not in manifest"))
|
||||
@ -778,11 +777,12 @@ proc start*(self: CodexNodeRef) {.async.} =
|
||||
if hostContracts =? self.contracts.host:
|
||||
hostContracts.sales.onStore = proc(
|
||||
request: StorageRequest,
|
||||
expiry: StorageTimestamp,
|
||||
slot: uint64,
|
||||
onBatch: BatchProc,
|
||||
isRepairing: bool = false,
|
||||
): Future[?!void] =
|
||||
self.onStore(request, slot, onBatch, isRepairing)
|
||||
self.onStore(request, expiry, slot, onBatch, isRepairing)
|
||||
|
||||
hostContracts.sales.onExpiryUpdate = proc(
|
||||
rootCid: Cid, expiry: SecondsSince1970
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
import pkg/stint
|
||||
|
||||
type
|
||||
Periodicity* = object
|
||||
seconds*: uint64
|
||||
|
||||
Period* = uint64
|
||||
Timestamp* = uint64
|
||||
|
||||
func periodOf*(periodicity: Periodicity, timestamp: Timestamp): Period =
|
||||
timestamp div periodicity.seconds
|
||||
|
||||
func periodStart*(periodicity: Periodicity, period: Period): Timestamp =
|
||||
period * periodicity.seconds
|
||||
|
||||
func periodEnd*(periodicity: Periodicity, period: Period): Timestamp =
|
||||
periodicity.periodStart(period + 1)
|
||||
@ -34,9 +34,10 @@ method run*(
|
||||
var ended: Future[void]
|
||||
try:
|
||||
let subscription = await market.subscribeRequestFailed(purchase.requestId, callback)
|
||||
let requestEnd = await market.getRequestEnd(purchase.requestId)
|
||||
|
||||
# Ensure that we're past the request end by waiting an additional second
|
||||
ended = clock.waitUntil((await market.getRequestEnd(purchase.requestId)) + 1)
|
||||
ended = clock.waitUntil(requestEnd.toSecondsSince1970 + 1)
|
||||
let fut = await one(ended, failed)
|
||||
await subscription.unsubscribe()
|
||||
if fut.id == failed.id:
|
||||
|
||||
@ -39,9 +39,9 @@ method run*(
|
||||
await subscription.unsubscribe()
|
||||
|
||||
proc withTimeout(future: Future[void]) {.async.} =
|
||||
let expiry = (await market.requestExpiresAt(request.id)) + 1
|
||||
let expiry = (await market.requestExpiresAt(request.id)) + 1'u8
|
||||
trace "waiting for request fulfillment or expiry", expiry
|
||||
await future.withTimeout(clock, expiry)
|
||||
await future.withTimeout(clock, expiry.toSecondsSince1970)
|
||||
|
||||
try:
|
||||
await wait().withTimeout()
|
||||
|
||||
@ -489,7 +489,7 @@ proc initSalesApi(node: CodexNodeRef, router: var RestRouter) =
|
||||
restAv.minPricePerBytePerSecond,
|
||||
restAv.totalCollateral,
|
||||
enabled = restAv.enabled |? true,
|
||||
until = restAv.until |? 0,
|
||||
until = restAv.until |? 0'StorageTimestamp,
|
||||
)
|
||||
), error:
|
||||
if error of CancelledError:
|
||||
@ -681,7 +681,7 @@ proc initPurchasingApi(node: CodexNodeRef, router: var RestRouter) =
|
||||
|
||||
let expiry = params.expiry
|
||||
|
||||
if expiry <= 0 or expiry >= params.duration:
|
||||
if expiry == 0'StorageDuration or expiry >= params.duration:
|
||||
return RestApiResponse.error(
|
||||
Http422,
|
||||
"Expiry must be greater than zero and less than the request's duration",
|
||||
@ -693,12 +693,12 @@ proc initPurchasingApi(node: CodexNodeRef, router: var RestRouter) =
|
||||
Http422, "Proof probability must be greater than zero", headers = headers
|
||||
)
|
||||
|
||||
if params.collateralPerByte <= 0:
|
||||
if params.collateralPerByte <= 0'Tokens:
|
||||
return RestApiResponse.error(
|
||||
Http422, "Collateral per byte must be greater than zero", headers = headers
|
||||
)
|
||||
|
||||
if params.pricePerBytePerSecond <= 0:
|
||||
if params.pricePerBytePerSecond <= 0'TokensPerSecond:
|
||||
return RestApiResponse.error(
|
||||
Http422,
|
||||
"Price per byte per second must be greater than zero",
|
||||
@ -706,7 +706,7 @@ proc initPurchasingApi(node: CodexNodeRef, router: var RestRouter) =
|
||||
)
|
||||
|
||||
let requestDurationLimit = contracts.purchasing.market.requestDurationLimit
|
||||
if params.duration.u64 > requestDurationLimit:
|
||||
if params.duration > requestDurationLimit:
|
||||
return RestApiResponse.error(
|
||||
Http422,
|
||||
"Duration exceeds limit of " & $requestDurationLimit & " seconds",
|
||||
|
||||
@ -16,7 +16,7 @@ type
|
||||
duration* {.serialize.}: StorageDuration
|
||||
proofProbability* {.serialize.}: UInt256
|
||||
pricePerBytePerSecond* {.serialize.}: TokensPerSecond
|
||||
collateralPerByte* {.serialize.}: UInt128
|
||||
collateralPerByte* {.serialize.}: Tokens
|
||||
expiry* {.serialize.}: StorageDuration
|
||||
nodes* {.serialize.}: ?uint
|
||||
tolerance* {.serialize.}: ?uint
|
||||
@ -29,12 +29,12 @@ type
|
||||
|
||||
RestAvailability* = object
|
||||
totalSize* {.serialize.}: uint64
|
||||
duration* {.serialize.}: uint64
|
||||
minPricePerBytePerSecond* {.serialize.}: UInt256
|
||||
totalCollateral* {.serialize.}: UInt256
|
||||
duration* {.serialize.}: StorageDuration
|
||||
minPricePerBytePerSecond* {.serialize.}: TokensPerSecond
|
||||
totalCollateral* {.serialize.}: Tokens
|
||||
freeSize* {.serialize.}: ?uint64
|
||||
enabled* {.serialize.}: ?bool
|
||||
until* {.serialize.}: ?SecondsSince1970
|
||||
until* {.serialize.}: ?StorageTimestamp
|
||||
|
||||
RestSalesAgent* = object
|
||||
state* {.serialize.}: string
|
||||
|
||||
@ -114,7 +114,7 @@ proc cleanUp(
|
||||
sales: Sales,
|
||||
agent: SalesAgent,
|
||||
reprocessSlot: bool,
|
||||
returnedCollateral: ?UInt256,
|
||||
returnedCollateral: ?Tokens,
|
||||
processing: Future[void],
|
||||
) {.async.} =
|
||||
let data = agent.data
|
||||
@ -186,7 +186,7 @@ proc processSlot(sales: Sales, item: SlotQueueItem, done: Future[void]) =
|
||||
)
|
||||
|
||||
agent.onCleanUp = proc(
|
||||
reprocessSlot = false, returnedCollateral = UInt256.none
|
||||
reprocessSlot = false, returnedCollateral = Tokens.none
|
||||
) {.async.} =
|
||||
await sales.cleanUp(agent, reprocessSlot, returnedCollateral, done)
|
||||
|
||||
@ -254,7 +254,7 @@ proc load*(sales: Sales) {.async.} =
|
||||
newSalesAgent(sales.context, slot.request.id, slot.slotIndex, some slot.request)
|
||||
|
||||
agent.onCleanUp = proc(
|
||||
reprocessSlot = false, returnedCollateral = UInt256.none
|
||||
reprocessSlot = false, returnedCollateral = Tokens.none
|
||||
) {.async.} =
|
||||
# since workers are not being dispatched, this future has not been created
|
||||
# by a worker. Create a dummy one here so we can call sales.cleanUp
|
||||
@ -282,7 +282,7 @@ proc OnAvailabilitySaved(
|
||||
queue.unpause()
|
||||
|
||||
proc onStorageRequested(
|
||||
sales: Sales, requestId: RequestId, ask: StorageAsk, expiry: uint64
|
||||
sales: Sales, requestId: RequestId, ask: StorageAsk, expiry: StorageTimestamp
|
||||
) {.raises: [].} =
|
||||
logScope:
|
||||
topics = "marketplace sales onStorageRequested"
|
||||
@ -294,7 +294,7 @@ proc onStorageRequested(
|
||||
|
||||
trace "storage requested, adding slots to queue"
|
||||
|
||||
let collateral = ask.collateralPerSlot().stuint(256)
|
||||
let collateral = ask.collateralPerSlot()
|
||||
|
||||
without items =? SlotQueueItem.init(requestId, ask, expiry, collateral).catch, err:
|
||||
if err of SlotsOutOfRangeError:
|
||||
@ -331,9 +331,9 @@ proc onSlotFreed(sales: Sales, requestId: RequestId, slotIndex: uint64) =
|
||||
error "unknown request in contract", error = err.msgDetail
|
||||
return
|
||||
|
||||
let collateral = request.ask.collateralPerSlot.stuint(256)
|
||||
let collateral = request.ask.collateralPerSlot
|
||||
let percentage = context.market.repairRewardPercentage
|
||||
let repairReward = (collateral * percentage.u256) div 100.u256
|
||||
let repairReward = (collateral * percentage) div 100'u
|
||||
|
||||
if slotIndex > uint16.high.uint64:
|
||||
error "Cannot cast slot index to uint16, value = ", slotIndex
|
||||
@ -365,7 +365,7 @@ proc subscribeRequested(sales: Sales) {.async.} =
|
||||
let market = context.market
|
||||
|
||||
proc onStorageRequested(
|
||||
requestId: RequestId, ask: StorageAsk, expiry: uint64
|
||||
requestId: RequestId, ask: StorageAsk, expiry: StorageTimestamp
|
||||
) {.raises: [].} =
|
||||
sales.onStorageRequested(requestId, ask, expiry)
|
||||
|
||||
|
||||
@ -14,17 +14,17 @@
|
||||
## |---------------------------------------------------| |--------------------------------------|
|
||||
## | AvailabilityId | id | PK |<-||-------o<-| AvailabilityId | availabilityId | FK |
|
||||
## |---------------------------------------------------| |--------------------------------------|
|
||||
## | UInt256 | totalSize | | | UInt256 | size | |
|
||||
## | uint64 | totalSize | | | uint64 | size | |
|
||||
## |---------------------------------------------------| |--------------------------------------|
|
||||
## | UInt256 | freeSize | | | UInt256 | slotIndex | |
|
||||
## | uint64 | freeSize | | | uint64 | slotIndex | |
|
||||
## |---------------------------------------------------| +--------------------------------------+
|
||||
## | UInt256 | duration | |
|
||||
## | StorageDuration | duration | |
|
||||
## |---------------------------------------------------|
|
||||
## | UInt256 | minPricePerBytePerSecond | |
|
||||
## | TokensPerSecond | minPricePerBytePerSecond | |
|
||||
## |---------------------------------------------------|
|
||||
## | UInt256 | totalCollateral | |
|
||||
## | Tokens | totalCollateral | |
|
||||
## |---------------------------------------------------|
|
||||
## | UInt256 | totalRemainingCollateral | |
|
||||
## | Tokens | totalRemainingCollateral | |
|
||||
## +---------------------------------------------------+
|
||||
|
||||
import pkg/upraises
|
||||
@ -34,7 +34,6 @@ push:
|
||||
import std/sequtils
|
||||
import std/sugar
|
||||
import std/typetraits
|
||||
import std/sequtils
|
||||
import std/times
|
||||
import pkg/chronos
|
||||
import pkg/datastore
|
||||
@ -67,16 +66,16 @@ type
|
||||
id* {.serialize.}: AvailabilityId
|
||||
totalSize* {.serialize.}: uint64
|
||||
freeSize* {.serialize.}: uint64
|
||||
duration* {.serialize.}: uint64
|
||||
minPricePerBytePerSecond* {.serialize.}: UInt256
|
||||
totalCollateral {.serialize.}: UInt256
|
||||
totalRemainingCollateral* {.serialize.}: UInt256
|
||||
duration* {.serialize.}: StorageDuration
|
||||
minPricePerBytePerSecond* {.serialize.}: TokensPerSecond
|
||||
totalCollateral {.serialize.}: Tokens
|
||||
totalRemainingCollateral* {.serialize.}: Tokens
|
||||
# If set to false, the availability will not accept new slots.
|
||||
# If enabled, it will not impact any existing slots that are already being hosted.
|
||||
enabled* {.serialize.}: bool
|
||||
# Specifies the latest timestamp after which the availability will no longer host any slots.
|
||||
# If set to 0, there will be no restrictions.
|
||||
until* {.serialize.}: SecondsSince1970
|
||||
until* {.serialize.}: StorageTimestamp
|
||||
|
||||
Reservation* = ref object
|
||||
id* {.serialize.}: ReservationId
|
||||
@ -84,7 +83,7 @@ type
|
||||
size* {.serialize.}: uint64
|
||||
requestId* {.serialize.}: RequestId
|
||||
slotIndex* {.serialize.}: uint64
|
||||
validUntil* {.serialize.}: SecondsSince1970
|
||||
validUntil* {.serialize.}: StorageTimestamp
|
||||
|
||||
Reservations* = ref object of RootObj
|
||||
availabilityLock: AsyncLock
|
||||
@ -144,11 +143,11 @@ proc init*(
|
||||
_: type Availability,
|
||||
totalSize: uint64,
|
||||
freeSize: uint64,
|
||||
duration: uint64,
|
||||
minPricePerBytePerSecond: UInt256,
|
||||
totalCollateral: UInt256,
|
||||
duration: StorageDuration,
|
||||
minPricePerBytePerSecond: TokensPerSecond,
|
||||
totalCollateral: Tokens,
|
||||
enabled: bool,
|
||||
until: SecondsSince1970,
|
||||
until: StorageTimestamp,
|
||||
): Availability =
|
||||
var id: array[32, byte]
|
||||
doAssert randomBytes(id) == 32
|
||||
@ -164,10 +163,10 @@ proc init*(
|
||||
until: until,
|
||||
)
|
||||
|
||||
func totalCollateral*(self: Availability): UInt256 {.inline.} =
|
||||
func totalCollateral*(self: Availability): Tokens {.inline.} =
|
||||
return self.totalCollateral
|
||||
|
||||
proc `totalCollateral=`*(self: Availability, value: UInt256) {.inline.} =
|
||||
proc `totalCollateral=`*(self: Availability, value: Tokens) {.inline.} =
|
||||
self.totalCollateral = value
|
||||
self.totalRemainingCollateral = value
|
||||
|
||||
@ -177,7 +176,7 @@ proc init*(
|
||||
size: uint64,
|
||||
requestId: RequestId,
|
||||
slotIndex: uint64,
|
||||
validUntil: SecondsSince1970,
|
||||
validUntil: StorageTimestamp,
|
||||
): Reservation =
|
||||
var id: array[32, byte]
|
||||
doAssert randomBytes(id) == 32
|
||||
@ -230,8 +229,8 @@ func key*(reservationId: ReservationId, availabilityId: AvailabilityId): ?!Key =
|
||||
func key*(availability: Availability): ?!Key =
|
||||
return availability.id.key
|
||||
|
||||
func maxCollateralPerByte*(availability: Availability): UInt256 =
|
||||
return availability.totalRemainingCollateral div availability.freeSize.stuint(256)
|
||||
func maxCollateralPerByte*(availability: Availability): Tokens =
|
||||
return availability.totalRemainingCollateral div availability.freeSize
|
||||
|
||||
func key*(reservation: Reservation): ?!Key =
|
||||
return key(reservation.id, reservation.availabilityId)
|
||||
@ -295,11 +294,6 @@ proc updateAvailability(
|
||||
logScope:
|
||||
availabilityId = obj.id
|
||||
|
||||
if obj.until < 0:
|
||||
let error =
|
||||
newException(UntilOutOfBoundsError, "Cannot set until to a negative value")
|
||||
return failure(error)
|
||||
|
||||
without key =? obj.key, error:
|
||||
return failure(error)
|
||||
|
||||
@ -314,7 +308,7 @@ proc updateAvailability(
|
||||
else:
|
||||
return failure(err)
|
||||
|
||||
if obj.until > 0:
|
||||
if obj.until > 0'StorageTimestamp:
|
||||
without allReservations =? await self.all(Reservation, obj.id), error:
|
||||
error.msg = "Error updating reservation: " & error.msg
|
||||
return failure(error)
|
||||
@ -383,7 +377,7 @@ proc deleteReservation*(
|
||||
self: Reservations,
|
||||
reservationId: ReservationId,
|
||||
availabilityId: AvailabilityId,
|
||||
returnedCollateral: ?UInt256 = UInt256.none,
|
||||
returnedCollateral = Tokens.none,
|
||||
): Future[?!void] {.async.} =
|
||||
logScope:
|
||||
reservationId
|
||||
@ -429,20 +423,15 @@ proc deleteReservation*(
|
||||
proc createAvailability*(
|
||||
self: Reservations,
|
||||
size: uint64,
|
||||
duration: uint64,
|
||||
minPricePerBytePerSecond: UInt256,
|
||||
totalCollateral: UInt256,
|
||||
duration: StorageDuration,
|
||||
minPricePerBytePerSecond: TokensPerSecond,
|
||||
totalCollateral: Tokens,
|
||||
enabled: bool,
|
||||
until: SecondsSince1970,
|
||||
until: StorageTimestamp,
|
||||
): Future[?!Availability] {.async.} =
|
||||
trace "creating availability",
|
||||
size, duration, minPricePerBytePerSecond, totalCollateral, enabled, until
|
||||
|
||||
if until < 0:
|
||||
let error =
|
||||
newException(UntilOutOfBoundsError, "Cannot set until to a negative value")
|
||||
return failure(error)
|
||||
|
||||
let availability = Availability.init(
|
||||
size, size, duration, minPricePerBytePerSecond, totalCollateral, enabled, until
|
||||
)
|
||||
@ -468,8 +457,8 @@ method createReservation*(
|
||||
slotSize: uint64,
|
||||
requestId: RequestId,
|
||||
slotIndex: uint64,
|
||||
collateralPerByte: UInt256,
|
||||
validUntil: SecondsSince1970,
|
||||
collateralPerByte: Tokens,
|
||||
validUntil: StorageTimestamp,
|
||||
): Future[?!Reservation] {.async, base.} =
|
||||
withLock(self.availabilityLock):
|
||||
without availabilityKey =? availabilityId.key, error:
|
||||
@ -500,7 +489,7 @@ method createReservation*(
|
||||
availability.freeSize -= slotSize
|
||||
|
||||
# adjust the remaining totalRemainingCollateral
|
||||
availability.totalRemainingCollateral -= slotSize.u256 * collateralPerByte
|
||||
availability.totalRemainingCollateral -= collateralPerByte * slotSize
|
||||
|
||||
# update availability with reduced size
|
||||
trace "Updating availability with reduced size"
|
||||
@ -695,9 +684,11 @@ proc all*(
|
||||
|
||||
proc findAvailability*(
|
||||
self: Reservations,
|
||||
size, duration: uint64,
|
||||
pricePerBytePerSecond, collateralPerByte: UInt256,
|
||||
validUntil: SecondsSince1970,
|
||||
size: uint64,
|
||||
duration: StorageDuration,
|
||||
pricePerBytePerSecond: TokensPerSecond,
|
||||
collateralPerByte: Tokens,
|
||||
validUntil: StorageTimestamp,
|
||||
): Future[?Availability] {.async.} =
|
||||
without storables =? (await self.storables(Availability)), e:
|
||||
error "failed to get all storables", error = e.msg
|
||||
@ -709,7 +700,7 @@ proc findAvailability*(
|
||||
duration <= availability.duration and
|
||||
collateralPerByte <= availability.maxCollateralPerByte and
|
||||
pricePerBytePerSecond >= availability.minPricePerBytePerSecond and
|
||||
(availability.until == 0 or availability.until >= validUntil):
|
||||
(availability.until == 0'StorageTimestamp or availability.until >= validUntil):
|
||||
trace "availability matched",
|
||||
id = availability.id,
|
||||
enabled = availability.enabled,
|
||||
|
||||
@ -28,7 +28,7 @@ type
|
||||
onFilled*: ?OnFilled
|
||||
|
||||
OnCleanUp* = proc(
|
||||
reprocessSlot = false, returnedCollateral = UInt256.none
|
||||
reprocessSlot = false, returnedCollateral = Tokens.none
|
||||
): Future[void] {.gcsafe, upraises: [].}
|
||||
OnFilled* = proc(request: StorageRequest, slotIndex: uint64) {.gcsafe, upraises: [].}
|
||||
|
||||
@ -82,7 +82,7 @@ proc subscribeCancellation(agent: SalesAgent) {.async.} =
|
||||
|
||||
try:
|
||||
let market = agent.context.market
|
||||
let expiry = await market.requestExpiresAt(data.requestId)
|
||||
let expiry = (await market.requestExpiresAt(data.requestId)).toSecondsSince1970
|
||||
|
||||
while true:
|
||||
let deadline = max(clock.now, expiry) + 1
|
||||
|
||||
@ -26,7 +26,11 @@ type
|
||||
|
||||
BlocksCb* = proc(blocks: seq[bt.Block]): Future[?!void] {.gcsafe, raises: [].}
|
||||
OnStore* = proc(
|
||||
request: StorageRequest, slot: uint64, blocksCb: BlocksCb, isRepairing: bool
|
||||
request: StorageRequest,
|
||||
expiry: StorageTimestamp,
|
||||
slot: uint64,
|
||||
blocksCb: BlocksCb,
|
||||
isRepairing: bool
|
||||
): Future[?!void] {.gcsafe, upraises: [].}
|
||||
OnProve* = proc(slot: Slot, challenge: ProofChallenge): Future[?!Groth16Proof] {.
|
||||
gcsafe, upraises: []
|
||||
|
||||
@ -32,11 +32,11 @@ type
|
||||
requestId: RequestId
|
||||
slotIndex: uint16
|
||||
slotSize: uint64
|
||||
duration: uint64
|
||||
pricePerBytePerSecond: UInt256
|
||||
repairReward: UInt256
|
||||
collateral: UInt256
|
||||
expiry: uint64
|
||||
duration: StorageDuration
|
||||
pricePerBytePerSecond: TokensPerSecond
|
||||
repairReward: Tokens
|
||||
collateral: Tokens
|
||||
expiry: ?StorageTimestamp
|
||||
seen: bool
|
||||
|
||||
# don't need to -1 to prevent overflow when adding 1 (to always allow push)
|
||||
@ -70,14 +70,14 @@ const DefaultMaxWorkers = 3
|
||||
# slots.
|
||||
const DefaultMaxSize = 128'u16
|
||||
|
||||
proc profitability(item: SlotQueueItem): UInt256 =
|
||||
proc profitability(item: SlotQueueItem): Tokens =
|
||||
let price =
|
||||
StorageAsk(
|
||||
duration: item.duration.stuint(40),
|
||||
pricePerBytePerSecond: item.pricePerBytePerSecond.stuint(96),
|
||||
duration: item.duration,
|
||||
pricePerBytePerSecond: item.pricePerBytePerSecond,
|
||||
slotSize: item.slotSize,
|
||||
).pricePerSlot
|
||||
return price.stuint(256) + item.repairReward
|
||||
return price + item.repairReward
|
||||
|
||||
proc `<`*(a, b: SlotQueueItem): bool =
|
||||
# for A to have a higher priority than B (in a min queue), A must be less than
|
||||
@ -98,8 +98,9 @@ proc `<`*(a, b: SlotQueueItem): bool =
|
||||
scoreA.addIf(a.collateral < b.collateral, 2)
|
||||
scoreB.addIf(a.collateral > b.collateral, 2)
|
||||
|
||||
scoreA.addIf(a.expiry > b.expiry, 1)
|
||||
scoreB.addIf(a.expiry < b.expiry, 1)
|
||||
if expiryA =? a.expiry and expiryB =? b.expiry:
|
||||
scoreA.addIf(expiryA > expiryB, 1)
|
||||
scoreB.addIf(expiryA < expiryB, 1)
|
||||
|
||||
return scoreA > scoreB
|
||||
|
||||
@ -141,22 +142,22 @@ proc init(_: type SlotQueueWorker): SlotQueueWorker =
|
||||
|
||||
SlotQueueWorker(doneProcessing: workerFut)
|
||||
|
||||
proc init*(
|
||||
proc init(
|
||||
_: type SlotQueueItem,
|
||||
requestId: RequestId,
|
||||
slotIndex: uint16,
|
||||
ask: StorageAsk,
|
||||
expiry: uint64,
|
||||
collateral: UInt256,
|
||||
repairReward = 0.u256,
|
||||
expiry: ?StorageTimestamp,
|
||||
collateral: Tokens,
|
||||
repairReward = 0'Tokens,
|
||||
seen = false,
|
||||
): SlotQueueItem =
|
||||
SlotQueueItem(
|
||||
requestId: requestId,
|
||||
slotIndex: slotIndex,
|
||||
slotSize: ask.slotSize,
|
||||
duration: ask.duration.u64,
|
||||
pricePerBytePerSecond: ask.pricePerBytePerSecond.stuint(256),
|
||||
duration: ask.duration,
|
||||
pricePerBytePerSecond: ask.pricePerBytePerSecond,
|
||||
collateral: collateral,
|
||||
expiry: expiry,
|
||||
seen: seen,
|
||||
@ -164,22 +165,39 @@ proc init*(
|
||||
|
||||
proc init*(
|
||||
_: type SlotQueueItem,
|
||||
request: StorageRequest,
|
||||
requestId: RequestId,
|
||||
slotIndex: uint16,
|
||||
collateral: UInt256,
|
||||
repairReward = 0.u256,
|
||||
ask: StorageAsk,
|
||||
expiry: StorageTimestamp,
|
||||
collateral: Tokens,
|
||||
repairReward = 0'Tokens,
|
||||
seen = false,
|
||||
): SlotQueueItem =
|
||||
SlotQueueItem.init(
|
||||
request.id, slotIndex, request.ask, request.expiry.u64, collateral, repairReward
|
||||
)
|
||||
SlotQueueItem.init(requestId, slotIndex, ask, some expiry, collateral, repairReward, seen)
|
||||
|
||||
proc init*(
|
||||
_: type SlotQueueItem,
|
||||
request: StorageRequest,
|
||||
slotIndex: uint16,
|
||||
collateral: Tokens,
|
||||
repairReward = 0'Tokens,
|
||||
): SlotQueueItem =
|
||||
SlotQueueItem(
|
||||
requestId: request.id,
|
||||
slotIndex: slotIndex,
|
||||
slotSize: request.ask.slotSize,
|
||||
duration: request.ask.duration,
|
||||
pricePerBytePerSecond: request.ask.pricePerBytePerSecond,
|
||||
collateral: collateral
|
||||
)
|
||||
|
||||
proc init(
|
||||
_: type SlotQueueItem,
|
||||
requestId: RequestId,
|
||||
ask: StorageAsk,
|
||||
expiry: uint64,
|
||||
collateral: UInt256,
|
||||
repairReward = 0.u256,
|
||||
expiry: ?StorageTimestamp,
|
||||
collateral: Tokens,
|
||||
repairReward = 0'Tokens,
|
||||
): seq[SlotQueueItem] {.raises: [SlotsOutOfRangeError].} =
|
||||
if not ask.slots.inRange:
|
||||
raise newException(SlotsOutOfRangeError, "Too many slots")
|
||||
@ -194,14 +212,24 @@ proc init*(
|
||||
Rng.instance.shuffle(items)
|
||||
return items
|
||||
|
||||
proc init*(
|
||||
_: type SlotQueueItem,
|
||||
requestId: RequestId,
|
||||
ask: StorageAsk,
|
||||
expiry: StorageTimestamp,
|
||||
collateral: Tokens,
|
||||
repairReward = 0'Tokens,
|
||||
): seq[SlotQueueItem] {.raises: [SlotsOutOfRangeError].} =
|
||||
SlotQueueItem.init(requestId, ask, some expiry, collateral, repairReward)
|
||||
|
||||
proc init*(
|
||||
_: type SlotQueueItem,
|
||||
request: StorageRequest,
|
||||
collateral: UInt256,
|
||||
repairReward = 0.u256,
|
||||
): seq[SlotQueueItem] =
|
||||
collateral: Tokens,
|
||||
repairReward = 0'Tokens,
|
||||
): seq[SlotQueueItem] {.raises: [SlotsOutOfRangeError].} =
|
||||
return SlotQueueItem.init(
|
||||
request.id, request.ask, request.expiry.u64, collateral, repairReward
|
||||
request.id, request.ask, StorageTimestamp.none, collateral, repairReward
|
||||
)
|
||||
|
||||
proc inRange*(val: SomeUnsignedInt): bool =
|
||||
@ -216,13 +244,13 @@ proc slotIndex*(self: SlotQueueItem): uint16 =
|
||||
proc slotSize*(self: SlotQueueItem): uint64 =
|
||||
self.slotSize
|
||||
|
||||
proc duration*(self: SlotQueueItem): uint64 =
|
||||
proc duration*(self: SlotQueueItem): StorageDuration =
|
||||
self.duration
|
||||
|
||||
proc pricePerBytePerSecond*(self: SlotQueueItem): UInt256 =
|
||||
proc pricePerBytePerSecond*(self: SlotQueueItem): TokensPerSecond =
|
||||
self.pricePerBytePerSecond
|
||||
|
||||
proc collateralPerByte*(self: SlotQueueItem): UInt256 =
|
||||
proc collateralPerByte*(self: SlotQueueItem): Tokens =
|
||||
self.collateralPerByte
|
||||
|
||||
proc seen*(self: SlotQueueItem): bool =
|
||||
|
||||
@ -31,7 +31,7 @@ method run*(
|
||||
raiseAssert "no sale request"
|
||||
|
||||
try:
|
||||
var returnedCollateral = UInt256.none
|
||||
var returnedCollateral = Tokens.none
|
||||
|
||||
if await slotIsFilledByMe(market, data.requestId, data.slotIndex):
|
||||
debug "Collecting collateral and partial payout",
|
||||
@ -53,7 +53,7 @@ method run*(
|
||||
if onCleanUp =? agent.onCleanUp:
|
||||
await onCleanUp(
|
||||
reprocessSlot = false,
|
||||
returnedCollateral = some currentCollateral.stuint(256),
|
||||
returnedCollateral = returnedCollateral,
|
||||
)
|
||||
|
||||
warn "Sale cancelled due to timeout",
|
||||
|
||||
@ -38,6 +38,7 @@ method run*(
|
||||
let agent = SalesAgent(machine)
|
||||
let data = agent.data
|
||||
let context = agent.context
|
||||
let market = context.market
|
||||
let reservations = context.reservations
|
||||
|
||||
without onStore =? context.onStore:
|
||||
@ -67,11 +68,20 @@ method run*(
|
||||
return await reservations.release(reservation.id, reservation.availabilityId, bytes)
|
||||
|
||||
try:
|
||||
let slotId = slotId(request.id, data.slotIndex)
|
||||
let isRepairing = (await context.market.slotState(slotId)) == SlotState.Repair
|
||||
let requestId = request.id
|
||||
let slotId = slotId(requestId, data.slotIndex)
|
||||
let requestState = await market.requestState(requestId)
|
||||
let isRepairing = (await market.slotState(slotId)) == SlotState.Repair
|
||||
|
||||
trace "Retrieving expiry"
|
||||
var expiry: StorageTimestamp
|
||||
if state =? requestState and state == RequestState.Started:
|
||||
expiry = await market.getRequestEnd(requestId)
|
||||
else:
|
||||
expiry = await market.requestExpiresAt(requestId)
|
||||
|
||||
trace "Starting download"
|
||||
if err =? (await onStore(request, data.slotIndex, onBlocks, isRepairing)).errorOption:
|
||||
if err =? (await onStore(request, expiry, data.slotIndex, onBlocks, isRepairing)).errorOption:
|
||||
return some State(SaleErrored(error: err, reprocessSlot: false))
|
||||
|
||||
trace "Download complete"
|
||||
|
||||
@ -55,7 +55,7 @@ method run*(
|
||||
without onExpiryUpdate =? context.onExpiryUpdate:
|
||||
raiseAssert "onExpiryUpdate callback not set"
|
||||
|
||||
let requestEnd = await market.getRequestEnd(data.requestId)
|
||||
let requestEnd = (await market.getRequestEnd(data.requestId)).toSecondsSince1970
|
||||
if err =? (await onExpiryUpdate(request.content.cid, requestEnd)).errorOption:
|
||||
return some State(SaleErrored(error: err))
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ logScope:
|
||||
topics = "marketplace sales finished"
|
||||
|
||||
type SaleFinished* = ref object of SaleState
|
||||
returnedCollateral*: ?UInt256
|
||||
returnedCollateral*: ?Tokens
|
||||
|
||||
method `$`*(state: SaleFinished): string =
|
||||
"SaleFinished"
|
||||
|
||||
@ -25,9 +25,9 @@ method onFailed*(state: SaleInitialProving, request: StorageRequest): ?State =
|
||||
|
||||
proc waitUntilNextPeriod(clock: Clock, periodicity: Periodicity) {.async.} =
|
||||
trace "Waiting until next period"
|
||||
let period = periodicity.periodOf(clock.now().Timestamp)
|
||||
let period = periodicity.periodOf(clock.now())
|
||||
let periodEnd = periodicity.periodEnd(period)
|
||||
await clock.waitUntil((periodEnd + 1).toSecondsSince1970)
|
||||
await clock.waitUntil((periodEnd + 1'u8).toSecondsSince1970)
|
||||
|
||||
proc waitForStableChallenge(market: Market, clock: Clock, slotId: SlotId) {.async.} =
|
||||
let periodicity = market.periodicity
|
||||
|
||||
@ -73,10 +73,10 @@ method run*(
|
||||
without availability =?
|
||||
await reservations.findAvailability(
|
||||
request.ask.slotSize,
|
||||
request.ask.duration.u64,
|
||||
request.ask.pricePerBytePerSecond.stuint(256),
|
||||
request.ask.collateralPerByte.stuint(256),
|
||||
requestEnd.u64
|
||||
request.ask.duration,
|
||||
request.ask.pricePerBytePerSecond,
|
||||
request.ask.collateralPerByte,
|
||||
requestEnd
|
||||
):
|
||||
debug "No availability found for request, ignoring"
|
||||
|
||||
@ -90,8 +90,8 @@ method run*(
|
||||
request.ask.slotSize,
|
||||
request.id,
|
||||
data.slotIndex,
|
||||
request.ask.collateralPerByte.stuint(256),
|
||||
requestEnd.u64,
|
||||
request.ask.collateralPerByte,
|
||||
requestEnd
|
||||
), error:
|
||||
trace "Creation of reservation failed"
|
||||
# Race condition:
|
||||
|
||||
@ -26,7 +26,7 @@ method prove*(
|
||||
challenge: ProofChallenge,
|
||||
onProve: OnProve,
|
||||
market: Market,
|
||||
currentPeriod: Period,
|
||||
currentPeriod: ProofPeriod,
|
||||
) {.base, async.} =
|
||||
try:
|
||||
without proof =? (await onProve(slot, challenge)), err:
|
||||
@ -58,14 +58,14 @@ proc proveLoop(
|
||||
slotIndex
|
||||
slotId = slot.id
|
||||
|
||||
proc getCurrentPeriod(): Period =
|
||||
proc getCurrentPeriod(): ProofPeriod =
|
||||
let periodicity = market.periodicity
|
||||
return periodicity.periodOf(clock.now().Timestamp)
|
||||
return periodicity.periodOf(clock.now())
|
||||
|
||||
proc waitUntilPeriod(period: Period) {.async.} =
|
||||
proc waitUntilPeriod(period: ProofPeriod) {.async.} =
|
||||
let periodicity = market.periodicity
|
||||
# Ensure that we're past the period boundary by waiting an additional second
|
||||
await clock.waitUntil((periodicity.periodStart(period) + 1).toSecondsSince1970)
|
||||
await clock.waitUntil((periodicity.periodStart(period) + 1'u8).toSecondsSince1970)
|
||||
|
||||
while true:
|
||||
let currentPeriod = getCurrentPeriod()
|
||||
@ -97,7 +97,7 @@ proc proveLoop(
|
||||
raise newException(SlotNotFilledError, message)
|
||||
|
||||
debug "waiting until next period"
|
||||
await waitUntilPeriod(currentPeriod + 1)
|
||||
await waitUntilPeriod(currentPeriod + 1'u8)
|
||||
|
||||
method `$`*(state: SaleProving): string =
|
||||
"SaleProving"
|
||||
|
||||
@ -20,7 +20,7 @@ when codex_enable_proof_failures:
|
||||
failEveryNProofs*: int
|
||||
proofCount: int
|
||||
|
||||
proc onSubmitProofError(error: ref CatchableError, period: Period, slotId: SlotId) =
|
||||
proc onSubmitProofError(error: ref CatchableError, period: ProofPeriod, slotId: SlotId) =
|
||||
error "Submitting invalid proof failed", period, slotId, msg = error.msgDetail
|
||||
|
||||
method prove*(
|
||||
@ -29,7 +29,7 @@ when codex_enable_proof_failures:
|
||||
challenge: ProofChallenge,
|
||||
onProve: OnProve,
|
||||
market: Market,
|
||||
currentPeriod: Period,
|
||||
currentPeriod: ProofPeriod,
|
||||
) {.async.} =
|
||||
try:
|
||||
trace "Processing proving in simulated mode"
|
||||
|
||||
@ -34,8 +34,8 @@ proc new*(
|
||||
proc slots*(validation: Validation): seq[SlotId] =
|
||||
validation.slots.toSeq
|
||||
|
||||
proc getCurrentPeriod(validation: Validation): Period =
|
||||
return validation.periodicity.periodOf(validation.clock.now().Timestamp)
|
||||
proc getCurrentPeriod(validation: Validation): ProofPeriod =
|
||||
return validation.periodicity.periodOf(validation.clock.now())
|
||||
|
||||
proc waitUntilNextPeriod(validation: Validation) {.async.} =
|
||||
let period = validation.getCurrentPeriod()
|
||||
@ -79,7 +79,7 @@ proc removeSlotsThatHaveEnded(validation: Validation) {.async.} =
|
||||
validation.slots.excl(ended)
|
||||
|
||||
proc markProofAsMissing(
|
||||
validation: Validation, slotId: SlotId, period: Period
|
||||
validation: Validation, slotId: SlotId, period: ProofPeriod
|
||||
) {.async.} =
|
||||
logScope:
|
||||
currentPeriod = validation.getCurrentPeriod()
|
||||
@ -99,7 +99,7 @@ proc markProofAsMissing(
|
||||
proc markProofsAsMissing(validation: Validation) {.async.} =
|
||||
let slots = validation.slots
|
||||
for slotId in slots:
|
||||
let previousPeriod = validation.getCurrentPeriod() - 1
|
||||
let previousPeriod = validation.getCurrentPeriod() - 1'u8
|
||||
await validation.markProofAsMissing(slotId, previousPeriod)
|
||||
|
||||
proc run(validation: Validation) {.async: (raises: []).} =
|
||||
@ -121,7 +121,7 @@ proc findEpoch(validation: Validation, secondsAgo: uint64): SecondsSince1970 =
|
||||
proc restoreHistoricalState(validation: Validation) {.async.} =
|
||||
trace "Restoring historical state..."
|
||||
let requestDurationLimit = validation.market.requestDurationLimit
|
||||
let startTimeEpoch = validation.findEpoch(secondsAgo = requestDurationLimit)
|
||||
let startTimeEpoch = validation.findEpoch(secondsAgo = requestDurationLimit.u64)
|
||||
let slotFilledEvents =
|
||||
await validation.market.queryPastSlotFilledEvents(fromTime = startTimeEpoch)
|
||||
for event in slotFilledEvents:
|
||||
@ -138,7 +138,7 @@ proc start*(validation: Validation) {.async.} =
|
||||
trace "Starting validator",
|
||||
groups = validation.config.groups, groupIndex = validation.config.groupIndex
|
||||
validation.periodicity = validation.market.periodicity
|
||||
validation.proofTimeout = validation.market.proofTimeout
|
||||
validation.proofTimeout = validation.market.proofTimeout.u64
|
||||
await validation.subscribeSlotFilled()
|
||||
await validation.restoreHistoricalState()
|
||||
validation.running = validation.run()
|
||||
|
||||
@ -66,17 +66,17 @@ proc example*(_: type MultiHash, mcodec = Sha256HashCodec): MultiHash =
|
||||
MultiHash.digest($mcodec, bytes).tryGet()
|
||||
|
||||
proc example*(
|
||||
_: type Availability, collateralPerByte = uint8.example.u256
|
||||
_: type Availability, collateralPerByte = Tokens.init(uint8.example)
|
||||
): Availability =
|
||||
let totalSize = uint16.example.uint64
|
||||
Availability.init(
|
||||
totalSize = totalSize,
|
||||
freeSize = uint16.example.uint64,
|
||||
duration = uint16.example.uint64,
|
||||
minPricePerBytePerSecond = uint8.example.u256,
|
||||
totalCollateral = totalSize.u256 * collateralPerByte,
|
||||
duration = StorageDuration.init(uint16.example),
|
||||
minPricePerBytePerSecond = TokensPerSecond.init(uint8.example),
|
||||
totalCollateral = collateralPerByte * totalSize,
|
||||
enabled = true,
|
||||
until = 0.SecondsSince1970,
|
||||
until = 0'StorageTimestamp,
|
||||
)
|
||||
|
||||
proc example*(_: type Reservation): Reservation =
|
||||
|
||||
@ -14,6 +14,7 @@ from pkg/ethers import BlockTag
|
||||
import codex/clock
|
||||
|
||||
import ../examples
|
||||
import ./mockclock
|
||||
|
||||
export market
|
||||
export tables
|
||||
@ -27,8 +28,8 @@ type
|
||||
activeRequests*: Table[Address, seq[RequestId]]
|
||||
activeSlots*: Table[Address, seq[SlotId]]
|
||||
requested*: seq[StorageRequest]
|
||||
requestEnds*: Table[RequestId, SecondsSince1970]
|
||||
requestExpiry*: Table[RequestId, SecondsSince1970]
|
||||
requestEnds*: Table[RequestId, StorageTimestamp]
|
||||
requestExpiry*: Table[RequestId, StorageTimestamp]
|
||||
requestState*: Table[RequestId, RequestState]
|
||||
slotState*: Table[SlotId, SlotState]
|
||||
fulfilled*: seq[Fulfillment]
|
||||
@ -51,7 +52,7 @@ type
|
||||
errorOnFillSlot*: ?(ref MarketError)
|
||||
errorOnFreeSlot*: ?(ref MarketError)
|
||||
errorOnGetHost*: ?(ref MarketError)
|
||||
clock: ?Clock
|
||||
clock: Clock
|
||||
|
||||
Fulfillment* = object
|
||||
requestId*: RequestId
|
||||
@ -63,8 +64,8 @@ type
|
||||
host*: Address
|
||||
slotIndex*: uint64
|
||||
proof*: Groth16Proof
|
||||
timestamp: ?SecondsSince1970
|
||||
collateral*: UInt128
|
||||
timestamp: SecondsSince1970
|
||||
collateral*: Tokens
|
||||
|
||||
Subscriptions = object
|
||||
onRequest: seq[RequestSubscription]
|
||||
@ -113,7 +114,7 @@ proc hash*(address: Address): Hash =
|
||||
proc hash*(requestId: RequestId): Hash =
|
||||
hash(requestId.toArray)
|
||||
|
||||
proc new*(_: type MockMarket, clock: ?Clock = Clock.none): MockMarket =
|
||||
proc new*(_: type MockMarket, clock: Clock = MockClock.new()): MockMarket =
|
||||
## Create a new mocked Market instance
|
||||
##
|
||||
let config = MarketplaceConfig(
|
||||
@ -124,13 +125,13 @@ proc new*(_: type MockMarket, clock: ?Clock = Clock.none): MockMarket =
|
||||
validatorRewardPercentage: 20,
|
||||
),
|
||||
proofs: ProofConfig(
|
||||
period: 10.stuint(40),
|
||||
timeout: 5.stuint(40),
|
||||
period: 10'StorageDuration,
|
||||
timeout: 5'StorageDuration,
|
||||
downtime: 64.uint8,
|
||||
downtimeProduct: 67.uint8,
|
||||
),
|
||||
reservations: SlotReservationsConfig(maxReservations: 3),
|
||||
requestDurationLimit: (60 * 60 * 24 * 30).stuint(40),
|
||||
requestDurationLimit: StorageDuration.init((60 * 60 * 24 * 30).stuint(40)),
|
||||
)
|
||||
MockMarket(
|
||||
signer: Address.example, config: config, canReserveSlot: true, clock: clock
|
||||
@ -142,13 +143,13 @@ method getSigner*(
|
||||
return market.signer
|
||||
|
||||
method periodicity*(mock: MockMarket): Periodicity =
|
||||
return Periodicity(seconds: mock.config.proofs.period.u64)
|
||||
return Periodicity(seconds: mock.config.proofs.period)
|
||||
|
||||
method proofTimeout*(market: MockMarket): uint64 =
|
||||
return market.config.proofs.timeout.u64
|
||||
method proofTimeout*(market: MockMarket): StorageDuration =
|
||||
return market.config.proofs.timeout
|
||||
|
||||
method requestDurationLimit*(market: MockMarket): uint64 =
|
||||
return market.config.requestDurationLimit.u64
|
||||
method requestDurationLimit*(market: MockMarket): StorageDuration =
|
||||
return market.config.requestDurationLimit
|
||||
|
||||
method proofDowntime*(market: MockMarket): uint8 =
|
||||
return market.config.proofs.downtime
|
||||
@ -162,10 +163,15 @@ method getPointer*(market: MockMarket, slotId: SlotId): Future[uint8] {.async.}
|
||||
method requestStorage*(
|
||||
market: MockMarket, request: StorageRequest
|
||||
) {.async: (raises: [CancelledError, MarketError]).} =
|
||||
let now = StorageTimestamp.init(market.clock.now())
|
||||
let requestExpiresAt = now + request.expiry
|
||||
let requestEndsAt = now + request.ask.duration
|
||||
market.requested.add(request)
|
||||
market.requestExpiry[request.id] = requestExpiresAt
|
||||
market.requestEnds[request.id] = requestEndsAt
|
||||
var subscriptions = market.subscriptions.onRequest
|
||||
for subscription in subscriptions:
|
||||
subscription.callback(request.id, request.ask, request.expiry.u64)
|
||||
subscription.callback(request.id, request.ask, requestExpiresAt)
|
||||
|
||||
method myRequests*(market: MockMarket): Future[seq[RequestId]] {.async.} =
|
||||
return market.activeRequests[market.signer]
|
||||
@ -206,12 +212,12 @@ method slotState*(
|
||||
|
||||
method getRequestEnd*(
|
||||
market: MockMarket, id: RequestId
|
||||
): Future[SecondsSince1970] {.async.} =
|
||||
): Future[StorageTimestamp] {.async.} =
|
||||
return market.requestEnds[id]
|
||||
|
||||
method requestExpiresAt*(
|
||||
market: MockMarket, id: RequestId
|
||||
): Future[SecondsSince1970] {.async.} =
|
||||
): Future[StorageTimestamp] {.async.} =
|
||||
return market.requestExpiry[id]
|
||||
|
||||
method getHost*(
|
||||
@ -227,11 +233,11 @@ method getHost*(
|
||||
|
||||
method currentCollateral*(
|
||||
market: MockMarket, slotId: SlotId
|
||||
): Future[UInt128] {.async: (raises: [MarketError, CancelledError]).} =
|
||||
): Future[Tokens] {.async: (raises: [MarketError, CancelledError]).} =
|
||||
for slot in market.filled:
|
||||
if slotId == slotId(slot.requestId, slot.slotIndex):
|
||||
return slot.collateral
|
||||
return 0.u128
|
||||
return 0'Tokens
|
||||
|
||||
proc emitSlotFilled*(market: MockMarket, requestId: RequestId, slotIndex: uint64) =
|
||||
var subscriptions = market.subscriptions.onSlotFilled
|
||||
@ -273,7 +279,7 @@ proc fillSlot*(
|
||||
slotIndex: uint64,
|
||||
proof: Groth16Proof,
|
||||
host: Address,
|
||||
collateral = 0.u128,
|
||||
collateral = 0'Tokens,
|
||||
) =
|
||||
if error =? market.errorOnFillSlot:
|
||||
raise error
|
||||
@ -283,7 +289,7 @@ proc fillSlot*(
|
||||
slotIndex: slotIndex,
|
||||
proof: proof,
|
||||
host: host,
|
||||
timestamp: market.clock .? now,
|
||||
timestamp: market.clock.now,
|
||||
collateral: collateral,
|
||||
)
|
||||
market.filled.add(slot)
|
||||
@ -295,7 +301,7 @@ method fillSlot*(
|
||||
requestId: RequestId,
|
||||
slotIndex: uint64,
|
||||
proof: Groth16Proof,
|
||||
collateral: UInt128,
|
||||
collateral: Tokens,
|
||||
) {.async: (raises: [CancelledError, MarketError]).} =
|
||||
market.fillSlot(requestId, slotIndex, proof, market.signer, collateral)
|
||||
|
||||
@ -349,7 +355,7 @@ method submitProof*(
|
||||
subscription.callback(id)
|
||||
|
||||
method markProofAsMissing*(
|
||||
market: MockMarket, id: SlotId, period: Period
|
||||
market: MockMarket, id: SlotId, period: ProofPeriod
|
||||
) {.async: (raises: [CancelledError, MarketError]).} =
|
||||
market.markedAsMissingProofs.add(id)
|
||||
|
||||
@ -360,7 +366,7 @@ proc setCanProofBeMarkedAsMissing*(mock: MockMarket, id: SlotId, required: bool)
|
||||
mock.canBeMarkedAsMissing.excl(id)
|
||||
|
||||
method canProofBeMarkedAsMissing*(
|
||||
market: MockMarket, id: SlotId, period: Period
|
||||
market: MockMarket, id: SlotId, period: ProofPeriod
|
||||
): Future[bool] {.async.} =
|
||||
return market.canBeMarkedAsMissing.contains(id)
|
||||
|
||||
@ -495,7 +501,7 @@ method queryPastStorageRequestedEvents*(
|
||||
): Future[seq[StorageRequested]] {.async.} =
|
||||
return market.requested.map(
|
||||
request =>
|
||||
StorageRequested(requestId: request.id, ask: request.ask, expiry: request.expiry)
|
||||
StorageRequested(requestId: request.id, ask: request.ask, expiry: market.requestExpiry[request.id])
|
||||
)
|
||||
|
||||
method queryPastStorageRequestedEvents*(
|
||||
@ -503,7 +509,7 @@ method queryPastStorageRequestedEvents*(
|
||||
): Future[seq[StorageRequested]] {.async.} =
|
||||
return market.requested.map(
|
||||
request =>
|
||||
StorageRequested(requestId: request.id, ask: request.ask, expiry: request.expiry)
|
||||
StorageRequested(requestId: request.id, ask: request.ask, expiry: market.requestExpiry[request.id])
|
||||
)
|
||||
|
||||
method queryPastSlotFilledEvents*(
|
||||
@ -525,10 +531,7 @@ method queryPastSlotFilledEvents*(
|
||||
): Future[seq[SlotFilled]] {.async.} =
|
||||
let filtered = market.filled.filter(
|
||||
proc(slot: MockSlot): bool =
|
||||
if timestamp =? slot.timestamp:
|
||||
return timestamp >= fromTime
|
||||
else:
|
||||
true
|
||||
slot.timestamp >= fromTime
|
||||
)
|
||||
return filtered.map(
|
||||
slot => SlotFilled(requestId: slot.requestId, slotIndex: slot.slotIndex)
|
||||
|
||||
@ -28,8 +28,8 @@ method createReservation*(
|
||||
slotSize: uint64,
|
||||
requestId: RequestId,
|
||||
slotIndex: uint64,
|
||||
collateralPerByte: UInt256,
|
||||
validUntil: SecondsSince1970,
|
||||
collateralPerByte: Tokens,
|
||||
validUntil: StorageTimestamp,
|
||||
): Future[?!Reservation] {.async.} =
|
||||
if self.createReservationThrowBytesOutOfBoundsError:
|
||||
let error = newException(
|
||||
|
||||
@ -5,10 +5,10 @@ type MockSlotQueueItem* = object
|
||||
requestId*: RequestId
|
||||
slotIndex*: uint16
|
||||
slotSize*: uint64
|
||||
duration*: uint64
|
||||
pricePerBytePerSecond*: UInt256
|
||||
collateral*: UInt256
|
||||
expiry*: uint64
|
||||
duration*: StorageDuration
|
||||
pricePerBytePerSecond*: TokensPerSecond
|
||||
collateral*: Tokens
|
||||
expiry*: StorageTimestamp
|
||||
seen*: bool
|
||||
|
||||
proc toSlotQueueItem*(item: MockSlotQueueItem): SlotQueueItem =
|
||||
@ -17,8 +17,8 @@ proc toSlotQueueItem*(item: MockSlotQueueItem): SlotQueueItem =
|
||||
slotIndex = item.slotIndex,
|
||||
ask = StorageAsk(
|
||||
slotSize: item.slotSize,
|
||||
duration: item.duration.stuint(40),
|
||||
pricePerBytePerSecond: item.pricePerBytePerSecond.stuint(96),
|
||||
duration: item.duration,
|
||||
pricePerBytePerSecond: item.pricePerBytePerSecond,
|
||||
),
|
||||
expiry = item.expiry,
|
||||
seen = item.seen,
|
||||
|
||||
@ -116,8 +116,7 @@ asyncchecksuite "Test Node - Host contracts":
|
||||
let onStore = !sales.onStore
|
||||
var request = StorageRequest.example
|
||||
request.content.cid = verifiableBlock.cid
|
||||
request.expiry =
|
||||
(getTime() + DefaultBlockTtl.toTimesDuration + 1.hours).toUnix.stuint(40)
|
||||
let expiry = (getTime() + DefaultBlockTtl.toTimesDuration + 1.hours).toUnix
|
||||
var fetchedBytes: uint = 0
|
||||
|
||||
let onBlocks = proc(blocks: seq[bt.Block]): Future[?!void] {.async.} =
|
||||
@ -125,7 +124,7 @@ asyncchecksuite "Test Node - Host contracts":
|
||||
fetchedBytes += blk.data.len.uint
|
||||
return success()
|
||||
|
||||
(await onStore(request, 1.uint64, onBlocks, isRepairing = false)).tryGet()
|
||||
(await onStore(request, StorageTimestamp.init(expiry), 1.uint64, onBlocks, isRepairing = false)).tryGet()
|
||||
check fetchedBytes == 12 * DefaultBlockSize.uint
|
||||
|
||||
let indexer = verifiable.protectedStrategy.init(
|
||||
@ -139,4 +138,4 @@ asyncchecksuite "Test Node - Host contracts":
|
||||
bytes = (await localStoreMetaDs.get(key)).tryGet
|
||||
blkMd = BlockMetadata.decode(bytes).tryGet
|
||||
|
||||
check blkMd.expiry == request.expiry.toSecondsSince1970
|
||||
check blkMd.expiry == expiry
|
||||
|
||||
@ -188,11 +188,11 @@ asyncchecksuite "Test Node - Basic":
|
||||
cid = manifestBlock.cid,
|
||||
nodes = 5,
|
||||
tolerance = 2,
|
||||
duration = 100.stuint(40),
|
||||
pricePerBytePerSecond = 1.stuint(96),
|
||||
duration = 100'StorageDuration,
|
||||
pricePerBytePerSecond = 1'TokensPerSecond,
|
||||
proofProbability = 3.u256,
|
||||
expiry = 200.stuint(40),
|
||||
collateralPerByte = 1.u128,
|
||||
expiry = 200'StorageDuration,
|
||||
collateralPerByte = 1'Tokens,
|
||||
)
|
||||
).tryGet
|
||||
|
||||
|
||||
@ -3,6 +3,6 @@ import ../../helpers/mockclock
|
||||
|
||||
proc advanceToNextPeriod*(clock: MockClock, market: Market) =
|
||||
let periodicity = market.periodicity()
|
||||
let period = periodicity.periodOf(clock.now().Timestamp)
|
||||
let period = periodicity.periodOf(clock.now())
|
||||
let periodEnd = periodicity.periodEnd(period)
|
||||
clock.set(periodEnd.toSecondsSince1970 + 1)
|
||||
|
||||
@ -19,18 +19,18 @@ asyncchecksuite "sales state 'cancelled'":
|
||||
let slotIndex = request.ask.slots div 2
|
||||
let clock = MockClock.new()
|
||||
|
||||
let currentCollateral = UInt128.example
|
||||
let currentCollateral = Tokens.example
|
||||
|
||||
var market: MockMarket
|
||||
var state: SaleCancelled
|
||||
var agent: SalesAgent
|
||||
var reprocessSlotWas: ?bool
|
||||
var returnedCollateralValue: ?UInt256
|
||||
var returnedCollateralValue: ?Tokens
|
||||
|
||||
setup:
|
||||
market = MockMarket.new()
|
||||
let onCleanUp = proc(
|
||||
reprocessSlot = false, returnedCollateral = UInt256.none
|
||||
reprocessSlot = false, returnedCollateral = Tokens.none
|
||||
) {.async.} =
|
||||
reprocessSlotWas = some reprocessSlot
|
||||
returnedCollateralValue = returnedCollateral
|
||||
@ -40,10 +40,10 @@ asyncchecksuite "sales state 'cancelled'":
|
||||
agent.onCleanUp = onCleanUp
|
||||
state = SaleCancelled.new()
|
||||
reprocessSlotWas = bool.none
|
||||
returnedCollateralValue = UInt256.none
|
||||
returnedCollateralValue = Tokens.none
|
||||
teardown:
|
||||
reprocessSlotWas = bool.none
|
||||
returnedCollateralValue = UInt256.none
|
||||
returnedCollateralValue = Tokens.none
|
||||
|
||||
test "calls onCleanUp with reprocessSlot = true, and returnedCollateral = currentCollateral":
|
||||
market.fillSlot(
|
||||
@ -91,7 +91,7 @@ asyncchecksuite "sales state 'cancelled'":
|
||||
let next = await state.run(agent)
|
||||
check next == none State
|
||||
check eventually reprocessSlotWas == some false
|
||||
check eventually returnedCollateralValue == UInt256.none
|
||||
check eventually returnedCollateralValue == Tokens.none
|
||||
|
||||
test "calls onCleanUp and returns the collateral when an error is raised":
|
||||
market.fillSlot(
|
||||
|
||||
@ -24,7 +24,7 @@ asyncchecksuite "sales state 'errored'":
|
||||
|
||||
setup:
|
||||
let onCleanUp = proc(
|
||||
reprocessSlot = false, returnedCollateral = UInt256.none
|
||||
reprocessSlot = false, returnedCollateral = Tokens.none
|
||||
) {.async.} =
|
||||
reprocessSlotWas = reprocessSlot
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@ suite "sales state 'filled'":
|
||||
proof: Groth16Proof.default,
|
||||
)
|
||||
|
||||
market.requestEnds[request.id] = 321
|
||||
market.requestEnds[request.id] = 321'StorageTimestamp
|
||||
onExpiryUpdatePassedExpiry = -1
|
||||
let onExpiryUpdate = proc(
|
||||
rootCid: Cid, expiry: SecondsSince1970
|
||||
@ -55,11 +55,11 @@ suite "sales state 'filled'":
|
||||
slot.host = await market.getSigner()
|
||||
market.filled = @[slot]
|
||||
|
||||
let expectedExpiry = 123
|
||||
let expectedExpiry = 123'StorageTimestamp
|
||||
market.requestEnds[request.id] = expectedExpiry
|
||||
let next = await state.run(agent)
|
||||
check !next of SaleProving
|
||||
check onExpiryUpdatePassedExpiry == expectedExpiry
|
||||
check onExpiryUpdatePassedExpiry == expectedExpiry.toSecondsSince1970
|
||||
|
||||
test "switches to error state when slot is filled by another host":
|
||||
slot.host = Address.example
|
||||
|
||||
@ -18,19 +18,19 @@ asyncchecksuite "sales state 'finished'":
|
||||
let slotIndex = request.ask.slots div 2
|
||||
let clock = MockClock.new()
|
||||
|
||||
let currentCollateral = UInt256.example
|
||||
let currentCollateral = Tokens.example
|
||||
|
||||
var market: MockMarket
|
||||
var state: SaleFinished
|
||||
var agent: SalesAgent
|
||||
var reprocessSlotWas = bool.none
|
||||
var returnedCollateralValue = UInt256.none
|
||||
var returnedCollateralValue = Tokens.none
|
||||
var saleCleared = bool.none
|
||||
|
||||
setup:
|
||||
market = MockMarket.new()
|
||||
let onCleanUp = proc(
|
||||
reprocessSlot = false, returnedCollateral = UInt256.none
|
||||
reprocessSlot = false, returnedCollateral = Tokens.none
|
||||
) {.async.} =
|
||||
reprocessSlotWas = some reprocessSlot
|
||||
returnedCollateralValue = returnedCollateral
|
||||
|
||||
@ -24,7 +24,7 @@ asyncchecksuite "sales state 'ignored'":
|
||||
|
||||
setup:
|
||||
let onCleanUp = proc(
|
||||
reprocessSlot = false, returnedCollateral = UInt256.none
|
||||
reprocessSlot = false, returnedCollateral = Tokens.none
|
||||
) {.async.} =
|
||||
reprocessSlotWas = reprocessSlot
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ asyncchecksuite "sales state 'payout'":
|
||||
let slotIndex = request.ask.slots div 2
|
||||
let clock = MockClock.new()
|
||||
|
||||
let currentCollateral = UInt128.example
|
||||
let currentCollateral = Tokens.example
|
||||
|
||||
var market: MockMarket
|
||||
var state: SalePayout
|
||||
@ -41,4 +41,4 @@ asyncchecksuite "sales state 'payout'":
|
||||
)
|
||||
let next = await state.run(agent)
|
||||
check !next of SaleFinished
|
||||
check SaleFinished(!next).returnedCollateral == some collateral
|
||||
check SaleFinished(!next).returnedCollateral == some currentCollateral
|
||||
|
||||
@ -35,15 +35,15 @@ asyncchecksuite "sales state 'preparing'":
|
||||
|
||||
setup:
|
||||
let collateral =
|
||||
request.ask.collateralPerSlot.stuint(256) * request.ask.slots.u256
|
||||
request.ask.collateralPerSlot * request.ask.slots
|
||||
availability = Availability.init(
|
||||
totalSize = request.ask.slotSize + 100.uint64,
|
||||
freeSize = request.ask.slotSize + 100.uint64,
|
||||
duration = request.ask.duration.u64 + 60,
|
||||
minPricePerBytePerSecond = request.ask.pricePerBytePerSecond.stuint(256),
|
||||
duration = request.ask.duration + 60'u8,
|
||||
minPricePerBytePerSecond = request.ask.pricePerBytePerSecond,
|
||||
totalCollateral = collateral,
|
||||
enabled = true,
|
||||
until = 0.SecondsSince1970,
|
||||
until = 0'StorageTimestamp,
|
||||
)
|
||||
let repoDs = SQLiteDatastore.new(Memory).tryGet()
|
||||
let metaDs = SQLiteDatastore.new(Memory).tryGet()
|
||||
@ -57,7 +57,8 @@ asyncchecksuite "sales state 'preparing'":
|
||||
context.reservations = reservations
|
||||
agent = newSalesAgent(context, request.id, slotIndex, request.some)
|
||||
|
||||
market.requestEnds[request.id] = clock.now() + cast[int64](request.ask.duration)
|
||||
market.requestEnds[request.id] =
|
||||
StorageTimestamp.init(clock.now()) + request.ask.duration
|
||||
|
||||
teardown:
|
||||
await repo.stop()
|
||||
@ -81,7 +82,7 @@ asyncchecksuite "sales state 'preparing'":
|
||||
availability.minPricePerBytePerSecond,
|
||||
availability.totalCollateral,
|
||||
enabled,
|
||||
until = 0.SecondsSince1970,
|
||||
until = 0'StorageTimestamp,
|
||||
)
|
||||
availability = a.get
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ asyncchecksuite "Reservations module":
|
||||
repoDs: Datastore
|
||||
metaDs: Datastore
|
||||
reservations: Reservations
|
||||
collateralPerByte: UInt256
|
||||
collateralPerByte: Tokens
|
||||
let
|
||||
repoTmp = TempLevelDb.new()
|
||||
metaTmp = TempLevelDb.new()
|
||||
@ -34,16 +34,16 @@ asyncchecksuite "Reservations module":
|
||||
metaDs = metaTmp.newDb()
|
||||
repo = RepoStore.new(repoDs, metaDs)
|
||||
reservations = Reservations.new(repo)
|
||||
collateralPerByte = uint8.example.u256
|
||||
collateralPerByte = Tokens.init(uint8.example)
|
||||
|
||||
teardown:
|
||||
await repoTmp.destroyDb()
|
||||
await metaTmp.destroyDb()
|
||||
|
||||
proc createAvailability(enabled = true, until = 0.SecondsSince1970): Availability =
|
||||
proc createAvailability(enabled = true, until = 0'StorageTimestamp): Availability =
|
||||
let example = Availability.example(collateralPerByte)
|
||||
let totalSize = rand(100000 .. 200000).uint64
|
||||
let totalCollateral = totalSize.u256 * collateralPerByte
|
||||
let totalCollateral = collateralPerByte * totalSize
|
||||
let availability = waitFor reservations.createAvailability(
|
||||
totalSize, example.duration, example.minPricePerBytePerSecond, totalCollateral,
|
||||
enabled, until,
|
||||
@ -52,9 +52,9 @@ asyncchecksuite "Reservations module":
|
||||
|
||||
proc createReservation(availability: Availability): Reservation =
|
||||
let size = rand(1 ..< availability.freeSize.int)
|
||||
let validUntil = getTime().toUnix() + 30.SecondsSince1970
|
||||
let validUntil = StorageTimestamp.init(getTime().toUnix() + 30)
|
||||
let reservation = waitFor reservations.createReservation(
|
||||
availability.id, size.uint64, RequestId.example, uint64.example, 1.u256,
|
||||
availability.id, size.uint64, RequestId.example, uint64.example, 1'Tokens,
|
||||
validUntil,
|
||||
)
|
||||
return reservation.get
|
||||
@ -69,10 +69,22 @@ asyncchecksuite "Reservations module":
|
||||
|
||||
test "generates unique ids for storage availability":
|
||||
let availability1 = Availability.init(
|
||||
1.uint64, 2.uint64, 3.uint64, 4.u256, 5.u256, true, 0.SecondsSince1970
|
||||
1.uint64,
|
||||
2.uint64,
|
||||
3'StorageDuration,
|
||||
4'TokensPerSecond,
|
||||
5'Tokens,
|
||||
true,
|
||||
0'StorageTimestamp
|
||||
)
|
||||
let availability2 = Availability.init(
|
||||
1.uint64, 2.uint64, 3.uint64, 4.u256, 5.u256, true, 0.SecondsSince1970
|
||||
1.uint64,
|
||||
2.uint64,
|
||||
3'StorageDuration,
|
||||
4'TokensPerSecond,
|
||||
5'Tokens,
|
||||
true,
|
||||
0'StorageTimestamp
|
||||
)
|
||||
check availability1.id != availability2.id
|
||||
|
||||
@ -136,9 +148,9 @@ asyncchecksuite "Reservations module":
|
||||
|
||||
test "cannot create reservation with non-existant availability":
|
||||
let availability = Availability.example
|
||||
let validUntil = getTime().toUnix() + 30.SecondsSince1970
|
||||
let validUntil = StorageTimestamp.init(getTime().toUnix() + 30)
|
||||
let created = await reservations.createReservation(
|
||||
availability.id, uint64.example, RequestId.example, uint64.example, 1.u256,
|
||||
availability.id, uint64.example, RequestId.example, uint64.example, 1'Tokens,
|
||||
validUntil,
|
||||
)
|
||||
check created.isErr
|
||||
@ -146,13 +158,13 @@ asyncchecksuite "Reservations module":
|
||||
|
||||
test "cannot create reservation larger than availability size":
|
||||
let availability = createAvailability()
|
||||
let validUntil = getTime().toUnix() + 30.SecondsSince1970
|
||||
let validUntil = StorageTimestamp.init(getTime().toUnix() + 30)
|
||||
let created = await reservations.createReservation(
|
||||
availability.id,
|
||||
availability.totalSize + 1,
|
||||
RequestId.example,
|
||||
uint64.example,
|
||||
UInt256.example,
|
||||
Tokens.example,
|
||||
validUntil,
|
||||
)
|
||||
check created.isErr
|
||||
@ -161,19 +173,19 @@ asyncchecksuite "Reservations module":
|
||||
test "cannot create reservation larger than availability size - concurrency test":
|
||||
proc concurrencyTest(): Future[void] {.async.} =
|
||||
let availability = createAvailability()
|
||||
let validUntil = getTime().toUnix() + 30.SecondsSince1970
|
||||
let validUntil = StorageTimestamp.init(getTime().toUnix() + 30)
|
||||
let one = reservations.createReservation(
|
||||
availability.id,
|
||||
availability.totalSize - 1,
|
||||
RequestId.example,
|
||||
uint64.example,
|
||||
UInt256.example,
|
||||
Tokens.example,
|
||||
validUntil,
|
||||
)
|
||||
|
||||
let two = reservations.createReservation(
|
||||
availability.id, availability.totalSize, RequestId.example, uint64.example,
|
||||
UInt256.example, validUntil,
|
||||
Tokens.example, validUntil
|
||||
)
|
||||
|
||||
let oneResult = await one
|
||||
@ -280,42 +292,15 @@ asyncchecksuite "Reservations module":
|
||||
|
||||
test "create availability set until to 0 by default":
|
||||
let availability = createAvailability()
|
||||
check availability.until == 0.SecondsSince1970
|
||||
check availability.until == 0'StorageTimestamp
|
||||
|
||||
test "create availability whith correct values":
|
||||
var until = getTime().toUnix()
|
||||
var until = StorageTimestamp.init(getTime().toUnix())
|
||||
|
||||
let availability = createAvailability(enabled = false, until = until)
|
||||
check availability.enabled == false
|
||||
check availability.until == until
|
||||
|
||||
test "create an availability fails when trying set until with a negative value":
|
||||
let totalSize = rand(100000 .. 200000).uint64
|
||||
let example = Availability.example(collateralPerByte)
|
||||
let totalCollateral = totalSize.u256 * collateralPerByte
|
||||
|
||||
let result = await reservations.createAvailability(
|
||||
totalSize,
|
||||
example.duration,
|
||||
example.minPricePerBytePerSecond,
|
||||
totalCollateral,
|
||||
enabled = true,
|
||||
until = -1.SecondsSince1970,
|
||||
)
|
||||
|
||||
check result.isErr
|
||||
check result.error of UntilOutOfBoundsError
|
||||
|
||||
test "update an availability fails when trying set until with a negative value":
|
||||
let until = getTime().toUnix()
|
||||
let availability = createAvailability(until = until)
|
||||
|
||||
availability.until = -1
|
||||
|
||||
let result = await reservations.update(availability)
|
||||
check result.isErr
|
||||
check result.error of UntilOutOfBoundsError
|
||||
|
||||
test "reservation can be partially released":
|
||||
let availability = createAvailability()
|
||||
let reservation = createReservation(availability)
|
||||
@ -392,7 +377,7 @@ asyncchecksuite "Reservations module":
|
||||
var added: Availability
|
||||
reservations.OnAvailabilitySaved = proc(a: Availability) {.async: (raises: []).} =
|
||||
added = a
|
||||
availability.duration += 1
|
||||
availability.duration += 1'StorageDuration
|
||||
discard await reservations.update(availability)
|
||||
|
||||
check added == availability
|
||||
@ -402,7 +387,7 @@ asyncchecksuite "Reservations module":
|
||||
var called = false
|
||||
reservations.OnAvailabilitySaved = proc(a: Availability) {.async: (raises: []).} =
|
||||
called = true
|
||||
availability.duration -= 1
|
||||
availability.duration -= 1'StorageDuration
|
||||
discard await reservations.update(availability)
|
||||
|
||||
check not called
|
||||
@ -412,7 +397,7 @@ asyncchecksuite "Reservations module":
|
||||
var added: Availability
|
||||
reservations.OnAvailabilitySaved = proc(a: Availability) {.async: (raises: []).} =
|
||||
added = a
|
||||
availability.minPricePerBytePerSecond += 1.u256
|
||||
availability.minPricePerBytePerSecond += 1'TokensPerSecond
|
||||
discard await reservations.update(availability)
|
||||
|
||||
check added == availability
|
||||
@ -422,7 +407,7 @@ asyncchecksuite "Reservations module":
|
||||
var called = false
|
||||
reservations.OnAvailabilitySaved = proc(a: Availability) {.async: (raises: []).} =
|
||||
called = true
|
||||
availability.minPricePerBytePerSecond -= 1.u256
|
||||
availability.minPricePerBytePerSecond -= 1'TokensPerSecond
|
||||
discard await reservations.update(availability)
|
||||
|
||||
check not called
|
||||
@ -432,7 +417,7 @@ asyncchecksuite "Reservations module":
|
||||
var added: Availability
|
||||
reservations.OnAvailabilitySaved = proc(a: Availability) {.async: (raises: []).} =
|
||||
added = a
|
||||
availability.totalCollateral = availability.totalCollateral + 1.u256
|
||||
availability.totalCollateral = availability.totalCollateral + 1'Tokens
|
||||
discard await reservations.update(availability)
|
||||
|
||||
check added == availability
|
||||
@ -442,14 +427,14 @@ asyncchecksuite "Reservations module":
|
||||
var called = false
|
||||
reservations.OnAvailabilitySaved = proc(a: Availability) {.async: (raises: []).} =
|
||||
called = true
|
||||
availability.totalCollateral = availability.totalCollateral - 1.u256
|
||||
availability.totalCollateral = availability.totalCollateral - 1'Tokens
|
||||
discard await reservations.update(availability)
|
||||
|
||||
check not called
|
||||
|
||||
test "availabilities can be found":
|
||||
let availability = createAvailability()
|
||||
let validUntil = getTime().toUnix() + 30.SecondsSince1970
|
||||
let validUntil = StorageTimestamp.init(getTime().toUnix() + 30)
|
||||
let found = await reservations.findAvailability(
|
||||
availability.freeSize, availability.duration,
|
||||
availability.minPricePerBytePerSecond, collateralPerByte, validUntil,
|
||||
@ -460,7 +445,7 @@ asyncchecksuite "Reservations module":
|
||||
|
||||
test "does not find an availability when is it disabled":
|
||||
let availability = createAvailability(enabled = false)
|
||||
let validUntil = getTime().toUnix() + 30.SecondsSince1970
|
||||
let validUntil = StorageTimestamp.init(getTime().toUnix() + 30)
|
||||
let found = await reservations.findAvailability(
|
||||
availability.freeSize, availability.duration,
|
||||
availability.minPricePerBytePerSecond, collateralPerByte, validUntil,
|
||||
@ -470,9 +455,9 @@ asyncchecksuite "Reservations module":
|
||||
|
||||
test "finds an availability when the until date is after the duration":
|
||||
let example = Availability.example(collateralPerByte)
|
||||
let until = getTime().toUnix() + example.duration.SecondsSince1970
|
||||
let until = StorageTimestamp.init(getTime().toUnix()) + example.duration
|
||||
let availability = createAvailability(until = until)
|
||||
let validUntil = getTime().toUnix() + 30.SecondsSince1970
|
||||
let validUntil = StorageTimestamp.init(getTime().toUnix() + 30)
|
||||
let found = await reservations.findAvailability(
|
||||
availability.freeSize, availability.duration,
|
||||
availability.minPricePerBytePerSecond, collateralPerByte, validUntil,
|
||||
@ -483,9 +468,9 @@ asyncchecksuite "Reservations module":
|
||||
|
||||
test "does not find an availability when the until date is before the duration":
|
||||
let example = Availability.example(collateralPerByte)
|
||||
let until = getTime().toUnix() + 1.SecondsSince1970
|
||||
let until = StorageTimestamp.init(getTime().toUnix() + 1)
|
||||
let availability = createAvailability(until = until)
|
||||
let validUntil = getTime().toUnix() + 30.SecondsSince1970
|
||||
let validUntil = StorageTimestamp.init(getTime().toUnix() + 30)
|
||||
let found = await reservations.findAvailability(
|
||||
availability.freeSize, availability.duration,
|
||||
availability.minPricePerBytePerSecond, collateralPerByte, validUntil,
|
||||
@ -495,7 +480,7 @@ asyncchecksuite "Reservations module":
|
||||
|
||||
test "non-matching availabilities are not found":
|
||||
let availability = createAvailability()
|
||||
let validUntil = getTime().toUnix() + 30.SecondsSince1970
|
||||
let validUntil = StorageTimestamp.init(getTime().toUnix() + 30)
|
||||
let found = await reservations.findAvailability(
|
||||
availability.freeSize + 1,
|
||||
availability.duration,
|
||||
@ -508,7 +493,7 @@ asyncchecksuite "Reservations module":
|
||||
|
||||
test "non-existent availability cannot be found":
|
||||
let availability = Availability.example
|
||||
let validUntil = getTime().toUnix() + 30.SecondsSince1970
|
||||
let validUntil = StorageTimestamp.init(getTime().toUnix() + 30)
|
||||
let found = await reservations.findAvailability(
|
||||
availability.freeSize, availability.duration,
|
||||
availability.minPricePerBytePerSecond, collateralPerByte, validUntil,
|
||||
@ -533,11 +518,11 @@ asyncchecksuite "Reservations module":
|
||||
test "fails to create availability with size that is larger than available quota":
|
||||
let created = await reservations.createAvailability(
|
||||
DefaultQuotaBytes.uint64 + 1,
|
||||
uint64.example,
|
||||
UInt256.example,
|
||||
UInt256.example,
|
||||
StorageDuration.example,
|
||||
TokensPerSecond.example,
|
||||
Tokens.example,
|
||||
enabled = true,
|
||||
until = 0.SecondsSince1970,
|
||||
until = 0'StorageTimestamp,
|
||||
)
|
||||
check created.isErr
|
||||
check created.error of ReserveFailedError
|
||||
|
||||
@ -37,21 +37,20 @@ asyncchecksuite "Sales - start":
|
||||
var repo: RepoStore
|
||||
var queue: SlotQueue
|
||||
var itemsProcessed: seq[SlotQueueItem]
|
||||
var expiry: SecondsSince1970
|
||||
|
||||
setup:
|
||||
request = StorageRequest(
|
||||
ask: StorageAsk(
|
||||
slots: 4,
|
||||
slotSize: 100.uint64,
|
||||
duration: 60.stuint(40),
|
||||
pricePerBytePerSecond: 1.stuint(96),
|
||||
collateralPerByte: 1.u128,
|
||||
duration: 60'StorageDuration,
|
||||
pricePerBytePerSecond: 1'TokensPerSecond,
|
||||
collateralPerByte: 1'Tokens,
|
||||
),
|
||||
content: StorageContent(
|
||||
cid: Cid.init("zb2rhheVmk3bLks5MgzTqyznLu1zqGH5jrfTA1eAZXrjx7Vob").tryGet
|
||||
),
|
||||
expiry: (getTime() + initDuration(hours = 1)).toUnix.stuint(40),
|
||||
expiry: 60'StorageDuration,
|
||||
)
|
||||
|
||||
market = MockMarket.new()
|
||||
@ -63,7 +62,11 @@ asyncchecksuite "Sales - start":
|
||||
sales = Sales.new(market, clock, repo)
|
||||
reservations = sales.context.reservations
|
||||
sales.onStore = proc(
|
||||
request: StorageRequest, slot: uint64, onBatch: BatchProc, isRepairing = false
|
||||
request: StorageRequest,
|
||||
expiry: StorageTimestamp,
|
||||
slot: uint64,
|
||||
onBatch: BatchProc,
|
||||
isRepairing = false
|
||||
): Future[?!void] {.async.} =
|
||||
return success()
|
||||
|
||||
@ -78,8 +81,6 @@ asyncchecksuite "Sales - start":
|
||||
): Future[?!Groth16Proof] {.async.} =
|
||||
return success(proof)
|
||||
itemsProcessed = @[]
|
||||
expiry = (clock.now() + 42)
|
||||
request.expiry = expiry.stuint(40)
|
||||
|
||||
teardown:
|
||||
await sales.stop()
|
||||
@ -100,7 +101,6 @@ asyncchecksuite "Sales - start":
|
||||
request.ask.slots = 2
|
||||
market.requested = @[request]
|
||||
market.requestState[request.id] = RequestState.New
|
||||
market.requestExpiry[request.id] = expiry
|
||||
|
||||
let slot0 = MockSlot(requestId: request.id, slotIndex: 0, proof: proof, host: me)
|
||||
await fillSlot(slot0.slotIndex)
|
||||
@ -129,9 +129,9 @@ asyncchecksuite "Sales":
|
||||
metaTmp = TempLevelDb.new()
|
||||
|
||||
var totalAvailabilitySize: uint64
|
||||
var minPricePerBytePerSecond: UInt256
|
||||
var requestedCollateralPerByte: UInt128
|
||||
var totalCollateral: UInt256
|
||||
var minPricePerBytePerSecond: TokensPerSecond
|
||||
var requestedCollateralPerByte: Tokens
|
||||
var totalCollateral: Tokens
|
||||
var availability: Availability
|
||||
var request: StorageRequest
|
||||
var sales: Sales
|
||||
@ -144,37 +144,36 @@ asyncchecksuite "Sales":
|
||||
|
||||
setup:
|
||||
totalAvailabilitySize = 100.uint64
|
||||
minPricePerBytePerSecond = 1.u256
|
||||
requestedCollateralPerByte = 1.u128
|
||||
totalCollateral = requestedCollateralPerByte.stuint(256) * totalAvailabilitySize.stuint(256)
|
||||
minPricePerBytePerSecond = 1'TokensPerSecond
|
||||
requestedCollateralPerByte = 1'Tokens
|
||||
totalCollateral = requestedCollateralPerByte * totalAvailabilitySize
|
||||
availability = Availability.init(
|
||||
totalSize = totalAvailabilitySize,
|
||||
freeSize = totalAvailabilitySize,
|
||||
duration = 60.uint64,
|
||||
duration = 60'StorageDuration,
|
||||
minPricePerBytePerSecond = minPricePerBytePerSecond,
|
||||
totalCollateral = totalCollateral,
|
||||
enabled = true,
|
||||
until = 0.SecondsSince1970,
|
||||
until = 0'StorageTimestamp,
|
||||
)
|
||||
request = StorageRequest(
|
||||
ask: StorageAsk(
|
||||
slots: 4,
|
||||
slotSize: 100.uint64,
|
||||
duration: 60.stuint(40),
|
||||
pricePerBytePerSecond: minPricePerBytePerSecond.stuint(96),
|
||||
collateralPerByte: 1.u128,
|
||||
duration: 60'StorageDuration,
|
||||
pricePerBytePerSecond: minPricePerBytePerSecond,
|
||||
collateralPerByte: 1'Tokens,
|
||||
),
|
||||
content: StorageContent(
|
||||
cid: Cid.init("zb2rhheVmk3bLks5MgzTqyznLu1zqGH5jrfTA1eAZXrjx7Vob").tryGet
|
||||
),
|
||||
expiry: (getTime() + initDuration(hours = 1)).toUnix.stuint(40),
|
||||
expiry: 60'StorageDuration,
|
||||
)
|
||||
|
||||
market = MockMarket.new()
|
||||
|
||||
let me = await market.getSigner()
|
||||
market.activeSlots[me] = @[]
|
||||
market.requestEnds[request.id] = request.expiry.toSecondsSince1970
|
||||
|
||||
clock = MockClock.new()
|
||||
let repoDs = repoTmp.newDb()
|
||||
@ -184,7 +183,11 @@ asyncchecksuite "Sales":
|
||||
sales = Sales.new(market, clock, repo)
|
||||
reservations = sales.context.reservations
|
||||
sales.onStore = proc(
|
||||
request: StorageRequest, slot: uint64, onBatch: BatchProc, isRepairing = false
|
||||
request: StorageRequest,
|
||||
expiry: StorageTimestamp,
|
||||
slot: uint64,
|
||||
onBatch: BatchProc,
|
||||
isRepairing = false
|
||||
): Future[?!void] {.async.} =
|
||||
return success()
|
||||
|
||||
@ -224,7 +227,7 @@ asyncchecksuite "Sales":
|
||||
let key = availability.id.key.get
|
||||
(waitFor reservations.get(key, Availability)).get
|
||||
|
||||
proc createAvailability(enabled = true, until = 0.SecondsSince1970) =
|
||||
proc createAvailability(enabled = true, until = 0'StorageTimestamp) =
|
||||
let a = waitFor reservations.createAvailability(
|
||||
availability.totalSize, availability.duration,
|
||||
availability.minPricePerBytePerSecond, availability.totalCollateral, enabled,
|
||||
@ -233,7 +236,7 @@ asyncchecksuite "Sales":
|
||||
availability = a.get # update id
|
||||
|
||||
proc notProcessed(itemsProcessed: seq[SlotQueueItem], request: StorageRequest): bool =
|
||||
let collateral =request.ask.collateralPerSlot.stuint(256)
|
||||
let collateral = request.ask.collateralPerSlot
|
||||
let items = SlotQueueItem.init(request, collateral)
|
||||
for i in 0 ..< items.len:
|
||||
if itemsProcessed.contains(items[i]):
|
||||
@ -254,7 +257,7 @@ asyncchecksuite "Sales":
|
||||
done.complete()
|
||||
|
||||
var request1 = StorageRequest.example
|
||||
request1.ask.collateralPerByte = request.ask.collateralPerByte + 1
|
||||
request1.ask.collateralPerByte = request.ask.collateralPerByte + 1'u8
|
||||
createAvailability()
|
||||
# saturate queue
|
||||
while queue.len < queue.size - 1:
|
||||
@ -281,7 +284,7 @@ asyncchecksuite "Sales":
|
||||
done.complete()
|
||||
createAvailability()
|
||||
await market.requestStorage(request)
|
||||
let collateral = request.ask.collateralPerSlot.stuint(256)
|
||||
let collateral = request.ask.collateralPerSlot
|
||||
let items = SlotQueueItem.init(request, collateral)
|
||||
check eventually items.allIt(itemsProcessed.contains(it))
|
||||
|
||||
@ -298,14 +301,14 @@ asyncchecksuite "Sales":
|
||||
test "removes slot index from slot queue once SlotFilled emitted":
|
||||
let request1 = await addRequestToSaturatedQueue()
|
||||
market.emitSlotFilled(request1.id, 1.uint64)
|
||||
let collateral = request1.ask.collateralPerSlot.stuint(256)
|
||||
let collateral = request1.ask.collateralPerSlot
|
||||
let expected = SlotQueueItem.init(request1, 1'u16, collateral)
|
||||
check always (not itemsProcessed.contains(expected))
|
||||
|
||||
test "removes slot index from slot queue once SlotReservationsFull emitted":
|
||||
let request1 = await addRequestToSaturatedQueue()
|
||||
market.emitSlotReservationsFull(request1.id, 1.uint64)
|
||||
let collateral = request1.ask.collateralPerSlot.stuint(256)
|
||||
let collateral = request1.ask.collateralPerSlot
|
||||
let expected = SlotQueueItem.init(request1, 1'u16, collateral)
|
||||
check always (not itemsProcessed.contains(expected))
|
||||
|
||||
@ -322,14 +325,14 @@ asyncchecksuite "Sales":
|
||||
|
||||
market.emitSlotFreed(request.id, 2.uint64)
|
||||
|
||||
let collateral = request.ask.collateralPerSlot.stuint(256)
|
||||
let collateral = request.ask.collateralPerSlot
|
||||
let expected = SlotQueueItem.init(request, 2.uint16, collateral)
|
||||
|
||||
check eventually itemsProcessed.contains(expected)
|
||||
|
||||
test "items in queue are readded (and marked seen) once ignored":
|
||||
await market.requestStorage(request)
|
||||
let collateral = request.ask.collateralPerSlot.stuint(256)
|
||||
let collateral = request.ask.collateralPerSlot
|
||||
let items = SlotQueueItem.init(request, collateral)
|
||||
check eventually queue.len > 0
|
||||
# queue starts paused, allow items to be added to the queue
|
||||
@ -351,7 +354,7 @@ asyncchecksuite "Sales":
|
||||
test "queue is paused once availability is insufficient to service slots in queue":
|
||||
createAvailability() # enough to fill a single slot
|
||||
await market.requestStorage(request)
|
||||
let collateral = request.ask.collateralPerSlot.stuint(256)
|
||||
let collateral = request.ask.collateralPerSlot
|
||||
let items = SlotQueueItem.init(request, collateral)
|
||||
check eventually queue.len > 0
|
||||
# queue starts paused, allow items to be added to the queue
|
||||
@ -369,7 +372,7 @@ asyncchecksuite "Sales":
|
||||
|
||||
test "availability size is reduced by request slot size when fully downloaded":
|
||||
sales.onStore = proc(
|
||||
request: StorageRequest, slot: uint64, onBatch: BatchProc, isRepairing = false
|
||||
request: StorageRequest, expiry: StorageTimestamp, slot: uint64, onBatch: BatchProc, isRepairing = false
|
||||
): Future[?!void] {.async.} =
|
||||
let blk = bt.Block.new(@[1.byte]).get
|
||||
await onBatch(blk.repeat(request.ask.slotSize.int))
|
||||
@ -382,7 +385,7 @@ asyncchecksuite "Sales":
|
||||
test "bytes are returned to availability once finished":
|
||||
var slotIndex = 0.uint64
|
||||
sales.onStore = proc(
|
||||
request: StorageRequest, slot: uint64, onBatch: BatchProc, isRepairing = false
|
||||
request: StorageRequest, expiry: StorageTimestamp, slot: uint64, onBatch: BatchProc, isRepairing = false
|
||||
): Future[?!void] {.async.} =
|
||||
slotIndex = slot
|
||||
let blk = bt.Block.new(@[1.byte]).get
|
||||
@ -400,12 +403,12 @@ asyncchecksuite "Sales":
|
||||
|
||||
# complete request
|
||||
market.slotState[request.slotId(slotIndex)] = SlotState.Finished
|
||||
clock.advance(request.ask.duration.truncate(int64))
|
||||
clock.advance(request.ask.duration.u64.int64)
|
||||
|
||||
check eventually getAvailability().freeSize == origSize
|
||||
|
||||
test "ignores download when duration not long enough":
|
||||
availability.duration = request.ask.duration.truncate(uint64) - 1
|
||||
availability.duration = request.ask.duration - 1'u8
|
||||
createAvailability()
|
||||
await market.requestStorage(request)
|
||||
check wasIgnored()
|
||||
@ -417,8 +420,8 @@ asyncchecksuite "Sales":
|
||||
check wasIgnored()
|
||||
|
||||
test "ignores request when reward is too low":
|
||||
let price = request.ask.pricePerBytePerSecond.stuint(256)
|
||||
availability.minPricePerBytePerSecond = price + 1
|
||||
let price = request.ask.pricePerBytePerSecond
|
||||
availability.minPricePerBytePerSecond = price + 1'u8
|
||||
createAvailability()
|
||||
await market.requestStorage(request)
|
||||
check wasIgnored()
|
||||
@ -445,20 +448,21 @@ asyncchecksuite "Sales":
|
||||
check wasIgnored()
|
||||
|
||||
test "ignores request when availability until terminates before the duration":
|
||||
let until = getTime().toUnix()
|
||||
let until = StorageTimestamp.init(getTime().toUnix())
|
||||
createAvailability(until = until)
|
||||
await market.requestStorage(request)
|
||||
|
||||
check wasIgnored()
|
||||
|
||||
test "retrieves request when availability until terminates after the duration":
|
||||
let requestEnd = getTime().toUnix() + cast[int64](request.ask.duration)
|
||||
let until = requestEnd + 1
|
||||
let requestEnd =
|
||||
StorageTimestamp.init(getTime().toUnix()) + request.ask.duration
|
||||
let until = requestEnd + 1'StorageDuration
|
||||
createAvailability(until = until)
|
||||
|
||||
var storingRequest: StorageRequest
|
||||
sales.onStore = proc(
|
||||
request: StorageRequest, slot: uint64, onBatch: BatchProc, isRepairing = false
|
||||
request: StorageRequest, expiry: StorageTimestamp, slot: uint64, onBatch: BatchProc, isRepairing = false
|
||||
): Future[?!void] {.async.} =
|
||||
storingRequest = request
|
||||
return success()
|
||||
@ -471,7 +475,7 @@ asyncchecksuite "Sales":
|
||||
var storingRequest: StorageRequest
|
||||
var storingSlot: uint64
|
||||
sales.onStore = proc(
|
||||
request: StorageRequest, slot: uint64, onBatch: BatchProc, isRepairing = false
|
||||
request: StorageRequest, expiry: StorageTimestamp, slot: uint64, onBatch: BatchProc, isRepairing = false
|
||||
): Future[?!void] {.async.} =
|
||||
storingRequest = request
|
||||
storingSlot = slot
|
||||
@ -484,7 +488,7 @@ asyncchecksuite "Sales":
|
||||
test "makes storage available again when data retrieval fails":
|
||||
let error = newException(IOError, "data retrieval failed")
|
||||
sales.onStore = proc(
|
||||
request: StorageRequest, slot: uint64, onBatch: BatchProc, isRepairing = false
|
||||
request: StorageRequest, expiry: StorageTimestamp, slot: uint64, onBatch: BatchProc, isRepairing = false
|
||||
): Future[?!void] {.async.} =
|
||||
return failure(error)
|
||||
createAvailability()
|
||||
@ -553,7 +557,7 @@ asyncchecksuite "Sales":
|
||||
test "makes storage available again when other host fills the slot":
|
||||
let otherHost = Address.example
|
||||
sales.onStore = proc(
|
||||
request: StorageRequest, slot: uint64, onBatch: BatchProc, isRepairing = false
|
||||
request: StorageRequest, expiry: StorageTimestamp, slot: uint64, onBatch: BatchProc, isRepairing = false
|
||||
): Future[?!void] {.async.} =
|
||||
await sleepAsync(chronos.hours(1))
|
||||
return success()
|
||||
@ -564,12 +568,9 @@ asyncchecksuite "Sales":
|
||||
check eventually (await reservations.all(Availability)).get == @[availability]
|
||||
|
||||
test "makes storage available again when request expires":
|
||||
let expiry = getTime().toUnix() + 10
|
||||
market.requestExpiry[request.id] = expiry
|
||||
|
||||
let origSize = availability.freeSize
|
||||
sales.onStore = proc(
|
||||
request: StorageRequest, slot: uint64, onBatch: BatchProc, isRepairing = false
|
||||
request: StorageRequest, expiry: StorageTimestamp, slot: uint64, onBatch: BatchProc, isRepairing = false
|
||||
): Future[?!void] {.async.} =
|
||||
await sleepAsync(chronos.hours(1))
|
||||
return success()
|
||||
@ -580,23 +581,21 @@ asyncchecksuite "Sales":
|
||||
# would otherwise not set the timeout early enough as it uses `clock.now` in the deadline calculation.
|
||||
await sleepAsync(chronos.milliseconds(100))
|
||||
market.requestState[request.id] = RequestState.Cancelled
|
||||
clock.set(expiry + 1)
|
||||
clock.set(market.requestExpiry[request.id].toSecondsSince1970 + 1)
|
||||
check eventually (await reservations.all(Availability)).get == @[availability]
|
||||
check getAvailability().freeSize == origSize
|
||||
|
||||
test "verifies that request is indeed expired from onchain before firing onCancelled":
|
||||
let expiry = getTime().toUnix() + 10
|
||||
# ensure only one slot, otherwise once bytes are returned to the
|
||||
# availability, the queue will be unpaused and availability will be consumed
|
||||
# by other slots
|
||||
request.ask.slots = 1
|
||||
market.requestExpiry[request.id] = expiry
|
||||
market.requestEnds[request.id] =
|
||||
getTime().toUnix() + cast[int64](request.ask.duration)
|
||||
StorageTimestamp.init(getTime().toUnix()) + request.ask.duration
|
||||
|
||||
let origSize = availability.freeSize
|
||||
sales.onStore = proc(
|
||||
request: StorageRequest, slot: uint64, onBatch: BatchProc, isRepairing = false
|
||||
request: StorageRequest, expiry: StorageTimestamp, slot: uint64, onBatch: BatchProc, isRepairing = false
|
||||
): Future[?!void] {.async.} =
|
||||
await sleepAsync(chronos.hours(1))
|
||||
return success()
|
||||
@ -608,7 +607,7 @@ asyncchecksuite "Sales":
|
||||
# If we would not await, then the `clock.set` would run "too fast" as the `subscribeCancellation()`
|
||||
# would otherwise not set the timeout early enough as it uses `clock.now` in the deadline calculation.
|
||||
await sleepAsync(chronos.milliseconds(100))
|
||||
clock.set(expiry + 1)
|
||||
clock.set(market.requestExpiry[request.id].toSecondsSince1970 + 1)
|
||||
check getAvailability().freeSize == 0
|
||||
|
||||
market.requestState[request.id] = RequestState.Cancelled
|
||||
@ -621,7 +620,6 @@ asyncchecksuite "Sales":
|
||||
request.ask.slots = 2
|
||||
market.requested = @[request]
|
||||
market.requestState[request.id] = RequestState.New
|
||||
market.requestEnds[request.id] = request.expiry.toSecondsSince1970
|
||||
|
||||
proc fillSlot(slotIdx: uint64 = 0) {.async.} =
|
||||
let address = await market.getSigner()
|
||||
@ -651,9 +649,9 @@ asyncchecksuite "Sales":
|
||||
|
||||
test "deletes inactive reservations on load":
|
||||
createAvailability()
|
||||
let validUntil = getTime().toUnix() + 30.SecondsSince1970
|
||||
let validUntil = StorageTimestamp.init(getTime().toUnix() + 30)
|
||||
discard await reservations.createReservation(
|
||||
availability.id, 100.uint64, RequestId.example, 0.uint64, UInt256.example,
|
||||
availability.id, 100.uint64, RequestId.example, 0.uint64, Tokens.example,
|
||||
validUntil,
|
||||
)
|
||||
check (await reservations.all(Reservation)).get.len == 1
|
||||
@ -662,16 +660,16 @@ asyncchecksuite "Sales":
|
||||
check getAvailability().freeSize == availability.freeSize # was restored
|
||||
|
||||
test "update an availability fails when trying change the until date before an existing reservation":
|
||||
let until = getTime().toUnix() + 300.SecondsSince1970
|
||||
let until = StorageTimestamp.init(getTime().toUnix() + 300)
|
||||
createAvailability(until = until)
|
||||
|
||||
market.requestEnds[request.id] =
|
||||
getTime().toUnix() + cast[int64](request.ask.duration)
|
||||
StorageTimestamp.init(getTime().toUnix()) + request.ask.duration
|
||||
|
||||
await market.requestStorage(request)
|
||||
await allowRequestToStart()
|
||||
|
||||
availability.until = getTime().toUnix()
|
||||
availability.until = StorageTimestamp.init(getTime().toUnix())
|
||||
|
||||
let result = await reservations.update(availability)
|
||||
check result.isErr
|
||||
|
||||
@ -33,6 +33,7 @@ method onSlotFilled*(
|
||||
|
||||
asyncchecksuite "Sales agent":
|
||||
let request = StorageRequest.example
|
||||
var expiry: StorageTimestamp
|
||||
var agent: SalesAgent
|
||||
var context: SalesContext
|
||||
var slotIndex: uint64
|
||||
@ -41,7 +42,7 @@ asyncchecksuite "Sales agent":
|
||||
|
||||
setup:
|
||||
market = MockMarket.new()
|
||||
let expiry = getTime().toUnix() + request.expiry.toSecondsSince1970
|
||||
expiry = StorageTimestamp.init(getTime().toUnix()) + request.expiry
|
||||
market.requestExpiry[request.id] = expiry
|
||||
clock = MockClock.new()
|
||||
context = SalesContext(market: market, clock: clock)
|
||||
@ -84,7 +85,7 @@ asyncchecksuite "Sales agent":
|
||||
agent.start(MockState.new())
|
||||
await agent.subscribe()
|
||||
market.requestState[request.id] = RequestState.Cancelled
|
||||
clock.set(market.requestExpiry[request.id] + 1)
|
||||
clock.set(expiry.toSecondsSince1970 + 1)
|
||||
check eventually onCancelCalled
|
||||
|
||||
for requestState in {
|
||||
@ -94,7 +95,7 @@ asyncchecksuite "Sales agent":
|
||||
agent.start(MockState.new())
|
||||
await agent.subscribe()
|
||||
market.requestState[request.id] = requestState
|
||||
clock.set(market.requestExpiry[request.id] + 1)
|
||||
clock.set(expiry.toSecondsSince1970 + 1)
|
||||
await sleepAsync(100.millis)
|
||||
check not onCancelCalled
|
||||
|
||||
@ -103,7 +104,7 @@ asyncchecksuite "Sales agent":
|
||||
agent.start(MockState.new())
|
||||
await agent.subscribe()
|
||||
market.requestState[request.id] = requestState
|
||||
clock.set(market.requestExpiry[request.id] + 1)
|
||||
clock.set(expiry.toSecondsSince1970 + 1)
|
||||
check eventually agent.data.cancelled.finished
|
||||
|
||||
test "cancelled future is finished (cancelled) when onFulfilled called":
|
||||
|
||||
@ -65,7 +65,6 @@ suite "Slot queue workers":
|
||||
doneProcessing.complete()
|
||||
|
||||
setup:
|
||||
let request = StorageRequest.example
|
||||
queue = SlotQueue.new(maxSize = 5, maxWorkers = 3)
|
||||
queue.onProcessSlot = onProcessSlot
|
||||
|
||||
@ -166,23 +165,21 @@ suite "Slot queue":
|
||||
|
||||
test "correctly compares SlotQueueItems":
|
||||
var requestA = StorageRequest.example
|
||||
requestA.ask.duration = 1.stuint(40)
|
||||
requestA.ask.pricePerBytePerSecond = 1.stuint(96)
|
||||
check requestA.ask.pricePerSlot == 1.u128 * requestA.ask.slotSize.u128
|
||||
requestA.ask.collateralPerByte = 100000.u128
|
||||
requestA.expiry = 1001.stuint(40)
|
||||
requestA.ask.duration = 1'StorageDuration
|
||||
requestA.ask.pricePerBytePerSecond = 1'TokensPerSecond
|
||||
check requestA.ask.pricePerSlot == 1'Tokens * requestA.ask.slotSize
|
||||
requestA.ask.collateralPerByte = 100000'Tokens
|
||||
|
||||
var requestB = StorageRequest.example
|
||||
requestB.ask.duration = 100.stuint(40)
|
||||
requestB.ask.pricePerBytePerSecond = 1000.stuint(96)
|
||||
check requestB.ask.pricePerSlot == 100000.u128 * requestB.ask.slotSize.u128
|
||||
requestB.ask.collateralPerByte = 1.u128
|
||||
requestB.expiry = 1000.stuint(40)
|
||||
requestB.ask.duration = 100'StorageDuration
|
||||
requestB.ask.pricePerBytePerSecond = 1000'TokensPerSecond
|
||||
check requestB.ask.pricePerSlot == 100000'Tokens * requestB.ask.slotSize
|
||||
requestB.ask.collateralPerByte = 1'Tokens
|
||||
|
||||
let itemA =
|
||||
SlotQueueItem.init(requestA, 0, requestA.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(requestA, 0, requestA.ask.collateralPerSlot)
|
||||
let itemB =
|
||||
SlotQueueItem.init(requestB, 0, requestB.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(requestB, 0, requestB.ask.collateralPerSlot)
|
||||
check itemB < itemA # B higher priority than A
|
||||
check itemA > itemB
|
||||
|
||||
@ -192,20 +189,20 @@ suite "Slot queue":
|
||||
requestId: request.id,
|
||||
slotIndex: 0,
|
||||
slotSize: 1.uint64,
|
||||
duration: 1.uint64,
|
||||
pricePerBytePerSecond: 2.u256, # profitability is higher (good)
|
||||
collateral: 1.u256,
|
||||
expiry: 1.uint64,
|
||||
duration: 1'StorageDuration,
|
||||
pricePerBytePerSecond: 2'TokensPerSecond, # profitability is higher (good)
|
||||
collateral: 1'Tokens,
|
||||
expiry: 1'StorageTimestamp,
|
||||
seen: true, # seen (bad), more weight than profitability
|
||||
)
|
||||
let itemB = MockSlotQueueItem(
|
||||
requestId: request.id,
|
||||
slotIndex: 0,
|
||||
slotSize: 1.uint64,
|
||||
duration: 1.uint64,
|
||||
pricePerBytePerSecond: 1.u256, # profitability is lower (bad)
|
||||
collateral: 1.u256,
|
||||
expiry: 1.uint64,
|
||||
duration: 1'StorageDuration,
|
||||
pricePerBytePerSecond: 1'TokensPerSecond, # profitability is lower (bad)
|
||||
collateral: 1'Tokens,
|
||||
expiry: 1'StorageTimestamp,
|
||||
seen: false, # not seen (good)
|
||||
)
|
||||
check itemB.toSlotQueueItem < itemA.toSlotQueueItem # B higher priority than A
|
||||
@ -217,21 +214,21 @@ suite "Slot queue":
|
||||
requestId: request.id,
|
||||
slotIndex: 0,
|
||||
slotSize: 1.uint64,
|
||||
duration: 1.uint64,
|
||||
pricePerBytePerSecond: 1.u256, # reward is lower (bad)
|
||||
collateral: 1.u256, # collateral is lower (good)
|
||||
expiry: 1.uint64,
|
||||
duration: 1'StorageDuration,
|
||||
pricePerBytePerSecond: 1'TokensPerSecond, # reward is lower (bad)
|
||||
collateral: 1'Tokens, # collateral is lower (good)
|
||||
expiry: 1'StorageTimestamp,
|
||||
seen: false,
|
||||
)
|
||||
let itemB = MockSlotQueueItem(
|
||||
requestId: request.id,
|
||||
slotIndex: 0,
|
||||
slotSize: 1.uint64,
|
||||
duration: 1.uint64,
|
||||
pricePerBytePerSecond: 2.u256,
|
||||
duration: 1'StorageDuration,
|
||||
pricePerBytePerSecond: 2'TokensPerSecond,
|
||||
# reward is higher (good), more weight than collateral
|
||||
collateral: 2.u256, # collateral is higher (bad)
|
||||
expiry: 1.uint64,
|
||||
collateral: 2'Tokens, # collateral is higher (bad)
|
||||
expiry: 1'StorageTimestamp,
|
||||
seen: false,
|
||||
)
|
||||
|
||||
@ -243,20 +240,20 @@ suite "Slot queue":
|
||||
requestId: request.id,
|
||||
slotIndex: 0,
|
||||
slotSize: 1.uint64,
|
||||
duration: 1.uint64,
|
||||
pricePerBytePerSecond: 1.u256,
|
||||
collateral: 2.u256, # collateral is higher (bad)
|
||||
expiry: 2.uint64, # expiry is longer (good)
|
||||
duration: 1'StorageDuration,
|
||||
pricePerBytePerSecond: 1'TokensPerSecond,
|
||||
collateral: 2'Tokens, # collateral is higher (bad)
|
||||
expiry: 2'StorageTimestamp, # expiry is longer (good)
|
||||
seen: false,
|
||||
)
|
||||
let itemB = MockSlotQueueItem(
|
||||
requestId: request.id,
|
||||
slotIndex: 0,
|
||||
slotSize: 1.uint64,
|
||||
duration: 1.uint64,
|
||||
pricePerBytePerSecond: 1.u256,
|
||||
collateral: 1.u256, # collateral is lower (good), more weight than expiry
|
||||
expiry: 1.uint64, # expiry is shorter (bad)
|
||||
duration: 1'StorageDuration,
|
||||
pricePerBytePerSecond: 1'TokensPerSecond,
|
||||
collateral: 1'Tokens, # collateral is lower (good), more weight than expiry
|
||||
expiry: 1'StorageTimestamp, # expiry is shorter (bad)
|
||||
seen: false,
|
||||
)
|
||||
|
||||
@ -268,20 +265,20 @@ suite "Slot queue":
|
||||
requestId: request.id,
|
||||
slotIndex: 0,
|
||||
slotSize: 1.uint64, # slotSize is smaller (good)
|
||||
duration: 1.uint64,
|
||||
pricePerBytePerSecond: 1.u256,
|
||||
collateral: 1.u256,
|
||||
expiry: 1.uint64, # expiry is shorter (bad)
|
||||
duration: 1'StorageDuration,
|
||||
pricePerBytePerSecond: 1'TokensPerSecond,
|
||||
collateral: 1'Tokens,
|
||||
expiry: 1'StorageTimestamp, # expiry is shorter (bad)
|
||||
seen: false,
|
||||
)
|
||||
let itemB = MockSlotQueueItem(
|
||||
requestId: request.id,
|
||||
slotIndex: 0,
|
||||
slotSize: 2.uint64, # slotSize is larger (bad)
|
||||
duration: 1.uint64,
|
||||
pricePerBytePerSecond: 1.u256,
|
||||
collateral: 1.u256,
|
||||
expiry: 2.uint64, # expiry is longer (good), more weight than slotSize
|
||||
duration: 1'StorageDuration,
|
||||
pricePerBytePerSecond: 1'TokensPerSecond,
|
||||
collateral: 1'Tokens,
|
||||
expiry: 2'StorageTimestamp, # expiry is longer (good), more weight than slotSize
|
||||
seen: false,
|
||||
)
|
||||
|
||||
@ -293,20 +290,20 @@ suite "Slot queue":
|
||||
requestId: request.id,
|
||||
slotIndex: 0,
|
||||
slotSize: 2.uint64, # slotSize is larger (bad)
|
||||
duration: 1.uint64,
|
||||
pricePerBytePerSecond: 1.u256,
|
||||
collateral: 1.u256,
|
||||
expiry: 1.uint64, # expiry is shorter (bad)
|
||||
duration: 1'StorageDuration,
|
||||
pricePerBytePerSecond: 1'TokensPerSecond,
|
||||
collateral: 1'Tokens,
|
||||
expiry: 1'StorageTimestamp, # expiry is shorter (bad)
|
||||
seen: false,
|
||||
)
|
||||
let itemB = MockSlotQueueItem(
|
||||
requestId: request.id,
|
||||
slotIndex: 0,
|
||||
slotSize: 1.uint64, # slotSize is smaller (good)
|
||||
duration: 1.uint64,
|
||||
pricePerBytePerSecond: 1.u256,
|
||||
collateral: 1.u256,
|
||||
expiry: 1.uint64,
|
||||
duration: 1'StorageDuration,
|
||||
pricePerBytePerSecond: 1'TokensPerSecond,
|
||||
collateral: 1'Tokens,
|
||||
expiry: 1'StorageTimestamp,
|
||||
seen: false,
|
||||
)
|
||||
|
||||
@ -314,14 +311,14 @@ suite "Slot queue":
|
||||
|
||||
test "expands available all possible slot indices on init":
|
||||
let request = StorageRequest.example
|
||||
let items = SlotQueueItem.init(request, request.ask.collateralPerSlot.stuint(256))
|
||||
let items = SlotQueueItem.init(request, request.ask.collateralPerSlot)
|
||||
check items.len.uint64 == request.ask.slots
|
||||
var checked = 0
|
||||
for slotIndex in 0'u16 ..< request.ask.slots.uint16:
|
||||
check items.anyIt(
|
||||
it ==
|
||||
SlotQueueItem.init(
|
||||
request, slotIndex, request.ask.collateralPerSlot.stuint(256)
|
||||
request, slotIndex, request.ask.collateralPerSlot
|
||||
)
|
||||
)
|
||||
inc checked
|
||||
@ -357,8 +354,8 @@ suite "Slot queue":
|
||||
let items = SlotQueueItem.init(
|
||||
request.id,
|
||||
request.ask,
|
||||
request.expiry.u64,
|
||||
request.ask.collateralPerSlot.stuint(256),
|
||||
0'StorageTimestamp,
|
||||
request.ask.collateralPerSlot,
|
||||
)
|
||||
check items.len.uint16 == maxUInt16
|
||||
|
||||
@ -371,8 +368,8 @@ suite "Slot queue":
|
||||
discard SlotQueueItem.init(
|
||||
request.id,
|
||||
request.ask,
|
||||
request.expiry.u64,
|
||||
request.ask.collateralPerSlot.stuint(256),
|
||||
0'StorageTimestamp,
|
||||
request.ask.collateralPerSlot,
|
||||
)
|
||||
|
||||
test "cannot push duplicate items":
|
||||
@ -413,11 +410,11 @@ suite "Slot queue":
|
||||
newSlotQueue(maxSize = 8, maxWorkers = 1, processSlotDelay = 10.millis)
|
||||
let request0 = StorageRequest.example
|
||||
var request1 = StorageRequest.example
|
||||
request1.ask.collateralPerByte += 1.u128
|
||||
request1.ask.collateralPerByte += 1'Tokens
|
||||
let items0 =
|
||||
SlotQueueItem.init(request0, request0.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(request0, request0.ask.collateralPerSlot)
|
||||
let items1 =
|
||||
SlotQueueItem.init(request1, request1.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(request1, request1.ask.collateralPerSlot)
|
||||
check queue.push(items0).isOk
|
||||
check queue.push(items1).isOk
|
||||
let last = items1[items1.high]
|
||||
@ -429,11 +426,11 @@ suite "Slot queue":
|
||||
newSlotQueue(maxSize = 8, maxWorkers = 1, processSlotDelay = 10.millis)
|
||||
let request0 = StorageRequest.example
|
||||
var request1 = StorageRequest.example
|
||||
request1.ask.collateralPerByte += 1.u128
|
||||
request1.ask.collateralPerByte += 1'Tokens
|
||||
let items0 =
|
||||
SlotQueueItem.init(request0, request0.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(request0, request0.ask.collateralPerSlot)
|
||||
let items1 =
|
||||
SlotQueueItem.init(request1, request1.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(request1, request1.ask.collateralPerSlot)
|
||||
check queue.push(items0).isOk
|
||||
check queue.push(items1).isOk
|
||||
queue.delete(request1.id)
|
||||
@ -453,17 +450,17 @@ suite "Slot queue":
|
||||
request4.ask.collateralPerByte = request3.ask.collateralPerByte + 1
|
||||
request5.ask.collateralPerByte = request4.ask.collateralPerByte + 1
|
||||
let item0 =
|
||||
SlotQueueItem.init(request0, 0, request0.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(request0, 0, request0.ask.collateralPerSlot)
|
||||
let item1 =
|
||||
SlotQueueItem.init(request1, 0, request1.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(request1, 0, request1.ask.collateralPerSlot)
|
||||
let item2 =
|
||||
SlotQueueItem.init(request2, 0, request2.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(request2, 0, request2.ask.collateralPerSlot)
|
||||
let item3 =
|
||||
SlotQueueItem.init(request3, 0, request3.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(request3, 0, request3.ask.collateralPerSlot)
|
||||
let item4 =
|
||||
SlotQueueItem.init(request4, 0, request4.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(request4, 0, request4.ask.collateralPerSlot)
|
||||
let item5 =
|
||||
SlotQueueItem.init(request5, 0, request5.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(request5, 0, request5.ask.collateralPerSlot)
|
||||
check queue.contains(item5) == false
|
||||
check queue.push(@[item0, item1, item2, item3, item4, item5]).isOk
|
||||
check queue.contains(item5)
|
||||
@ -471,37 +468,36 @@ suite "Slot queue":
|
||||
test "sorts items by profitability descending (higher pricePerBytePerSecond == higher priority == goes first in the list)":
|
||||
var request = StorageRequest.example
|
||||
let item0 =
|
||||
SlotQueueItem.init(request, 0, request.ask.collateralPerSlot.stuint(256))
|
||||
request.ask.pricePerBytePerSecond += 1.stuint(96)
|
||||
SlotQueueItem.init(request, 0, request.ask.collateralPerSlot)
|
||||
request.ask.pricePerBytePerSecond += 1'TokensPerSecond
|
||||
let item1 =
|
||||
SlotQueueItem.init(request, 1, request.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(request, 1, request.ask.collateralPerSlot)
|
||||
check item1 < item0
|
||||
|
||||
test "sorts items by collateral ascending (higher required collateral = lower priority == comes later in the list)":
|
||||
var request = StorageRequest.example
|
||||
let item0 =
|
||||
SlotQueueItem.init(request, 0, request.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(request, 0, request.ask.collateralPerSlot)
|
||||
let item1 = SlotQueueItem.init(
|
||||
request, 1, request.ask.collateralPerSlot.stuint(256) + 1.u256
|
||||
request, 1, request.ask.collateralPerSlot + 1'Tokens
|
||||
)
|
||||
check item1 > item0
|
||||
|
||||
test "sorts items by expiry descending (longer expiry = higher priority)":
|
||||
var request = StorageRequest.example
|
||||
let item0 =
|
||||
SlotQueueItem.init(request, 0, request.ask.collateralPerSlot.stuint(256))
|
||||
request.expiry += 1.stuint(40)
|
||||
SlotQueueItem.init(request.id, 0, request.ask, 3'StorageTimestamp, request.ask.collateralPerSlot)
|
||||
let item1 =
|
||||
SlotQueueItem.init(request, 1, request.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(request.id, 1, request.ask, 7'StorageTimestamp, request.ask.collateralPerSlot)
|
||||
check item1 < item0
|
||||
|
||||
test "sorts items by slot size descending (bigger dataset = higher profitability = higher priority)":
|
||||
var request = StorageRequest.example
|
||||
let item0 =
|
||||
SlotQueueItem.init(request, 0, request.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(request, 0, request.ask.collateralPerSlot)
|
||||
request.ask.slotSize += 1
|
||||
let item1 =
|
||||
SlotQueueItem.init(request, 1, request.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(request, 1, request.ask.collateralPerSlot)
|
||||
check item1 < item0
|
||||
|
||||
test "should call callback once an item is added":
|
||||
@ -523,16 +519,16 @@ suite "Slot queue":
|
||||
# calling the callback for each pushed/updated item
|
||||
var request = StorageRequest.example
|
||||
let item0 =
|
||||
SlotQueueItem.init(request, 0, request.ask.collateralPerSlot.stuint(256))
|
||||
request.ask.pricePerBytePerSecond += 1.stuint(96)
|
||||
SlotQueueItem.init(request, 0, request.ask.collateralPerSlot)
|
||||
request.ask.pricePerBytePerSecond += 1'TokensPerSecond
|
||||
let item1 =
|
||||
SlotQueueItem.init(request, 1, request.ask.collateralPerSlot.stuint(256))
|
||||
request.ask.pricePerBytePerSecond += 1.stuint(96)
|
||||
SlotQueueItem.init(request, 1, request.ask.collateralPerSlot)
|
||||
request.ask.pricePerBytePerSecond += 1'TokensPerSecond
|
||||
let item2 =
|
||||
SlotQueueItem.init(request, 2, request.ask.collateralPerSlot.stuint(256))
|
||||
request.ask.pricePerBytePerSecond += 1.stuint(96)
|
||||
SlotQueueItem.init(request, 2, request.ask.collateralPerSlot)
|
||||
request.ask.pricePerBytePerSecond += 1'TokensPerSecond
|
||||
let item3 =
|
||||
SlotQueueItem.init(request, 3, request.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(request, 3, request.ask.collateralPerSlot)
|
||||
|
||||
check queue.push(item0).isOk
|
||||
await sleepAsync(1.millis)
|
||||
@ -558,16 +554,16 @@ suite "Slot queue":
|
||||
# calling the callback for each pushed/updated item
|
||||
var request = StorageRequest.example
|
||||
let item0 =
|
||||
SlotQueueItem.init(request, 0, request.ask.collateralPerSlot.stuint(256))
|
||||
request.ask.pricePerBytePerSecond += 1.stuint(96)
|
||||
SlotQueueItem.init(request, 0, request.ask.collateralPerSlot)
|
||||
request.ask.pricePerBytePerSecond += 1'TokensPerSecond
|
||||
let item1 =
|
||||
SlotQueueItem.init(request, 1, request.ask.collateralPerSlot.stuint(256))
|
||||
request.ask.pricePerBytePerSecond += 1.stuint(96)
|
||||
SlotQueueItem.init(request, 1, request.ask.collateralPerSlot)
|
||||
request.ask.pricePerBytePerSecond += 1'TokensPerSecond
|
||||
let item2 =
|
||||
SlotQueueItem.init(request, 2, request.ask.collateralPerSlot.stuint(256))
|
||||
request.ask.pricePerBytePerSecond += 1.stuint(96)
|
||||
SlotQueueItem.init(request, 2, request.ask.collateralPerSlot)
|
||||
request.ask.pricePerBytePerSecond += 1'TokensPerSecond
|
||||
let item3 =
|
||||
SlotQueueItem.init(request, 3, request.ask.collateralPerSlot.stuint(256))
|
||||
SlotQueueItem.init(request, 3, request.ask.collateralPerSlot)
|
||||
|
||||
check queue.push(item0).isOk
|
||||
check queue.push(item1).isOk
|
||||
@ -591,7 +587,7 @@ suite "Slot queue":
|
||||
queue.pause
|
||||
|
||||
let request = StorageRequest.example
|
||||
var items = SlotQueueItem.init(request, request.ask.collateralPerSlot.stuint(256))
|
||||
var items = SlotQueueItem.init(request, request.ask.collateralPerSlot)
|
||||
check queue.push(items).isOk
|
||||
# check all items processed
|
||||
check eventually queue.len == 0
|
||||
@ -603,8 +599,8 @@ suite "Slot queue":
|
||||
request.id,
|
||||
0'u16,
|
||||
request.ask,
|
||||
request.expiry.u64,
|
||||
request.ask.collateralPerSlot.stuint(256),
|
||||
0'StorageTimestamp,
|
||||
request.ask.collateralPerSlot,
|
||||
seen = true,
|
||||
)
|
||||
check queue.paused
|
||||
@ -618,8 +614,8 @@ suite "Slot queue":
|
||||
request.id,
|
||||
1'u16,
|
||||
request.ask,
|
||||
request.expiry.u64,
|
||||
request.ask.collateralPerSlot.stuint(256),
|
||||
0'StorageTimestamp,
|
||||
request.ask.collateralPerSlot,
|
||||
seen = false,
|
||||
)
|
||||
check queue.paused
|
||||
@ -636,16 +632,16 @@ suite "Slot queue":
|
||||
request.id,
|
||||
0'u16,
|
||||
request.ask,
|
||||
request.expiry.u64,
|
||||
request.ask.collateralPerSlot.stuint(256),
|
||||
0'StorageTimestamp,
|
||||
request.ask.collateralPerSlot,
|
||||
seen = false,
|
||||
)
|
||||
let seen = SlotQueueItem.init(
|
||||
request.id,
|
||||
1'u16,
|
||||
request.ask,
|
||||
request.expiry.u64,
|
||||
request.ask.collateralPerSlot.stuint(256),
|
||||
0'StorageTimestamp,
|
||||
request.ask.collateralPerSlot,
|
||||
seen = true,
|
||||
)
|
||||
# push causes unpause
|
||||
@ -664,16 +660,16 @@ suite "Slot queue":
|
||||
request.id,
|
||||
0'u16,
|
||||
request.ask,
|
||||
request.expiry.u64,
|
||||
request.ask.collateralPerSlot.stuint(256),
|
||||
0'StorageTimestamp,
|
||||
request.ask.collateralPerSlot,
|
||||
seen = false,
|
||||
)
|
||||
let seen = SlotQueueItem.init(
|
||||
request.id,
|
||||
1'u16,
|
||||
request.ask,
|
||||
request.expiry.u64,
|
||||
request.ask.collateralPerSlot.stuint(256),
|
||||
0'StorageTimestamp,
|
||||
request.ask.collateralPerSlot,
|
||||
seen = true,
|
||||
)
|
||||
# push seen item to ensure that queue is pausing
|
||||
@ -696,16 +692,16 @@ suite "Slot queue":
|
||||
request.id,
|
||||
0'u16,
|
||||
request.ask,
|
||||
request.expiry.u64,
|
||||
request.ask.collateralPerSlot.stuint(256),
|
||||
0'StorageTimestamp,
|
||||
request.ask.collateralPerSlot,
|
||||
seen = true,
|
||||
)
|
||||
let item1 = SlotQueueItem.init(
|
||||
request.id,
|
||||
1'u16,
|
||||
request.ask,
|
||||
request.expiry.u64,
|
||||
request.ask.collateralPerSlot.stuint(256),
|
||||
0'StorageTimestamp,
|
||||
request.ask.collateralPerSlot,
|
||||
seen = true,
|
||||
)
|
||||
check queue.push(item0).isOk
|
||||
|
||||
@ -29,8 +29,8 @@ asyncchecksuite "Purchasing":
|
||||
ask: StorageAsk(
|
||||
slots: uint8.example.uint64,
|
||||
slotSize: uint32.example.uint64,
|
||||
duration: uint16.example.stuint(40),
|
||||
pricePerBytePerSecond: uint8.example.stuint(96),
|
||||
duration: StorageDuration.init(uint16.example),
|
||||
pricePerBytePerSecond: TokensPerSecond.init(uint8.example),
|
||||
)
|
||||
)
|
||||
|
||||
@ -82,36 +82,34 @@ asyncchecksuite "Purchasing":
|
||||
check market.requested[0].client == await market.getSigner()
|
||||
|
||||
test "succeeds when request is finished":
|
||||
market.requestExpiry[populatedRequest.id] = getTime().toUnix() + 10
|
||||
let expiry = StorageTimestamp.init(getTime().toUnix() + 10)
|
||||
market.requestExpiry[populatedRequest.id] = expiry
|
||||
let purchase = await purchasing.purchase(populatedRequest)
|
||||
|
||||
check eventually market.requested.len > 0
|
||||
let request = market.requested[0]
|
||||
let requestEnd = getTime().toUnix() + 42
|
||||
let requestEnd = StorageTimestamp.init(getTime().toUnix() + 42)
|
||||
market.requestEnds[request.id] = requestEnd
|
||||
|
||||
market.emitRequestFulfilled(request.id)
|
||||
clock.set(requestEnd + 1)
|
||||
clock.set(requestEnd.toSecondsSince1970 + 1)
|
||||
await purchase.wait()
|
||||
check purchase.error.isNone
|
||||
|
||||
test "fails when request times out":
|
||||
let expiry = getTime().toUnix() + 10
|
||||
market.requestExpiry[populatedRequest.id] = expiry
|
||||
let purchase = await purchasing.purchase(populatedRequest)
|
||||
check eventually market.requested.len > 0
|
||||
|
||||
clock.set(expiry + 1)
|
||||
let expiry = market.requestExpiry[populatedRequest.id]
|
||||
clock.set(expiry.toSecondsSince1970 + 1)
|
||||
expect PurchaseTimeout:
|
||||
await purchase.wait()
|
||||
|
||||
test "checks that funds were withdrawn when purchase times out":
|
||||
let expiry = getTime().toUnix() + 10
|
||||
market.requestExpiry[populatedRequest.id] = expiry
|
||||
let purchase = await purchasing.purchase(populatedRequest)
|
||||
check eventually market.requested.len > 0
|
||||
let request = market.requested[0]
|
||||
clock.set(expiry + 1)
|
||||
let expiry = market.requestExpiry[populatedRequest.id]
|
||||
clock.set(expiry.toSecondsSince1970 + 1)
|
||||
expect PurchaseTimeout:
|
||||
await purchase.wait()
|
||||
check market.withdrawn == @[request.id]
|
||||
@ -130,8 +128,8 @@ suite "Purchasing state machine":
|
||||
ask: StorageAsk(
|
||||
slots: uint8.example.uint64,
|
||||
slotSize: uint32.example.uint64,
|
||||
duration: uint16.example.stuint(40),
|
||||
pricePerBytePerSecond: uint8.example.stuint(96),
|
||||
duration: StorageDuration.init(uint16.example),
|
||||
pricePerBytePerSecond: TokensPerSecond.init(uint8.example),
|
||||
)
|
||||
)
|
||||
|
||||
@ -158,7 +156,7 @@ suite "Purchasing state machine":
|
||||
market.requestState[request5.id] = RequestState.Failed
|
||||
|
||||
# ensure the started state doesn't error, giving a false positive test result
|
||||
market.requestEnds[request2.id] = clock.now() - 1
|
||||
market.requestEnds[request2.id] = StorageTimestamp.init(clock.now() - 1)
|
||||
|
||||
await purchasing.load()
|
||||
check eventually purchasing.getPurchase(PurchaseId(request1.id)) .? finished ==
|
||||
@ -184,8 +182,8 @@ suite "Purchasing state machine":
|
||||
test "moves to PurchaseStarted when request state is Started":
|
||||
let request = StorageRequest.example
|
||||
let purchase = Purchase.new(request, market, clock)
|
||||
let duration = request.ask.duration.toSecondsSince1970
|
||||
market.requestEnds[request.id] = clock.now() + duration
|
||||
let duration = request.ask.duration
|
||||
market.requestEnds[request.id] = StorageTimestamp.init(clock.now()) + duration
|
||||
market.requested = @[request]
|
||||
market.requestState[request.id] = RequestState.Started
|
||||
let next = await PurchaseUnknown().run(purchase)
|
||||
@ -218,8 +216,8 @@ suite "Purchasing state machine":
|
||||
test "moves to PurchaseFailed state once RequestFailed emitted":
|
||||
let request = StorageRequest.example
|
||||
let purchase = Purchase.new(request, market, clock)
|
||||
let duration = request.ask.duration.toSecondsSince1970
|
||||
market.requestEnds[request.id] = clock.now() + duration
|
||||
let duration = request.ask.duration
|
||||
market.requestEnds[request.id] = StorageTimestamp.init(clock.now) + duration
|
||||
let future = PurchaseStarted().run(purchase)
|
||||
|
||||
market.emitRequestFailed(request.id)
|
||||
@ -230,11 +228,11 @@ suite "Purchasing state machine":
|
||||
test "moves to PurchaseFinished state once request finishes":
|
||||
let request = StorageRequest.example
|
||||
let purchase = Purchase.new(request, market, clock)
|
||||
let duration = request.ask.duration.toSecondsSince1970
|
||||
market.requestEnds[request.id] = clock.now() + duration
|
||||
let duration = request.ask.duration
|
||||
market.requestEnds[request.id] = StorageTimestamp.init(clock.now) + duration
|
||||
let future = PurchaseStarted().run(purchase)
|
||||
|
||||
clock.advance(duration + 1)
|
||||
clock.advance(duration.u64.int64 + 1)
|
||||
|
||||
let next = await future
|
||||
check !next of PurchaseFinished
|
||||
|
||||
@ -2,8 +2,8 @@ import pkg/chronos
|
||||
import std/strformat
|
||||
import std/times
|
||||
|
||||
import codex/contracts/periods
|
||||
import codex/validation
|
||||
import codex/periods
|
||||
import codex/clock
|
||||
|
||||
import ../asynctest
|
||||
@ -16,8 +16,8 @@ logScope:
|
||||
topics = "testValidation"
|
||||
|
||||
asyncchecksuite "validation":
|
||||
let period = 10.uint64
|
||||
let timeout = 5.uint64
|
||||
let period = 10'StorageDuration
|
||||
let timeout = 5'StorageDuration
|
||||
let maxSlots = MaxSlots(100)
|
||||
let validationGroups = ValidationGroups(8).some
|
||||
let slot = Slot.example
|
||||
@ -50,9 +50,9 @@ asyncchecksuite "validation":
|
||||
setup:
|
||||
groupIndex = groupIndexForSlotId(slot.id, !validationGroups)
|
||||
clock = MockClock.new()
|
||||
market = MockMarket.new(clock = Clock(clock).some)
|
||||
market.config.proofs.period = period.stuint(40)
|
||||
market.config.proofs.timeout = timeout.stuint(40)
|
||||
market = MockMarket.new(clock)
|
||||
market.config.proofs.period = period
|
||||
market.config.proofs.timeout = timeout
|
||||
validation = newValidation(clock, market, maxSlots, validationGroups, groupIndex)
|
||||
|
||||
teardown:
|
||||
@ -61,7 +61,7 @@ asyncchecksuite "validation":
|
||||
|
||||
proc advanceToNextPeriod() =
|
||||
let periodicity = Periodicity(seconds: period)
|
||||
let period = periodicity.periodOf(clock.now().Timestamp)
|
||||
let period = periodicity.periodOf(StorageTimestamp.init(clock.now()))
|
||||
let periodEnd = periodicity.periodEnd(period)
|
||||
clock.set(periodEnd.toSecondsSince1970 + 1)
|
||||
|
||||
|
||||
@ -15,10 +15,10 @@ ethersuite "Marketplace contracts":
|
||||
var periodicity: Periodicity
|
||||
var request: StorageRequest
|
||||
var slotId: SlotId
|
||||
var filledAt: UInt256
|
||||
var filledAt: StorageTimestamp
|
||||
|
||||
proc expectedPayout(endTimestamp: UInt256): UInt256 =
|
||||
return (endTimestamp - filledAt) * request.ask.pricePerSlotPerSecond.stuint(256)
|
||||
proc expectedPayout(endTimestamp: StorageTimestamp): Tokens =
|
||||
return request.ask.pricePerSlotPerSecond * filledAt.until(endTimestamp)
|
||||
|
||||
proc switchAccount(account: Signer) =
|
||||
marketplace = marketplace.connect(account)
|
||||
@ -35,25 +35,26 @@ ethersuite "Marketplace contracts":
|
||||
token = Erc20Token.new(tokenAddress, ethProvider.getSigner())
|
||||
|
||||
let config = await marketplace.configuration()
|
||||
periodicity = Periodicity(seconds: config.proofs.period.u64)
|
||||
periodicity = Periodicity(seconds: config.proofs.period)
|
||||
|
||||
request = StorageRequest.example
|
||||
request.client = await client.getAddress()
|
||||
|
||||
switchAccount(client)
|
||||
discard await token.approve(marketplace.address, request.totalPrice.stuint(256)).confirm(1)
|
||||
discard await token.approve(marketplace.address, request.totalPrice.u256).confirm(1)
|
||||
discard await marketplace.requestStorage(request).confirm(1)
|
||||
switchAccount(host)
|
||||
discard
|
||||
await token.approve(marketplace.address, request.ask.collateralPerSlot.stuint(256)).confirm(1)
|
||||
await token.approve(marketplace.address, request.ask.collateralPerSlot.u256).confirm(1)
|
||||
discard await marketplace.reserveSlot(request.id, 0.uint64).confirm(1)
|
||||
let receipt = await marketplace.fillSlot(request.id, 0.uint64, proof).confirm(1)
|
||||
filledAt = await ethProvider.blockTime(BlockTag.init(!receipt.blockNumber))
|
||||
let receiptTime = await ethProvider.blockTime(BlockTag.init(!receipt.blockNumber))
|
||||
filledAt = StorageTimestamp.init(receiptTime.stuint(40))
|
||||
slotId = request.slotId(0.uint64)
|
||||
|
||||
proc waitUntilProofRequired(slotId: SlotId) {.async.} =
|
||||
let currentPeriod =
|
||||
periodicity.periodOf((await ethProvider.currentTime()).truncate(uint64))
|
||||
periodicity.periodOf((await ethProvider.currentTime()).truncate(int64))
|
||||
await ethProvider.advanceTimeTo(periodicity.periodEnd(currentPeriod).u256)
|
||||
while not (
|
||||
(await marketplace.isProofRequired(slotId)) and
|
||||
@ -65,7 +66,7 @@ ethersuite "Marketplace contracts":
|
||||
proc startContract() {.async.} =
|
||||
for slotIndex in 1 ..< request.ask.slots:
|
||||
discard await token
|
||||
.approve(marketplace.address, request.ask.collateralPerSlot.stuint(256))
|
||||
.approve(marketplace.address, request.ask.collateralPerSlot.u256)
|
||||
.confirm(1)
|
||||
discard await marketplace.reserveSlot(request.id, slotIndex.uint64).confirm(1)
|
||||
discard await marketplace.fillSlot(request.id, slotIndex.uint64, proof).confirm(1)
|
||||
@ -79,11 +80,11 @@ ethersuite "Marketplace contracts":
|
||||
switchAccount(host)
|
||||
await waitUntilProofRequired(slotId)
|
||||
let missingPeriod =
|
||||
periodicity.periodOf((await ethProvider.currentTime()).truncate(uint64))
|
||||
periodicity.periodOf((await ethProvider.currentTime()).truncate(int64))
|
||||
let endOfPeriod = periodicity.periodEnd(missingPeriod)
|
||||
await ethProvider.advanceTimeTo(endOfPeriod.u256 + 1)
|
||||
switchAccount(client)
|
||||
discard await marketplace.markProofAsMissing(slotId, missingPeriod.stuint(40)).confirm(1)
|
||||
discard await marketplace.markProofAsMissing(slotId, missingPeriod).confirm(1)
|
||||
|
||||
test "can be paid out at the end":
|
||||
switchAccount(host)
|
||||
@ -94,15 +95,14 @@ ethersuite "Marketplace contracts":
|
||||
let startBalance = await token.balanceOf(address)
|
||||
discard await marketplace.freeSlot(slotId).confirm(1)
|
||||
let endBalance = await token.balanceOf(address)
|
||||
check endBalance ==
|
||||
(startBalance + expectedPayout(requestEnd.u256) + request.ask.collateralPerSlot.stuint(256))
|
||||
check (endBalance - startBalance) == (expectedPayout(requestEnd) + request.ask.collateralPerSlot).u256
|
||||
|
||||
test "cannot mark proofs missing for cancelled request":
|
||||
let expiry = await marketplace.requestExpiry(request.id)
|
||||
await ethProvider.advanceTimeTo((expiry + 1).u256)
|
||||
switchAccount(client)
|
||||
let missingPeriod =
|
||||
periodicity.periodOf((await ethProvider.currentTime()).truncate(uint64))
|
||||
periodicity.periodOf((await ethProvider.currentTime()).truncate(int64))
|
||||
await ethProvider.advanceTime(periodicity.seconds.u256)
|
||||
expect Marketplace_SlotNotAcceptingProofs:
|
||||
discard await marketplace.markProofAsMissing(slotId, missingPeriod.stuint(40)).confirm(1)
|
||||
discard await marketplace.markProofAsMissing(slotId, missingPeriod).confirm(1)
|
||||
|
||||
@ -30,10 +30,8 @@ ethersuite "On-Chain Market":
|
||||
var host: Signer
|
||||
var otherHost: Signer
|
||||
|
||||
proc expectedPayout(
|
||||
r: StorageRequest, startTimestamp: UInt256, endTimestamp: UInt256
|
||||
): UInt256 =
|
||||
return (endTimestamp - startTimestamp) * r.ask.pricePerSlotPerSecond.stuint(256)
|
||||
proc expectedPayout(request: StorageRequest, start, finish: StorageTimestamp): Tokens =
|
||||
return request.ask.pricePerSlotPerSecond * start.until(finish)
|
||||
|
||||
proc switchAccount(account: Signer) {.async.} =
|
||||
marketplace = marketplace.connect(account)
|
||||
@ -49,7 +47,7 @@ ethersuite "On-Chain Market":
|
||||
let tokenAddress = await marketplace.token()
|
||||
token = Erc20Token.new(tokenAddress, ethProvider.getSigner())
|
||||
|
||||
periodicity = Periodicity(seconds: config.proofs.period.u64)
|
||||
periodicity = Periodicity(seconds: config.proofs.period)
|
||||
|
||||
request = StorageRequest.example
|
||||
request.client = accounts[0]
|
||||
@ -60,7 +58,7 @@ ethersuite "On-Chain Market":
|
||||
|
||||
proc advanceToNextPeriod() {.async.} =
|
||||
let currentPeriod =
|
||||
periodicity.periodOf((await ethProvider.currentTime()).truncate(uint64))
|
||||
periodicity.periodOf((await ethProvider.currentTime()).truncate(int64))
|
||||
await ethProvider.advanceTimeTo((periodicity.periodEnd(currentPeriod) + 1).u256)
|
||||
|
||||
proc advanceToCancelledRequest(request: StorageRequest) {.async.} =
|
||||
@ -88,12 +86,12 @@ ethersuite "On-Chain Market":
|
||||
let periodicity = market.periodicity
|
||||
let config = await marketplace.configuration()
|
||||
let periodLength = config.proofs.period
|
||||
check periodicity.seconds == periodLength.u64
|
||||
check periodicity.seconds == periodLength
|
||||
|
||||
test "can retrieve proof timeout":
|
||||
let proofTimeout = market.proofTimeout
|
||||
let config = await marketplace.configuration()
|
||||
check proofTimeout == config.proofs.timeout.u64
|
||||
check proofTimeout == config.proofs.timeout
|
||||
|
||||
test "supports marketplace requests":
|
||||
await market.requestStorage(request)
|
||||
@ -114,12 +112,12 @@ ethersuite "On-Chain Market":
|
||||
|
||||
let endBalanceClient = await token.balanceOf(clientAddress)
|
||||
|
||||
check endBalanceClient == (startBalanceClient + request.totalPrice.stuint(256))
|
||||
check endBalanceClient == (startBalanceClient + request.totalPrice.u256)
|
||||
|
||||
test "supports request subscriptions":
|
||||
var receivedIds: seq[RequestId]
|
||||
var receivedAsks: seq[StorageAsk]
|
||||
proc onRequest(id: RequestId, ask: StorageAsk, expiry: uint64) =
|
||||
proc onRequest(id: RequestId, ask: StorageAsk, expiry: StorageTimestamp) =
|
||||
receivedIds.add(id)
|
||||
receivedAsks.add(ask)
|
||||
|
||||
@ -168,7 +166,7 @@ ethersuite "On-Chain Market":
|
||||
await market.fillSlot(request.id, slotIndex, proof, request.ask.collateralPerSlot)
|
||||
await waitUntilProofRequired(slotId)
|
||||
let missingPeriod =
|
||||
periodicity.periodOf((await ethProvider.currentTime()).truncate(uint64))
|
||||
periodicity.periodOf((await ethProvider.currentTime()).truncate(int64))
|
||||
await advanceToNextPeriod()
|
||||
await market.markProofAsMissing(slotId, missingPeriod)
|
||||
check (await marketplace.missingProofs(slotId)) == 1
|
||||
@ -180,7 +178,7 @@ ethersuite "On-Chain Market":
|
||||
await market.fillSlot(request.id, slotIndex, proof, request.ask.collateralPerSlot)
|
||||
await waitUntilProofRequired(slotId)
|
||||
let missingPeriod =
|
||||
periodicity.periodOf((await ethProvider.currentTime()).truncate(uint64))
|
||||
periodicity.periodOf((await ethProvider.currentTime()).truncate(int64))
|
||||
await advanceToNextPeriod()
|
||||
check (await market.canProofBeMarkedAsMissing(slotId, missingPeriod)) == true
|
||||
|
||||
@ -324,9 +322,9 @@ ethersuite "On-Chain Market":
|
||||
break
|
||||
await waitUntilProofRequired(slotId)
|
||||
let missingPeriod =
|
||||
periodicity.periodOf((await ethProvider.currentTime()).truncate(uint64))
|
||||
periodicity.periodOf((await ethProvider.currentTime()).truncate(int64))
|
||||
await advanceToNextPeriod()
|
||||
discard await marketplace.markProofAsMissing(slotId, missingPeriod.stuint(40)).confirm(1)
|
||||
discard await marketplace.markProofAsMissing(slotId, missingPeriod).confirm(1)
|
||||
check eventually receivedIds == @[request.id]
|
||||
await subscription.unsubscribe()
|
||||
|
||||
@ -510,7 +508,8 @@ ethersuite "On-Chain Market":
|
||||
await switchAccount(host)
|
||||
await market.reserveSlot(request.id, 0.uint64)
|
||||
await market.fillSlot(request.id, 0.uint64, proof, request.ask.collateralPerSlot)
|
||||
let filledAt = await ethProvider.blockTime(BlockTag.latest)
|
||||
let blockTime = await ethProvider.blockTime(BlockTag.latest)
|
||||
let filledAt = StorageTimestamp.init(blockTime.stuint(40))
|
||||
|
||||
for slotIndex in 1 ..< request.ask.slots:
|
||||
await market.reserveSlot(request.id, slotIndex.uint64)
|
||||
@ -525,8 +524,8 @@ ethersuite "On-Chain Market":
|
||||
await market.freeSlot(request.slotId(0.uint64))
|
||||
let endBalance = await token.balanceOf(address)
|
||||
|
||||
let expectedPayout = request.expectedPayout(filledAt, requestEnd.u256)
|
||||
check endBalance == (startBalance + expectedPayout + request.ask.collateralPerSlot.stuint(256))
|
||||
let expectedPayout = request.expectedPayout(filledAt, requestEnd)
|
||||
check (endBalance - startBalance) == (expectedPayout + request.ask.collateralPerSlot).u256
|
||||
|
||||
test "the request is added to cache after the first access":
|
||||
await market.requestStorage(request)
|
||||
|
||||
@ -37,33 +37,39 @@ 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)
|
||||
|
||||
proc example*(_: type UInt128): UInt128 =
|
||||
UInt128.fromBytes(array[16, byte].example)
|
||||
proc example*[bits](_: type StUint[bits]): StUint[bits] =
|
||||
StUint[bits].fromBytes(array[bits div 8, byte].example)
|
||||
|
||||
proc example*[T: distinct](_: type T): T =
|
||||
type baseType = T.distinctBase
|
||||
T(baseType.example)
|
||||
|
||||
proc example*(_: type StorageDuration): StorageDuration =
|
||||
StorageDuration.init(StUint[40].example)
|
||||
|
||||
proc example*(_: type TokensPerSecond): TokensPerSecond =
|
||||
TokensPerSecond.init(StUint[96].example)
|
||||
|
||||
proc example*(_: type Tokens): Tokens =
|
||||
Tokens.init(UInt128.example)
|
||||
|
||||
proc example*(_: type StorageRequest): StorageRequest =
|
||||
StorageRequest(
|
||||
client: Address.example,
|
||||
ask: StorageAsk(
|
||||
slots: 4,
|
||||
slotSize: (1 * 1024 * 1024 * 1024).uint64, # 1 Gigabyte
|
||||
duration: (10 * 60 * 60).stuint(40), # 10 hours
|
||||
collateralPerByte: 1.u128,
|
||||
duration: StorageDuration.init((10 * 60 * 60).stuint(40)), # 10 hours
|
||||
collateralPerByte: 1'Tokens,
|
||||
proofProbability: 4.u256, # require a proof roughly once every 4 periods
|
||||
pricePerBytePerSecond: 1.stuint(96),
|
||||
pricePerBytePerSecond: 1'TokensPerSecond,
|
||||
maxSlotLoss: 2, # 2 slots can be freed without data considered to be lost
|
||||
),
|
||||
content: StorageContent(
|
||||
cid: Cid.init("zb2rhheVmk3bLks5MgzTqyznLu1zqGH5jrfTA1eAZXrjx7Vob").tryGet,
|
||||
merkleRoot: array[32, byte].example,
|
||||
),
|
||||
expiry: (60 * 60).stuint(40), # 1 hour ,
|
||||
expiry: StorageDuration.init((60 * 60).stuint(40)), # 1 hour ,
|
||||
nonce: Nonce.example,
|
||||
)
|
||||
|
||||
@ -75,7 +81,7 @@ proc example*(_: type Slot): Slot =
|
||||
proc example*(_: type SlotQueueItem): SlotQueueItem =
|
||||
let request = StorageRequest.example
|
||||
let slot = Slot.example
|
||||
let collateral = request.ask.collateralPerSlot.stuint(256)
|
||||
let collateral = request.ask.collateralPerSlot
|
||||
SlotQueueItem.init(request, slot.slotIndex.uint16, collateral)
|
||||
|
||||
proc example(_: type G1Point): G1Point =
|
||||
|
||||
@ -217,16 +217,14 @@ proc space*(
|
||||
proc requestStorageRaw*(
|
||||
client: CodexClient,
|
||||
cid: Cid,
|
||||
duration: StUint[40],
|
||||
pricePerBytePerSecond: StUint[96],
|
||||
duration: StorageDuration,
|
||||
pricePerBytePerSecond: TokensPerSecond,
|
||||
proofProbability: UInt256,
|
||||
collateralPerByte: UInt128,
|
||||
expiry = 0.stuint(40),
|
||||
collateralPerByte: Tokens,
|
||||
expiry = none StorageDuration,
|
||||
nodes: uint = 3,
|
||||
tolerance: uint = 1,
|
||||
): Future[HttpClientResponseRef] {.
|
||||
async: (raw: true, raises: [CancelledError, HttpError])
|
||||
.} =
|
||||
): Future[HttpClientResponseRef] {.async: (raises: [CancelledError, HttpError]).} =
|
||||
## Call request storage REST endpoint
|
||||
##
|
||||
let url = client.baseurl & "/storage/request/" & $cid
|
||||
@ -240,19 +238,35 @@ proc requestStorageRaw*(
|
||||
"tolerance": tolerance,
|
||||
}
|
||||
|
||||
if expiry != 0.stuint(40):
|
||||
json["expiry"] = %($expiry)
|
||||
if expiry =? expiry:
|
||||
json["expiry"] = %expiry
|
||||
|
||||
return client.post(url, $json)
|
||||
return await client.post(url, $json)
|
||||
|
||||
proc requestStorageRaw*(
|
||||
client: CodexClient,
|
||||
cid: Cid,
|
||||
duration: StorageDuration,
|
||||
pricePerBytePerSecond: TokensPerSecond,
|
||||
proofProbability: UInt256,
|
||||
collateralPerByte: Tokens,
|
||||
expiry: StorageDuration,
|
||||
nodes: uint = 3,
|
||||
tolerance: uint = 1,
|
||||
): Future[HttpClientResponseRef] {.async: (raises: [CancelledError, HttpError]).} =
|
||||
return await client.requestStorageRaw(
|
||||
cid, duration, pricePerBytePerSecond, proofProbability, collateralPerByte,
|
||||
some expiry, nodes, tolerance
|
||||
)
|
||||
|
||||
proc requestStorage*(
|
||||
client: CodexClient,
|
||||
cid: Cid,
|
||||
duration: StUint[40],
|
||||
pricePerBytePerSecond: StUint[96],
|
||||
duration: StorageDuration,
|
||||
pricePerBytePerSecond: TokensPerSecond,
|
||||
proofProbability: UInt256,
|
||||
expiry: StUint[40],
|
||||
collateralPerByte: UInt128,
|
||||
expiry = none StorageDuration,
|
||||
collateralPerByte: Tokens,
|
||||
nodes: uint = 3,
|
||||
tolerance: uint = 1,
|
||||
): Future[?!PurchaseId] {.async: (raises: [CancelledError, HttpError]).} =
|
||||
@ -269,6 +283,22 @@ proc requestStorage*(
|
||||
doAssert(false, body)
|
||||
PurchaseId.fromHex(body).catch
|
||||
|
||||
proc requestStorage*(
|
||||
client: CodexClient,
|
||||
cid: Cid,
|
||||
duration: StorageDuration,
|
||||
pricePerBytePerSecond: TokensPerSecond,
|
||||
proofProbability: UInt256,
|
||||
expiry: StorageDuration,
|
||||
collateralPerByte: Tokens,
|
||||
nodes: uint = 3,
|
||||
tolerance: uint = 1,
|
||||
): Future[?!PurchaseId] {.async: (raises: [CancelledError, HttpError]).} =
|
||||
return await client.requestStorage(
|
||||
cid, duration, pricePerBytePerSecond, proofProbability, some expiry,
|
||||
collateralPerByte, nodes, tolerance
|
||||
)
|
||||
|
||||
proc getPurchase*(
|
||||
client: CodexClient, purchaseId: PurchaseId
|
||||
): Future[?!RestPurchase] {.async: (raises: [CancelledError, HttpError]).} =
|
||||
@ -291,10 +321,12 @@ proc getSalesAgent*(
|
||||
|
||||
proc postAvailabilityRaw*(
|
||||
client: CodexClient,
|
||||
totalSize, duration: uint64,
|
||||
minPricePerBytePerSecond, totalCollateral: UInt256,
|
||||
totalSize: uint64,
|
||||
duration: StorageDuration,
|
||||
minPricePerBytePerSecond: TokensPerSecond,
|
||||
totalCollateral: Tokens,
|
||||
enabled: ?bool = bool.none,
|
||||
until: ?SecondsSince1970 = SecondsSince1970.none,
|
||||
until = StorageTimestamp.none,
|
||||
): Future[HttpClientResponseRef] {.async: (raises: [CancelledError, HttpError]).} =
|
||||
## Post sales availability endpoint
|
||||
##
|
||||
@ -312,10 +344,12 @@ proc postAvailabilityRaw*(
|
||||
|
||||
proc postAvailability*(
|
||||
client: CodexClient,
|
||||
totalSize, duration: uint64,
|
||||
minPricePerBytePerSecond, totalCollateral: UInt256,
|
||||
totalSize: uint64,
|
||||
duration: StorageDuration,
|
||||
minPricePerBytePerSecond: TokensPerSecond,
|
||||
totalCollateral: Tokens,
|
||||
enabled: ?bool = bool.none,
|
||||
until: ?SecondsSince1970 = SecondsSince1970.none,
|
||||
until = StorageTimestamp.none,
|
||||
): Future[?!Availability] {.async: (raises: [CancelledError, HttpError]).} =
|
||||
let response = await client.postAvailabilityRaw(
|
||||
totalSize = totalSize,
|
||||
@ -335,10 +369,13 @@ proc postAvailability*(
|
||||
proc patchAvailabilityRaw*(
|
||||
client: CodexClient,
|
||||
availabilityId: AvailabilityId,
|
||||
totalSize, freeSize, duration: ?uint64 = uint64.none,
|
||||
minPricePerBytePerSecond, totalCollateral: ?UInt256 = UInt256.none,
|
||||
totalSize = none uint64,
|
||||
freeSize = none uint64,
|
||||
duration = none StorageDuration,
|
||||
minPricePerBytePerSecond = none TokensPerSecond,
|
||||
enabled: ?bool = bool.none,
|
||||
until: ?SecondsSince1970 = SecondsSince1970.none,
|
||||
until = StorageTimestamp.none,
|
||||
totalCollateral = none Tokens,
|
||||
): Future[HttpClientResponseRef] {.
|
||||
async: (raw: true, raises: [CancelledError, HttpError])
|
||||
.} =
|
||||
@ -375,10 +412,12 @@ proc patchAvailabilityRaw*(
|
||||
proc patchAvailability*(
|
||||
client: CodexClient,
|
||||
availabilityId: AvailabilityId,
|
||||
totalSize, duration: ?uint64 = uint64.none,
|
||||
minPricePerBytePerSecond, totalCollateral: ?UInt256 = UInt256.none,
|
||||
totalSize = none uint64,
|
||||
duration = none StorageDuration,
|
||||
minPricePerBytePerSecond = none TokensPerSecond,
|
||||
totalCollateral = none Tokens,
|
||||
enabled: ?bool = bool.none,
|
||||
until: ?SecondsSince1970 = SecondsSince1970.none,
|
||||
until = StorageTimestamp.none,
|
||||
): Future[void] {.async: (raises: [CancelledError, HttpError]).} =
|
||||
let response = await client.patchAvailabilityRaw(
|
||||
availabilityId,
|
||||
|
||||
@ -2,7 +2,7 @@ import pkg/chronos
|
||||
import pkg/ethers/erc20
|
||||
from pkg/libp2p import Cid
|
||||
import pkg/codex/contracts/marketplace as mp
|
||||
import pkg/codex/periods
|
||||
import pkg/codex/contracts/periods
|
||||
import pkg/codex/utils/json
|
||||
from pkg/codex/utils import roundUp, divUp
|
||||
import ./multinodes
|
||||
@ -15,21 +15,21 @@ export multinodes
|
||||
template marketplacesuite*(name: string, body: untyped) =
|
||||
multinodesuite name:
|
||||
var marketplace {.inject, used.}: Marketplace
|
||||
var period: uint64
|
||||
var period: StorageDuration
|
||||
var periodicity: Periodicity
|
||||
var token {.inject, used.}: Erc20Token
|
||||
|
||||
proc getCurrentPeriod(): Future[Period] {.async.} =
|
||||
return periodicity.periodOf((await ethProvider.currentTime()).truncate(uint64))
|
||||
proc getCurrentPeriod(): Future[ProofPeriod] {.async.} =
|
||||
return periodicity.periodOf((await ethProvider.currentTime()).truncate(int64))
|
||||
|
||||
proc advanceToNextPeriod() {.async.} =
|
||||
let periodicity = Periodicity(seconds: period)
|
||||
let currentTime = (await ethProvider.currentTime()).truncate(uint64)
|
||||
let currentTime = (await ethProvider.currentTime()).truncate(int64)
|
||||
let currentPeriod = periodicity.periodOf(currentTime)
|
||||
let endOfPeriod = periodicity.periodEnd(currentPeriod)
|
||||
await ethProvider.advanceTimeTo(endOfPeriod.u256 + 1)
|
||||
|
||||
template eventuallyP(condition: untyped, finalPeriod: Period): bool =
|
||||
template eventuallyP(condition: untyped, finalPeriod: ProofPeriod): bool =
|
||||
proc eventuallyP(): Future[bool] {.async.} =
|
||||
while (
|
||||
let currentPeriod = await getCurrentPeriod()
|
||||
@ -43,32 +43,32 @@ template marketplacesuite*(name: string, body: untyped) =
|
||||
|
||||
await eventuallyP()
|
||||
|
||||
proc periods(p: int): uint64 =
|
||||
p.uint64 * period
|
||||
proc periods(p: int): StorageDuration =
|
||||
period * p.uint32
|
||||
|
||||
proc slotSize(blocks, nodes, tolerance: int): UInt256 =
|
||||
proc slotSize(blocks, nodes, tolerance: int): uint64 =
|
||||
let ecK = nodes - tolerance
|
||||
let blocksRounded = roundUp(blocks, ecK)
|
||||
let blocksPerSlot = divUp(blocksRounded, ecK)
|
||||
(DefaultBlockSize * blocksPerSlot.NBytes).Natural.u256
|
||||
(DefaultBlockSize * blocksPerSlot.NBytes).Natural.uint64
|
||||
|
||||
proc datasetSize(blocks, nodes, tolerance: int): UInt256 =
|
||||
return nodes.u256 * slotSize(blocks, nodes, tolerance)
|
||||
proc datasetSize(blocks, nodes, tolerance: int): uint64 =
|
||||
return nodes.uint64 * slotSize(blocks, nodes, tolerance)
|
||||
|
||||
proc createAvailabilities(
|
||||
datasetSize: uint64,
|
||||
duration: uint64,
|
||||
collateralPerByte: UInt256,
|
||||
minPricePerBytePerSecond: UInt256,
|
||||
duration: StorageDuration,
|
||||
collateralPerByte: Tokens,
|
||||
minPricePerBytePerSecond: TokensPerSecond,
|
||||
): Future[void] {.async: (raises: [CancelledError, HttpError, ConfigurationError]).} =
|
||||
let totalCollateral = datasetSize.u256 * collateralPerByte
|
||||
let totalCollateral = collateralPerByte * datasetSize
|
||||
# post availability to each provider
|
||||
for i in 0 ..< providers().len:
|
||||
let provider = providers()[i].client
|
||||
|
||||
discard await provider.postAvailability(
|
||||
totalSize = datasetSize,
|
||||
duration = duration.uint64,
|
||||
duration = duration,
|
||||
minPricePerBytePerSecond = minPricePerBytePerSecond,
|
||||
totalCollateral = totalCollateral,
|
||||
)
|
||||
@ -77,10 +77,10 @@ template marketplacesuite*(name: string, body: untyped) =
|
||||
client: CodexClient,
|
||||
cid: Cid,
|
||||
proofProbability = 1.u256,
|
||||
duration = 12.periods.stuint(40),
|
||||
pricePerBytePerSecond = 1.stuint(96),
|
||||
collateralPerByte = 1.u128,
|
||||
expiry = 4.periods.stuint(40),
|
||||
duration = 12.periods,
|
||||
pricePerBytePerSecond = 1'TokensPerSecond,
|
||||
collateralPerByte = 1'Tokens,
|
||||
expiry = 4.periods,
|
||||
nodes = providers().len,
|
||||
tolerance = 0,
|
||||
): Future[PurchaseId] {.async: (raises: [CancelledError, HttpError]).} =
|
||||
@ -104,7 +104,7 @@ template marketplacesuite*(name: string, body: untyped) =
|
||||
let tokenAddress = await marketplace.token()
|
||||
token = Erc20Token.new(tokenAddress, ethProvider.getSigner())
|
||||
let config = await marketplace.configuration()
|
||||
period = config.proofs.period.u64
|
||||
period = config.proofs.period
|
||||
periodicity = Periodicity(seconds: period)
|
||||
|
||||
body
|
||||
|
||||
@ -16,9 +16,9 @@ marketplacesuite "Bug #821 - node crashes during erasure coding":
|
||||
providers: CodexConfigs.init(nodes = 0).some,
|
||||
):
|
||||
let
|
||||
pricePerBytePerSecond = 1.u256
|
||||
pricePerBytePerSecond = 1'TokensPerSecond
|
||||
duration = 20.periods
|
||||
collateralPerByte = 1.u256
|
||||
collateralPerByte = 1'Tokens
|
||||
expiry = 10.periods
|
||||
data = await RandomChunker.example(blocks = 8)
|
||||
client = clients()[0]
|
||||
@ -36,15 +36,15 @@ marketplacesuite "Bug #821 - node crashes during erasure coding":
|
||||
# client requests storage but requires multiple slots to host the content
|
||||
discard await clientApi.requestStorage(
|
||||
cid,
|
||||
duration = duration.stuint(40),
|
||||
pricePerBytePerSecond = pricePerBytePerSecond.stuint(96),
|
||||
expiry = expiry.stuint(40),
|
||||
collateralPerByte = collateralPerByte.stuint(128),
|
||||
duration = duration,
|
||||
pricePerBytePerSecond = pricePerBytePerSecond,
|
||||
expiry = expiry,
|
||||
collateralPerByte = collateralPerByte,
|
||||
nodes = 3,
|
||||
tolerance = 1,
|
||||
)
|
||||
|
||||
check eventually(requestId.isSome, timeout = expiry.int * 1000)
|
||||
check eventually(requestId.isSome, timeout = expiry.u64.int * 1000)
|
||||
|
||||
let
|
||||
request = await marketplace.getRequest(requestId.get)
|
||||
|
||||
@ -18,8 +18,8 @@ marketplacesuite "Marketplace":
|
||||
var client: CodexClient
|
||||
var clientAccount: Address
|
||||
|
||||
const minPricePerBytePerSecond = 1.u256
|
||||
const collateralPerByte = 1.u128
|
||||
const minPricePerBytePerSecond = 1'TokensPerSecond
|
||||
const collateralPerByte = 1'Tokens
|
||||
const blocks = 8
|
||||
const ecNodes = 3
|
||||
const ecTolerance = 1
|
||||
@ -42,9 +42,9 @@ marketplacesuite "Marketplace":
|
||||
let availability = (
|
||||
await host.postAvailability(
|
||||
totalSize = size,
|
||||
duration = 20 * 60.uint64,
|
||||
duration = StorageDuration.init(20'u32 * 60),
|
||||
minPricePerBytePerSecond = minPricePerBytePerSecond,
|
||||
totalCollateral = size.u256 * minPricePerBytePerSecond,
|
||||
totalCollateral = collateralPerByte * size,
|
||||
)
|
||||
).get
|
||||
|
||||
@ -52,10 +52,10 @@ marketplacesuite "Marketplace":
|
||||
let cid = (await client.upload(data)).get
|
||||
let id = await client.requestStorage(
|
||||
cid,
|
||||
duration = 20 * 60.stuint(40),
|
||||
pricePerBytePerSecond = minPricePerBytePerSecond.stuint(96),
|
||||
duration = StorageDuration.init(20'u32 * 60),
|
||||
pricePerBytePerSecond = minPricePerBytePerSecond,
|
||||
proofProbability = 3.u256,
|
||||
expiry = 10 * 60.stuint(40),
|
||||
expiry = StorageDuration.init(10'u32 * 60),
|
||||
collateralPerByte = collateralPerByte,
|
||||
nodes = ecNodes,
|
||||
tolerance = ecTolerance,
|
||||
@ -82,7 +82,7 @@ marketplacesuite "Marketplace":
|
||||
let marketplace = Marketplace.new(Marketplace.address, ethProvider.getSigner())
|
||||
let tokenAddress = await marketplace.token()
|
||||
let token = Erc20Token.new(tokenAddress, ethProvider.getSigner())
|
||||
let duration = 20 * 60.uint64
|
||||
let duration = StorageDuration.init(20'u32 * 60)
|
||||
|
||||
# host makes storage available
|
||||
let startBalanceHost = await token.balanceOf(hostAccount)
|
||||
@ -91,7 +91,7 @@ marketplacesuite "Marketplace":
|
||||
totalSize = size,
|
||||
duration = duration,
|
||||
minPricePerBytePerSecond = minPricePerBytePerSecond,
|
||||
totalCollateral = size.u256 * minPricePerBytePerSecond,
|
||||
totalCollateral = collateralPerByte * size,
|
||||
)
|
||||
).get
|
||||
|
||||
@ -99,10 +99,10 @@ marketplacesuite "Marketplace":
|
||||
let cid = (await client.upload(data)).get
|
||||
let id = await client.requestStorage(
|
||||
cid,
|
||||
duration = duration.stuint(40),
|
||||
pricePerBytePerSecond = minPricePerBytePerSecond.stuint(96),
|
||||
duration = duration,
|
||||
pricePerBytePerSecond = minPricePerBytePerSecond,
|
||||
proofProbability = 3.u256,
|
||||
expiry = (10 * 60).stuint(40),
|
||||
expiry = StorageDuration.init(10'u32 * 60),
|
||||
collateralPerByte = collateralPerByte,
|
||||
nodes = ecNodes,
|
||||
tolerance = ecTolerance,
|
||||
@ -125,7 +125,7 @@ marketplacesuite "Marketplace":
|
||||
let slotSize = slotSize(blocks, ecNodes, ecTolerance)
|
||||
let pricePerSlotPerSecond = minPricePerBytePerSecond * slotSize
|
||||
check eventually (await token.balanceOf(hostAccount)) - startBalanceHost >=
|
||||
(duration - 5 * 60).u256 * pricePerSlotPerSecond * ecNodes.u256
|
||||
(duration.u256 - 5 * 60) * pricePerSlotPerSecond.u256 * ecNodes.u256
|
||||
|
||||
# Checking that client node receives some funds back that were not used for the host nodes
|
||||
check eventually(
|
||||
@ -134,8 +134,8 @@ marketplacesuite "Marketplace":
|
||||
)
|
||||
|
||||
marketplacesuite "Marketplace payouts":
|
||||
const minPricePerBytePerSecond = 1.u256
|
||||
const collateralPerByte = 1.u128
|
||||
const minPricePerBytePerSecond = 1'TokensPerSecond
|
||||
const collateralPerByte = 1'Tokens
|
||||
const blocks = 8
|
||||
const ecNodes = 3
|
||||
const ecTolerance = 1
|
||||
@ -167,14 +167,14 @@ marketplacesuite "Marketplace payouts":
|
||||
|
||||
# provider makes storage available
|
||||
let datasetSize = datasetSize(blocks, ecNodes, ecTolerance)
|
||||
let totalAvailabilitySize = (datasetSize div 2).truncate(uint64)
|
||||
let totalAvailabilitySize = datasetSize div 2
|
||||
discard await providerApi.postAvailability(
|
||||
# make availability size small enough that we can't fill all the slots,
|
||||
# thus causing a cancellation
|
||||
totalSize = totalAvailabilitySize,
|
||||
duration = duration.uint64,
|
||||
duration = duration,
|
||||
minPricePerBytePerSecond = minPricePerBytePerSecond,
|
||||
totalCollateral = collateralPerByte.stuint(256) * totalAvailabilitySize.u256,
|
||||
totalCollateral = collateralPerByte * totalAvailabilitySize,
|
||||
)
|
||||
|
||||
let cid = (await clientApi.upload(data)).get
|
||||
@ -189,16 +189,16 @@ marketplacesuite "Marketplace payouts":
|
||||
# client requests storage but requires multiple slots to host the content
|
||||
let id = await clientApi.requestStorage(
|
||||
cid,
|
||||
duration = duration.stuint(40),
|
||||
pricePerBytePerSecond = minPricePerBytePerSecond.stuint(96),
|
||||
expiry = expiry.stuint(40),
|
||||
duration = duration,
|
||||
pricePerBytePerSecond = minPricePerBytePerSecond,
|
||||
expiry = expiry,
|
||||
collateralPerByte = collateralPerByte,
|
||||
nodes = ecNodes,
|
||||
tolerance = ecTolerance,
|
||||
)
|
||||
|
||||
# wait until one slot is filled
|
||||
check eventually(slotIdxFilled.isSome, timeout = expiry.int * 1000)
|
||||
check eventually(slotIdxFilled.isSome, timeout = expiry.u64.int64 * 1000)
|
||||
let slotId = slotId(!(await clientApi.requestId(id)), !slotIdxFilled)
|
||||
|
||||
# wait until sale is cancelled
|
||||
@ -213,7 +213,7 @@ marketplacesuite "Marketplace payouts":
|
||||
check eventually (
|
||||
let endBalanceProvider = (await token.balanceOf(provider.ethAccount))
|
||||
endBalanceProvider > startBalanceProvider and
|
||||
endBalanceProvider < startBalanceProvider + expiry.u256 * pricePerSlotPerSecond
|
||||
endBalanceProvider < startBalanceProvider + expiry.u256 * pricePerSlotPerSecond.u256
|
||||
)
|
||||
check eventually(
|
||||
(
|
||||
|
||||
@ -14,8 +14,8 @@ logScope:
|
||||
topics = "integration test proofs"
|
||||
|
||||
marketplacesuite "Hosts submit regular proofs":
|
||||
const minPricePerBytePerSecond = 1.u256
|
||||
const collateralPerByte = 1.u256
|
||||
const minPricePerBytePerSecond = 1'TokensPerSecond
|
||||
const collateralPerByte = 1'Tokens
|
||||
const blocks = 8
|
||||
const ecNodes = 3
|
||||
const ecTolerance = 1
|
||||
@ -43,7 +43,7 @@ marketplacesuite "Hosts submit regular proofs":
|
||||
let datasetSize =
|
||||
datasetSize(blocks = blocks, nodes = ecNodes, tolerance = ecTolerance)
|
||||
await createAvailabilities(
|
||||
datasetSize.truncate(uint64),
|
||||
datasetSize,
|
||||
duration,
|
||||
collateralPerByte,
|
||||
minPricePerBytePerSecond,
|
||||
@ -53,8 +53,8 @@ marketplacesuite "Hosts submit regular proofs":
|
||||
|
||||
let purchaseId = await client0.requestStorage(
|
||||
cid,
|
||||
expiry = expiry.stuint(40),
|
||||
duration = duration.stuint(40),
|
||||
expiry = expiry,
|
||||
duration = duration,
|
||||
nodes = ecNodes,
|
||||
tolerance = ecTolerance,
|
||||
)
|
||||
@ -65,7 +65,7 @@ marketplacesuite "Hosts submit regular proofs":
|
||||
let slotSize = slotSize(blocks, ecNodes, ecTolerance)
|
||||
|
||||
check eventually(
|
||||
await client0.purchaseStateIs(purchaseId, "started"), timeout = expiry.int * 1000
|
||||
await client0.purchaseStateIs(purchaseId, "started"), timeout = expiry.u64.int * 1000
|
||||
)
|
||||
|
||||
var proofWasSubmitted = false
|
||||
@ -74,7 +74,7 @@ marketplacesuite "Hosts submit regular proofs":
|
||||
|
||||
let subscription = await marketplace.subscribe(ProofSubmitted, onProofSubmitted)
|
||||
|
||||
check eventually(proofWasSubmitted, timeout = (duration - expiry).int * 1000)
|
||||
check eventually(proofWasSubmitted, timeout = (duration - expiry).u64.int * 1000)
|
||||
|
||||
await subscription.unsubscribe()
|
||||
|
||||
@ -84,8 +84,8 @@ marketplacesuite "Simulate invalid proofs":
|
||||
# tightened so that they are showing, as an integration test, that specific
|
||||
# proofs are being marked as missed by the validator.
|
||||
|
||||
const minPricePerBytePerSecond = 1.u256
|
||||
const collateralPerByte = 1.u256
|
||||
const minPricePerBytePerSecond = 1'TokensPerSecond
|
||||
const collateralPerByte = 1'Tokens
|
||||
const blocks = 8
|
||||
const ecNodes = 3
|
||||
const ecTolerance = 1
|
||||
@ -120,7 +120,7 @@ marketplacesuite "Simulate invalid proofs":
|
||||
let datasetSize =
|
||||
datasetSize(blocks = blocks, nodes = ecNodes, tolerance = ecTolerance)
|
||||
await createAvailabilities(
|
||||
datasetSize.truncate(uint64),
|
||||
datasetSize,
|
||||
duration,
|
||||
collateralPerByte,
|
||||
minPricePerBytePerSecond,
|
||||
@ -131,8 +131,8 @@ marketplacesuite "Simulate invalid proofs":
|
||||
let purchaseId = (
|
||||
await client0.requestStorage(
|
||||
cid,
|
||||
expiry = expiry.stuint(40),
|
||||
duration = duration.stuint(40),
|
||||
expiry = expiry,
|
||||
duration = duration,
|
||||
nodes = ecNodes,
|
||||
tolerance = ecTolerance,
|
||||
proofProbability = 1.u256,
|
||||
@ -141,7 +141,7 @@ marketplacesuite "Simulate invalid proofs":
|
||||
let requestId = (await client0.requestId(purchaseId)).get
|
||||
|
||||
check eventually(
|
||||
await client0.purchaseStateIs(purchaseId, "started"), timeout = expiry.int * 1000
|
||||
await client0.purchaseStateIs(purchaseId, "started"), timeout = expiry.u64.int * 1000
|
||||
)
|
||||
|
||||
var slotWasFreed = false
|
||||
@ -151,7 +151,7 @@ marketplacesuite "Simulate invalid proofs":
|
||||
|
||||
let subscription = await marketplace.subscribe(SlotFreed, onSlotFreed)
|
||||
|
||||
check eventually(slotWasFreed, timeout = (duration - expiry).int * 1000)
|
||||
check eventually(slotWasFreed, timeout = (duration - expiry).u64.int * 1000)
|
||||
|
||||
await subscription.unsubscribe()
|
||||
|
||||
@ -185,7 +185,7 @@ marketplacesuite "Simulate invalid proofs":
|
||||
let datasetSize =
|
||||
datasetSize(blocks = blocks, nodes = ecNodes, tolerance = ecTolerance)
|
||||
await createAvailabilities(
|
||||
datasetSize.truncate(uint64),
|
||||
datasetSize,
|
||||
duration,
|
||||
collateralPerByte,
|
||||
minPricePerBytePerSecond,
|
||||
@ -195,8 +195,8 @@ marketplacesuite "Simulate invalid proofs":
|
||||
|
||||
let purchaseId = await client0.requestStorage(
|
||||
cid,
|
||||
expiry = expiry.stuint(40),
|
||||
duration = duration.stuint(40),
|
||||
expiry = expiry,
|
||||
duration = duration,
|
||||
nodes = ecNodes,
|
||||
tolerance = ecTolerance,
|
||||
proofProbability = 1.u256,
|
||||
@ -214,7 +214,7 @@ marketplacesuite "Simulate invalid proofs":
|
||||
let filledSubscription = await marketplace.subscribe(SlotFilled, onSlotFilled)
|
||||
|
||||
# wait for the first slot to be filled
|
||||
check eventually(slotWasFilled, timeout = expiry.int * 1000)
|
||||
check eventually(slotWasFilled, timeout = expiry.u64.int * 1000)
|
||||
|
||||
var slotWasFreed = false
|
||||
proc onSlotFreed(event: ?!SlotFreed) =
|
||||
@ -224,7 +224,7 @@ marketplacesuite "Simulate invalid proofs":
|
||||
let freedSubscription = await marketplace.subscribe(SlotFreed, onSlotFreed)
|
||||
|
||||
# In 2 periods you cannot have enough invalid proofs submitted:
|
||||
await sleepAsync(2.periods.int.seconds)
|
||||
await sleepAsync(2.periods.u64.int.seconds)
|
||||
check not slotWasFreed
|
||||
|
||||
await filledSubscription.unsubscribe()
|
||||
|
||||
@ -12,21 +12,21 @@ twonodessuite "Purchasing":
|
||||
let id1 = (
|
||||
await client1.requestStorage(
|
||||
cid,
|
||||
duration = 100.stuint(40),
|
||||
pricePerBytePerSecond = 1.stuint(96),
|
||||
duration = 100'StorageDuration,
|
||||
pricePerBytePerSecond = 1'TokensPerSecond,
|
||||
proofProbability = 3.u256,
|
||||
expiry = 10.stuint(40),
|
||||
collateralPerByte = 1.u128,
|
||||
expiry = 10'StorageDuration,
|
||||
collateralPerByte = 1'Tokens,
|
||||
)
|
||||
).get
|
||||
let id2 = (
|
||||
await client1.requestStorage(
|
||||
cid,
|
||||
duration = 400.stuint(40),
|
||||
pricePerBytePerSecond = 2.stuint(96),
|
||||
duration = 400'StorageDuration,
|
||||
pricePerBytePerSecond = 2'TokensPerSecond,
|
||||
proofProbability = 6.u256,
|
||||
expiry = 10.stuint(40),
|
||||
collateralPerByte = 2.u128,
|
||||
expiry = 10'StorageDuration,
|
||||
collateralPerByte = 2'Tokens,
|
||||
)
|
||||
).get
|
||||
check id1 != id2
|
||||
@ -42,11 +42,11 @@ twonodessuite "Purchasing":
|
||||
let id = (
|
||||
await client1.requestStorage(
|
||||
cid,
|
||||
duration = 100.stuint(40),
|
||||
pricePerBytePerSecond = 1.stuint(96),
|
||||
duration = 100'StorageDuration,
|
||||
pricePerBytePerSecond = 1'TokensPerSecond,
|
||||
proofProbability = 3.u256,
|
||||
expiry = 30.stuint(40),
|
||||
collateralPerByte = 1.u128,
|
||||
expiry = 30'StorageDuration,
|
||||
collateralPerByte = 1'Tokens,
|
||||
nodes = 3,
|
||||
tolerance = 1,
|
||||
)
|
||||
@ -55,11 +55,11 @@ twonodessuite "Purchasing":
|
||||
let request = (await client1.getPurchase(id)).get.request.get
|
||||
|
||||
check request.content.cid.data.buffer.len > 0
|
||||
check request.ask.duration == 100.stuint(40)
|
||||
check request.ask.pricePerBytePerSecond == 1.stuint(96)
|
||||
check request.ask.duration == 100'StorageDuration
|
||||
check request.ask.pricePerBytePerSecond == 1'TokensPerSecond
|
||||
check request.ask.proofProbability == 3.u256
|
||||
check request.expiry == 30.stuint(40)
|
||||
check request.ask.collateralPerByte == 1.u128
|
||||
check request.expiry == 30'StorageDuration
|
||||
check request.ask.collateralPerByte == 1'Tokens
|
||||
check request.ask.slots == 3'u64
|
||||
check request.ask.maxSlotLoss == 1'u64
|
||||
|
||||
@ -85,11 +85,11 @@ twonodessuite "Purchasing":
|
||||
let id = (
|
||||
await client1.requestStorage(
|
||||
cid,
|
||||
duration = (10 * 60).stuint(40),
|
||||
pricePerBytePerSecond = 1.stuint(96),
|
||||
duration = StorageDuration.init(10'u32 * 60),
|
||||
pricePerBytePerSecond = 1'TokensPerSecond,
|
||||
proofProbability = 3.u256,
|
||||
expiry = 5 * 60.stuint(40),
|
||||
collateralPerByte = 1.u128,
|
||||
expiry = StorageDuration.init(5'u32 * 60),
|
||||
collateralPerByte = 1'Tokens,
|
||||
nodes = 3.uint,
|
||||
tolerance = 1.uint,
|
||||
)
|
||||
@ -104,11 +104,11 @@ twonodessuite "Purchasing":
|
||||
await client1.purchaseStateIs(id, "submitted"), timeout = 3 * 60 * 1000
|
||||
)
|
||||
let request = (await client1.getPurchase(id)).get.request.get
|
||||
check request.ask.duration == (10 * 60).stuint(40)
|
||||
check request.ask.pricePerBytePerSecond == 1.stuint(96)
|
||||
check request.ask.duration == StorageDuration.init(10'u32 * 60)
|
||||
check request.ask.pricePerBytePerSecond == 1'TokensPerSecond
|
||||
check request.ask.proofProbability == 3.u256
|
||||
check request.expiry == (5 * 60).stuint(40)
|
||||
check request.ask.collateralPerByte == 1.u128
|
||||
check request.expiry == StorageDuration.init(5'u32 * 60)
|
||||
check request.ask.collateralPerByte == 1'Tokens
|
||||
check request.ask.slots == 3'u64
|
||||
check request.ask.maxSlotLoss == 1'u64
|
||||
|
||||
@ -118,10 +118,10 @@ twonodessuite "Purchasing":
|
||||
|
||||
let responseMissing = await client1.requestStorageRaw(
|
||||
cid,
|
||||
duration = 1.stuint(40),
|
||||
pricePerBytePerSecond = 1.stuint(96),
|
||||
duration = 1'StorageDuration,
|
||||
pricePerBytePerSecond = 1'TokensPerSecond,
|
||||
proofProbability = 3.u256,
|
||||
collateralPerByte = 1.u128,
|
||||
collateralPerByte = 1'Tokens,
|
||||
)
|
||||
check responseMissing.status == 422
|
||||
check (await responseMissing.body) ==
|
||||
@ -129,11 +129,11 @@ twonodessuite "Purchasing":
|
||||
|
||||
let responseBefore = await client1.requestStorageRaw(
|
||||
cid,
|
||||
duration = 10.stuint(40),
|
||||
pricePerBytePerSecond = 1.stuint(96),
|
||||
duration = 10'StorageDuration,
|
||||
pricePerBytePerSecond = 1'TokensPerSecond,
|
||||
proofProbability = 3.u256,
|
||||
collateralPerByte = 1.u128,
|
||||
expiry = 10.stuint(40),
|
||||
collateralPerByte = 1'Tokens,
|
||||
expiry = 10'StorageDuration,
|
||||
)
|
||||
check responseBefore.status == 422
|
||||
check "Expiry must be greater than zero and less than the request's duration" in
|
||||
|
||||
@ -27,15 +27,12 @@ twonodessuite "REST API":
|
||||
|
||||
test "node shows used and available space", twoNodesConfig:
|
||||
discard (await client1.upload("some file contents")).get
|
||||
let totalSize = 12.uint64
|
||||
let minPricePerBytePerSecond = 1.u256
|
||||
let totalCollateral = totalSize.u256 * minPricePerBytePerSecond
|
||||
discard (
|
||||
await client1.postAvailability(
|
||||
totalSize = totalSize,
|
||||
duration = 2.uint64,
|
||||
minPricePerBytePerSecond = minPricePerBytePerSecond,
|
||||
totalCollateral = totalCollateral,
|
||||
totalSize = 12.uint64,
|
||||
duration = 2'StorageDuration,
|
||||
minPricePerBytePerSecond = 1'TokensPerSecond,
|
||||
totalCollateral = 100'Tokens,
|
||||
enabled = true.some,
|
||||
)
|
||||
).get
|
||||
@ -63,11 +60,11 @@ twonodessuite "REST API":
|
||||
let response = (
|
||||
await client1.requestStorageRaw(
|
||||
cid,
|
||||
duration = 10.stuint(40),
|
||||
pricePerBytePerSecond = 1.stuint(96),
|
||||
duration = 10'StorageDuration,
|
||||
pricePerBytePerSecond = 1'TokensPerSecond,
|
||||
proofProbability = 3.u256,
|
||||
collateralPerByte = 1.u128,
|
||||
expiry = 9.stuint(40),
|
||||
collateralPerByte = 1'Tokens,
|
||||
expiry = 9'StorageDuration,
|
||||
)
|
||||
)
|
||||
|
||||
@ -84,11 +81,11 @@ twonodessuite "REST API":
|
||||
let cid = (await client1.upload(data)).get
|
||||
let response = await client1.requestStorageRaw(
|
||||
cid,
|
||||
duration = 100.stuint(40),
|
||||
pricePerBytePerSecond = 1.stuint(96),
|
||||
duration = 100'StorageDuration,
|
||||
pricePerBytePerSecond = 1'TokensPerSecond,
|
||||
proofProbability = 3.u256,
|
||||
collateralPerByte = 1.u128,
|
||||
expiry = 30.stuint(40),
|
||||
collateralPerByte = 1'Tokens,
|
||||
expiry = 30'StorageDuration,
|
||||
nodes = nodes.uint,
|
||||
tolerance = tolerance.uint,
|
||||
)
|
||||
|
||||
@ -23,11 +23,11 @@ multinodesuite "Rest API validation":
|
||||
|
||||
let response = await client.requestStorageRaw(
|
||||
cid,
|
||||
duration = 100.stuint(40),
|
||||
pricePerBytePerSecond = 1.stuint(96),
|
||||
duration = 100'StorageDuration,
|
||||
pricePerBytePerSecond = 1'TokensPerSecond,
|
||||
proofProbability = 3.u256,
|
||||
collateralPerByte = 1.u128,
|
||||
expiry = 30.stuint(40),
|
||||
collateralPerByte = 1'Tokens,
|
||||
expiry = 30'StorageDuration,
|
||||
nodes = 3.uint,
|
||||
tolerance = 0.uint,
|
||||
)
|
||||
@ -39,11 +39,11 @@ multinodesuite "Rest API validation":
|
||||
let cid = (await client.upload("some file contents")).get
|
||||
let response = await client.requestStorageRaw(
|
||||
cid,
|
||||
duration = 10.stuint(40),
|
||||
pricePerBytePerSecond = 1.stuint(96),
|
||||
duration = 10'StorageDuration,
|
||||
pricePerBytePerSecond = 1'TokensPerSecond,
|
||||
proofProbability = 3.u256,
|
||||
collateralPerByte = 1.u128,
|
||||
expiry = 9.stuint(40),
|
||||
collateralPerByte = 1'Tokens,
|
||||
expiry = 9'StorageDuration,
|
||||
)
|
||||
|
||||
check:
|
||||
@ -63,11 +63,11 @@ multinodesuite "Rest API validation":
|
||||
let response = (
|
||||
await client.requestStorageRaw(
|
||||
cid,
|
||||
duration = 100.stuint(40),
|
||||
pricePerBytePerSecond = 1.stuint(96),
|
||||
duration = 100'StorageDuration,
|
||||
pricePerBytePerSecond = 1'TokensPerSecond,
|
||||
proofProbability = 3.u256,
|
||||
expiry = 30.stuint(40),
|
||||
collateralPerByte = 1.u128,
|
||||
expiry = 30'StorageDuration,
|
||||
collateralPerByte = 1'Tokens,
|
||||
nodes = nodes.uint,
|
||||
tolerance =tolerance.uint,
|
||||
)
|
||||
@ -84,11 +84,11 @@ multinodesuite "Rest API validation":
|
||||
let response = (
|
||||
await client.requestStorageRaw(
|
||||
cid,
|
||||
duration = 100.stuint(40),
|
||||
pricePerBytePerSecond = 1.stuint(96),
|
||||
duration = 100'StorageDuration,
|
||||
pricePerBytePerSecond = 1'TokensPerSecond,
|
||||
proofProbability = 3.u256,
|
||||
expiry = 30.stuint(40),
|
||||
collateralPerByte = 1.u128,
|
||||
expiry = 30'StorageDuration,
|
||||
collateralPerByte = 1'Tokens,
|
||||
nodes = 3.uint,
|
||||
tolerance = 0.uint,
|
||||
)
|
||||
@ -114,9 +114,9 @@ multinodesuite "Rest API validation":
|
||||
test "updating non-existing availability", config:
|
||||
let nonExistingResponse = await client.patchAvailabilityRaw(
|
||||
AvailabilityId.example,
|
||||
duration = 100.uint64.some,
|
||||
minPricePerBytePerSecond = 2.u256.some,
|
||||
totalCollateral = 200.u256.some,
|
||||
duration = some 100'StorageDuration,
|
||||
minPricePerBytePerSecond = some 2'TokensPerSecond,
|
||||
totalCollateral = some 200'Tokens,
|
||||
)
|
||||
check nonExistingResponse.status == 404
|
||||
|
||||
@ -124,9 +124,9 @@ multinodesuite "Rest API validation":
|
||||
let availability = (
|
||||
await client.postAvailability(
|
||||
totalSize = 140000.uint64,
|
||||
duration = 200.uint64,
|
||||
minPricePerBytePerSecond = 3.u256,
|
||||
totalCollateral = 300.u256,
|
||||
duration = 200'StorageDuration,
|
||||
minPricePerBytePerSecond = 3'TokensPerSecond,
|
||||
totalCollateral = 300'Tokens,
|
||||
)
|
||||
).get
|
||||
let freeSizeResponse =
|
||||
@ -137,9 +137,9 @@ multinodesuite "Rest API validation":
|
||||
test "creating availability above the node quota returns 422", config:
|
||||
let response = await client.postAvailabilityRaw(
|
||||
totalSize = 24000000000.uint64,
|
||||
duration = 200.uint64,
|
||||
minPricePerBytePerSecond = 3.u256,
|
||||
totalCollateral = 300.u256,
|
||||
duration = 200'StorageDuration,
|
||||
minPricePerBytePerSecond = 3'TokensPerSecond,
|
||||
totalCollateral = 300'Tokens,
|
||||
)
|
||||
|
||||
check response.status == 422
|
||||
@ -149,9 +149,9 @@ multinodesuite "Rest API validation":
|
||||
let availability = (
|
||||
await client.postAvailability(
|
||||
totalSize = 140000.uint64,
|
||||
duration = 200.uint64,
|
||||
minPricePerBytePerSecond = 3.u256,
|
||||
totalCollateral = 300.u256,
|
||||
duration = 200'StorageDuration,
|
||||
minPricePerBytePerSecond = 3'TokensPerSecond,
|
||||
totalCollateral = 300'Tokens,
|
||||
)
|
||||
).get
|
||||
let response = await client.patchAvailabilityRaw(
|
||||
@ -164,9 +164,9 @@ multinodesuite "Rest API validation":
|
||||
test "creating availability when total size is zero returns 422", config:
|
||||
let response = await client.postAvailabilityRaw(
|
||||
totalSize = 0.uint64,
|
||||
duration = 200.uint64,
|
||||
minPricePerBytePerSecond = 3.u256,
|
||||
totalCollateral = 300.u256,
|
||||
duration = 200'StorageDuration,
|
||||
minPricePerBytePerSecond = 3'TokensPerSecond,
|
||||
totalCollateral = 300'Tokens,
|
||||
)
|
||||
|
||||
check response.status == 422
|
||||
@ -176,9 +176,9 @@ multinodesuite "Rest API validation":
|
||||
let availability = (
|
||||
await client.postAvailability(
|
||||
totalSize = 140000.uint64,
|
||||
duration = 200.uint64,
|
||||
minPricePerBytePerSecond = 3.u256,
|
||||
totalCollateral = 300.u256,
|
||||
duration = 200'StorageDuration,
|
||||
minPricePerBytePerSecond = 3'TokensPerSecond,
|
||||
totalCollateral = 300'Tokens,
|
||||
)
|
||||
).get
|
||||
let response =
|
||||
@ -204,9 +204,9 @@ multinodesuite "Rest API validation":
|
||||
let availability = (
|
||||
await client.postAvailability(
|
||||
totalSize = 140000.uint64,
|
||||
duration = 200.uint64,
|
||||
minPricePerBytePerSecond = 3.u256,
|
||||
totalCollateral = 300.u256,
|
||||
duration = 200'StorageDuration,
|
||||
minPricePerBytePerSecond = 3'TokensPerSecond,
|
||||
totalCollateral = 300'Tokens,
|
||||
)
|
||||
).get
|
||||
|
||||
@ -223,11 +223,11 @@ multinodesuite "Rest API validation":
|
||||
let cid = (await client.upload(data)).get
|
||||
let response = await client.requestStorageRaw(
|
||||
cid,
|
||||
duration = 100.stuint(40),
|
||||
pricePerBytePerSecond = 1.stuint(96),
|
||||
duration = 100'StorageDuration,
|
||||
pricePerBytePerSecond = 1'TokensPerSecond,
|
||||
proofProbability = 3.u256,
|
||||
expiry = 30.stuint(40),
|
||||
collateralPerByte = 1.u128,
|
||||
expiry = 30'StorageDuration,
|
||||
collateralPerByte = 1'Tokens,
|
||||
nodes = 3.uint,
|
||||
tolerance = 0.uint,
|
||||
)
|
||||
@ -241,11 +241,11 @@ multinodesuite "Rest API validation":
|
||||
|
||||
let response = await client.requestStorageRaw(
|
||||
cid,
|
||||
duration = (31 * 24 * 60 * 60).stuint(40), # 31 days TODO: this should not be hardcoded, but waits for https://github.com/codex-storage/nim-codex/issues/1056
|
||||
pricePerBytePerSecond = 1.stuint(96),
|
||||
duration = StorageDuration.init(31'u32 * 24 * 60 * 60), # 31 days TODO: this should not be hardcoded, but waits for https://github.com/codex-storage/nim-codex/issues/1056
|
||||
pricePerBytePerSecond = 1'TokensPerSecond,
|
||||
proofProbability = 3.u256,
|
||||
expiry = 30.stuint(40),
|
||||
collateralPerByte = 1.u128,
|
||||
expiry = 30'StorageDuration,
|
||||
collateralPerByte = 1'Tokens,
|
||||
nodes = 3.uint,
|
||||
tolerance = 2.uint,
|
||||
)
|
||||
@ -259,11 +259,11 @@ multinodesuite "Rest API validation":
|
||||
|
||||
let response = await client.requestStorageRaw(
|
||||
cid,
|
||||
duration = 100.stuint(40),
|
||||
pricePerBytePerSecond = 1.stuint(96),
|
||||
duration = 100'StorageDuration,
|
||||
pricePerBytePerSecond = 1'TokensPerSecond,
|
||||
proofProbability = 3.u256,
|
||||
expiry = 0.stuint(40),
|
||||
collateralPerByte = 1.u128,
|
||||
expiry = 0'StorageDuration,
|
||||
collateralPerByte = 1'Tokens,
|
||||
nodes = 3.uint,
|
||||
tolerance = 0.uint,
|
||||
)
|
||||
@ -278,11 +278,11 @@ multinodesuite "Rest API validation":
|
||||
|
||||
let response = await client.requestStorageRaw(
|
||||
cid,
|
||||
duration = 100.stuint(40),
|
||||
pricePerBytePerSecond = 1.stuint(96),
|
||||
duration = 100'StorageDuration,
|
||||
pricePerBytePerSecond = 1'TokensPerSecond,
|
||||
proofProbability = 0.u256,
|
||||
expiry = 30.stuint(40),
|
||||
collateralPerByte = 1.u128,
|
||||
expiry = 30'StorageDuration,
|
||||
collateralPerByte = 1'Tokens,
|
||||
nodes = 3.uint,
|
||||
tolerance = 0.uint,
|
||||
)
|
||||
@ -296,11 +296,11 @@ multinodesuite "Rest API validation":
|
||||
|
||||
let response = await client.requestStorageRaw(
|
||||
cid,
|
||||
duration = 100.stuint(40),
|
||||
pricePerBytePerSecond = 0.stuint(96),
|
||||
duration = 100'StorageDuration,
|
||||
pricePerBytePerSecond = 0'TokensPerSecond,
|
||||
proofProbability = 3.u256,
|
||||
expiry = 30.stuint(40),
|
||||
collateralPerByte = 1.u128,
|
||||
expiry = 30'StorageDuration,
|
||||
collateralPerByte = 1'Tokens,
|
||||
nodes = 3.uint,
|
||||
tolerance = 0.uint,
|
||||
)
|
||||
@ -315,30 +315,14 @@ multinodesuite "Rest API validation":
|
||||
|
||||
let response = await client.requestStorageRaw(
|
||||
cid,
|
||||
duration = 100.stuint(40),
|
||||
pricePerBytePerSecond = 1.stuint(96),
|
||||
duration = 100'StorageDuration,
|
||||
pricePerBytePerSecond = 1'TokensPerSecond,
|
||||
proofProbability = 3.u256,
|
||||
expiry = 30.stuint(40),
|
||||
collateralPerByte = 0.u128,
|
||||
expiry = 30'StorageDuration,
|
||||
collateralPerByte = 0'Tokens,
|
||||
nodes = 3.uint,
|
||||
tolerance = 0.uint,
|
||||
)
|
||||
|
||||
check response.status == 422
|
||||
check (await response.body) == "Collateral per byte must be greater than zero"
|
||||
|
||||
test "creating availability fails when until is negative", config:
|
||||
let totalSize = 12.uint64
|
||||
let minPricePerBytePerSecond = 1.u256
|
||||
let totalCollateral = totalSize.u256 * minPricePerBytePerSecond
|
||||
let response = await client.postAvailabilityRaw(
|
||||
totalSize = totalSize,
|
||||
duration = 2.uint64,
|
||||
minPricePerBytePerSecond = minPricePerBytePerSecond,
|
||||
totalCollateral = totalCollateral,
|
||||
until = -1.SecondsSince1970.some,
|
||||
)
|
||||
|
||||
check:
|
||||
response.status == 422
|
||||
(await response.body) == "Cannot set until to a negative value"
|
||||
|
||||
@ -36,17 +36,17 @@ multinodesuite "Sales":
|
||||
let availability1 = (
|
||||
await host.postAvailability(
|
||||
totalSize = 1.uint64,
|
||||
duration = 2.uint64,
|
||||
minPricePerBytePerSecond = 3.u256,
|
||||
totalCollateral = 4.u256,
|
||||
duration = 2'StorageDuration,
|
||||
minPricePerBytePerSecond = 3'TokensPerSecond,
|
||||
totalCollateral = 4'Tokens,
|
||||
)
|
||||
).get
|
||||
let availability2 = (
|
||||
await host.postAvailability(
|
||||
totalSize = 4.uint64,
|
||||
duration = 5.uint64,
|
||||
minPricePerBytePerSecond = 6.u256,
|
||||
totalCollateral = 7.u256,
|
||||
duration = 5'StorageDuration,
|
||||
minPricePerBytePerSecond = 6'TokensPerSecond,
|
||||
totalCollateral = 7'Tokens,
|
||||
)
|
||||
).get
|
||||
check availability1 != availability2
|
||||
@ -55,9 +55,9 @@ multinodesuite "Sales":
|
||||
let availability = (
|
||||
await host.postAvailability(
|
||||
totalSize = 1.uint64,
|
||||
duration = 2.uint64,
|
||||
minPricePerBytePerSecond = 3.u256,
|
||||
totalCollateral = 4.u256,
|
||||
duration = 2'StorageDuration,
|
||||
minPricePerBytePerSecond = 3'TokensPerSecond,
|
||||
totalCollateral = 4'Tokens,
|
||||
)
|
||||
).get
|
||||
check availability in (await host.getAvailabilities()).get
|
||||
@ -66,28 +66,28 @@ multinodesuite "Sales":
|
||||
let availability = (
|
||||
await host.postAvailability(
|
||||
totalSize = 140000.uint64,
|
||||
duration = 200.uint64,
|
||||
minPricePerBytePerSecond = 3.u256,
|
||||
totalCollateral = 300.u256,
|
||||
duration = 200'StorageDuration,
|
||||
minPricePerBytePerSecond = 3'TokensPerSecond,
|
||||
totalCollateral = 300'Tokens,
|
||||
)
|
||||
).get
|
||||
|
||||
var until = getTime().toUnix()
|
||||
var until = StorageTimestamp.init(getTime().toUnix())
|
||||
|
||||
await host.patchAvailability(
|
||||
availability.id,
|
||||
duration = 100.uint64.some,
|
||||
minPricePerBytePerSecond = 2.u256.some,
|
||||
totalCollateral = 200.u256.some,
|
||||
duration = some 100'StorageDuration,
|
||||
minPricePerBytePerSecond = some 2'TokensPerSecond,
|
||||
totalCollateral = some 200'Tokens,
|
||||
enabled = false.some,
|
||||
until = until.some,
|
||||
)
|
||||
|
||||
let updatedAvailability =
|
||||
((await host.getAvailabilities()).get).findItem(availability).get
|
||||
check updatedAvailability.duration == 100.uint64
|
||||
check updatedAvailability.minPricePerBytePerSecond == 2
|
||||
check updatedAvailability.totalCollateral == 200
|
||||
check updatedAvailability.duration == 100'StorageDuration
|
||||
check updatedAvailability.minPricePerBytePerSecond == 2'TokensPerSecond
|
||||
check updatedAvailability.totalCollateral == 200'Tokens
|
||||
check updatedAvailability.totalSize == 140000.uint64
|
||||
check updatedAvailability.freeSize == 140000.uint64
|
||||
check updatedAvailability.enabled == false
|
||||
@ -97,9 +97,9 @@ multinodesuite "Sales":
|
||||
let availability = (
|
||||
await host.postAvailability(
|
||||
totalSize = 140000.uint64,
|
||||
duration = 200.uint64,
|
||||
minPricePerBytePerSecond = 3.u256,
|
||||
totalCollateral = 300.u256,
|
||||
duration = 200'StorageDuration,
|
||||
minPricePerBytePerSecond = 3'TokensPerSecond,
|
||||
totalCollateral = 300'Tokens,
|
||||
)
|
||||
).get
|
||||
await host.patchAvailability(availability.id, totalSize = 100000.uint64.some)
|
||||
@ -113,13 +113,13 @@ multinodesuite "Sales":
|
||||
salesConfig:
|
||||
let originalSize = 0xFFFFFF.uint64
|
||||
let data = await RandomChunker.example(blocks = 8)
|
||||
let minPricePerBytePerSecond = 3.u256
|
||||
let collateralPerByte = 1.u256
|
||||
let totalCollateral = originalSize.u256 * collateralPerByte
|
||||
let minPricePerBytePerSecond = 3'TokensPerSecond
|
||||
let collateralPerByte = 1'Tokens
|
||||
let totalCollateral = collateralPerByte * originalSize
|
||||
let availability = (
|
||||
await host.postAvailability(
|
||||
totalSize = originalSize,
|
||||
duration = 20 * 60.uint64,
|
||||
duration = StorageDuration.init(20'u32 * 60),
|
||||
minPricePerBytePerSecond = minPricePerBytePerSecond,
|
||||
totalCollateral = totalCollateral,
|
||||
)
|
||||
@ -130,11 +130,11 @@ multinodesuite "Sales":
|
||||
let id = (
|
||||
await client.requestStorage(
|
||||
cid,
|
||||
duration = (20 * 60).stuint(40),
|
||||
pricePerBytePerSecond = minPricePerBytePerSecond.stuint(96),
|
||||
duration = StorageDuration.init(20'u32 * 60),
|
||||
pricePerBytePerSecond = minPricePerBytePerSecond,
|
||||
proofProbability = 3.u256,
|
||||
expiry = (10 * 60).stuint(40),
|
||||
collateralPerByte = collateralPerByte.stuint(128),
|
||||
expiry = StorageDuration.init(10'u32 * 60),
|
||||
collateralPerByte = collateralPerByte,
|
||||
nodes = 3,
|
||||
tolerance = 1,
|
||||
)
|
||||
@ -165,29 +165,13 @@ multinodesuite "Sales":
|
||||
check newUpdatedAvailability.totalSize == originalSize + 20000
|
||||
check newUpdatedAvailability.freeSize - updatedAvailability.freeSize == 20000
|
||||
|
||||
test "updating availability fails with until negative", salesConfig:
|
||||
let availability = (
|
||||
await host.postAvailability(
|
||||
totalSize = 140000.uint64,
|
||||
duration = 200.uint64,
|
||||
minPricePerBytePerSecond = 3.u256,
|
||||
totalCollateral = 300.u256,
|
||||
)
|
||||
).get
|
||||
|
||||
let response =
|
||||
await host.patchAvailabilityRaw(availability.id, until = -1.SecondsSince1970.some)
|
||||
|
||||
check:
|
||||
(await response.body) == "Cannot set until to a negative value"
|
||||
|
||||
test "returns an error when trying to update the until date before an existing a request is finished",
|
||||
salesConfig:
|
||||
let size = 0xFFFFFF.uint64
|
||||
let data = await RandomChunker.example(blocks = 8)
|
||||
let duration = 20 * 60.uint64
|
||||
let minPricePerBytePerSecond = 3.u256
|
||||
let collateralPerByte = 1.u256
|
||||
let duration = StorageDuration.init(20'u32 * 60)
|
||||
let minPricePerBytePerSecond = 3'TokensPerSecond
|
||||
let collateralPerByte = 1'Tokens
|
||||
let ecNodes = 3.uint
|
||||
let ecTolerance = 1.uint
|
||||
|
||||
@ -197,7 +181,7 @@ multinodesuite "Sales":
|
||||
totalSize = size,
|
||||
duration = duration,
|
||||
minPricePerBytePerSecond = minPricePerBytePerSecond,
|
||||
totalCollateral = size.u256 * minPricePerBytePerSecond,
|
||||
totalCollateral = collateralPerByte * size,
|
||||
)
|
||||
).get
|
||||
|
||||
@ -209,7 +193,7 @@ multinodesuite "Sales":
|
||||
duration = duration,
|
||||
pricePerBytePerSecond = minPricePerBytePerSecond,
|
||||
proofProbability = 3.u256,
|
||||
expiry = 10 * 60.uint64,
|
||||
expiry = StorageDuration.init(10'u32 * 60),
|
||||
collateralPerByte = collateralPerByte,
|
||||
nodes = ecNodes,
|
||||
tolerance = ecTolerance,
|
||||
@ -223,7 +207,7 @@ multinodesuite "Sales":
|
||||
check purchase.error == none string
|
||||
|
||||
let unixNow = getTime().toUnix()
|
||||
let until = unixNow + 1.SecondsSince1970
|
||||
let until = StorageTimestamp.init(unixNow + 1)
|
||||
|
||||
let response = await host.patchAvailabilityRaw(
|
||||
availabilityId = availability.id, until = until.some
|
||||
|
||||
@ -39,8 +39,8 @@ marketplacesuite "Validation":
|
||||
const ecTolerance = 1
|
||||
const proofProbability = 1.u256
|
||||
|
||||
const collateralPerByte = 1.u256
|
||||
const minPricePerBytePerSecond = 1.u256
|
||||
const collateralPerByte = 1'Tokens
|
||||
const minPricePerBytePerSecond = 1'TokensPerSecond
|
||||
|
||||
proc waitForRequestToFail(
|
||||
marketplace: Marketplace, requestId: RequestId, timeout = 10, step = 5
|
||||
@ -94,13 +94,13 @@ marketplacesuite "Validation":
|
||||
discard await ethProvider.send("evm_mine")
|
||||
|
||||
var currentTime = await ethProvider.currentTime()
|
||||
let requestEndTime = currentTime.truncate(uint64) + duration
|
||||
let requestEndTime = currentTime.truncate(uint64) + duration.u64
|
||||
|
||||
let data = await RandomChunker.example(blocks = blocks)
|
||||
let datasetSize =
|
||||
datasetSize(blocks = blocks, nodes = ecNodes, tolerance = ecTolerance)
|
||||
await createAvailabilities(
|
||||
datasetSize.truncate(uint64),
|
||||
datasetSize,
|
||||
duration,
|
||||
collateralPerByte,
|
||||
minPricePerBytePerSecond,
|
||||
@ -109,8 +109,8 @@ marketplacesuite "Validation":
|
||||
let cid = (await client0.upload(data)).get
|
||||
let purchaseId = await client0.requestStorage(
|
||||
cid,
|
||||
expiry = expiry.stuint(40),
|
||||
duration = duration.stuint(40),
|
||||
expiry = expiry,
|
||||
duration = duration,
|
||||
nodes = ecNodes,
|
||||
tolerance = ecTolerance,
|
||||
proofProbability = proofProbability,
|
||||
@ -121,7 +121,7 @@ marketplacesuite "Validation":
|
||||
|
||||
if not eventuallyS(
|
||||
await client0.purchaseStateIs(purchaseId, "started"),
|
||||
timeout = (expiry + 60).int,
|
||||
timeout = (expiry.u64 + 60).int,
|
||||
step = 5,
|
||||
):
|
||||
debug "validation suite: timed out waiting for the purchase to start"
|
||||
@ -164,13 +164,13 @@ marketplacesuite "Validation":
|
||||
discard await ethProvider.send("evm_mine")
|
||||
|
||||
var currentTime = await ethProvider.currentTime()
|
||||
let requestEndTime = currentTime.truncate(uint64) + duration
|
||||
let requestEndTime = currentTime.truncate(uint64) + duration.u64
|
||||
|
||||
let data = await RandomChunker.example(blocks = blocks)
|
||||
let datasetSize =
|
||||
datasetSize(blocks = blocks, nodes = ecNodes, tolerance = ecTolerance)
|
||||
await createAvailabilities(
|
||||
datasetSize.truncate(uint64),
|
||||
datasetSize,
|
||||
duration,
|
||||
collateralPerByte,
|
||||
minPricePerBytePerSecond,
|
||||
@ -179,8 +179,8 @@ marketplacesuite "Validation":
|
||||
let cid = (await client0.upload(data)).get
|
||||
let purchaseId = await client0.requestStorage(
|
||||
cid,
|
||||
expiry = expiry.stuint(40),
|
||||
duration = duration.stuint(40),
|
||||
expiry = expiry,
|
||||
duration = duration,
|
||||
nodes = ecNodes,
|
||||
tolerance = ecTolerance,
|
||||
proofProbability = proofProbability,
|
||||
@ -191,7 +191,7 @@ marketplacesuite "Validation":
|
||||
|
||||
if not eventuallyS(
|
||||
await client0.purchaseStateIs(purchaseId, "started"),
|
||||
timeout = (expiry + 60).int,
|
||||
timeout = (expiry.u64 + 60).int,
|
||||
step = 5,
|
||||
):
|
||||
debug "validation suite: timed out waiting for the purchase to start"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user