Introduce Purchasing and Market

This commit is contained in:
Mark Spanbroek 2022-03-23 13:57:48 +01:00 committed by markspanbroek
parent a3fdd35f73
commit 5f10549f19
6 changed files with 152 additions and 0 deletions

11
dagger/market.nim Normal file
View File

@ -0,0 +1,11 @@
import pkg/chronos
import ./contracts/requests
export chronos
export requests
type
Market* = ref object of RootObj
method requestStorage*(market: Market, request: StorageRequest) {.base, async.} =
raiseAssert("not implemented")

57
dagger/purchasing.nim Normal file
View File

@ -0,0 +1,57 @@
import std/times
import pkg/stint
import pkg/chronos
import pkg/questionable
import pkg/nimcrypto
import ./market
export questionable
type
Purchasing* = ref object
market: Market
proofProbability*: UInt256
requestExpiryInterval*: UInt256
PurchaseRequest* = object
duration*: UInt256
size*: UInt256
contentHash*: array[32, byte]
maxPrice*: UInt256
proofProbability*: ?UInt256
expiry*: ?UInt256
Purchase* = ref object
const DefaultProofProbability = 100.u256
const DefaultRequestExpiryInterval = (10 * 60).u256
proc new*(_: type Purchasing, market: Market): Purchasing =
Purchasing(
market: market,
proofProbability: DefaultProofProbability,
requestExpiryInterval: DefaultRequestExpiryInterval
)
proc getProofProbability(purchasing: Purchasing, request: PurchaseRequest): UInt256 =
request.proofProbability |? purchasing.proofProbability
proc getExpiry(purchasing: Purchasing, request: PurchaseRequest): UInt256 =
request.expiry |? (getTime().toUnix().u256 + purchasing.requestExpiryInterval)
proc getNonce(): array[32, byte] =
doAssert randomBytes(result) == 32
proc purchase*(purchasing: Purchasing, request: PurchaseRequest): Purchase =
let request: StorageRequest = (
client: Address.default, # TODO
duration: request.duration,
size: request.size,
contentHash: request.contentHash,
proofProbability: purchasing.getProofProbability(request),
maxPrice: request.maxPrice,
expiry: purchasing.getExpiry(request),
nonce: getNonce()
)
asyncSpawn purchasing.market.requestStorage(request)
proc wait*(purchase: Purchase) {.async.} =
discard

View File

@ -2,9 +2,11 @@ import std/random
import std/sequtils import std/sequtils
import pkg/libp2p import pkg/libp2p
import pkg/nitro import pkg/nitro
import pkg/stint
import pkg/dagger/rng import pkg/dagger/rng
import pkg/dagger/stores import pkg/dagger/stores
import pkg/dagger/blocktype import pkg/dagger/blocktype
import pkg/dagger/purchasing
proc example*(_: type EthAddress): EthAddress = proc example*(_: type EthAddress): EthAddress =
EthPrivateKey.random().toPublicKey.toAddress EthPrivateKey.random().toPublicKey.toAddress
@ -19,6 +21,13 @@ proc example*(_: type UInt48): UInt48 =
# workaround for https://github.com/nim-lang/Nim/issues/17670 # workaround for https://github.com/nim-lang/Nim/issues/17670
uint64.rand mod (UInt48.high + 1) uint64.rand mod (UInt48.high + 1)
proc example*[T: SomeInteger](_: type T): T =
rand(T)
proc example*[T,N](_: type array[N, T]): array[N, T] =
for item in result.mitems:
item = T.example
proc example*(_: type Wallet): Wallet = proc example*(_: type Wallet): Wallet =
Wallet.init(EthPrivateKey.random()) Wallet.init(EthPrivateKey.random())
@ -53,3 +62,10 @@ proc example*(_: type BlockExcPeerCtx): BlockExcPeerCtx =
proc example*(_: type Cid): Cid = proc example*(_: type Cid): Cid =
Block.example.cid Block.example.cid
proc example*(_: type PurchaseRequest): PurchaseRequest =
PurchaseRequest(
duration: uint16.example.u256,
size: uint32.example.u256,
contentHash: array[32, byte].example
)

View File

@ -0,0 +1,8 @@
import pkg/dagger/market
type
MockMarket* = ref object of Market
requests*: seq[StorageRequest]
method requestStorage*(market: MockMarket, request: StorageRequest) {.async.} =
market.requests.add(request)

View File

@ -0,0 +1,59 @@
import std/times
import pkg/asynctest
import pkg/chronos
import pkg/stint
import pkg/dagger/purchasing
import ./helpers/mockmarket
import ./examples
suite "Purchasing":
var purchasing: Purchasing
var market: MockMarket
var purchaseRequest: PurchaseRequest
setup:
market = MockMarket.new()
purchasing = Purchasing.new(market)
purchaseRequest = PurchaseRequest.example
test "submits a storage request when asked":
await purchasing.purchase(purchaseRequest).wait()
let storageRequest = market.requests[0]
check storageRequest.duration == purchaseRequest.duration
check storageRequest.size == purchaseRequest.size
check storageRequest.contentHash == purchaseRequest.contentHash
check storageRequest.maxPrice == purchaseRequest.maxPrice
test "has a default value for proof probability":
check purchasing.proofProbability != 0.u256
test "can change default value for proof probability":
purchasing.proofProbability = 42.u256
await purchasing.purchase(purchaseRequest).wait()
check market.requests[0].proofProbability == 42.u256
test "can override proof probability per request":
purchaseRequest.proofProbability = some 42.u256
await purchasing.purchase(purchaseRequest).wait()
check market.requests[0].proofProbability == 42.u256
test "has a default value for request expiration interval":
check purchasing.requestExpiryInterval != 0.u256
test "can change default value for request expiration interval":
purchasing.requestExpiryInterval = 42.u256
let start = getTime().toUnix()
await purchasing.purchase(purchaseRequest).wait()
check market.requests[0].expiry == (start + 42).u256
test "can override expiry time per request":
let expiry = (getTime().toUnix() + 42).u256
purchaseRequest.expiry = some expiry
await purchasing.purchase(purchaseRequest).wait()
check market.requests[0].expiry == expiry
test "includes a random nonce in every storage request":
await purchasing.purchase(purchaseRequest).wait()
await purchasing.purchase(purchaseRequest).wait()
check market.requests[0].nonce != market.requests[1].nonce

View File

@ -5,5 +5,6 @@ import ./dagger/testchunking
import ./dagger/testmanifest import ./dagger/testmanifest
import ./dagger/testnode import ./dagger/testnode
import ./dagger/teststorestream import ./dagger/teststorestream
import ./dagger/testpurchasing
{.warning[UnusedImport]: off.} {.warning[UnusedImport]: off.}