rework cli to accept circuit params
This commit is contained in:
parent
9e13d2251a
commit
2e0f087389
141
codex.nim
141
codex.nim
|
@ -23,6 +23,7 @@ import ./codex/codex
|
||||||
import ./codex/logutils
|
import ./codex/logutils
|
||||||
import ./codex/units
|
import ./codex/units
|
||||||
import ./codex/utils/keyutils
|
import ./codex/utils/keyutils
|
||||||
|
import ./codex/codextypes
|
||||||
|
|
||||||
export codex, conf, libp2p, chronos, logutils
|
export codex, conf, libp2p, chronos, logutils
|
||||||
|
|
||||||
|
@ -54,91 +55,93 @@ when isMainModule:
|
||||||
config.setupLogging()
|
config.setupLogging()
|
||||||
config.setupMetrics()
|
config.setupMetrics()
|
||||||
|
|
||||||
case config.cmd:
|
if config.nat == ValidIpAddress.init(IPv4_any()):
|
||||||
of StartUpCommand.noCommand:
|
error "`--nat` cannot be set to the any (`0.0.0.0`) address"
|
||||||
|
quit QuitFailure
|
||||||
|
|
||||||
if config.nat == ValidIpAddress.init(IPv4_any()):
|
if config.nat == ValidIpAddress.init("127.0.0.1"):
|
||||||
error "`--nat` cannot be set to the any (`0.0.0.0`) address"
|
warn "`--nat` is set to loopback, your node wont properly announce over the DHT"
|
||||||
|
|
||||||
|
if not(checkAndCreateDataDir((config.dataDir).string)):
|
||||||
|
# We are unable to access/create data folder or data folder's
|
||||||
|
# permissions are insecure.
|
||||||
|
quit QuitFailure
|
||||||
|
|
||||||
|
trace "Data dir initialized", dir = $config.dataDir
|
||||||
|
|
||||||
|
if not(checkAndCreateDataDir((config.dataDir / "repo"))):
|
||||||
|
# We are unable to access/create data folder or data folder's
|
||||||
|
# permissions are insecure.
|
||||||
|
quit QuitFailure
|
||||||
|
|
||||||
|
trace "Repo dir initialized", dir = config.dataDir / "repo"
|
||||||
|
|
||||||
|
var
|
||||||
|
state: CodexStatus
|
||||||
|
pendingFuts: seq[Future[void]]
|
||||||
|
|
||||||
|
let
|
||||||
|
keyPath =
|
||||||
|
if isAbsolute(config.netPrivKeyFile):
|
||||||
|
config.netPrivKeyFile
|
||||||
|
else:
|
||||||
|
config.dataDir / config.netPrivKeyFile
|
||||||
|
|
||||||
|
privateKey = setupKey(keyPath).expect("Should setup private key!")
|
||||||
|
server = try:
|
||||||
|
CodexServer.new(config, privateKey)
|
||||||
|
except Exception as exc:
|
||||||
|
error "Failed to start Codex", msg = exc.msg
|
||||||
quit QuitFailure
|
quit QuitFailure
|
||||||
|
|
||||||
if config.nat == ValidIpAddress.init("127.0.0.1"):
|
## Ctrl+C handling
|
||||||
warn "`--nat` is set to loopback, your node wont properly announce over the DHT"
|
proc controlCHandler() {.noconv.} =
|
||||||
|
when defined(windows):
|
||||||
|
# workaround for https://github.com/nim-lang/Nim/issues/4057
|
||||||
|
try:
|
||||||
|
setupForeignThreadGc()
|
||||||
|
except Exception as exc: raiseAssert exc.msg # shouldn't happen
|
||||||
|
notice "Shutting down after having received SIGINT"
|
||||||
|
|
||||||
if not(checkAndCreateDataDir((config.dataDir).string)):
|
pendingFuts.add(server.stop())
|
||||||
# We are unable to access/create data folder or data folder's
|
state = CodexStatus.Stopping
|
||||||
# permissions are insecure.
|
|
||||||
quit QuitFailure
|
|
||||||
|
|
||||||
trace "Data dir initialized", dir = $config.dataDir
|
notice "Stopping Codex"
|
||||||
|
|
||||||
if not(checkAndCreateDataDir((config.dataDir / "repo"))):
|
try:
|
||||||
# We are unable to access/create data folder or data folder's
|
setControlCHook(controlCHandler)
|
||||||
# permissions are insecure.
|
except Exception as exc: # TODO Exception
|
||||||
quit QuitFailure
|
warn "Cannot set ctrl-c handler", msg = exc.msg
|
||||||
|
|
||||||
trace "Repo dir initialized", dir = config.dataDir / "repo"
|
# equivalent SIGTERM handler
|
||||||
|
when defined(posix):
|
||||||
var
|
proc SIGTERMHandler(signal: cint) {.noconv.} =
|
||||||
state: CodexStatus
|
notice "Shutting down after having received SIGTERM"
|
||||||
pendingFuts: seq[Future[void]]
|
|
||||||
|
|
||||||
let
|
|
||||||
keyPath =
|
|
||||||
if isAbsolute(config.netPrivKeyFile):
|
|
||||||
config.netPrivKeyFile
|
|
||||||
else:
|
|
||||||
config.dataDir / config.netPrivKeyFile
|
|
||||||
|
|
||||||
privateKey = setupKey(keyPath).expect("Should setup private key!")
|
|
||||||
server = CodexServer.new(config, privateKey)
|
|
||||||
|
|
||||||
## Ctrl+C handling
|
|
||||||
proc controlCHandler() {.noconv.} =
|
|
||||||
when defined(windows):
|
|
||||||
# workaround for https://github.com/nim-lang/Nim/issues/4057
|
|
||||||
try:
|
|
||||||
setupForeignThreadGc()
|
|
||||||
except Exception as exc: raiseAssert exc.msg # shouldn't happen
|
|
||||||
notice "Shutting down after having received SIGINT"
|
|
||||||
|
|
||||||
pendingFuts.add(server.stop())
|
pendingFuts.add(server.stop())
|
||||||
state = CodexStatus.Stopping
|
state = CodexStatus.Stopping
|
||||||
|
|
||||||
notice "Stopping Codex"
|
notice "Stopping Codex"
|
||||||
|
|
||||||
|
c_signal(ansi_c.SIGTERM, SIGTERMHandler)
|
||||||
|
|
||||||
|
pendingFuts.add(server.start())
|
||||||
|
|
||||||
|
state = CodexStatus.Running
|
||||||
|
while state == CodexStatus.Running:
|
||||||
try:
|
try:
|
||||||
setControlCHook(controlCHandler)
|
|
||||||
except Exception as exc: # TODO Exception
|
|
||||||
warn "Cannot set ctrl-c handler", msg = exc.msg
|
|
||||||
|
|
||||||
# equivalent SIGTERM handler
|
|
||||||
when defined(posix):
|
|
||||||
proc SIGTERMHandler(signal: cint) {.noconv.} =
|
|
||||||
notice "Shutting down after having received SIGTERM"
|
|
||||||
|
|
||||||
pendingFuts.add(server.stop())
|
|
||||||
state = CodexStatus.Stopping
|
|
||||||
|
|
||||||
notice "Stopping Codex"
|
|
||||||
|
|
||||||
c_signal(ansi_c.SIGTERM, SIGTERMHandler)
|
|
||||||
|
|
||||||
pendingFuts.add(server.start())
|
|
||||||
|
|
||||||
state = CodexStatus.Running
|
|
||||||
while state == CodexStatus.Running:
|
|
||||||
# poll chronos
|
# poll chronos
|
||||||
chronos.poll()
|
chronos.poll()
|
||||||
|
except Exception as exc:
|
||||||
# wait fot futures to finish
|
error "Unhandled exception in async proc, aborting", msg = exc.msg
|
||||||
let res = waitFor allFinished(pendingFuts)
|
|
||||||
state = CodexStatus.Stopped
|
|
||||||
|
|
||||||
if res.anyIt( it.failed ):
|
|
||||||
error "Codex didn't shutdown correctly"
|
|
||||||
quit QuitFailure
|
quit QuitFailure
|
||||||
|
|
||||||
notice "Exited codex"
|
# wait fot futures to finish
|
||||||
|
let res = waitFor allFinished(pendingFuts)
|
||||||
|
state = CodexStatus.Stopped
|
||||||
|
|
||||||
of StartUpCommand.initNode:
|
if res.anyIt( it.failed ):
|
||||||
discard
|
error "Codex didn't shutdown correctly"
|
||||||
|
quit QuitFailure
|
||||||
|
|
||||||
|
notice "Exited codex"
|
||||||
|
|
158
codex/codex.nim
158
codex/codex.nim
|
@ -22,12 +22,14 @@ import pkg/stew/io2
|
||||||
import pkg/stew/shims/net as stewnet
|
import pkg/stew/shims/net as stewnet
|
||||||
import pkg/datastore
|
import pkg/datastore
|
||||||
import pkg/ethers except Rng
|
import pkg/ethers except Rng
|
||||||
|
import pkg/stew/io2
|
||||||
|
|
||||||
import ./node
|
import ./node
|
||||||
import ./conf
|
import ./conf
|
||||||
import ./rng
|
import ./rng
|
||||||
import ./rest/api
|
import ./rest/api
|
||||||
import ./stores
|
import ./stores
|
||||||
|
import ./slots
|
||||||
import ./blockexchange
|
import ./blockexchange
|
||||||
import ./utils/fileutils
|
import ./utils/fileutils
|
||||||
import ./erasure
|
import ./erasure
|
||||||
|
@ -65,77 +67,70 @@ proc bootstrapInteractions(
|
||||||
config = s.config
|
config = s.config
|
||||||
repo = s.repoStore
|
repo = s.repoStore
|
||||||
|
|
||||||
|
|
||||||
if not config.persistence and not config.validator:
|
|
||||||
if config.ethAccount.isSome or config.ethPrivateKey.isSome:
|
|
||||||
warn "Ethereum account was set, but neither persistence nor validator is enabled"
|
|
||||||
return
|
|
||||||
|
|
||||||
if not config.ethAccount.isSome and not config.ethPrivateKey.isSome:
|
|
||||||
if config.persistence:
|
|
||||||
error "Persistence enabled, but no Ethereum account was set"
|
|
||||||
if config.validator:
|
|
||||||
error "Validator enabled, but no Ethereum account was set"
|
|
||||||
quit QuitFailure
|
|
||||||
|
|
||||||
let provider = JsonRpcProvider.new(config.ethProvider)
|
|
||||||
var signer: Signer
|
|
||||||
if account =? config.ethAccount:
|
|
||||||
signer = provider.getSigner(account)
|
|
||||||
elif keyFile =? config.ethPrivateKey:
|
|
||||||
without isSecure =? checkSecureFile(keyFile):
|
|
||||||
error "Could not check file permissions: does Ethereum private key file exist?"
|
|
||||||
quit QuitFailure
|
|
||||||
if not isSecure:
|
|
||||||
error "Ethereum private key file does not have safe file permissions"
|
|
||||||
quit QuitFailure
|
|
||||||
without key =? keyFile.readAllChars():
|
|
||||||
error "Unable to read Ethereum private key file"
|
|
||||||
quit QuitFailure
|
|
||||||
without wallet =? EthWallet.new(key.strip(), provider):
|
|
||||||
error "Invalid Ethereum private key in file"
|
|
||||||
quit QuitFailure
|
|
||||||
signer = wallet
|
|
||||||
|
|
||||||
let deploy = Deployment.new(provider, config)
|
|
||||||
without marketplaceAddress =? await deploy.address(Marketplace):
|
|
||||||
error "No Marketplace address was specified or there is no known address for the current network"
|
|
||||||
quit QuitFailure
|
|
||||||
|
|
||||||
let marketplace = Marketplace.new(marketplaceAddress, signer)
|
|
||||||
let market = OnChainMarket.new(marketplace)
|
|
||||||
let clock = OnChainClock.new(provider)
|
|
||||||
|
|
||||||
var client: ?ClientInteractions
|
|
||||||
var host: ?HostInteractions
|
|
||||||
var validator: ?ValidatorInteractions
|
|
||||||
|
|
||||||
if config.validator or config.persistence:
|
|
||||||
s.codexNode.clock = clock
|
|
||||||
else:
|
|
||||||
s.codexNode.clock = SystemClock()
|
|
||||||
|
|
||||||
if config.persistence:
|
if config.persistence:
|
||||||
# This is used for simulation purposes. Normal nodes won't be compiled with this flag
|
if not config.ethAccount.isSome and not config.ethPrivateKey.isSome:
|
||||||
# and hence the proof failure will always be 0.
|
error "Persistence enabled, but no Ethereum account was set"
|
||||||
when codex_enable_proof_failures:
|
quit QuitFailure
|
||||||
let proofFailures = config.simulateProofFailures
|
|
||||||
if proofFailures > 0:
|
let provider = JsonRpcProvider.new(config.ethProvider)
|
||||||
warn "Enabling proof failure simulation!"
|
var signer: Signer
|
||||||
|
if account =? config.ethAccount:
|
||||||
|
signer = provider.getSigner(account)
|
||||||
|
elif keyFile =? config.ethPrivateKey:
|
||||||
|
without isSecure =? checkSecureFile(keyFile):
|
||||||
|
error "Could not check file permissions: does Ethereum private key file exist?"
|
||||||
|
quit QuitFailure
|
||||||
|
if not isSecure:
|
||||||
|
error "Ethereum private key file does not have safe file permissions"
|
||||||
|
quit QuitFailure
|
||||||
|
without key =? keyFile.readAllChars():
|
||||||
|
error "Unable to read Ethereum private key file"
|
||||||
|
quit QuitFailure
|
||||||
|
without wallet =? EthWallet.new(key.strip(), provider):
|
||||||
|
error "Invalid Ethereum private key in file"
|
||||||
|
quit QuitFailure
|
||||||
|
signer = wallet
|
||||||
|
|
||||||
|
let deploy = Deployment.new(provider, config)
|
||||||
|
without marketplaceAddress =? await deploy.address(Marketplace):
|
||||||
|
error "No Marketplace address was specified or there is no known address for the current network"
|
||||||
|
quit QuitFailure
|
||||||
|
|
||||||
|
let marketplace = Marketplace.new(marketplaceAddress, signer)
|
||||||
|
let market = OnChainMarket.new(marketplace)
|
||||||
|
let clock = OnChainClock.new(provider)
|
||||||
|
|
||||||
|
var client: ?ClientInteractions
|
||||||
|
var host: ?HostInteractions
|
||||||
|
var validator: ?ValidatorInteractions
|
||||||
|
|
||||||
|
if config.validator or config.persistence:
|
||||||
|
s.codexNode.clock = clock
|
||||||
else:
|
else:
|
||||||
let proofFailures = 0
|
s.codexNode.clock = SystemClock()
|
||||||
if config.simulateProofFailures > 0:
|
|
||||||
warn "Proof failure simulation is not enabled for this build! Configuration ignored"
|
|
||||||
|
|
||||||
let purchasing = Purchasing.new(market, clock)
|
if config.persistence:
|
||||||
let sales = Sales.new(market, clock, repo, proofFailures)
|
# This is used for simulation purposes. Normal nodes won't be compiled with this flag
|
||||||
client = some ClientInteractions.new(clock, purchasing)
|
# and hence the proof failure will always be 0.
|
||||||
host = some HostInteractions.new(clock, sales)
|
when codex_enable_proof_failures:
|
||||||
if config.validator:
|
let proofFailures = config.simulateProofFailures
|
||||||
let validation = Validation.new(clock, market, config.validatorMaxSlots)
|
if proofFailures > 0:
|
||||||
validator = some ValidatorInteractions.new(clock, validation)
|
warn "Enabling proof failure simulation!"
|
||||||
|
else:
|
||||||
|
let proofFailures = 0
|
||||||
|
if config.simulateProofFailures > 0:
|
||||||
|
warn "Proof failure simulation is not enabled for this build! Configuration ignored"
|
||||||
|
|
||||||
s.codexNode.contracts = (client, host, validator)
|
let purchasing = Purchasing.new(market, clock)
|
||||||
|
let sales = Sales.new(market, clock, repo, proofFailures)
|
||||||
|
client = some ClientInteractions.new(clock, purchasing)
|
||||||
|
host = some HostInteractions.new(clock, sales)
|
||||||
|
|
||||||
|
if config.validator:
|
||||||
|
let validation = Validation.new(clock, market, config.validatorMaxSlots)
|
||||||
|
validator = some ValidatorInteractions.new(clock, validation)
|
||||||
|
|
||||||
|
s.codexNode.contracts = (client, host, validator)
|
||||||
|
|
||||||
proc start*(s: CodexServer) {.async.} =
|
proc start*(s: CodexServer) {.async.} =
|
||||||
trace "Starting codex node", config = $s.config
|
trace "Starting codex node", config = $s.config
|
||||||
|
@ -262,11 +257,38 @@ proc new*(
|
||||||
blockDiscovery = DiscoveryEngine.new(repoStore, peerStore, network, discovery, pendingBlocks)
|
blockDiscovery = DiscoveryEngine.new(repoStore, peerStore, network, discovery, pendingBlocks)
|
||||||
engine = BlockExcEngine.new(repoStore, wallet, network, blockDiscovery, peerStore, pendingBlocks)
|
engine = BlockExcEngine.new(repoStore, wallet, network, blockDiscovery, peerStore, pendingBlocks)
|
||||||
store = NetworkStore.new(engine, repoStore)
|
store = NetworkStore.new(engine, repoStore)
|
||||||
|
erasure = Erasure.new(store, leoEncoderProvider, leoDecoderProvider)
|
||||||
|
prover = if config.persistence:
|
||||||
|
if not fileAccessible($config.circomR1cs, {AccessFlags.Read}):
|
||||||
|
error "Circom R1CS file not accessible"
|
||||||
|
raise (ref Defect)(
|
||||||
|
msg: "r1cs file not readable or doesn't exist")
|
||||||
|
|
||||||
|
if not fileAccessible($config.circomWasm, {AccessFlags.Read}):
|
||||||
|
error "Circom WASM file not accessible"
|
||||||
|
raise (ref Defect)(
|
||||||
|
msg: "wasm file not readable or doesn't exist")
|
||||||
|
|
||||||
|
let zkey = if not config.circomNoZkey:
|
||||||
|
if not fileAccessible($config.circomNoZkey, {AccessFlags.Read}):
|
||||||
|
error "Circom WASM file not accessible"
|
||||||
|
raise (ref Defect)(
|
||||||
|
msg: "wasm file not readable or doesn't exist")
|
||||||
|
|
||||||
|
$config.circomNoZkey
|
||||||
|
else:
|
||||||
|
""
|
||||||
|
|
||||||
|
some Prover.new(store, CircomCompat.init($config.circomR1cs, $config.circomWasm, zkey))
|
||||||
|
else:
|
||||||
|
none Prover
|
||||||
|
|
||||||
codexNode = CodexNodeRef.new(
|
codexNode = CodexNodeRef.new(
|
||||||
switch = switch,
|
switch = switch,
|
||||||
networkStore = store,
|
store = store,
|
||||||
engine = engine,
|
engine = engine,
|
||||||
|
erasure = erasure,
|
||||||
|
prover = prover,
|
||||||
discovery = discovery)
|
discovery = discovery)
|
||||||
|
|
||||||
restServer = RestServerRef.new(
|
restServer = RestServerRef.new(
|
||||||
|
|
387
codex/conf.nim
387
codex/conf.nim
|
@ -7,9 +7,7 @@
|
||||||
## This file may not be copied, modified, or distributed except according to
|
## This file may not be copied, modified, or distributed except according to
|
||||||
## those terms.
|
## those terms.
|
||||||
|
|
||||||
import pkg/upraises
|
{.push raises: [].}
|
||||||
|
|
||||||
push: {.upraises: [].}
|
|
||||||
|
|
||||||
import std/os
|
import std/os
|
||||||
import std/terminal
|
import std/terminal
|
||||||
|
@ -33,30 +31,47 @@ import pkg/ethers
|
||||||
import pkg/questionable
|
import pkg/questionable
|
||||||
import pkg/questionable/results
|
import pkg/questionable/results
|
||||||
|
|
||||||
|
import ./codextypes
|
||||||
import ./discovery
|
import ./discovery
|
||||||
import ./logutils
|
import ./logutils
|
||||||
import ./stores
|
import ./stores
|
||||||
import ./units
|
import ./units
|
||||||
import ./utils
|
import ./utils
|
||||||
|
|
||||||
export units
|
export units, net, codextypes
|
||||||
export net
|
|
||||||
export
|
export
|
||||||
DefaultQuotaBytes,
|
DefaultQuotaBytes,
|
||||||
DefaultBlockTtl,
|
DefaultBlockTtl,
|
||||||
DefaultBlockMaintenanceInterval,
|
DefaultBlockMaintenanceInterval,
|
||||||
DefaultNumberOfBlocksToMaintainPerInterval
|
DefaultNumberOfBlocksToMaintainPerInterval
|
||||||
|
|
||||||
|
proc defaultDataDir*(): string =
|
||||||
|
let dataDir = when defined(windows):
|
||||||
|
"AppData" / "Roaming" / "Codex"
|
||||||
|
elif defined(macosx):
|
||||||
|
"Library" / "Application Support" / "Codex"
|
||||||
|
else:
|
||||||
|
".cache" / "codex"
|
||||||
|
|
||||||
|
getHomeDir() / dataDir
|
||||||
|
|
||||||
const
|
const
|
||||||
codex_enable_api_debug_peers* {.booldefine.} = false
|
codex_enable_api_debug_peers* {.booldefine.} = false
|
||||||
codex_enable_proof_failures* {.booldefine.} = false
|
codex_enable_proof_failures* {.booldefine.} = false
|
||||||
codex_use_hardhat* {.booldefine.} = false
|
codex_use_hardhat* {.booldefine.} = false
|
||||||
codex_enable_log_counter* {.booldefine.} = false
|
codex_enable_log_counter* {.booldefine.} = false
|
||||||
|
|
||||||
|
DefaultDataDir* = defaultDataDir()
|
||||||
|
|
||||||
type
|
type
|
||||||
StartUpCommand* {.pure.} = enum
|
StartUpCmd* {.pure.} = enum
|
||||||
noCommand,
|
noCmd
|
||||||
initNode
|
persistence
|
||||||
|
|
||||||
|
PersistenceCmd* {.pure.} = enum
|
||||||
|
noCmd
|
||||||
|
validator
|
||||||
|
|
||||||
LogKind* {.pure.} = enum
|
LogKind* {.pure.} = enum
|
||||||
Auto = "auto"
|
Auto = "auto"
|
||||||
|
@ -106,126 +121,125 @@ type
|
||||||
|
|
||||||
dataDir* {.
|
dataDir* {.
|
||||||
desc: "The directory where codex will store configuration and data"
|
desc: "The directory where codex will store configuration and data"
|
||||||
defaultValue: defaultDataDir()
|
defaultValue: DefaultDataDir
|
||||||
defaultValueDesc: ""
|
defaultValueDesc: $DefaultDataDir
|
||||||
abbr: "d"
|
abbr: "d"
|
||||||
name: "data-dir" }: OutDir
|
name: "data-dir" }: OutDir
|
||||||
|
|
||||||
|
listenAddrs* {.
|
||||||
|
desc: "Multi Addresses to listen on"
|
||||||
|
defaultValue: @[
|
||||||
|
MultiAddress.init("/ip4/0.0.0.0/tcp/0")
|
||||||
|
.expect("Should init multiaddress")]
|
||||||
|
defaultValueDesc: "/ip4/0.0.0.0/tcp/0"
|
||||||
|
abbr: "i"
|
||||||
|
name: "listen-addrs" }: seq[MultiAddress]
|
||||||
|
|
||||||
|
# TODO: change this once we integrate nat support
|
||||||
|
nat* {.
|
||||||
|
desc: "IP Addresses to announce behind a NAT"
|
||||||
|
defaultValue: ValidIpAddress.init("127.0.0.1")
|
||||||
|
defaultValueDesc: "127.0.0.1"
|
||||||
|
abbr: "a"
|
||||||
|
name: "nat" }: ValidIpAddress
|
||||||
|
|
||||||
|
discoveryIp* {.
|
||||||
|
desc: "Discovery listen address"
|
||||||
|
defaultValue: ValidIpAddress.init(IPv4_any())
|
||||||
|
defaultValueDesc: "0.0.0.0"
|
||||||
|
abbr: "e"
|
||||||
|
name: "disc-ip" }: ValidIpAddress
|
||||||
|
|
||||||
|
discoveryPort* {.
|
||||||
|
desc: "Discovery (UDP) port"
|
||||||
|
defaultValue: 8090.Port
|
||||||
|
defaultValueDesc: "8090"
|
||||||
|
abbr: "u"
|
||||||
|
name: "disc-port" }: Port
|
||||||
|
|
||||||
|
netPrivKeyFile* {.
|
||||||
|
desc: "Source of network (secp256k1) private key file path or name"
|
||||||
|
defaultValue: "key"
|
||||||
|
name: "net-privkey" }: string
|
||||||
|
|
||||||
|
bootstrapNodes* {.
|
||||||
|
desc: "Specifies one or more bootstrap nodes to use when connecting to the network"
|
||||||
|
abbr: "b"
|
||||||
|
name: "bootstrap-node" }: seq[SignedPeerRecord]
|
||||||
|
|
||||||
|
maxPeers* {.
|
||||||
|
desc: "The maximum number of peers to connect to"
|
||||||
|
defaultValue: 160
|
||||||
|
name: "max-peers" }: int
|
||||||
|
|
||||||
|
agentString* {.
|
||||||
|
defaultValue: "Codex"
|
||||||
|
desc: "Node agent string which is used as identifier in network"
|
||||||
|
name: "agent-string" }: string
|
||||||
|
|
||||||
|
apiBindAddress* {.
|
||||||
|
desc: "The REST API bind address"
|
||||||
|
defaultValue: "127.0.0.1"
|
||||||
|
name: "api-bindaddr"
|
||||||
|
}: string
|
||||||
|
|
||||||
|
apiPort* {.
|
||||||
|
desc: "The REST Api port",
|
||||||
|
defaultValue: 8080.Port
|
||||||
|
defaultValueDesc: "8080"
|
||||||
|
name: "api-port"
|
||||||
|
abbr: "p" }: Port
|
||||||
|
|
||||||
|
repoKind* {.
|
||||||
|
desc: "Backend for main repo store (fs, sqlite)"
|
||||||
|
defaultValueDesc: "fs"
|
||||||
|
defaultValue: repoFS
|
||||||
|
name: "repo-kind" }: RepoKind
|
||||||
|
|
||||||
|
storageQuota* {.
|
||||||
|
desc: "The size of the total storage quota dedicated to the node"
|
||||||
|
defaultValue: DefaultQuotaBytes
|
||||||
|
defaultValueDesc: $DefaultQuotaBytes
|
||||||
|
name: "storage-quota"
|
||||||
|
abbr: "q" }: NBytes
|
||||||
|
|
||||||
|
blockTtl* {.
|
||||||
|
desc: "Default block timeout in seconds - 0 disables the ttl"
|
||||||
|
defaultValue: DefaultBlockTtl
|
||||||
|
defaultValueDesc: $DefaultBlockTtl
|
||||||
|
name: "block-ttl"
|
||||||
|
abbr: "t" }: Duration
|
||||||
|
|
||||||
|
blockMaintenanceInterval* {.
|
||||||
|
desc: "Time interval in seconds - determines frequency of block maintenance cycle: how often blocks are checked for expiration and cleanup"
|
||||||
|
defaultValue: DefaultBlockMaintenanceInterval
|
||||||
|
defaultValueDesc: $DefaultBlockMaintenanceInterval
|
||||||
|
name: "block-mi" }: Duration
|
||||||
|
|
||||||
|
blockMaintenanceNumberOfBlocks* {.
|
||||||
|
desc: "Number of blocks to check every maintenance cycle"
|
||||||
|
defaultValue: DefaultNumberOfBlocksToMaintainPerInterval
|
||||||
|
defaultValueDesc: $DefaultNumberOfBlocksToMaintainPerInterval
|
||||||
|
name: "block-mn" }: int
|
||||||
|
|
||||||
|
cacheSize* {.
|
||||||
|
desc: "The size of the block cache, 0 disables the cache - might help on slow hardrives"
|
||||||
|
defaultValue: 0
|
||||||
|
defaultValueDesc: "0"
|
||||||
|
name: "cache-size"
|
||||||
|
abbr: "c" }: NBytes
|
||||||
|
|
||||||
|
logFile* {.
|
||||||
|
desc: "Logs to file"
|
||||||
|
defaultValue: string.none
|
||||||
|
name: "log-file"
|
||||||
|
hidden
|
||||||
|
.}: Option[string]
|
||||||
|
|
||||||
case cmd* {.
|
case cmd* {.
|
||||||
command
|
defaultValue: noCmd
|
||||||
defaultValue: noCommand }: StartUpCommand
|
command }: StartUpCmd
|
||||||
|
of persistence:
|
||||||
of noCommand:
|
|
||||||
|
|
||||||
listenAddrs* {.
|
|
||||||
desc: "Multi Addresses to listen on"
|
|
||||||
defaultValue: @[
|
|
||||||
MultiAddress.init("/ip4/0.0.0.0/tcp/0")
|
|
||||||
.expect("Should init multiaddress")]
|
|
||||||
defaultValueDesc: "/ip4/0.0.0.0/tcp/0"
|
|
||||||
abbr: "i"
|
|
||||||
name: "listen-addrs" }: seq[MultiAddress]
|
|
||||||
|
|
||||||
# TODO: change this once we integrate nat support
|
|
||||||
nat* {.
|
|
||||||
desc: "IP Addresses to announce behind a NAT"
|
|
||||||
defaultValue: ValidIpAddress.init("127.0.0.1")
|
|
||||||
defaultValueDesc: "127.0.0.1"
|
|
||||||
abbr: "a"
|
|
||||||
name: "nat" }: ValidIpAddress
|
|
||||||
|
|
||||||
discoveryIp* {.
|
|
||||||
desc: "Discovery listen address"
|
|
||||||
defaultValue: ValidIpAddress.init(IPv4_any())
|
|
||||||
defaultValueDesc: "0.0.0.0"
|
|
||||||
abbr: "e"
|
|
||||||
name: "disc-ip" }: ValidIpAddress
|
|
||||||
|
|
||||||
discoveryPort* {.
|
|
||||||
desc: "Discovery (UDP) port"
|
|
||||||
defaultValue: 8090.Port
|
|
||||||
defaultValueDesc: "8090"
|
|
||||||
abbr: "u"
|
|
||||||
name: "disc-port" }: Port
|
|
||||||
|
|
||||||
netPrivKeyFile* {.
|
|
||||||
desc: "Source of network (secp256k1) private key file path or name"
|
|
||||||
defaultValue: "key"
|
|
||||||
name: "net-privkey" }: string
|
|
||||||
|
|
||||||
bootstrapNodes* {.
|
|
||||||
desc: "Specifies one or more bootstrap nodes to use when connecting to the network"
|
|
||||||
abbr: "b"
|
|
||||||
name: "bootstrap-node" }: seq[SignedPeerRecord]
|
|
||||||
|
|
||||||
maxPeers* {.
|
|
||||||
desc: "The maximum number of peers to connect to"
|
|
||||||
defaultValue: 160
|
|
||||||
name: "max-peers" }: int
|
|
||||||
|
|
||||||
agentString* {.
|
|
||||||
defaultValue: "Codex"
|
|
||||||
desc: "Node agent string which is used as identifier in network"
|
|
||||||
name: "agent-string" }: string
|
|
||||||
|
|
||||||
apiBindAddress* {.
|
|
||||||
desc: "The REST API bind address"
|
|
||||||
defaultValue: "127.0.0.1"
|
|
||||||
name: "api-bindaddr"
|
|
||||||
}: string
|
|
||||||
|
|
||||||
apiPort* {.
|
|
||||||
desc: "The REST Api port",
|
|
||||||
defaultValue: 8080.Port
|
|
||||||
defaultValueDesc: "8080"
|
|
||||||
name: "api-port"
|
|
||||||
abbr: "p" }: Port
|
|
||||||
|
|
||||||
repoKind* {.
|
|
||||||
desc: "Backend for main repo store (fs, sqlite)"
|
|
||||||
defaultValueDesc: "fs"
|
|
||||||
defaultValue: repoFS
|
|
||||||
name: "repo-kind" }: RepoKind
|
|
||||||
|
|
||||||
storageQuota* {.
|
|
||||||
desc: "The size of the total storage quota dedicated to the node"
|
|
||||||
defaultValue: DefaultQuotaBytes
|
|
||||||
defaultValueDesc: $DefaultQuotaBytes
|
|
||||||
name: "storage-quota"
|
|
||||||
abbr: "q" }: NBytes
|
|
||||||
|
|
||||||
blockTtl* {.
|
|
||||||
desc: "Default block timeout in seconds - 0 disables the ttl"
|
|
||||||
defaultValue: DefaultBlockTtl
|
|
||||||
defaultValueDesc: $DefaultBlockTtl
|
|
||||||
name: "block-ttl"
|
|
||||||
abbr: "t" }: Duration
|
|
||||||
|
|
||||||
blockMaintenanceInterval* {.
|
|
||||||
desc: "Time interval in seconds - determines frequency of block maintenance cycle: how often blocks are checked for expiration and cleanup"
|
|
||||||
defaultValue: DefaultBlockMaintenanceInterval
|
|
||||||
defaultValueDesc: $DefaultBlockMaintenanceInterval
|
|
||||||
name: "block-mi" }: Duration
|
|
||||||
|
|
||||||
blockMaintenanceNumberOfBlocks* {.
|
|
||||||
desc: "Number of blocks to check every maintenance cycle"
|
|
||||||
defaultValue: DefaultNumberOfBlocksToMaintainPerInterval
|
|
||||||
defaultValueDesc: $DefaultNumberOfBlocksToMaintainPerInterval
|
|
||||||
name: "block-mn" }: int
|
|
||||||
|
|
||||||
cacheSize* {.
|
|
||||||
desc: "The size of the block cache, 0 disables the cache - might help on slow hardrives"
|
|
||||||
defaultValue: 0
|
|
||||||
defaultValueDesc: "0"
|
|
||||||
name: "cache-size"
|
|
||||||
abbr: "c" }: NBytes
|
|
||||||
|
|
||||||
persistence* {.
|
|
||||||
desc: "Enables persistence mechanism, requires an Ethereum node"
|
|
||||||
defaultValue: false
|
|
||||||
name: "persistence"
|
|
||||||
.}: bool
|
|
||||||
|
|
||||||
ethProvider* {.
|
ethProvider* {.
|
||||||
desc: "The URL of the JSON-RPC API of the Ethereum node"
|
desc: "The URL of the JSON-RPC API of the Ethereum node"
|
||||||
defaultValue: "ws://localhost:8545"
|
defaultValue: "ws://localhost:8545"
|
||||||
|
@ -235,55 +249,118 @@ type
|
||||||
ethAccount* {.
|
ethAccount* {.
|
||||||
desc: "The Ethereum account that is used for storage contracts"
|
desc: "The Ethereum account that is used for storage contracts"
|
||||||
defaultValue: EthAddress.none
|
defaultValue: EthAddress.none
|
||||||
|
defaultValueDesc: ""
|
||||||
name: "eth-account"
|
name: "eth-account"
|
||||||
.}: Option[EthAddress]
|
.}: Option[EthAddress]
|
||||||
|
|
||||||
ethPrivateKey* {.
|
ethPrivateKey* {.
|
||||||
desc: "File containing Ethereum private key for storage contracts"
|
desc: "File containing Ethereum private key for storage contracts"
|
||||||
defaultValue: string.none
|
defaultValue: string.none
|
||||||
|
defaultValueDesc: ""
|
||||||
name: "eth-private-key"
|
name: "eth-private-key"
|
||||||
.}: Option[string]
|
.}: Option[string]
|
||||||
|
|
||||||
marketplaceAddress* {.
|
marketplaceAddress* {.
|
||||||
desc: "Address of deployed Marketplace contract"
|
desc: "Address of deployed Marketplace contract"
|
||||||
defaultValue: EthAddress.none
|
defaultValue: EthAddress.none
|
||||||
|
defaultValueDesc: ""
|
||||||
name: "marketplace-address"
|
name: "marketplace-address"
|
||||||
.}: Option[EthAddress]
|
.}: Option[EthAddress]
|
||||||
|
|
||||||
validator* {.
|
circomR1cs* {.
|
||||||
desc: "Enables validator, requires an Ethereum node"
|
desc: "The r1cs file for the storage circuit"
|
||||||
|
defaultValue: $DefaultDataDir / "circuits" / "proof_main.r1cs"
|
||||||
|
defaultValueDesc: $DefaultDataDir & "/circuits/proof_main.r1cs"
|
||||||
|
name: "circom-r1cs"
|
||||||
|
.}: InputFile
|
||||||
|
|
||||||
|
circomWasm* {.
|
||||||
|
desc: "The wasm file for the storage circuit"
|
||||||
|
defaultValue: $DefaultDataDir / "circuits" / "proof_main.wasm"
|
||||||
|
defaultValueDesc: $DefaultDataDir & "/circuits/proof_main.wasm"
|
||||||
|
name: "circom-wasm"
|
||||||
|
.}: InputFile
|
||||||
|
|
||||||
|
circomZkey* {.
|
||||||
|
desc: "The zkey file for the storage circuit"
|
||||||
|
defaultValue: $DefaultDataDir / "circuits" / "proof_main.zkey"
|
||||||
|
defaultValueDesc: $DefaultDataDir & "/circuits/proof_main.zkey"
|
||||||
|
name: "circom-zkey"
|
||||||
|
.}: InputFile
|
||||||
|
|
||||||
|
# TODO: should probably be hidden and behind a feature flag
|
||||||
|
circomNoZkey* {.
|
||||||
|
desc: "Ignore the zkey file - use only for testing!"
|
||||||
defaultValue: false
|
defaultValue: false
|
||||||
name: "validator"
|
name: "circom-no-zkey"
|
||||||
.}: bool
|
.}: bool
|
||||||
|
|
||||||
validatorMaxSlots* {.
|
numProofSamples* {.
|
||||||
desc: "Maximum number of slots that the validator monitors"
|
desc: "Number of samples to prove"
|
||||||
defaultValue: 1000
|
defaultValue: DefaultSamplesNum
|
||||||
name: "validator-max-slots"
|
defaultValueDesc: $DefaultSamplesNum
|
||||||
.}: int
|
name: "proof-samples" }: int
|
||||||
|
|
||||||
simulateProofFailures* {.
|
maxSlotDepth* {.
|
||||||
desc: "Simulates proof failures once every N proofs. 0 = disabled."
|
desc: "The maximum depth of the slot tree"
|
||||||
defaultValue: 0
|
defaultValue: DefaultMaxSlotDepth
|
||||||
name: "simulate-proof-failures"
|
defaultValueDesc: $DefaultMaxSlotDepth
|
||||||
hidden
|
name: "max-slot-depth" }: int
|
||||||
|
|
||||||
|
maxDatasetDepth* {.
|
||||||
|
desc: "The maximum depth of the dataset tree"
|
||||||
|
defaultValue: DefaultMaxDatasetDepth
|
||||||
|
defaultValueDesc: $DefaultMaxDatasetDepth
|
||||||
|
name: "max-dataset-depth" }: int
|
||||||
|
|
||||||
|
maxBlockDepth* {.
|
||||||
|
desc: "The maximum depth of the network block merkle tree"
|
||||||
|
defaultValue: DefaultBlockDepth
|
||||||
|
defaultValueDesc: $DefaultBlockDepth
|
||||||
|
name: "max-block-depth" }: int
|
||||||
|
|
||||||
|
maxCellElms* {.
|
||||||
|
desc: "The maximum number of elements in a cell"
|
||||||
|
defaultValue: DefaultCellElms
|
||||||
|
defaultValueDesc: $DefaultCellElms
|
||||||
|
name: "max-cell-elements" }: int
|
||||||
|
|
||||||
|
case persistenceCmd* {.
|
||||||
|
defaultValue: noCmd
|
||||||
|
command }: PersistenceCmd
|
||||||
|
|
||||||
|
of validator:
|
||||||
|
validatorMaxSlots* {.
|
||||||
|
desc: "Maximum number of slots that the validator monitors"
|
||||||
|
defaultValue: 1000
|
||||||
|
name: "validator-max-slots"
|
||||||
.}: int
|
.}: int
|
||||||
|
|
||||||
logFile* {.
|
# TODO: should go behind a feature flag
|
||||||
desc: "Logs to file"
|
simulateProofFailures* {.
|
||||||
defaultValue: string.none
|
desc: "Simulates proof failures once every N proofs. 0 = disabled."
|
||||||
name: "log-file"
|
defaultValue: 0
|
||||||
hidden
|
name: "simulate-proof-failures"
|
||||||
.}: Option[string]
|
hidden
|
||||||
|
.}: int
|
||||||
|
|
||||||
of initNode:
|
of PersistenceCmd.noCmd:
|
||||||
discard
|
discard # end of validator
|
||||||
|
|
||||||
|
of StartUpCmd.noCmd:
|
||||||
|
discard # end of persistence
|
||||||
|
|
||||||
EthAddress* = ethers.Address
|
EthAddress* = ethers.Address
|
||||||
|
|
||||||
logutils.formatIt(LogFormat.textLines, EthAddress): it.short0xHexLog
|
logutils.formatIt(LogFormat.textLines, EthAddress): it.short0xHexLog
|
||||||
logutils.formatIt(LogFormat.json, EthAddress): %it
|
logutils.formatIt(LogFormat.json, EthAddress): %it
|
||||||
|
|
||||||
|
func persistence*(self: CodexConf): bool =
|
||||||
|
self.cmd == StartUpCmd.persistence
|
||||||
|
|
||||||
|
func validator*(self: CodexConf): bool =
|
||||||
|
self.persistence and self.persistenceCmd == PersistenceCmd.validator
|
||||||
|
|
||||||
proc getCodexVersion(): string =
|
proc getCodexVersion(): string =
|
||||||
let tag = strip(staticExec("git tag"))
|
let tag = strip(staticExec("git tag"))
|
||||||
if tag.isEmptyOrWhitespace:
|
if tag.isEmptyOrWhitespace:
|
||||||
|
@ -308,16 +385,6 @@ const
|
||||||
"Codex revision: " & codexRevision & "\p" &
|
"Codex revision: " & codexRevision & "\p" &
|
||||||
nimBanner
|
nimBanner
|
||||||
|
|
||||||
proc defaultDataDir*(): string =
|
|
||||||
let dataDir = when defined(windows):
|
|
||||||
"AppData" / "Roaming" / "Codex"
|
|
||||||
elif defined(macosx):
|
|
||||||
"Library" / "Application Support" / "Codex"
|
|
||||||
else:
|
|
||||||
".cache" / "codex"
|
|
||||||
|
|
||||||
getHomeDir() / dataDir
|
|
||||||
|
|
||||||
proc parseCmdArg*(T: typedesc[MultiAddress],
|
proc parseCmdArg*(T: typedesc[MultiAddress],
|
||||||
input: string): MultiAddress
|
input: string): MultiAddress
|
||||||
{.upraises: [ValueError, LPError].} =
|
{.upraises: [ValueError, LPError].} =
|
||||||
|
@ -326,7 +393,7 @@ proc parseCmdArg*(T: typedesc[MultiAddress],
|
||||||
if res.isOk:
|
if res.isOk:
|
||||||
ma = res.get()
|
ma = res.get()
|
||||||
else:
|
else:
|
||||||
warn "Invalid MultiAddress", input=input, error=res.error()
|
warn "Invalid MultiAddress", input=input, error = res.error()
|
||||||
quit QuitFailure
|
quit QuitFailure
|
||||||
ma
|
ma
|
||||||
|
|
||||||
|
@ -334,10 +401,10 @@ proc parseCmdArg*(T: type SignedPeerRecord, uri: string): T =
|
||||||
var res: SignedPeerRecord
|
var res: SignedPeerRecord
|
||||||
try:
|
try:
|
||||||
if not res.fromURI(uri):
|
if not res.fromURI(uri):
|
||||||
warn "Invalid SignedPeerRecord uri", uri=uri
|
warn "Invalid SignedPeerRecord uri", uri = uri
|
||||||
quit QuitFailure
|
quit QuitFailure
|
||||||
except CatchableError as exc:
|
except CatchableError as exc:
|
||||||
warn "Invalid SignedPeerRecord uri", uri=uri, error=exc.msg
|
warn "Invalid SignedPeerRecord uri", uri = uri, error = exc.msg
|
||||||
quit QuitFailure
|
quit QuitFailure
|
||||||
res
|
res
|
||||||
|
|
||||||
|
@ -348,7 +415,7 @@ proc parseCmdArg*(T: type NBytes, val: string): T =
|
||||||
var num = 0'i64
|
var num = 0'i64
|
||||||
let count = parseSize(val, num, alwaysBin = true)
|
let count = parseSize(val, num, alwaysBin = true)
|
||||||
if count == 0:
|
if count == 0:
|
||||||
warn "Invalid number of bytes", nbytes=val
|
warn "Invalid number of bytes", nbytes = val
|
||||||
quit QuitFailure
|
quit QuitFailure
|
||||||
NBytes(num)
|
NBytes(num)
|
||||||
|
|
||||||
|
@ -356,7 +423,7 @@ proc parseCmdArg*(T: type Duration, val: string): T =
|
||||||
var dur: Duration
|
var dur: Duration
|
||||||
let count = parseDuration(val, dur)
|
let count = parseDuration(val, dur)
|
||||||
if count == 0:
|
if count == 0:
|
||||||
warn "Invalid duration parse", dur=dur
|
warn "Cannot parse duration", dur = dur
|
||||||
quit QuitFailure
|
quit QuitFailure
|
||||||
dur
|
dur
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue