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):
Future[MarketSubscription] {.async.} =
proc onEvent(event: StorageRequested) {.upraises:[].} =
callback(event.request)
callback(event.requestId, event.ask)
let subscription = await market.contract.subscribe(StorageRequested, onEvent)
return OnChainMarketSubscription(eventSubscription: subscription)

View File

@ -8,36 +8,116 @@ export contractabi
type
StorageRequest* = object
client*: Address
duration*: UInt256
size*: UInt256
contentHash*: array[32, byte]
proofProbability*: UInt256
maxPrice*: UInt256
ask*: StorageAsk
content*: StorageContent
expiry*: UInt256
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 =
StorageRequest(
client: tupl[0],
duration: tupl[1],
size: tupl[2],
contentHash: tupl[3],
proofProbability: tupl[4],
maxPrice: tupl[5],
expiry: tupl[6],
nonce: tupl[7]
ask: tupl[1],
content: tupl[2],
expiry: tupl[3],
nonce: tupl[4]
)
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 =
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) =
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 =
let tupl = ?decoder.read(StorageRequest.fieldTypes)
success StorageRequest.fromTuple(tupl)
func id*(request: StorageRequest): array[32, byte] =
let encoding = AbiEncoder.encode(request)
let encoding = AbiEncoder.encode((request, ))
keccak256.digest(encoding).data

View File

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

View File

@ -10,7 +10,7 @@ export offers
type
Market* = 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:[].}
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 =
result = request
if result.proofProbability == 0.u256:
result.proofProbability = purchasing.proofProbability
if result.ask.proofProbability == 0.u256:
result.ask.proofProbability = purchasing.proofProbability
if result.expiry == 0.u256:
result.expiry = (getTime().toUnix().u256 + purchasing.requestExpiryInterval)
if result.nonce == array[32, byte].default:

View File

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

View File

@ -1,6 +1,5 @@
import std/times
import pkg/stint
import pkg/nimcrypto
import pkg/ethers
import dagger/contracts
import ../examples
@ -13,11 +12,25 @@ proc example*(_: type Address): Address =
proc example*(_: type StorageRequest): StorageRequest =
StorageRequest(
client: Address.example,
duration: (10 * 60 * 60).u256, # 10 hours
size: (1 * 1024 * 1024 * 1024).u256, # 1 Gigabyte
contentHash: sha256.digest(0xdeadbeef'u32.toBytes).data,
proofProbability: 4.u256, # require a proof roughly once every 4 periods
maxPrice: 84.u256,
ask: StorageAsk(
size: (1 * 1024 * 1024 * 1024).u256, # 1 Gigabyte
duration: (10 * 60 * 60).u256, # 10 hours
proofProbability: 4.u256, # require a proof roughly once every 4 periods
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,
nonce: array[32, byte].example
)

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,9 @@ import ./examples
suite "Sales":
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 market: MockMarket
@ -52,7 +54,7 @@ suite "Sales":
test "ignores request when no matching storage is available":
sales.add(availability)
var tooBig = request
tooBig.size = request.size + 1
tooBig.ask.size = request.ask.size + 1
discard await market.requestStorage(tooBig)
check market.offered.len == 0

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