Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Applies multinodessuite in twonodessuite #1031

Merged
merged 19 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
1261f25
Sets timeout for codexclient httpClient. Adds reliable transfer test.
benbierens Dec 11, 2024
98843f3
disable new test to check timeout setting in CI
benbierens Dec 11, 2024
4c8788b
restores new test
benbierens Dec 11, 2024
cdaa924
Merge branch 'master' into feature/transfer-reliability-test
benbierens Dec 13, 2024
4c68959
Merge branch 'master' into feature/transfer-reliability-test
benbierens Dec 13, 2024
8b8b85f
adds heartbeat log and logfile to ci output
benbierens Dec 13, 2024
44c8ca7
Merge branch 'feature/transfer-reliability-test' of https://github.co…
benbierens Dec 13, 2024
661a3a4
fixes suite
benbierens Dec 13, 2024
c79c0af
fixes blocked output stream by switching to multinode fixture
benbierens Dec 16, 2024
de3a09d
new twonodessuite based on multinodesuite
benbierens Dec 16, 2024
b895c41
Applies updated twonodessuite
benbierens Dec 16, 2024
0d6fcee
Merge branch 'master' into feature/transfer-reliability-test
benbierens Dec 16, 2024
4170ded
removes heartbeat log
benbierens Dec 16, 2024
101df5e
applies multinodesuite in testsales
benbierens Dec 16, 2024
38c6eb1
applies multinodesuite in testmarketplace
benbierens Dec 16, 2024
d884b94
fixes account fetch for host and client in testmarketplace
benbierens Dec 16, 2024
ff0130c
adds waitTillNextPeriod at end of marketplace test
benbierens Dec 16, 2024
f1b1027
Uses marketplacesuite in testmarketplace
benbierens Dec 17, 2024
af0571a
Merge branch 'master' into feature/transfer-reliability-test
benbierens Dec 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions tests/integration/codexclient.nim
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ type CodexClient* = ref object

type CodexClientError* = object of CatchableError

const HttpClientTimeoutMs = 60 * 1000

proc new*(_: type CodexClient, baseurl: string): CodexClient =
CodexClient(
http: newHttpClient(),
http: newHttpClient(timeout=HttpClientTimeoutMs),
baseurl: baseurl,
session: HttpSessionRef.new({HttpClientFlag.Http11Pipeline})
)
Expand Down Expand Up @@ -247,7 +249,7 @@ proc close*(client: CodexClient) =

proc restart*(client: CodexClient) =
client.http.close()
client.http = newHttpClient()
client.http = newHttpClient(timeout=HttpClientTimeoutMs)

proc purchaseStateIs*(client: CodexClient, id: PurchaseId, state: string): bool =
client.getPurchase(id).option.?state == some state
Expand Down
6 changes: 3 additions & 3 deletions tests/integration/multinodes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ template multinodesuite*(name: string, body: untyped) =
let updatedLogFile = getLogFile(role, some roleIdx)
config.withLogFile(updatedLogFile)

