Update to latest dagger-contracts (#78)

- StorageRequest struct has changed

- StorageRequested event has changed,
  it no longer returns the entire request,
  but only the id and the ask
This commit is contained in:
markspanbroek 2022-04-11 20:03:55 +02:00 committed by GitHub
parent 168468a3fd
commit 1a3003e043
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 171 additions and 69 deletions

View File

@ -59,7 +59,7 @@ method subscribeRequests(market: OnChainMarket,
callback: OnRequest): callback: OnRequest):
Future[MarketSubscription] {.async.} = Future[MarketSubscription] {.async.} =
proc onEvent(event: StorageRequested) {.upraises:[].} = proc onEvent(event: StorageRequested) {.upraises:[].} =
callback(event.request) callback(event.requestId, event.ask)
let subscription = await market.contract.subscribe(StorageRequested, onEvent) let subscription = await market.contract.subscribe(StorageRequested, onEvent)
return OnChainMarketSubscription(eventSubscription: subscription) return OnChainMarketSubscription(eventSubscription: subscription)

View File

@ -8,36 +8,116 @@ export contractabi
type type
StorageRequest* = object StorageRequest* = object
client*: Address client*: Address
duration*: UInt256 ask*: StorageAsk
size*: UInt256 content*: StorageContent
contentHash*: array[32, byte]
proofProbability*: UInt256
maxPrice*: UInt256
expiry*: UInt256 expiry*: UInt256
nonce*: array[32, byte] nonce*: array[32, byte]
StorageAsk* = object
size*: UInt256
duration*: UInt256
proofProbability*: UInt256
maxPrice*: UInt256
StorageContent* = object
cid*: string
erasure*: StorageErasure
por*: StoragePoR
StorageErasure* = object
totalChunks*: uint64
totalNodes*: uint64
nodeId*: uint64
StoragePoR* = object
u*: seq[byte]
publicKey*: seq[byte]
name*: seq[byte]
func fromTuple(_: type StorageRequest, tupl: tuple): StorageRequest = func fromTuple(_: type StorageRequest, tupl: tuple): StorageRequest =
StorageRequest( StorageRequest(
client: tupl[0], client: tupl[0],
duration: tupl[1], ask: tupl[1],
size: tupl[2], content: tupl[2],
contentHash: tupl[3], expiry: tupl[3],
proofProbability: tupl[4], nonce: tupl[4]
maxPrice: tupl[5],
expiry: tupl[6],
nonce: tupl[7]
) )
func fromTuple(_: type StorageAsk, tupl: tuple): StorageAsk =
StorageAsk(
size: tupl[0],
duration: tupl[1],
proofProbability: tupl[2],
maxPrice: tupl[3]
)
func fromTuple(_: type StorageContent, tupl: tuple): StorageContent =
StorageContent(
cid: tupl[0],
erasure: tupl[1],
por: tupl[2]
)
func fromTuple(_: type StorageErasure, tupl: tuple): StorageErasure =
StorageErasure(
totalChunks: tupl[0],
totalNodes: tupl[1],
nodeId: tupl[2]
)
func fromTuple(_: type StoragePoR, tupl: tuple): StoragePoR =
StoragePoR(
u: tupl[0],
publicKey: tupl[1],
name: tupl[2]
)
func solidityType*(_: type StoragePoR): string =
solidityType(StoragePoR.fieldTypes)
func solidityType*(_: type StorageErasure): string =
solidityType(StorageErasure.fieldTypes)
func solidityType*(_: type StorageContent): string =
solidityType(StorageContent.fieldTypes)
func solidityType*(_: type StorageAsk): string =
solidityType(StorageAsk.fieldTypes)
func solidityType*(_: type StorageRequest): string = func solidityType*(_: type StorageRequest): string =
solidityType(StorageRequest.fieldTypes) solidityType(StorageRequest.fieldTypes)
func encode*(encoder: var AbiEncoder, por: StoragePoR) =
encoder.write(por.fieldValues)
func encode*(encoder: var AbiEncoder, erasure: StorageErasure) =
encoder.write(erasure.fieldValues)
func encode*(encoder: var AbiEncoder, content: StorageContent) =
encoder.write(content.fieldValues)
func encode*(encoder: var AbiEncoder, ask: StorageAsk) =
encoder.write(ask.fieldValues)
func encode*(encoder: var AbiEncoder, request: StorageRequest) = func encode*(encoder: var AbiEncoder, request: StorageRequest) =
encoder.write(request.fieldValues) encoder.write(request.fieldValues)
func decode*(decoder: var AbiDecoder, T: type StoragePoR): ?!T =
let tupl = ?decoder.read(StoragePoR.fieldTypes)
success StoragePoR.fromTuple(tupl)
func decode*(decoder: var AbiDecoder, T: type StorageErasure): ?!T =
let tupl = ?decoder.read(StorageErasure.fieldTypes)
success StorageErasure.fromTuple(tupl)
func decode*(decoder: var AbiDecoder, T: type StorageContent): ?!T =
let tupl = ?decoder.read(StorageContent.fieldTypes)
success StorageContent.fromTuple(tupl)
func decode*(decoder: var AbiDecoder, T: type StorageAsk): ?!T =
let tupl = ?decoder.read(StorageAsk.fieldTypes)
success StorageAsk.fromTuple(tupl)
func decode*(decoder: var AbiDecoder, T: type StorageRequest): ?!T = func decode*(decoder: var AbiDecoder, T: type StorageRequest): ?!T =
let tupl = ?decoder.read(StorageRequest.fieldTypes) let tupl = ?decoder.read(StorageRequest.fieldTypes)
success StorageRequest.fromTuple(tupl) success StorageRequest.fromTuple(tupl)
func id*(request: StorageRequest): array[32, byte] = func id*(request: StorageRequest): array[32, byte] =
let encoding = AbiEncoder.encode(request) let encoding = AbiEncoder.encode((request, ))
keccak256.digest(encoding).data keccak256.digest(encoding).data

