diff --git a/codex.nim b/codex.nim index f7215db6..ea89b6f9 100644 --- a/codex.nim +++ b/codex.nim @@ -23,6 +23,7 @@ import ./codex/codex import ./codex/logutils import ./codex/units import ./codex/utils/keyutils +import ./codex/codextypes export codex, conf, libp2p, chronos, logutils @@ -54,91 +55,93 @@ when isMainModule: config.setupLogging() config.setupMetrics() - case config.cmd: - of StartUpCommand.noCommand: + if config.nat == ValidIpAddress.init(IPv4_any()): + error "`--nat` cannot be set to the any (`0.0.0.0`) address" + quit QuitFailure - if config.nat == ValidIpAddress.init(IPv4_any()): - error "`--nat` cannot be set to the any (`0.0.0.0`) address" + if config.nat == ValidIpAddress.init("127.0.0.1"): + 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 - if config.nat == ValidIpAddress.init("127.0.0.1"): - warn "`--nat` is set to loopback, your node wont properly announce over the DHT" + ## 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" - if not(checkAndCreateDataDir((config.dataDir).string)): - # We are unable to access/create data folder or data folder's - # permissions are insecure. - quit QuitFailure + pendingFuts.add(server.stop()) + state = CodexStatus.Stopping - trace "Data dir initialized", dir = $config.dataDir + notice "Stopping Codex" - if not(checkAndCreateDataDir((config.dataDir / "repo"))): - # We are unable to access/create data folder or data folder's - # permissions are insecure. - quit QuitFailure + try: + setControlCHook(controlCHandler) + except Exception as exc: # TODO Exception + warn "Cannot set ctrl-c handler", msg = exc.msg - 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 = 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" + # 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: 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 chronos.poll() - - # wait fot futures to finish - let res = waitFor allFinished(pendingFuts) - state = CodexStatus.Stopped - - if res.anyIt( it.failed ): - error "Codex didn't shutdown correctly" + except Exception as exc: + error "Unhandled exception in async proc, aborting", msg = exc.msg quit QuitFailure - notice "Exited codex" + # wait fot futures to finish + let res = waitFor allFinished(pendingFuts) + state = CodexStatus.Stopped - of StartUpCommand.initNode: - discard + if res.anyIt( it.failed ): + error "Codex didn't shutdown correctly" + quit QuitFailure + + notice "Exited codex" diff --git a/codex/codex.nim b/codex/codex.nim index e5f1bfba..c9f1120b 100644 --- a/codex/codex.nim +++ b/codex/codex.nim @@ -22,12 +22,14 @@ import pkg/stew/io2 import pkg/stew/shims/net as stewnet import pkg/datastore import pkg/ethers except Rng +import pkg/stew/io2 import ./node import ./conf import ./rng import ./rest/api import ./stores +import ./slots import ./blockexchange import ./utils/fileutils import ./erasure @@ -65,77 +67,70 @@ proc bootstrapInteractions( config = s.config 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: - # This is used for simulation purposes. Normal nodes won't be compiled with this flag - # and hence the proof failure will always be 0. - when codex_enable_proof_failures: - let proofFailures = config.simulateProofFailures - if proofFailures > 0: - warn "Enabling proof failure simulation!" + if not config.ethAccount.isSome and not config.ethPrivateKey.isSome: + error "Persistence 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: - let proofFailures = 0 - if config.simulateProofFailures > 0: - warn "Proof failure simulation is not enabled for this build! Configuration ignored" + s.codexNode.clock = SystemClock() - 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) + 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. + when codex_enable_proof_failures: + let proofFailures = config.simulateProofFailures + if proofFailures > 0: + 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.} = trace "Starting codex node", config = $s.config @@ -262,11 +257,38 @@ proc new*( blockDiscovery = DiscoveryEngine.new(repoStore, peerStore, network, discovery, pendingBlocks) engine = BlockExcEngine.new(repoStore, wallet, network, blockDiscovery, peerStore, pendingBlocks) 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( switch = switch, - networkStore = store, + store = store, engine = engine, + erasure = erasure, + prover = prover, discovery = discovery) restServer = RestServerRef.new( diff --git a/codex/conf.nim b/codex/conf.nim index d375b740..37423905 100644 --- a/codex/conf.nim +++ b/codex/conf.nim @@ -7,9 +7,7 @@ ## This file may not be copied, modified, or distributed except according to ## those terms. -import pkg/upraises - -push: {.upraises: [].} +{.push raises: [].} import std/os import std/terminal @@ -33,30 +31,47 @@ import pkg/ethers import pkg/questionable import pkg/questionable/results +import ./codextypes import ./discovery import ./logutils import ./stores import ./units import ./utils -export units -export net +export units, net, codextypes + export DefaultQuotaBytes, DefaultBlockTtl, DefaultBlockMaintenanceInterval, 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 codex_enable_api_debug_peers* {.booldefine.} = false codex_enable_proof_failures* {.booldefine.} = false codex_use_hardhat* {.booldefine.} = false codex_enable_log_counter* {.booldefine.} = false + DefaultDataDir* = defaultDataDir() + type - StartUpCommand* {.pure.} = enum - noCommand, - initNode + StartUpCmd* {.pure.} = enum + noCmd + persistence + + PersistenceCmd* {.pure.} = enum + noCmd + validator LogKind* {.pure.} = enum Auto = "auto" @@ -106,126 +121,125 @@ type dataDir* {. desc: "The directory where codex will store configuration and data" - defaultValue: defaultDataDir() - defaultValueDesc: "" + defaultValue: DefaultDataDir + defaultValueDesc: $DefaultDataDir abbr: "d" 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* {. - command - defaultValue: noCommand }: StartUpCommand - - 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 - + defaultValue: noCmd + command }: StartUpCmd + of persistence: ethProvider* {. desc: "The URL of the JSON-RPC API of the Ethereum node" defaultValue: "ws://localhost:8545" @@ -235,55 +249,118 @@ type ethAccount* {. desc: "The Ethereum account that is used for storage contracts" defaultValue: EthAddress.none + defaultValueDesc: "" name: "eth-account" .}: Option[EthAddress] ethPrivateKey* {. desc: "File containing Ethereum private key for storage contracts" defaultValue: string.none + defaultValueDesc: "" name: "eth-private-key" .}: Option[string] marketplaceAddress* {. desc: "Address of deployed Marketplace contract" defaultValue: EthAddress.none + defaultValueDesc: "" name: "marketplace-address" .}: Option[EthAddress] - validator* {. - desc: "Enables validator, requires an Ethereum node" + circomR1cs* {. + 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 - name: "validator" + name: "circom-no-zkey" .}: bool - validatorMaxSlots* {. - desc: "Maximum number of slots that the validator monitors" - defaultValue: 1000 - name: "validator-max-slots" - .}: int + numProofSamples* {. + desc: "Number of samples to prove" + defaultValue: DefaultSamplesNum + defaultValueDesc: $DefaultSamplesNum + name: "proof-samples" }: int - simulateProofFailures* {. - desc: "Simulates proof failures once every N proofs. 0 = disabled." - defaultValue: 0 - name: "simulate-proof-failures" - hidden + maxSlotDepth* {. + desc: "The maximum depth of the slot tree" + defaultValue: DefaultMaxSlotDepth + defaultValueDesc: $DefaultMaxSlotDepth + 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 - logFile* {. - desc: "Logs to file" - defaultValue: string.none - name: "log-file" - hidden - .}: Option[string] + # TODO: should go behind a feature flag + simulateProofFailures* {. + desc: "Simulates proof failures once every N proofs. 0 = disabled." + defaultValue: 0 + name: "simulate-proof-failures" + hidden + .}: int - of initNode: - discard + of PersistenceCmd.noCmd: + discard # end of validator + + of StartUpCmd.noCmd: + discard # end of persistence EthAddress* = ethers.Address logutils.formatIt(LogFormat.textLines, EthAddress): it.short0xHexLog 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 = let tag = strip(staticExec("git tag")) if tag.isEmptyOrWhitespace: @@ -308,16 +385,6 @@ const "Codex revision: " & codexRevision & "\p" & 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], input: string): MultiAddress {.upraises: [ValueError, LPError].} = @@ -326,7 +393,7 @@ proc parseCmdArg*(T: typedesc[MultiAddress], if res.isOk: ma = res.get() else: - warn "Invalid MultiAddress", input=input, error=res.error() + warn "Invalid MultiAddress", input=input, error = res.error() quit QuitFailure ma @@ -334,10 +401,10 @@ proc parseCmdArg*(T: type SignedPeerRecord, uri: string): T = var res: SignedPeerRecord try: if not res.fromURI(uri): - warn "Invalid SignedPeerRecord uri", uri=uri + warn "Invalid SignedPeerRecord uri", uri = uri quit QuitFailure except CatchableError as exc: - warn "Invalid SignedPeerRecord uri", uri=uri, error=exc.msg + warn "Invalid SignedPeerRecord uri", uri = uri, error = exc.msg quit QuitFailure res @@ -348,7 +415,7 @@ proc parseCmdArg*(T: type NBytes, val: string): T = var num = 0'i64 let count = parseSize(val, num, alwaysBin = true) if count == 0: - warn "Invalid number of bytes", nbytes=val + warn "Invalid number of bytes", nbytes = val quit QuitFailure NBytes(num) @@ -356,7 +423,7 @@ proc parseCmdArg*(T: type Duration, val: string): T = var dur: Duration let count = parseDuration(val, dur) if count == 0: - warn "Invalid duration parse", dur=dur + warn "Cannot parse duration", dur = dur quit QuitFailure dur