if bootstrap.len > 0:
config.addCliOption("--bootstrap-node", bootstrap)
config.addCliOption("--api-port", $ await nextFreePort(8080 + nodeIdx))
config.addCliOption("--data-dir", datadir)
config.addCliOption("--nat", "127.0.0.1")
Expand Down Expand Up @@ -223,7 +225,6 @@ template multinodesuite*(name: string, body: untyped) =
proc startProviderNode(conf: CodexConfig): Future[NodeProcess] {.async.} =
let providerIdx = providers().len
var config = conf
config.addCliOption("--bootstrap-node", bootstrap)
config.addCliOption(StartUpCmd.persistence, "--eth-provider", jsonRpcProviderUrl)
config.addCliOption(StartUpCmd.persistence, "--eth-account", $accounts[running.len])
config.addCliOption(PersistenceCmd.prover, "--circom-r1cs",
Expand All @@ -238,7 +239,6 @@ template multinodesuite*(name: string, body: untyped) =
proc startValidatorNode(conf: CodexConfig): Future[NodeProcess] {.async.} =
let validatorIdx = validators().len
var config = conf
config.addCliOption("--bootstrap-node", bootstrap)
config.addCliOption(StartUpCmd.persistence, "--eth-provider", jsonRpcProviderUrl)
config.addCliOption(StartUpCmd.persistence, "--eth-account", $accounts[running.len])
config.addCliOption(StartUpCmd.persistence, "--validator")
Expand Down Expand Up @@ -311,7 +311,7 @@ template multinodesuite*(name: string, body: untyped) =
role: Role.Client,
node: node
)
if clients().len == 1:
if running.len == 1:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm sure there was a good reason for this, but could you please explain why? We don't want the running node to be a HardhatNode, which wouldn't give us what we want (bootstrap info)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is behind if var clients =? nodeConfigs.clients: and nodeConfigs.clients is of type ?CodexConfigs. So these should always be Codexes. I changed this because using clients() assumes that the config for this test has at least 1 client configured and that the client will always be started before any providers/validators (true because of the ordering of the code). If a user creates a config with only providers or validators, none of them would be used for bootstrap. With this change, the first node regardless of role will be the bootstrap node.

Copy link
Contributor

@emizzle emizzle Dec 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a user creates a configuration that runs a single hardhat node and at least one client node, running.len == 1 will never be true when processing the first client node. We don't want that.

Perhaps a better option would be to check that clients().len == 1 or providers.len() == 1

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a user creates a config with only providers or validators, none of them would be used for bootstrap. With this change, the first node regardless of role will be the bootstrap node.

Without a client config, there will be no bootstrap nodes, since this is nested under the iteration of clients.configs.

I've made some changes that add each started client and validator to a seq of bootstrap nodes, that are used to start the next node. That means each subsequently started node should be more connected to peers than the last. This also fixes the case when no clients were started, that bootstrap SPRs are still used. PR #1048

without ninfo =? CodexProcess(node).client.info():
# raise CatchableError instead of Defect (with .get or !) so we
# can gracefully shutdown and prevent zombies
Expand Down
12 changes: 8 additions & 4 deletions tests/integration/nodeprocess.nim
Original file line number Diff line number Diff line change
Expand Up @@ -147,16 +147,20 @@ method stop*(node: NodeProcess) {.base, async.} =

trace "node stopped"

proc waitUntilStarted*(node: NodeProcess) {.async.} =
proc waitUntilOutput*(node: NodeProcess, output: string) {.async.} =
logScope:
nodeName = node.name

trace "waiting until node started"
trace "waiting until", output

let started = newFuture[void]()
discard node.captureOutput(output, started).track(node)
await started.wait(60.seconds) # allow enough time for proof generation

proc waitUntilStarted*(node: NodeProcess) {.async.} =
let started = newFuture[void]()
try:
discard node.captureOutput(node.startedOutput, started).track(node)
await started.wait(60.seconds) # allow enough time for proof generation
await node.waitUntilOutput(node.startedOutput)
trace "node started"
except AsyncTimeoutError:
# attempt graceful shutdown in case node was partially started, prevent
Expand Down
91 changes: 0 additions & 91 deletions tests/integration/nodes.nim

This file was deleted.

23 changes: 13 additions & 10 deletions tests/integration/testblockexpiration.nim
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ from std/net import TimeoutError

import pkg/chronos
import ../ethertest
import ./nodes
import ./codexprocess
import ./nodeprocess

ethersuite "Node block expiration tests":
var node: NodeProcess
var node: CodexProcess
var baseurl: string

let dataDir = getTempDir() / "Codex1"
Expand All @@ -18,12 +19,12 @@ ethersuite "Node block expiration tests":
baseurl = "http://localhost:8080/api/codex/v1"

teardown:
node.stop()
await node.stop()

dataDir.removeDir()