View File

@ -13,7 +13,7 @@ type
Id = array[32, byte] Id = array[32, byte]
StorageRequested* = object of Event StorageRequested* = object of Event
requestId*: Id requestId*: Id
request*: StorageRequest ask*: StorageAsk
StorageOffered* = object of Event StorageOffered* = object of Event
offerId*: Id offerId*: Id
offer*: StorageOffer offer*: StorageOffer

View File

@ -10,7 +10,7 @@ export offers
type type
Market* = ref object of RootObj Market* = ref object of RootObj
Subscription* = ref object of RootObj Subscription* = ref object of RootObj
OnRequest* = proc(request: StorageRequest) {.gcsafe, upraises:[].} OnRequest* = proc(id: array[32, byte], ask: StorageAsk) {.gcsafe, upraises:[].}
OnOffer* = proc(offer: StorageOffer) {.gcsafe, upraises:[].} OnOffer* = proc(offer: StorageOffer) {.gcsafe, upraises:[].}
OnSelect* = proc(offerId: array[32, byte]) {.gcsafe, upraises: [].} OnSelect* = proc(offerId: array[32, byte]) {.gcsafe, upraises: [].}

View File

@ -38,8 +38,8 @@ proc new*(_: type Purchasing, market: Market): Purchasing =
proc populate*(purchasing: Purchasing, request: StorageRequest): StorageRequest = proc populate*(purchasing: Purchasing, request: StorageRequest): StorageRequest =
result = request result = request
if result.proofProbability == 0.u256: if result.ask.proofProbability == 0.u256:
result.proofProbability = purchasing.proofProbability result.ask.proofProbability = purchasing.proofProbability
if result.expiry == 0.u256: if result.expiry == 0.u256:
result.expiry = (getTime().toUnix().u256 + purchasing.requestExpiryInterval) result.expiry = (getTime().toUnix().u256 + purchasing.requestExpiryInterval)
if result.nonce == array[32, byte].default: if result.nonce == array[32, byte].default:

View File

