2022-05-19 19:56:03 +00:00
|
|
|
## Nim-Codex
|
2021-08-30 19:25:20 +00:00
|
|
|
## Copyright (c) 2021 Status Research & Development GmbH
|
|
|
|
## Licensed under either of
|
|
|
|
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
|
|
|
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
|
|
|
## at your option.
|
|
|
|
## This file may not be copied, modified, or distributed except according to
|
|
|
|
## those terms.
|
|
|
|
|
2022-01-10 15:32:56 +00:00
|
|
|
import std/sequtils
|
|
|
|
import std/os
|
2022-04-13 16:32:35 +00:00
|
|
|
import std/sugar
|
2022-01-10 15:32:56 +00:00
|
|
|
|
|
|
|
import pkg/chronicles
|
|
|
|
import pkg/chronos
|
|
|
|
import pkg/presto
|
|
|
|
import pkg/libp2p
|
|
|
|
import pkg/confutils
|
|
|
|
import pkg/confutils/defs
|
|
|
|
import pkg/nitro
|
|
|
|
import pkg/stew/io2
|
2022-04-13 16:32:35 +00:00
|
|
|
import pkg/stew/shims/net as stewnet
|
2022-01-10 15:32:56 +00:00
|
|
|
|
|
|
|
import ./node
|
|
|
|
import ./conf
|
|
|
|
import ./rng
|
|
|
|
import ./rest/api
|
2022-03-02 16:30:42 +00:00
|
|
|
import ./stores
|
2022-01-10 15:32:56 +00:00
|
|
|
import ./blockexchange
|
|
|
|
import ./utils/fileutils
|
2022-04-06 00:34:29 +00:00
|
|
|
import ./erasure
|
2022-04-13 16:32:35 +00:00
|
|
|
import ./discovery
|
2022-04-13 12:15:22 +00:00
|
|
|
import ./contracts
|
2022-01-10 15:32:56 +00:00
|
|
|
|
|
|
|
type
|
2022-05-19 19:56:03 +00:00
|
|
|
CodexServer* = ref object
|
2022-01-10 15:32:56 +00:00
|
|
|
runHandle: Future[void]
|
2022-05-19 19:56:03 +00:00
|
|
|
config: CodexConf
|
2022-01-10 15:32:56 +00:00
|
|
|
restServer: RestServerRef
|
2022-05-19 19:56:03 +00:00
|
|
|
codexNode: CodexNodeRef
|
2022-01-10 15:32:56 +00:00
|
|
|
|
2022-05-19 19:56:03 +00:00
|
|
|
proc start*(s: CodexServer) {.async.} =
|
2022-01-10 15:32:56 +00:00
|
|
|
s.restServer.start()
|
2022-05-19 19:56:03 +00:00
|
|
|
await s.codexNode.start()
|
2022-01-10 15:32:56 +00:00
|
|
|
|
|
|
|
s.runHandle = newFuture[void]()
|
|
|
|
await s.runHandle
|
|
|
|
|
2022-05-19 19:56:03 +00:00
|
|
|
proc stop*(s: CodexServer) {.async.} =
|
2022-01-10 15:32:56 +00:00
|
|
|
await allFuturesThrowing(
|
2022-05-19 19:56:03 +00:00
|
|
|
s.restServer.stop(), s.codexNode.stop())
|
2022-01-10 15:32:56 +00:00
|
|
|
|
|
|
|
s.runHandle.complete()
|
|
|
|
|
2022-08-09 04:29:06 +00:00
|
|
|
proc new(_: type ContractInteractions, config: CodexConf): ?ContractInteractions =
|
|
|
|
if not config.persistence:
|
|
|
|
if config.ethAccount.isSome:
|
|
|
|
warn "Ethereum account was set, but persistence is not enabled"
|
|
|
|
return
|
|
|
|
|
|
|
|
without account =? config.ethAccount:
|
|
|
|
error "Persistence enabled, but no Ethereum account was set"
|
|
|
|
quit QuitFailure
|
|
|
|
|
|
|
|
if deployment =? config.ethDeployment:
|
|
|
|
ContractInteractions.new(config.ethProvider, account, deployment)
|
|
|
|
else:
|
|
|
|
ContractInteractions.new(config.ethProvider, account)
|
|
|
|
|
2022-05-19 19:56:03 +00:00
|
|
|
proc new*(T: type CodexServer, config: CodexConf): T =
|
2022-01-10 15:32:56 +00:00
|
|
|
|
2022-04-13 16:32:35 +00:00
|
|
|
const SafePermissions = {UserRead, UserWrite}
|
2022-01-10 15:32:56 +00:00
|
|
|
let
|
2022-04-13 16:32:35 +00:00
|
|
|
privateKey =
|
|
|
|
if config.netPrivKeyFile == "random":
|
|
|
|
PrivateKey.random(Rng.instance()[]).get()
|
|
|
|
else:
|
|
|
|
let path =
|
|
|
|
if config.netPrivKeyFile.isAbsolute:
|
|
|
|
config.netPrivKeyFile
|
|
|
|
else:
|
|
|
|
config.dataDir / config.netPrivKeyFile
|
|
|
|
|
|
|
|
if path.fileAccessible({AccessFlags.Find}):
|
|
|
|
info "Found a network private key"
|
|
|
|
|
|
|
|
if path.getPermissionsSet().get() != SafePermissions:
|
|
|
|
warn "The network private key file is not safe, aborting"
|
|
|
|
quit QuitFailure
|
|
|
|
|
|
|
|
PrivateKey.init(path.readAllBytes().expect("accessible private key file")).
|
|
|
|
expect("valid private key file")
|
|
|
|
else:
|
|
|
|
info "Creating a private key and saving it"
|
|
|
|
let
|
|
|
|
res = PrivateKey.random(Rng.instance()[]).get()
|
|
|
|
bytes = res.getBytes().get()
|
|
|
|
|
|
|
|
path.writeFile(bytes, SafePermissions.toInt()).expect("writing private key file")
|
|
|
|
|
|
|
|
PrivateKey.init(bytes).expect("valid key bytes")
|
|
|
|
|
2022-01-10 15:32:56 +00:00
|
|
|
switch = SwitchBuilder
|
|
|
|
.new()
|
2022-04-13 16:32:35 +00:00
|
|
|
.withPrivateKey(privateKey)
|
2022-10-27 13:44:56 +00:00
|
|
|
.withAddresses(config.listenAddrs)
|
2022-01-10 15:32:56 +00:00
|
|
|
.withRng(Rng.instance())
|
|
|
|
.withNoise()
|
|
|
|
.withMplex(5.minutes, 5.minutes)
|
|
|
|
.withMaxConnections(config.maxPeers)
|
|
|
|
.withAgentVersion(config.agentString)
|
2022-04-13 16:32:35 +00:00
|
|
|
.withSignedPeerRecord(true)
|
2022-01-10 15:32:56 +00:00
|
|
|
.withTcpTransport({ServerFlags.ReuseAddr})
|
|
|
|
.build()
|
|
|
|
|
2022-08-04 23:51:05 +00:00
|
|
|
var
|
|
|
|
cache: CacheStore
|
|
|
|
|
|
|
|
if config.cacheSize > 0:
|
|
|
|
cache = CacheStore.new(cacheSize = config.cacheSize * MiB)
|
2022-03-02 16:30:42 +00:00
|
|
|
|
2022-01-10 15:32:56 +00:00
|
|
|
let
|
2022-09-30 02:16:59 +00:00
|
|
|
discoveryStore = Datastore(SQLiteDatastore.new(
|
|
|
|
config.dataDir / "dht")
|
|
|
|
.expect("Should not fail!"))
|
2022-10-27 13:44:56 +00:00
|
|
|
|
|
|
|
announceAddrs =
|
|
|
|
if config.announceAddrs.len <= 0:
|
|
|
|
config.announceAddrs
|
|
|
|
else:
|
|
|
|
config.listenAddrs
|
|
|
|
|
2022-05-19 02:29:15 +00:00
|
|
|
blockDiscovery = Discovery.new(
|
2022-10-27 13:44:56 +00:00
|
|
|
switch.peerInfo.privateKey,
|
|
|
|
announceAddrs = config.announceAddrs,
|
|
|
|
discoveryPort = config.discoveryPort,
|
|
|
|
bootstrapNodes = config.bootstrapNodes,
|
|
|
|
store = discoveryStore)
|
2022-04-13 16:32:35 +00:00
|
|
|
|
2022-01-10 15:32:56 +00:00
|
|
|
wallet = WalletRef.new(EthPrivateKey.random())
|
|
|
|
network = BlockExcNetwork.new(switch)
|
2022-08-08 21:42:05 +00:00
|
|
|
repoDir = config.dataDir / "repo"
|
|
|
|
|
|
|
|
if io2.createPath(repoDir).isErr:
|
|
|
|
trace "Unable to create data directory for block store", dataDir = repoDir
|
|
|
|
raise (ref Defect)(
|
|
|
|
msg: "Unable to create data directory for block store: " & repoDir)
|
|
|
|
|
|
|
|
let
|
2022-09-30 02:16:59 +00:00
|
|
|
localStore = FSStore.new(repoDir, cache = cache)
|
2022-05-19 02:29:15 +00:00
|
|
|
peerStore = PeerCtxStore.new()
|
|
|
|
pendingBlocks = PendingBlocksManager.new()
|
|
|
|
discovery = DiscoveryEngine.new(localStore, peerStore, network, blockDiscovery, pendingBlocks)
|
|
|
|
engine = BlockExcEngine.new(localStore, wallet, network, discovery, peerStore, pendingBlocks)
|
2022-01-10 15:32:56 +00:00
|
|
|
store = NetworkStore.new(engine, localStore)
|
2022-04-06 00:34:29 +00:00
|
|
|
erasure = Erasure.new(store, leoEncoderProvider, leoDecoderProvider)
|
2022-08-09 04:29:06 +00:00
|
|
|
contracts = ContractInteractions.new(config)
|
2022-05-19 19:56:03 +00:00
|
|
|
codexNode = CodexNodeRef.new(switch, store, engine, erasure, blockDiscovery, contracts)
|
2022-01-10 15:32:56 +00:00
|
|
|
restServer = RestServerRef.new(
|
2022-05-19 19:56:03 +00:00
|
|
|
codexNode.initRestApi(config),
|
2022-01-10 15:32:56 +00:00
|
|
|
initTAddress("127.0.0.1" , config.apiPort),
|
|
|
|
bufferSize = (1024 * 64),
|
|
|
|
maxRequestBodySize = int.high)
|
|
|
|
.tryGet()
|
|
|
|
|
|
|
|
switch.mount(network)
|
|
|
|
T(
|
|
|
|
config: config,
|
2022-05-19 19:56:03 +00:00
|
|
|
codexNode: codexNode,
|
2022-09-30 02:16:59 +00:00
|
|
|
restServer: restServer)
|