mirror of
https://github.com/logos-storage/logos-storage-nim.git
synced 2026-01-02 13:33:10 +00:00
* Add availability enabled parameter * Return bytes to availability when finished * Add until parameter * Remove debug message * Clean up and fix tests * Update documentations and cleanup * Avoid swallowing CancelledError * Move until validation to reservations module * Call onAvailabilityAdded callabck when the availability is enabled in sales * Remove until validation in restapi when creating an availability * Add openapi documentation * Use results instead of stew/results (#1112) * feat: request duration limit (#1057) * feat: request duration limit * Fix tests and duration type * Add custom error * Remove merge issue * Update codex contracts eth * Update market config and fix test * Fix SlotReservationsConfig syntax * Update dependencies * test: remove doubled test * chore: update contracts repo --------- Co-authored-by: Arnaud <arnaud@status.im> * fix(statemachine): do not raise from state.run (#1115) * fix(statemachine): do not raise from state.run * fix rebase * fix exception handling in SaleProvingSimulated.prove - re-raise CancelledError - don't return State on CatchableError - expect the Proofs_InvalidProof custom error instead of checking a string * asyncSpawn salesagent.onCancelled This was swallowing a KeyError in one of the tests (fixed in the previous commit) * remove error handling states in asyncstatemachine * revert unneeded changes * formatting * PR feedback, logging updates * chore(integration): simplify block expiration integration test (#1100) * chore(integration): simplify block expiration integration test * clean up * fix after rebase * perf: contract storage optimizations (#1094) * perf: contract storage optimizations * Apply optimization changes * Apply optimizing parameters sizing * Update codex-contracts-eth * bump latest changes in contracts branch * Change requestDurationLimit to uint64 * fix tests * fix tests --------- Co-authored-by: Arnaud <arnaud@status.im> Co-authored-by: Eric <5089238+emizzle@users.noreply.github.com> * bump contracts to master (#1122) * Add availability enabled parameter * Return bytes to availability when finished * Add until parameter * Clean up and fix tests * Move until validation to reservations module * Apply suggestion changes: return the reservation module error * Apply suggestion changes for until dates * Apply suggestion changes: reorganize tests * Fix indent * Remove test related to timing issue * Add raises errors to async pragram and remove useless try except * Update open api documentation * Fix wording * Remove the httpClient restart statements * Use market.getRequestEnd to set validUntil * Remove returnBytes * Use clock.now in testing * Move the api validation file to the right file --------- Co-authored-by: Adam Uhlíř <adam@uhlir.dev> Co-authored-by: Eric <5089238+emizzle@users.noreply.github.com>
385 lines
13 KiB
Nim
385 lines
13 KiB
Nim
import std/httpclient
|
|
import std/times
|
|
import pkg/ethers
|
|
import pkg/codex/manifest
|
|
import pkg/codex/conf
|
|
import pkg/codex/contracts
|
|
from pkg/codex/stores/repostore/types import DefaultQuotaBytes
|
|
import ../asynctest
|
|
import ../checktest
|
|
import ../examples
|
|
import ../codex/examples
|
|
import ./codexconfig
|
|
import ./codexprocess
|
|
|
|
from ./multinodes import Role, getTempDirName, jsonRpcProviderUrl, nextFreePort
|
|
|
|
# This suite allows to run fast the basic rest api validation.
|
|
# It starts only one node for all the checks in order to speed up
|
|
# the execution.
|
|
asyncchecksuite "Rest API validation":
|
|
var node: CodexProcess
|
|
var config = CodexConfigs.init(nodes = 1).configs[0]
|
|
let starttime = now().format("yyyy-MM-dd'_'HH:mm:ss")
|
|
let nodexIdx = 0
|
|
let datadir = getTempDirName(starttime, Role.Client, nodexIdx)
|
|
|
|
config.addCliOption("--api-port", $(waitFor nextFreePort(8081)))
|
|
config.addCliOption("--data-dir", datadir)
|
|
config.addCliOption("--nat", "none")
|
|
config.addCliOption("--listen-addrs", "/ip4/127.0.0.1/tcp/0")
|
|
config.addCliOption("--disc-port", $(waitFor nextFreePort(8081)))
|
|
config.addCliOption(StartUpCmd.persistence, "--eth-provider", jsonRpcProviderUrl)
|
|
config.addCliOption(StartUpCmd.persistence, "--eth-account", $EthAddress.example)
|
|
|
|
node =
|
|
waitFor CodexProcess.startNode(config.cliArgs, config.debugEnabled, $Role.Client)
|
|
|
|
waitFor node.waitUntilStarted()
|
|
|
|
let client = node.client()
|
|
|
|
test "should return 422 when attempting delete of non-existing dataset":
|
|
let data = await RandomChunker.example(blocks = 2)
|
|
let cid = (await client.upload(data)).get
|
|
let duration = 100.uint64
|
|
let pricePerBytePerSecond = 1.u256
|
|
let proofProbability = 3.u256
|
|
let expiry = 30.uint64
|
|
let collateralPerByte = 1.u256
|
|
let nodes = 3
|
|
let tolerance = 0
|
|
|
|
var responseBefore = await client.requestStorageRaw(
|
|
cid, duration, pricePerBytePerSecond, proofProbability, collateralPerByte, expiry,
|
|
nodes.uint, tolerance.uint,
|
|
)
|
|
|
|
check responseBefore.status == 422
|
|
check (await responseBefore.body) == "Tolerance needs to be bigger then zero"
|
|
|
|
test "request storage fails for datasets that are too small":
|
|
let cid = (await client.upload("some file contents")).get
|
|
let response = (
|
|
await client.requestStorageRaw(
|
|
cid,
|
|
duration = 10.uint64,
|
|
pricePerBytePerSecond = 1.u256,
|
|
proofProbability = 3.u256,
|
|
collateralPerByte = 1.u256,
|
|
expiry = 9.uint64,
|
|
)
|
|
)
|
|
|
|
check:
|
|
response.status == 422
|
|
(await response.body) ==
|
|
"Dataset too small for erasure parameters, need at least " &
|
|
$(2 * DefaultBlockSize.int) & " bytes"
|
|
|
|
test "request storage fails if nodes and tolerance aren't correct":
|
|
let data = await RandomChunker.example(blocks = 2)
|
|
let cid = (await client.upload(data)).get
|
|
let duration = 100.uint64
|
|
let pricePerBytePerSecond = 1.u256
|
|
let proofProbability = 3.u256
|
|
let expiry = 30.uint64
|
|
let collateralPerByte = 1.u256
|
|
let ecParams = @[(1, 1), (2, 1), (3, 2), (3, 3)]
|
|
|
|
for ecParam in ecParams:
|
|
let (nodes, tolerance) = ecParam
|
|
|
|
var responseBefore = (
|
|
await client.requestStorageRaw(
|
|
cid, duration, pricePerBytePerSecond, proofProbability, collateralPerByte,
|
|
expiry, nodes.uint, tolerance.uint,
|
|
)
|
|
)
|
|
|
|
check responseBefore.status == 422
|
|
check (await responseBefore.body) ==
|
|
"Invalid parameters: parameters must satify `1 < (nodes - tolerance) ≥ tolerance`"
|
|
|
|
test "request storage fails if tolerance > nodes (underflow protection)":
|
|
let data = await RandomChunker.example(blocks = 2)
|
|
let cid = (await client.upload(data)).get
|
|
let duration = 100.uint64
|
|
let pricePerBytePerSecond = 1.u256
|
|
let proofProbability = 3.u256
|
|
let expiry = 30.uint64
|
|
let collateralPerByte = 1.u256
|
|
let nodes = 3
|
|
let tolerance = 0
|
|
|
|
var responseBefore = (
|
|
await client.requestStorageRaw(
|
|
cid, duration, pricePerBytePerSecond, proofProbability, collateralPerByte,
|
|
expiry, nodes.uint, tolerance.uint,
|
|
)
|
|
)
|
|
|
|
check responseBefore.status == 422
|
|
check (await responseBefore.body) == "Tolerance needs to be bigger then zero"
|
|
|
|
test "upload fails if content disposition contains bad filename":
|
|
let headers = @[("Content-Disposition", "attachment; filename=\"exam*ple.txt\"")]
|
|
let response = await client.uploadRaw("some file contents", headers)
|
|
|
|
check response.status == 422
|
|
check (await response.body) == "The filename is not valid."
|
|
|
|
test "upload fails if content type is invalid":
|
|
let headers = @[("Content-Type", "hello/world")]
|
|
let response = await client.uploadRaw("some file contents", headers)
|
|
|
|
check response.status == 422
|
|
check (await response.body) == "The MIME type 'hello/world' is not valid."
|
|
|
|
test "updating non-existing availability":
|
|
let nonExistingResponse = await client.patchAvailabilityRaw(
|
|
AvailabilityId.example,
|
|
duration = 100.uint64.some,
|
|
minPricePerBytePerSecond = 2.u256.some,
|
|
totalCollateral = 200.u256.some,
|
|
)
|
|
check nonExistingResponse.status == 404
|
|
|
|
test "updating availability - freeSize is not allowed to be changed":
|
|
let availability = (
|
|
await client.postAvailability(
|
|
totalSize = 140000.uint64,
|
|
duration = 200.uint64,
|
|
minPricePerBytePerSecond = 3.u256,
|
|
totalCollateral = 300.u256,
|
|
)
|
|
).get
|
|
let freeSizeResponse =
|
|
await client.patchAvailabilityRaw(availability.id, freeSize = 110000.uint64.some)
|
|
check freeSizeResponse.status == 422
|
|
check "not allowed" in (await freeSizeResponse.body)
|
|
|
|
test "creating availability above the node quota returns 422":
|
|
let response = await client.postAvailabilityRaw(
|
|
totalSize = 24000000000.uint64,
|
|
duration = 200.uint64,
|
|
minPricePerBytePerSecond = 3.u256,
|
|
totalCollateral = 300.u256,
|
|
)
|
|
|
|
check response.status == 422
|
|
check (await response.body) == "Not enough storage quota"
|
|
|
|
test "updating availability above the node quota returns 422":
|
|
let availability = (
|
|
await client.postAvailability(
|
|
totalSize = 140000.uint64,
|
|
duration = 200.uint64,
|
|
minPricePerBytePerSecond = 3.u256,
|
|
totalCollateral = 300.u256,
|
|
)
|
|
).get
|
|
let response = await client.patchAvailabilityRaw(
|
|
availability.id, totalSize = 24000000000.uint64.some
|
|
)
|
|
|
|
check response.status == 422
|
|
check (await response.body) == "Not enough storage quota"
|
|
|
|
test "creating availability when total size is zero returns 422":
|
|
let response = await client.postAvailabilityRaw(
|
|
totalSize = 0.uint64,
|
|
duration = 200.uint64,
|
|
minPricePerBytePerSecond = 3.u256,
|
|
totalCollateral = 300.u256,
|
|
)
|
|
|
|
check response.status == 422
|
|
check (await response.body) == "Total size must be larger then zero"
|
|
|
|
test "updating availability when total size is zero returns 422":
|
|
let availability = (
|
|
await client.postAvailability(
|
|
totalSize = 140000.uint64,
|
|
duration = 200.uint64,
|
|
minPricePerBytePerSecond = 3.u256,
|
|
totalCollateral = 300.u256,
|
|
)
|
|
).get
|
|
let response =
|
|
await client.patchAvailabilityRaw(availability.id, totalSize = 0.uint64.some)
|
|
|
|
check response.status == 422
|
|
check (await response.body) == "Total size must be larger then zero"
|
|
|
|
test "creating availability when total size is negative returns 422":
|
|
let json =
|
|
%*{
|
|
"totalSize": "-1",
|
|
"duration": "200",
|
|
"minPricePerBytePerSecond": "3",
|
|
"totalCollateral": "300",
|
|
}
|
|
let response = await client.post(client.buildUrl("/sales/availability"), $json)
|
|
|
|
check response.status == 400
|
|
check (await response.body) == "Parsed integer outside of valid range"
|
|
|
|
test "updating availability when total size is negative returns 422":
|
|
let availability = (
|
|
await client.postAvailability(
|
|
totalSize = 140000.uint64,
|
|
duration = 200.uint64,
|
|
minPricePerBytePerSecond = 3.u256,
|
|
totalCollateral = 300.u256,
|
|
)
|
|
).get
|
|
|
|
let json = %*{"totalSize": "-1"}
|
|
let response = await client.patch(
|
|
client.buildUrl("/sales/availability/") & $availability.id, $json
|
|
)
|
|
|
|
check response.status == 400
|
|
check (await response.body) == "Parsed integer outside of valid range"
|
|
|
|
test "request storage fails if tolerance is zero":
|
|
let data = await RandomChunker.example(blocks = 2)
|
|
let cid = (await client.upload(data)).get
|
|
let duration = 100.uint64
|
|
let pricePerBytePerSecond = 1.u256
|
|
let proofProbability = 3.u256
|
|
let expiry = 30.uint64
|
|
let collateralPerByte = 1.u256
|
|
let nodes = 3
|
|
let tolerance = 0
|
|
|
|
var responseBefore = (
|
|
await client.requestStorageRaw(
|
|
cid, duration, pricePerBytePerSecond, proofProbability, collateralPerByte,
|
|
expiry, nodes.uint, tolerance.uint,
|
|
)
|
|
)
|
|
|
|
check responseBefore.status == 422
|
|
check (await responseBefore.body) == "Tolerance needs to be bigger then zero"
|
|
|
|
test "request storage fails if duration exceeds limit":
|
|
let data = await RandomChunker.example(blocks = 2)
|
|
let cid = (await client.upload(data)).get
|
|
let duration = (31 * 24 * 60 * 60).uint64
|
|
# 31 days TODO: this should not be hardcoded, but waits for https://github.com/codex-storage/nim-codex/issues/1056
|
|
let proofProbability = 3.u256
|
|
let expiry = 30.uint
|
|
let collateralPerByte = 1.u256
|
|
let nodes = 3
|
|
let tolerance = 2
|
|
let pricePerBytePerSecond = 1.u256
|
|
|
|
var responseBefore = (
|
|
await client.requestStorageRaw(
|
|
cid, duration, pricePerBytePerSecond, proofProbability, collateralPerByte,
|
|
expiry, nodes.uint, tolerance.uint,
|
|
)
|
|
)
|
|
|
|
check responseBefore.status == 422
|
|
check "Duration exceeds limit of" in (await responseBefore.body)
|
|
|
|
test "request storage fails if expiry is zero":
|
|
let data = await RandomChunker.example(blocks = 2)
|
|
let cid = (await client.upload(data)).get
|
|
let duration = 100.uint64
|
|
let pricePerBytePerSecond = 1.u256
|
|
let proofProbability = 3.u256
|
|
let expiry = 0.uint64
|
|
let collateralPerByte = 1.u256
|
|
let nodes = 3
|
|
let tolerance = 1
|
|
|
|
var responseBefore = await client.requestStorageRaw(
|
|
cid, duration, pricePerBytePerSecond, proofProbability, collateralPerByte, expiry,
|
|
nodes.uint, tolerance.uint,
|
|
)
|
|
|
|
check responseBefore.status == 422
|
|
check (await responseBefore.body) ==
|
|
"Expiry must be greater than zero and less than the request's duration"
|
|
|
|
test "request storage fails if proof probability is zero":
|
|
let data = await RandomChunker.example(blocks = 2)
|
|
let cid = (await client.upload(data)).get
|
|
let duration = 100.uint64
|
|
let pricePerBytePerSecond = 1.u256
|
|
let proofProbability = 0.u256
|
|
let expiry = 30.uint64
|
|
let collateralPerByte = 1.u256
|
|
let nodes = 3
|
|
let tolerance = 1
|
|
|
|
var responseBefore = await client.requestStorageRaw(
|
|
cid, duration, pricePerBytePerSecond, proofProbability, collateralPerByte, expiry,
|
|
nodes.uint, tolerance.uint,
|
|
)
|
|
|
|
check responseBefore.status == 422
|
|
check (await responseBefore.body) == "Proof probability must be greater than zero"
|
|
|
|
test "request storage fails if price per byte per second is zero":
|
|
let data = await RandomChunker.example(blocks = 2)
|
|
let cid = (await client.upload(data)).get
|
|
let duration = 100.uint64
|
|
let pricePerBytePerSecond = 0.u256
|
|
let proofProbability = 3.u256
|
|
let expiry = 30.uint64
|
|
let collateralPerByte = 1.u256
|
|
let nodes = 3
|
|
let tolerance = 1
|
|
|
|
var responseBefore = await client.requestStorageRaw(
|
|
cid, duration, pricePerBytePerSecond, proofProbability, collateralPerByte, expiry,
|
|
nodes.uint, tolerance.uint,
|
|
)
|
|
|
|
check responseBefore.status == 422
|
|
check (await responseBefore.body) ==
|
|
"Price per byte per second must be greater than zero"
|
|
|
|
test "request storage fails if collareral per byte is zero":
|
|
let data = await RandomChunker.example(blocks = 2)
|
|
let cid = (await client.upload(data)).get
|
|
let duration = 100.uint64
|
|
let pricePerBytePerSecond = 1.u256
|
|
let proofProbability = 3.u256
|
|
let expiry = 30.uint64
|
|
let collateralPerByte = 0.u256
|
|
let nodes = 3
|
|
let tolerance = 1
|
|
|
|
var responseBefore = await client.requestStorageRaw(
|
|
cid, duration, pricePerBytePerSecond, proofProbability, collateralPerByte, expiry,
|
|
nodes.uint, tolerance.uint,
|
|
)
|
|
|
|
check responseBefore.status == 422
|
|
check (await responseBefore.body) == "Collateral per byte must be greater than zero"
|
|
|
|
test "creating availability fails when until is negative":
|
|
let totalSize = 12.uint64
|
|
let minPricePerBytePerSecond = 1.u256
|
|
let totalCollateral = totalSize.u256 * minPricePerBytePerSecond
|
|
let response = await client.postAvailabilityRaw(
|
|
totalSize = totalSize,
|
|
duration = 2.uint64,
|
|
minPricePerBytePerSecond = minPricePerBytePerSecond,
|
|
totalCollateral = totalCollateral,
|
|
until = -1.SecondsSince1970.some,
|
|
)
|
|
|
|
check:
|
|
response.status == 422
|
|
(await response.body) == "Cannot set until to a negative value"
|
|
|
|
waitFor node.stop()
|
|
node.removeDataDir()
|