@ -24,7 +24,8 @@ type
minPrice*: UInt256 minPrice*: UInt256
Negotiation = ref object Negotiation = ref object
sales: Sales sales: Sales
request: StorageRequest requestId: array[32, byte]
ask: StorageAsk
availability: Availability availability: Availability
offer: ?StorageOffer offer: ?StorageOffer
subscription: ?Subscription subscription: ?Subscription
@ -52,17 +53,17 @@ func add*(sales: Sales, availability: Availability) =
func remove*(sales: Sales, availability: Availability) = func remove*(sales: Sales, availability: Availability) =
sales.available.keepItIf(it != availability) sales.available.keepItIf(it != availability)
func findAvailability(sales: Sales, request: StorageRequest): ?Availability = func findAvailability(sales: Sales, ask: StorageAsk): ?Availability =
for availability in sales.available: for availability in sales.available:
if request.size <= availability.size.u256 and if ask.size <= availability.size.u256 and
request.duration <= availability.duration.u256 and ask.duration <= availability.duration.u256 and
request.maxPrice >= availability.minPrice: ask.maxPrice >= availability.minPrice:
return some availability return some availability
proc createOffer(negotiation: Negotiation): StorageOffer = proc createOffer(negotiation: Negotiation): StorageOffer =
StorageOffer( StorageOffer(
requestId: negotiation.request.id, requestId: negotiation.requestId,
price: negotiation.request.maxPrice, price: negotiation.ask.maxPrice,
expiry: getTime().toUnix().u256 + negotiation.sales.offerExpiryInterval expiry: getTime().toUnix().u256 + negotiation.sales.offerExpiryInterval
) )
@ -117,13 +118,16 @@ proc start(negotiation: Negotiation) {.async.} =
await negotiation.subscribeSelect() await negotiation.subscribeSelect()
negotiation.waiting = some negotiation.waitForExpiry() negotiation.waiting = some negotiation.waitForExpiry()
proc handleRequest(sales: Sales, request: StorageRequest) {.async.} = proc handleRequest(sales: Sales,
without availability =? sales.findAvailability(request): requestId: array[32, byte],
ask: StorageAsk) {.async.} =
without availability =? sales.findAvailability(ask):
return return
let negotiation = Negotiation( let negotiation = Negotiation(
sales: sales, sales: sales,
request: request, requestId: requestId,
ask: ask,
availability: availability availability: availability
) )
@ -132,8 +136,8 @@ proc handleRequest(sales: Sales, request: StorageRequest) {.async.} =
proc start*(sales: Sales) = proc start*(sales: Sales) =
doAssert sales.subscription.isNone, "Sales already started" doAssert sales.subscription.isNone, "Sales already started"
proc onRequest(request: StorageRequest) {.gcsafe, upraises:[].} = proc onRequest(requestId: array[32, byte], ask: StorageAsk) {.gcsafe, upraises:[].} =
asyncSpawn sales.handleRequest(request) asyncSpawn sales.handleRequest(requestId, ask)
proc subscribe {.async.} = proc subscribe {.async.} =
sales.subscription = some await sales.market.subscribeRequests(onRequest) sales.subscription = some await sales.market.subscribeRequests(onRequest)

View File

@ -1,6 +1,5 @@
import std/times import std/times
import pkg/stint import pkg/stint
import pkg/nimcrypto
import pkg/ethers import pkg/ethers
import dagger/contracts import dagger/contracts
import ../examples import ../examples
@ -13,11 +12,25 @@ proc example*(_: type Address): Address =
proc example*(_: type StorageRequest): StorageRequest = proc example*(_: type StorageRequest): StorageRequest =
StorageRequest( StorageRequest(
client: Address.example, client: Address.example,
duration: (10 * 60 * 60).u256, # 10 hours ask: StorageAsk(
size: (1 * 1024 * 1024 * 1024).u256, # 1 Gigabyte size: (1 * 1024 * 1024 * 1024).u256, # 1 Gigabyte
contentHash: sha256.digest(0xdeadbeef'u32.toBytes).data, duration: (10 * 60 * 60).u256, # 10 hours
proofProbability: 4.u256, # require a proof roughly once every 4 periods proofProbability: 4.u256, # require a proof roughly once every 4 periods
maxPrice: 84.u256, maxPrice: 84.u256
),
content: StorageContent(
cid: "zb2rhheVmk3bLks5MgzTqyznLu1zqGH5jrfTA1eAZXrjx7Vob",
erasure: StorageErasure(
totalChunks: 12,
totalNodes: 4,
nodeId: 3
),
por: StoragePor(
u: @(array[480, byte].example),
publicKey: @(array[96, byte].example),
name: @(array[512, byte].example)
)
),
expiry: (getTime() + initDuration(hours=1)).toUnix.u256, expiry: (getTime() + initDuration(hours=1)).toUnix.u256,
nonce: array[32, byte].example nonce: array[32, byte].example
) )

View File

@ -45,7 +45,7 @@ ethersuite "Storage contracts":
offer.requestId = request.id offer.requestId = request.id
switchAccount(client) switchAccount(client)
await token.approve(storage.address, request.maxPrice) await token.approve(storage.address, request.ask.maxPrice)
await storage.requestStorage(request) await storage.requestStorage(request)
switchAccount(host) switchAccount(host)
await token.approve(storage.address, collateralAmount) await token.approve(storage.address, collateralAmount)

View File