proc startTestNode(blockTtlSeconds: int) =
node = startNode([
proc startTestNode(blockTtlSeconds: int) {.async.} =
node = await CodexProcess.startNode(@[
"--api-port=8080",
"--data-dir=" & dataDir,
"--nat=127.0.0.1",
Expand All @@ -32,9 +33,11 @@ ethersuite "Node block expiration tests":
"--disc-port=8090",
"--block-ttl=" & $blockTtlSeconds,
"--block-mi=1",
"--block-mn=10"
], debug = false)
node.waitUntilStarted()
"--block-mn=10"],
false,
"cli-test-node"
)
await node.waitUntilStarted()

proc uploadTestFile(): string =
let client = newHttpClient()
Expand All @@ -61,7 +64,7 @@ ethersuite "Node block expiration tests":
content.code == Http200

test "node retains not-expired file":
startTestNode(blockTtlSeconds = 10)
await startTestNode(blockTtlSeconds = 10)

let contentId = uploadTestFile()

Expand All @@ -74,7 +77,7 @@ ethersuite "Node block expiration tests":
response.body == content

test "node deletes expired file":
startTestNode(blockTtlSeconds = 1)
await startTestNode(blockTtlSeconds = 1)

let contentId = uploadTestFile()

Expand Down
45 changes: 27 additions & 18 deletions tests/integration/testcli.nim
Original file line number Diff line number Diff line change
@@ -1,57 +1,66 @@
import std/unittest
import std/tempfiles
import codex/conf
import codex/utils/fileutils
import ./nodes
import ../asynctest
import ../checktest
import ./codexprocess
import ./nodeprocess
import ../examples

suite "Command line interface":
asyncchecksuite "Command line interface":

let key = "4242424242424242424242424242424242424242424242424242424242424242"

proc startCodex(args: seq[string]): Future[CodexProcess] {.async.} =
return await CodexProcess.startNode(
args,
false,
"cli-test-node"
)

test "complains when persistence is enabled without ethereum account":
let node = startNode(@[
let node = await startCodex(@[
"persistence"
])
node.waitUntilOutput("Persistence enabled, but no Ethereum account was set")
node.stop()
await node.waitUntilOutput("Persistence enabled, but no Ethereum account was set")
await node.stop()

test "complains when ethereum private key file has wrong permissions":
let unsafeKeyFile = genTempPath("", "")
discard unsafeKeyFile.writeFile(key, 0o666)
let node = startNode(@[
let node = await startCodex(@[
"persistence",
"--eth-private-key=" & unsafeKeyFile])
node.waitUntilOutput("Ethereum private key file does not have safe file permissions")
node.stop()
await node.waitUntilOutput("Ethereum private key file does not have safe file permissions")
await node.stop()
discard removeFile(unsafeKeyFile)

let
marketplaceArg = "--marketplace-address=" & $EthAddress.example
expectedDownloadInstruction = "Proving circuit files are not found. Please run the following to download them:"

test "suggests downloading of circuit files when persistence is enabled without accessible r1cs file":
let node = startNode(@["persistence", "prover", marketplaceArg])
node.waitUntilOutput(expectedDownloadInstruction)
node.stop()
let node = await startCodex(@["persistence", "prover", marketplaceArg])
await node.waitUntilOutput(expectedDownloadInstruction)
await node.stop()

test "suggests downloading of circuit files when persistence is enabled without accessible wasm file":
let node = startNode(@[
let node = await startCodex(@[
"persistence",
"prover",
marketplaceArg,
"--circom-r1cs=tests/circuits/fixtures/proof_main.r1cs"
])
node.waitUntilOutput(expectedDownloadInstruction)
node.stop()
await node.waitUntilOutput(expectedDownloadInstruction)
await node.stop()

test "suggests downloading of circuit files when persistence is enabled without accessible zkey file":
let node = startNode(@[
let node = await startCodex(@[
"persistence",
"prover",
marketplaceArg,
"--circom-r1cs=tests/circuits/fixtures/proof_main.r1cs",
"--circom-wasm=tests/circuits/fixtures/proof_main.wasm"
])
node.waitUntilOutput(expectedDownloadInstruction)
node.stop()
await node.waitUntilOutput(expectedDownloadInstruction)
await node.stop()
Loading
Loading