Introduce Sales
This commit is contained in:
parent
75ec8c0bfd
commit
061b32296a
|
@ -0,0 +1,74 @@
|
||||||
|
import std/sequtils
|
||||||
|
import pkg/questionable
|
||||||
|
import pkg/upraises
|
||||||
|
import pkg/stint
|
||||||
|
import pkg/nimcrypto
|
||||||
|
import ./market
|
||||||
|
|
||||||
|
export stint
|
||||||
|
|
||||||
|
type
|
||||||
|
Sales* = ref object
|
||||||
|
market: Market
|
||||||
|
available*: seq[Availability]
|
||||||
|
subscription: ?Subscription
|
||||||
|
|
||||||
|
Availability* = object
|
||||||
|
id*: array[32, byte]
|
||||||
|
size*: uint64
|
||||||
|
duration*: uint64
|
||||||
|
minPrice*: UInt256
|
||||||
|
|
||||||
|
func new*(_: type Sales, market: Market): Sales =
|
||||||
|
Sales(market: market)
|
||||||
|
|
||||||
|
proc new*(_: type Availability,
|
||||||
|
size: uint64,
|
||||||
|
duration: uint64,
|
||||||
|
minPrice: UInt256): Availability =
|
||||||
|
var id: array[32, byte]
|
||||||
|
doAssert randomBytes(id) == 32
|
||||||
|
Availability(id: id, size: size, duration: duration, minPrice: minPrice)
|
||||||
|
|
||||||
|
func add*(sales: Sales, availability: Availability) =
|
||||||
|
sales.available.add(availability)
|
||||||
|
|
||||||
|
func remove*(sales: Sales, availability: Availability) =
|
||||||
|
sales.available.keepItIf(it != availability)
|
||||||
|
|
||||||
|
func findAvailability(sales: Sales, request: StorageRequest): ?Availability =
|
||||||
|
for availability in sales.available:
|
||||||
|
if request.size <= availability.size.u256 and
|
||||||
|
request.duration <= availability.duration.u256 and
|
||||||
|
request.maxPrice >= availability.minPrice:
|
||||||
|
return some availability
|
||||||
|
|
||||||
|
func createOffer(sales: Sales,
|
||||||
|
request: StorageRequest,
|
||||||
|
availability: Availability): StorageOffer =
|
||||||
|
StorageOffer(
|
||||||
|
requestId: request.id,
|
||||||
|
price: request.maxPrice
|
||||||
|
)
|
||||||
|
|
||||||
|
proc handleRequest(sales: Sales, request: StorageRequest) {.async.} =
|
||||||
|
if availability =? sales.findAvailability(request):
|
||||||
|
sales.remove(availability)
|
||||||
|
let offer = sales.createOffer(request, availability)
|
||||||
|
await sales.market.offerStorage(offer)
|
||||||
|
|
||||||
|
proc start*(sales: Sales) =
|
||||||
|
doAssert sales.subscription.isNone, "Sales already started"
|
||||||
|
|
||||||
|
proc onRequest(request: StorageRequest) {.gcsafe, upraises:[].} =
|
||||||
|
asyncSpawn sales.handleRequest(request)
|
||||||
|
|
||||||
|
proc subscribe {.async.} =
|
||||||
|
sales.subscription = some await sales.market.subscribeRequests(onRequest)
|
||||||
|
|
||||||
|
asyncSpawn subscribe()
|
||||||
|
|
||||||
|
proc stop*(sales: Sales) =
|
||||||
|
if subscription =? sales.subscription:
|
||||||
|
asyncSpawn subscription.unsubscribe()
|
||||||
|
sales.subscription = Subscription.none
|
|
@ -6,6 +6,7 @@ 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/sales
|
||||||
import ../examples
|
import ../examples
|
||||||
|
|
||||||
export examples
|
export examples
|
||||||
|
@ -51,3 +52,6 @@ proc example*(_: type BlockExcPeerCtx): BlockExcPeerCtx =
|
||||||
|
|
||||||
proc example*(_: type Cid): Cid =
|
proc example*(_: type Cid): Cid =
|
||||||
Block.example.cid
|
Block.example.cid
|
||||||
|
|
||||||
|
proc example*(_: type Availability): Availability =
|
||||||
|
Availability.new(uint16.example, uint16.example, uint64.example.u256)
|
||||||
|
|
|
@ -2,6 +2,8 @@ import std/sequtils
|
||||||
import std/heapqueue
|
import std/heapqueue
|
||||||
import pkg/dagger/market
|
import pkg/dagger/market
|
||||||
|
|
||||||
|
export market
|
||||||
|
|
||||||
type
|
type
|
||||||
MockMarket* = ref object of Market
|
MockMarket* = ref object of Market
|
||||||
requested*: seq[StorageRequest]
|
requested*: seq[StorageRequest]
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
import pkg/asynctest
|
||||||
|
import pkg/chronos
|
||||||
|
import pkg/dagger/sales
|
||||||
|
import ./helpers/mockmarket
|
||||||
|
import ./examples
|
||||||
|
|
||||||
|
suite "Sales":
|
||||||
|
|
||||||
|
var sales: Sales
|
||||||
|
var market: MockMarket
|
||||||
|
|
||||||
|
setup:
|
||||||
|
market = MockMarket.new()
|
||||||
|
sales = Sales.new(market)
|
||||||
|
|
||||||
|
test "has no availability initially":
|
||||||
|
check sales.available.len == 0
|
||||||
|
|
||||||
|
test "can add available storage":
|
||||||
|
let availability1 = Availability.example
|
||||||
|
let availability2 = Availability.example
|
||||||
|
sales.add(availability1)
|
||||||
|
check sales.available.contains(availability1)
|
||||||
|
sales.add(availability2)
|
||||||
|
check sales.available.contains(availability1)
|
||||||
|
check sales.available.contains(availability2)
|
||||||
|
|
||||||
|
test "can remove available storage":
|
||||||
|
let availability = Availability.example
|
||||||
|
sales.add(availability)
|
||||||
|
sales.remove(availability)
|
||||||
|
check sales.available.len == 0
|
||||||
|
|
||||||
|
test "generates unique ids for storage availability":
|
||||||
|
let availability1 = Availability.new(size=1, duration=2, minPrice=3.u256)
|
||||||
|
let availability2 = Availability.new(size=1, duration=2, minPrice=3.u256)
|
||||||
|
check availability1.id != availability2.id
|
||||||
|
|
||||||
|
test "offers available storage when matching request comes in":
|
||||||
|
let availability = Availability.new(size=100, duration=60, minPrice=42.u256)
|
||||||
|
sales.add(availability)
|
||||||
|
sales.start()
|
||||||
|
let request = StorageRequest(duration:60.u256, size:100.u256, maxPrice:42.u256)
|
||||||
|
await market.requestStorage(request)
|
||||||
|
check market.offered.len == 1
|
||||||
|
check market.offered[0].price == 42.u256
|
||||||
|
sales.stop()
|
||||||
|
|
||||||
|
test "ignores request when no matching storage is available":
|
||||||
|
let availability = Availability.new(size=99, duration=60, minPrice=42.u256)
|
||||||
|
sales.add(availability)
|
||||||
|
sales.start()
|
||||||
|
let request = StorageRequest(duration:60.u256, size:100.u256, maxPrice:42.u256)
|
||||||
|
await market.requestStorage(request)
|
||||||
|
check market.offered.len == 0
|
||||||
|
sales.stop()
|
||||||
|
|
||||||
|
test "makes storage unavailable when offer is submitted":
|
||||||
|
let availability = Availability.new(size=100, duration=60, minPrice=42.u256)
|
||||||
|
sales.add(availability)
|
||||||
|
sales.start()
|
||||||
|
let request = StorageRequest(duration:60.u256, size:100.u256, maxPrice:42.u256)
|
||||||
|
await market.requestStorage(request)
|
||||||
|
check sales.available.len == 0
|
||||||
|
sales.stop()
|
|
@ -6,5 +6,6 @@ import ./dagger/testmanifest
|
||||||
import ./dagger/testnode
|
import ./dagger/testnode
|
||||||
import ./dagger/teststorestream
|
import ./dagger/teststorestream
|
||||||
import ./dagger/testpurchasing
|
import ./dagger/testpurchasing
|
||||||
|
import ./dagger/testsales
|
||||||
|
|
||||||
{.warning[UnusedImport]: off.}
|
{.warning[UnusedImport]: off.}
|
||||||
|
|
Loading…
Reference in New Issue