@ -30,7 +30,7 @@ ethersuite "On-Chain Market":
request.client = accounts[0] request.client = accounts[0]
offer.host = accounts[0] offer.host = accounts[0]
offer.requestId = request.id offer.requestId = request.id
offer.price = request.maxPrice offer.price = request.ask.maxPrice
test "fails to instantiate when contract does not have a signer": test "fails to instantiate when contract does not have a signer":
let storageWithoutSigner = storage.connect(provider) let storageWithoutSigner = storage.connect(provider)
@ -38,33 +38,36 @@ ethersuite "On-Chain Market":
discard OnChainMarket.new(storageWithoutSigner) discard OnChainMarket.new(storageWithoutSigner)
test "supports storage requests": test "supports storage requests":
await token.approve(storage.address, request.maxPrice) await token.approve(storage.address, request.ask.maxPrice)
check (await market.requestStorage(request)) == request check (await market.requestStorage(request)) == request
test "sets client address when submitting storage request": test "sets client address when submitting storage request":
var requestWithoutClient = request var requestWithoutClient = request
requestWithoutClient.client = Address.default requestWithoutClient.client = Address.default
await token.approve(storage.address, request.maxPrice) await token.approve(storage.address, request.ask.maxPrice)
let submitted = await market.requestStorage(requestWithoutClient) let submitted = await market.requestStorage(requestWithoutClient)
check submitted.client == accounts[0] check submitted.client == accounts[0]
test "supports request subscriptions": test "supports request subscriptions":
var received: seq[StorageRequest] var receivedIds: seq[array[32, byte]]
proc onRequest(request: StorageRequest) = var receivedAsks: seq[StorageAsk]
received.add(request) proc onRequest(id: array[32, byte], ask: StorageAsk) =
receivedIds.add(id)
receivedAsks.add(ask)
let subscription = await market.subscribeRequests(onRequest) let subscription = await market.subscribeRequests(onRequest)
await token.approve(storage.address, request.maxPrice) await token.approve(storage.address, request.ask.maxPrice)
discard await market.requestStorage(request) discard await market.requestStorage(request)
check received == @[request] check receivedIds == @[request.id]
check receivedAsks == @[request.ask]
await subscription.unsubscribe() await subscription.unsubscribe()
test "supports storage offers": test "supports storage offers":
await token.approve(storage.address, request.maxPrice) await token.approve(storage.address, request.ask.maxPrice)
discard await market.requestStorage(request) discard await market.requestStorage(request)
check (await market.offerStorage(offer)) == offer check (await market.offerStorage(offer)) == offer
test "sets host address when submitting storage offer": test "sets host address when submitting storage offer":
await token.approve(storage.address, request.maxPrice) await token.approve(storage.address, request.ask.maxPrice)
discard await market.requestStorage(request) discard await market.requestStorage(request)
var offerWithoutHost = offer var offerWithoutHost = offer
offerWithoutHost.host = Address.default offerWithoutHost.host = Address.default
@ -72,7 +75,7 @@ ethersuite "On-Chain Market":
check submitted.host == accounts[0] check submitted.host == accounts[0]
test "supports offer subscriptions": test "supports offer subscriptions":
await token.approve(storage.address, request.maxPrice) await token.approve(storage.address, request.ask.maxPrice)
discard await market.requestStorage(request) discard await market.requestStorage(request)
var received: seq[StorageOffer] var received: seq[StorageOffer]
proc onOffer(offer: StorageOffer) = proc onOffer(offer: StorageOffer) =
@ -88,11 +91,11 @@ ethersuite "On-Chain Market":
otherRequest.client = accounts[0] otherRequest.client = accounts[0]
otherOffer.host = accounts[0] otherOffer.host = accounts[0]
otherOffer.requestId = otherRequest.id otherOffer.requestId = otherRequest.id
otherOffer.price = otherRequest.maxPrice otherOffer.price = otherrequest.ask.maxPrice
await token.approve(storage.address, request.maxPrice) await token.approve(storage.address, request.ask.maxPrice)
discard await market.requestStorage(request) discard await market.requestStorage(request)
await token.approve(storage.address, otherRequest.maxPrice) await token.approve(storage.address, otherrequest.ask.maxPrice)
discard await market.requestStorage(otherRequest) discard await market.requestStorage(otherRequest)
var submitted: seq[StorageOffer] var submitted: seq[StorageOffer]
@ -109,7 +112,7 @@ ethersuite "On-Chain Market":
await subscription.unsubscribe() await subscription.unsubscribe()
test "supports selection of an offer": test "supports selection of an offer":
await token.approve(storage.address, request.maxPrice) await token.approve(storage.address, request.ask.maxPrice)
discard await market.requestStorage(request) discard await market.requestStorage(request)
discard await market.offerStorage(offer) discard await market.offerStorage(offer)
@ -130,12 +133,12 @@ ethersuite "On-Chain Market":
otherRequest.client = accounts[0] otherRequest.client = accounts[0]
otherOffer.host = accounts[0] otherOffer.host = accounts[0]
otherOffer.requestId = otherRequest.id otherOffer.requestId = otherRequest.id
otherOffer.price = otherRequest.maxPrice otherOffer.price = otherrequest.ask.maxPrice
await token.approve(storage.address, request.maxPrice) await token.approve(storage.address, request.ask.maxPrice)
discard await market.requestStorage(request) discard await market.requestStorage(request)
discard await market.offerStorage(offer) discard await market.offerStorage(offer)
await token.approve(storage.address, otherRequest.maxPrice) await token.approve(storage.address, otherrequest.ask.maxPrice)
discard await market.requestStorage(otherRequest) discard await market.requestStorage(otherRequest)
discard await market.offerStorage(otherOffer) discard await market.offerStorage(otherOffer)

