fix: require expiry from api (#629)
Co-authored-by: markspanbroek <mark@spanbroek.net>
This commit is contained in:
parent
8681a40ee7
commit
79fce39dbf
|
@ -34,6 +34,7 @@ import ./utils/fileutils
|
|||
import ./erasure
|
||||
import ./discovery
|
||||
import ./contracts
|
||||
import ./systemclock
|
||||
import ./contracts/clock
|
||||
import ./contracts/deployment
|
||||
import ./utils/addrutils
|
||||
|
@ -55,12 +56,15 @@ type
|
|||
EthWallet = ethers.Wallet
|
||||
|
||||
proc bootstrapInteractions(
|
||||
config: CodexConf,
|
||||
repo: RepoStore
|
||||
): Future[Contracts] {.async.} =
|
||||
s: CodexServer
|
||||
): Future[void] {.async.} =
|
||||
## bootstrap interactions and return contracts
|
||||
## using clients, hosts, validators pairings
|
||||
##
|
||||
let
|
||||
config = s.config
|
||||
repo = s.repoStore
|
||||
|
||||
|
||||
if not config.persistence and not config.validator:
|
||||
if config.ethAccount.isSome or config.ethPrivateKey.isSome:
|
||||
|
@ -106,6 +110,11 @@ proc bootstrapInteractions(
|
|||
var host: ?HostInteractions
|
||||
var validator: ?ValidatorInteractions
|
||||
|
||||
if config.validator or config.persistence:
|
||||
s.codexNode.clock = clock
|
||||
else:
|
||||
s.codexNode.clock = SystemClock()
|
||||
|
||||
if config.persistence:
|
||||
# This is used for simulation purposes. Normal nodes won't be compiled with this flag
|
||||
# and hence the proof failure will always be 0.
|
||||
|
@ -126,7 +135,7 @@ proc bootstrapInteractions(
|
|||
let validation = Validation.new(clock, market, config.validatorMaxSlots)
|
||||
validator = some ValidatorInteractions.new(clock, validation)
|
||||
|
||||
return (client, host, validator)
|
||||
s.codexNode.contracts = (client, host, validator)
|
||||
|
||||
proc start*(s: CodexServer) {.async.} =
|
||||
trace "Starting codex node", config = $s.config
|
||||
|
@ -161,7 +170,7 @@ proc start*(s: CodexServer) {.async.} =
|
|||
s.codexNode.discovery.updateAnnounceRecord(announceAddrs)
|
||||
s.codexNode.discovery.updateDhtRecord(s.config.nat, s.config.discoveryPort)
|
||||
|
||||
s.codexNode.contracts = await bootstrapInteractions(s.config, s.repoStore)
|
||||
await s.bootstrapInteractions()
|
||||
await s.codexNode.start()
|
||||
s.restServer.start()
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ type
|
|||
clock*: Clock
|
||||
|
||||
method start*(self: ContractInteractions) {.async, base.} =
|
||||
await self.clock.start()
|
||||
discard
|
||||
|
||||
method stop*(self: ContractInteractions) {.async, base.} =
|
||||
await self.clock.stop()
|
||||
discard
|
||||
|
|
|
@ -26,6 +26,7 @@ import pkg/libp2p/routing_record
|
|||
import pkg/libp2p/signed_envelope
|
||||
|
||||
import ./chunker
|
||||
import ./clock
|
||||
import ./blocktype as bt
|
||||
import ./manifest
|
||||
import ./merkletree
|
||||
|
@ -62,6 +63,7 @@ type
|
|||
erasure*: Erasure
|
||||
discovery*: Discovery
|
||||
contracts*: Contracts
|
||||
clock*: Clock
|
||||
|
||||
OnManifest* = proc(cid: Cid, manifest: Manifest): void {.gcsafe, closure.}
|
||||
|
||||
|
@ -320,7 +322,7 @@ proc requestStorage*(
|
|||
tolerance: uint,
|
||||
reward: UInt256,
|
||||
collateral: UInt256,
|
||||
expiry = UInt256.none): Future[?!PurchaseId] {.async.} =
|
||||
expiry: UInt256): Future[?!PurchaseId] {.async.} =
|
||||
## Initiate a request for storage sequence, this might
|
||||
## be a multistep procedure.
|
||||
##
|
||||
|
@ -384,7 +386,7 @@ proc requestStorage*(
|
|||
name: @[] # TODO: PoR setup
|
||||
)
|
||||
),
|
||||
expiry: expiry |? 0.u256
|
||||
expiry: expiry
|
||||
)
|
||||
|
||||
let purchase = await contracts.purchasing.purchase(request)
|
||||
|
@ -418,6 +420,9 @@ proc start*(node: CodexNodeRef) {.async.} =
|
|||
if not node.discovery.isNil:
|
||||
await node.discovery.start()
|
||||
|
||||
if not node.clock.isNil:
|
||||
await node.clock.start()
|
||||
|
||||
if hostContracts =? node.contracts.host:
|
||||
# TODO: remove Sales callbacks, pass BlockStore and StorageProofs instead
|
||||
hostContracts.sales.onStore = proc(request: StorageRequest,
|
||||
|
@ -499,6 +504,9 @@ proc stop*(node: CodexNodeRef) {.async.} =
|
|||
if not node.discovery.isNil:
|
||||
await node.discovery.stop()
|
||||
|
||||
if not node.clock.isNil:
|
||||
await node.clock.stop()
|
||||
|
||||
if clientContracts =? node.contracts.client:
|
||||
await clientContracts.stop()
|
||||
|
||||
|
|
|
@ -270,6 +270,9 @@ proc initPurchasingApi(node: CodexNodeRef, router: var RestRouter) =
|
|||
## colateral - requested collateral from hosts when they fill slot
|
||||
|
||||
try:
|
||||
without contracts =? node.contracts.client:
|
||||
return RestApiResponse.error(Http503, "Purchasing unavailable")
|
||||
|
||||
without cid =? cid.tryGet.catch, error:
|
||||
return RestApiResponse.error(Http400, error.msg)
|
||||
|
||||
|
@ -281,6 +284,15 @@ proc initPurchasingApi(node: CodexNodeRef, router: var RestRouter) =
|
|||
let nodes = params.nodes |? 1
|
||||
let tolerance = params.tolerance |? 0
|
||||
|
||||
without expiry =? params.expiry:
|
||||
return RestApiResponse.error(Http400, "Expiry required")
|
||||
|
||||
if node.clock.isNil:
|
||||
return RestApiResponse.error(Http500)
|
||||
|
||||
if expiry <= node.clock.now.u256:
|
||||
return RestApiResponse.error(Http400, "Expiry needs to be in future")
|
||||
|
||||
without purchaseId =? await node.requestStorage(
|
||||
cid,
|
||||
params.duration,
|
||||
|
@ -289,7 +301,7 @@ proc initPurchasingApi(node: CodexNodeRef, router: var RestRouter) =
|
|||
tolerance,
|
||||
params.reward,
|
||||
params.collateral,
|
||||
params.expiry), error:
|
||||
expiry), error:
|
||||
|
||||
return RestApiResponse.error(Http500, error.msg)
|
||||
|
||||
|
|
|
@ -135,6 +135,7 @@ components:
|
|||
- duration
|
||||
- proofProbability
|
||||
- collateral
|
||||
- expiry
|
||||
properties:
|
||||
duration:
|
||||
$ref: "#/components/schemas/Duration"
|
||||
|
|
|
@ -54,6 +54,35 @@ proc list*(client: CodexClient): ?!seq[RestContent] =
|
|||
let json = ? parseJson(response.body).catch
|
||||
seq[RestContent].fromJson(json)
|
||||
|
||||
proc requestStorageRaw*(
|
||||
client: CodexClient,
|
||||
cid: Cid,
|
||||
duration: UInt256,
|
||||
reward: UInt256,
|
||||
proofProbability: UInt256,
|
||||
collateral: UInt256,
|
||||
expiry: UInt256 = 0.u256,
|
||||
nodes: uint = 1,
|
||||
tolerance: uint = 0
|
||||
): Response =
|
||||
|
||||
## Call request storage REST endpoint
|
||||
##
|
||||
let url = client.baseurl & "/storage/request/" & $cid
|
||||
let json = %*{
|
||||
"duration": duration,
|
||||
"reward": reward,
|
||||
"proofProbability": proofProbability,
|
||||
"collateral": collateral,
|
||||
"nodes": nodes,
|
||||
"tolerance": tolerance
|
||||
}
|
||||
|
||||
if expiry != 0:
|
||||
json["expiry"] = %expiry
|
||||
|
||||
return client.http.post(url, $json)
|
||||
|
||||
proc requestStorage*(
|
||||
client: CodexClient,
|
||||
cid: Cid,
|
||||
|
@ -67,17 +96,7 @@ proc requestStorage*(
|
|||
): ?!PurchaseId =
|
||||
## Call request storage REST endpoint
|
||||
##
|
||||
let url = client.baseurl & "/storage/request/" & $cid
|
||||
let json = %*{
|
||||
"duration": duration,
|
||||
"reward": reward,
|
||||
"proofProbability": proofProbability,
|
||||
"expiry": expiry,
|
||||
"collateral": collateral,
|
||||
"nodes": nodes,
|
||||
"tolerance": tolerance
|
||||
}
|
||||
let response = client.http.post(url, $json)
|
||||
let response = client.requestStorageRaw(cid, duration, reward, proofProbability, collateral, expiry, nodes, tolerance)
|
||||
assert response.status == "200 OK"
|
||||
PurchaseId.fromHex(response.body).catch
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import std/options
|
||||
import std/sequtils
|
||||
import std/httpclient
|
||||
from pkg/libp2p import `==`
|
||||
import pkg/chronos
|
||||
import pkg/stint
|
||||
|
@ -216,6 +217,19 @@ twonodessuite "Integration tests", debug1 = false, debug2 = false:
|
|||
|
||||
check eventually (await token.balanceOf(account2)) - startBalance == duration*reward
|
||||
|
||||
test "node requires expiry and its value to be in future":
|
||||
let currentTime = await provider.currentTime()
|
||||
let cid = client1.upload("some file contents").get
|
||||
|
||||
let responseMissing = client1.requestStorageRaw(cid, duration=1.u256, reward=2.u256, proofProbability=3.u256, collateral=200.u256)
|
||||
check responseMissing.status == "400 Bad Request"
|
||||
check responseMissing.body == "Expiry required"
|
||||
|
||||
let responsePast = client1.requestStorageRaw(cid, duration=1.u256, reward=2.u256, proofProbability=3.u256, collateral=200.u256, expiry=currentTime-10)
|
||||
check responsePast.status == "400 Bad Request"
|
||||
check responsePast.body == "Expiry needs to be in future"
|
||||
|
||||
|
||||
test "expired request partially pays out for stored time":
|
||||
let marketplace = Marketplace.new(Marketplace.address, provider.getSigner())
|
||||
let tokenAddress = await marketplace.token()
|
||||
|
|
Loading…
Reference in New Issue