2023-03-27 13:47:25 +00:00
|
|
|
import std/httpclient
|
|
|
|
import std/strutils
|
2023-11-21 00:14:06 +00:00
|
|
|
|
2023-09-01 05:44:41 +00:00
|
|
|
from pkg/libp2p import Cid, `$`, init
|
|
|
|
import pkg/chronicles
|
2023-03-27 13:47:25 +00:00
|
|
|
import pkg/stint
|
|
|
|
import pkg/questionable/results
|
2023-09-01 05:44:41 +00:00
|
|
|
import pkg/codex/rest/json
|
|
|
|
import pkg/codex/purchasing
|
|
|
|
import pkg/codex/errors
|
|
|
|
import pkg/codex/sales/reservations
|
2023-03-27 13:47:25 +00:00
|
|
|
|
2023-10-31 23:49:12 +00:00
|
|
|
export purchasing
|
|
|
|
|
2023-03-27 13:47:25 +00:00
|
|
|
type CodexClient* = ref object
|
|
|
|
http: HttpClient
|
|
|
|
baseurl: string
|
|
|
|
|
|
|
|
proc new*(_: type CodexClient, baseurl: string): CodexClient =
|
|
|
|
CodexClient(http: newHttpClient(), baseurl: baseurl)
|
|
|
|
|
|
|
|
proc info*(client: CodexClient): JsonNode =
|
|
|
|
let url = client.baseurl & "/debug/info"
|
|
|
|
client.http.getContent(url).parseJson()
|
|
|
|
|
|
|
|
proc setLogLevel*(client: CodexClient, level: string) =
|
|
|
|
let url = client.baseurl & "/debug/chronicles/loglevel?level=" & level
|
|
|
|
let headers = newHttpHeaders({"Content-Type": "text/plain"})
|
|
|
|
let response = client.http.request(url, httpMethod=HttpPost, headers=headers)
|
|
|
|
assert response.status == "200 OK"
|
|
|
|
|
2023-09-01 05:44:41 +00:00
|
|
|
proc upload*(client: CodexClient, contents: string): ?!Cid =
|
2023-11-09 08:47:09 +00:00
|
|
|
let response = client.http.post(client.baseurl & "/data", contents)
|
2023-03-27 13:47:25 +00:00
|
|
|
assert response.status == "200 OK"
|
2023-09-01 05:44:41 +00:00
|
|
|
Cid.init(response.body).mapFailure
|
2023-03-27 13:47:25 +00:00
|
|
|
|
2023-11-21 00:14:06 +00:00
|
|
|
proc download*(client: CodexClient, cid: Cid, local = false): ?!string =
|
|
|
|
let
|
|
|
|
response = client.http.get(
|
|
|
|
client.baseurl & "/data/" & $cid &
|
|
|
|
(if local: "" else: "/network"))
|
|
|
|
|
|
|
|
if response.status != "200 OK":
|
|
|
|
return failure(response.status)
|
|
|
|
|
|
|
|
success response.body
|
|
|
|
|
|
|
|
proc list*(client: CodexClient): ?!seq[RestContent] =
|
|
|
|
let url = client.baseurl & "/data"
|
|
|
|
let response = client.http.get(url)
|
|
|
|
|
|
|
|
if response.status != "200 OK":
|
|
|
|
return failure(response.status)
|
|
|
|
|
|
|
|
let json = ? parseJson(response.body).catch
|
|
|
|
seq[RestContent].fromJson(json)
|
|
|
|
|
2023-11-22 11:35:26 +00:00
|
|
|
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)
|
|
|
|
|
2023-06-22 15:11:18 +00:00
|
|
|
proc requestStorage*(
|
|
|
|
client: CodexClient,
|
2023-09-01 05:44:41 +00:00
|
|
|
cid: Cid,
|
|
|
|
duration: UInt256,
|
|
|
|
reward: UInt256,
|
|
|
|
proofProbability: UInt256,
|
2023-06-22 15:11:18 +00:00
|
|
|
expiry: UInt256,
|
2023-09-01 05:44:41 +00:00
|
|
|
collateral: UInt256,
|
|
|
|
nodes: uint = 1,
|
|
|
|
tolerance: uint = 0
|
|
|
|
): ?!PurchaseId =
|
2023-06-22 15:11:18 +00:00
|
|
|
## Call request storage REST endpoint
|
2023-09-01 05:44:41 +00:00
|
|
|
##
|
2023-11-22 11:35:26 +00:00
|
|
|
let response = client.requestStorageRaw(cid, duration, reward, proofProbability, collateral, expiry, nodes, tolerance)
|
2023-03-27 13:47:25 +00:00
|
|
|
assert response.status == "200 OK"
|
2023-09-01 05:44:41 +00:00
|
|
|
PurchaseId.fromHex(response.body).catch
|
2023-03-27 13:47:25 +00:00
|
|
|
|
2023-09-01 05:44:41 +00:00
|
|
|
proc getPurchase*(client: CodexClient, purchaseId: PurchaseId): ?!RestPurchase =
|
|
|
|
let url = client.baseurl & "/storage/purchases/" & purchaseId.toHex
|
2023-12-05 07:58:21 +00:00
|
|
|
try:
|
|
|
|
let body = client.http.getContent(url)
|
|
|
|
let json = ? parseJson(body).catch
|
|
|
|
return RestPurchase.fromJson(json)
|
|
|
|
except CatchableError as e:
|
|
|
|
return failure e.msg
|
2023-03-27 13:47:25 +00:00
|
|
|
|
2023-11-02 12:00:35 +00:00
|
|
|
proc getSalesAgent*(client: CodexClient, slotId: SlotId): ?!RestSalesAgent =
|
|
|
|
let url = client.baseurl & "/sales/slots/" & slotId.toHex
|
|
|
|
try:
|
|
|
|
let body = client.http.getContent(url)
|
|
|
|
let json = ? parseJson(body).catch
|
|
|
|
return RestSalesAgent.fromJson(json)
|
|
|
|
except CatchableError as e:
|
|
|
|
return failure e.msg
|
|
|
|
|
2023-10-24 10:12:54 +00:00
|
|
|
proc getSlots*(client: CodexClient): ?!seq[Slot] =
|
2023-06-20 12:52:15 +00:00
|
|
|
let url = client.baseurl & "/sales/slots"
|
|
|
|
let body = client.http.getContent(url)
|
2023-10-24 10:12:54 +00:00
|
|
|
let json = ? parseJson(body).catch
|
|
|
|
seq[Slot].fromJson(json)
|
2023-06-20 12:52:15 +00:00
|
|
|
|
2023-06-22 15:11:18 +00:00
|
|
|
proc postAvailability*(
|
|
|
|
client: CodexClient,
|
2023-09-01 05:44:41 +00:00
|
|
|
size, duration, minPrice, maxCollateral: UInt256
|
|
|
|
): ?!Availability =
|
2023-06-22 15:11:18 +00:00
|
|
|
## Post sales availability endpoint
|
2023-09-01 05:44:41 +00:00
|
|
|
##
|
2023-03-27 13:47:25 +00:00
|
|
|
let url = client.baseurl & "/sales/availability"
|
|
|
|
let json = %*{
|
2023-09-01 05:44:41 +00:00
|
|
|
"size": size,
|
|
|
|
"duration": duration,
|
|
|
|
"minPrice": minPrice,
|
|
|
|
"maxCollateral": maxCollateral,
|
2023-03-27 13:47:25 +00:00
|
|
|
}
|
|
|
|
let response = client.http.post(url, $json)
|
fix: unknown state goes to payout when slot state is finished (#555)
Support logging to file
Log the entire config and fix build error
Process slot queue on reservation callback onMarkUnused
Add Reservation object, rename reserve > create
refactor Reservations api to include Reservation CRUD
All tests that use the Reservation module updated
- add requestId and slotIndex to Reservation (hopefully these will prove to be useful when we persist Reservations until request are completed, to add back bytes to Availability)
- add querying of all reservations, with accompanying tests
- change from find to findAvailabilities
- move onCleanUp from SalesContext to SalesAgent as it was getting overwritten for each slot processed
- remove sales agent AFTER deleting reservation, as this was causing some SIGSEGVs
- retrofit testsales and testslotqueue to match updated Reservations module API
Add deletion of inactive reservations on sales load
clean up
add exception message detail util
Apply to onStore errors as we are seeing undetailed errors in the dist tests logs
add missing file
change slotsize to reflect current implemenation
Fix slotSize to reduce by one block
Revert change to slotSize that reduces it by one block
Add additional test check for querying reservations/availabilities
filter past requests based on availability
Because availability filtering on push was removed, when availability is added and past storage request events are queried, those requests need to be filtered by availability before being added to the queue.
Revert "filter past requests based on availability"
This reverts commit 0c2362658b523e0de425794b1fa30ebd53bd30ae.
Add debugging for dist tests
Add cancel on error during filling state
When calling fillSlot, any transaction errors that occur (possibly during estimate gas) will cause that tx to be replaced with a cancellation transaction (a 0-valued tx to ourselves).
more debug logging
fix build
wait for fillSlot to be mined (so that a revert error can be extracted)
fix confirmation of fillSlot
add more debugging
moar debugging
debugging: change echo to trace
bump ethers to add chronicles
fix contracts tests
switch to earlier nim-ethers commit
bump json-rpc and nim-ethers
bump nim-ethers to prevent parsing newHeads log from crashing sales state machine
moar debugging
moar debugging
moar debugging
bump ethers to fix "key not found: data" error
ethers debug logging
bump ethers - better Transaction object deserialization
bump ethers to replay tx with past tx format
bump ethers to add serialization for PastTransaction
ethers bump: better logging, separate logic for revert reason string
fix build
ethers: update revert reason retreival
remove unneeded confirm
ethers: try replay without decrementing blockNumber
ethers: include type and chainId in replayed txs
ethers: add gas into and remove type from replayed txs
ensure gas is being serialized in Transaction
ethers: fix build error
bump ethers: rebased on top of cancel tx due to estimateGas error PR
Fix proving with latest ethers bump (tested on master)
Update multinode suite for better simulateFailedProofs enabling, add proofs test
Improve multinode suite for better debug options, including logging to file
There is a 503 "sales unavailable" error
improve multinode test suite, add logging to file
2023-09-27 13:57:41 +00:00
|
|
|
doAssert response.status == "200 OK", "expected 200 OK, got " & response.status & ", body: " & response.body
|
2023-09-01 05:44:41 +00:00
|
|
|
Availability.fromJson(response.body.parseJson)
|
2023-03-27 13:47:25 +00:00
|
|
|
|
2023-09-01 05:44:41 +00:00
|
|
|
proc getAvailabilities*(client: CodexClient): ?!seq[Availability] =
|
2023-06-22 15:11:18 +00:00
|
|
|
## Call sales availability REST endpoint
|
2023-03-27 13:47:25 +00:00
|
|
|
let url = client.baseurl & "/sales/availability"
|
|
|
|
let body = client.http.getContent(url)
|
2023-09-01 05:44:41 +00:00
|
|
|
seq[Availability].fromJson(parseJson(body))
|
2023-03-27 13:47:25 +00:00
|
|
|
|
|
|
|
proc close*(client: CodexClient) =
|
|
|
|
client.http.close()
|
|
|
|
|
|
|
|
proc restart*(client: CodexClient) =
|
|
|
|
client.http.close()
|
|
|
|
client.http = newHttpClient()
|
2023-10-26 04:47:08 +00:00
|
|
|
|
2023-10-31 23:49:12 +00:00
|
|
|
proc purchaseStateIs*(client: CodexClient, id: PurchaseId, state: string): bool =
|
2023-11-09 03:20:29 +00:00
|
|
|
without purchase =? client.getPurchase(id):
|
|
|
|
return false
|
|
|
|
return purchase.state == state
|
2023-10-31 23:49:12 +00:00
|
|
|
|
2023-11-02 12:00:35 +00:00
|
|
|
proc saleStateIs*(client: CodexClient, id: SlotId, state: string): bool =
|
2023-11-09 03:20:29 +00:00
|
|
|
without agent =? client.getSalesAgent(id):
|
|
|
|
return false
|
|
|
|
return agent.state == state
|
2023-11-02 12:00:35 +00:00
|
|
|
|
2023-10-31 23:49:12 +00:00
|
|
|
proc requestId*(client: CodexClient, id: PurchaseId): ?RequestId =
|
|
|
|
return client.getPurchase(id).option.?requestId
|