View File

@ -38,7 +38,7 @@ method requestStorage*(market: MockMarket,
market.requested.add(request) market.requested.add(request)
let subscriptions = market.subscriptions.onRequest let subscriptions = market.subscriptions.onRequest
for subscription in subscriptions: for subscription in subscriptions:
subscription.callback(request) subscription.callback(request.id, request.ask)
return request return request
method offerStorage*(market: MockMarket, method offerStorage*(market: MockMarket,

View File

@ -16,9 +16,10 @@ suite "Purchasing":
market = MockMarket.new() market = MockMarket.new()
purchasing = Purchasing.new(market) purchasing = Purchasing.new(market)
request = StorageRequest( request = StorageRequest(
duration: uint16.example.u256, ask: StorageAsk(
size: uint32.example.u256, duration: uint16.example.u256,
contentHash: array[32, byte].example size: uint32.example.u256,
)
) )
proc purchaseAndWait(request: StorageRequest) {.async.} = proc purchaseAndWait(request: StorageRequest) {.async.} =
@ -29,10 +30,9 @@ suite "Purchasing":
test "submits a storage request when asked": test "submits a storage request when asked":
await purchaseAndWait(request) await purchaseAndWait(request)
let submitted = market.requested[0] let submitted = market.requested[0]
check submitted.duration == request.duration check submitted.ask.duration == request.ask.duration
check submitted.size == request.size check submitted.ask.size == request.ask.size
check submitted.contentHash == request.contentHash check submitted.ask.maxPrice == request.ask.maxPrice
check submitted.maxPrice == request.maxPrice
test "has a default value for proof probability": test "has a default value for proof probability":
check purchasing.proofProbability != 0.u256 check purchasing.proofProbability != 0.u256
@ -40,12 +40,12 @@ suite "Purchasing":
test "can change default value for proof probability": test "can change default value for proof probability":
purchasing.proofProbability = 42.u256 purchasing.proofProbability = 42.u256
await purchaseAndWait(request) await purchaseAndWait(request)
check market.requested[0].proofProbability == 42.u256 check market.requested[0].ask.proofProbability == 42.u256
test "can override proof probability per request": test "can override proof probability per request":
request.proofProbability = 42.u256 request.ask.proofProbability = 42.u256
await purchaseAndWait(request) await purchaseAndWait(request)
check market.requested[0].proofProbability == 42.u256 check market.requested[0].ask.proofProbability == 42.u256
test "has a default value for request expiration interval": test "has a default value for request expiration interval":
check purchasing.requestExpiryInterval != 0.u256 check purchasing.requestExpiryInterval != 0.u256

View File

@ -8,7 +8,9 @@ import ./examples
suite "Sales": suite "Sales":
let availability = Availability.init(size=100, duration=60, minPrice=42.u256) let availability = Availability.init(size=100, duration=60, minPrice=42.u256)
let request = StorageRequest(duration: 60.u256, size: 100.u256, maxPrice:42.u256) let request = StorageRequest(
ask: StorageAsk(duration: 60.u256, size: 100.u256, maxPrice:42.u256)
)
var sales: Sales var sales: Sales
var market: MockMarket var market: MockMarket
@ -52,7 +54,7 @@ suite "Sales":
test "ignores request when no matching storage is available": test "ignores request when no matching storage is available":
sales.add(availability) sales.add(availability)
var tooBig = request var tooBig = request
tooBig.size = request.size + 1 tooBig.ask.size = request.ask.size + 1
discard await market.requestStorage(tooBig) discard await market.requestStorage(tooBig)
check market.offered.len == 0 check market.offered.len == 0

@ -1 +1 @@
Subproject commit 29b5775951e774cb170b23cb6772cd7f1e7b5499 Subproject commit 6aa2894521faa53a9896e800caf713499b33c318