2025-12-18 18:23:09 +01:00
|
|
|
## Logos Storage
|
2021-08-30 13:25:20 -06: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 09:32:56 -06:00
|
|
|
import std/sequtils
|
2023-09-13 16:17:56 +02:00
|
|
|
import std/strutils
|
2022-01-10 09:32:56 -06:00
|
|
|
import std/os
|
2022-12-02 18:00:55 -06:00
|
|
|
import std/tables
|
2025-02-12 23:26:26 +05:30
|
|
|
import std/cpuinfo
|
2025-12-11 22:03:36 +01:00
|
|
|
import std/net
|
2022-01-10 09:32:56 -06:00
|
|
|
|
|
|
|
|
import pkg/chronos
|
2025-02-12 23:26:26 +05:30
|
|
|
import pkg/taskpools
|
2022-01-10 09:32:56 -06:00
|
|
|
import pkg/presto
|
|
|
|
|
import pkg/libp2p
|
|
|
|
|
import pkg/confutils
|
|
|
|
|
import pkg/confutils/defs
|
|
|
|
|
import pkg/stew/io2
|
2022-12-02 18:00:55 -06:00
|
|
|
import pkg/datastore
|
2024-03-12 10:57:13 +01:00
|
|
|
import pkg/stew/io2
|
2022-01-10 09:32:56 -06:00
|
|
|
|
|
|
|
|
import ./node
|
|
|
|
|
import ./conf
|
2025-05-29 20:37:38 -03:00
|
|
|
import ./rng as random
|
2022-01-10 09:32:56 -06:00
|
|
|
import ./rest/api
|
2022-03-03 03:30:42 +11:00
|
|
|
import ./stores
|
2022-01-10 09:32:56 -06:00
|
|
|
import ./blockexchange
|
|
|
|
|
import ./utils/fileutils
|
2022-04-13 18:32:35 +02:00
|
|
|
import ./discovery
|
2023-11-22 12:35:26 +01:00
|
|
|
import ./systemclock
|
2022-11-01 18:58:41 -06:00
|
|
|
import ./utils/addrutils
|
2022-12-02 18:00:55 -06:00
|
|
|
import ./namespaces
|
2024-02-19 12:12:10 -06:00
|
|
|
import ./codextypes
|
feat: create logging proxy (#663)
* implement a logging proxy
The logging proxy:
- prevents the need to import chronicles (as well as export except toJson),
- prevents the need to override `writeValue` or use or import nim-json-seralization elsewhere in the codebase, allowing for sole use of utils/json for de/serialization,
- and handles json formatting correctly in chronicles json sinks
* Rename logging -> logutils to avoid ambiguity with common names
* clean up
* add setProperty for JsonRecord, remove nim-json-serialization conflict
* Allow specifying textlines and json format separately
Not specifying a LogFormat will apply the formatting to both textlines and json sinks.
Specifying a LogFormat will apply the formatting to only that sink.
* remove unneeded usages of std/json
We only need to import utils/json instead of std/json
* move serialization from rest/json to utils/json so it can be shared
* fix NoColors ambiguity
Was causing unit tests to fail on Windows.
* Remove nre usage to fix Windows error
Windows was erroring with `could not load: pcre64.dll`. Instead of fixing that error, remove the pcre usage :)
* Add logutils module doc
* Shorten logutils.formatIt for `NBytes`
Both json and textlines formatIt were not needed, and could be combined into one formatIt
* remove debug integration test config
debug output and logformat of json for integration test logs
* Use ## module doc to support docgen
* bump nim-poseidon2 to export fromBytes
Before the changes in this branch, fromBytes was likely being resolved by nim-stew, or other dependency. With the changes in this branch, that dependency was removed and fromBytes could no longer be resolved. By exporting fromBytes from nim-poseidon, the correct resolution is now happening.
* fixes to get compiling after rebasing master
* Add support for Result types being logged using formatIt
2024-01-23 18:35:03 +11:00
|
|
|
import ./logutils
|
2025-01-09 23:41:22 +05:30
|
|
|
import ./nat
|
2022-11-01 18:58:41 -06:00
|
|
|
|
|
|
|
|
logScope:
|
|
|
|
|
topics = "codex node"
|
2022-01-10 09:32:56 -06:00
|
|
|
|
|
|
|
|
type
|
2022-05-19 14:56:03 -05:00
|
|
|
CodexServer* = ref object
|
|
|
|
|
config: CodexConf
|
2022-01-10 09:32:56 -06:00
|
|
|
restServer: RestServerRef
|
2022-05-19 14:56:03 -05:00
|
|
|
codexNode: CodexNodeRef
|
2022-12-02 18:00:55 -06:00
|
|
|
repoStore: RepoStore
|
2023-03-08 16:04:54 +01:00
|
|
|
maintenance: BlockMaintainer
|
2025-06-13 01:19:42 +03:00
|
|
|
taskpool: Taskpool
|
2025-11-13 11:34:09 +04:00
|
|
|
isStarted: bool
|
2022-01-10 09:32:56 -06:00
|
|
|
|
2022-11-01 18:58:41 -06:00
|
|
|
CodexPrivateKey* = libp2p.PrivateKey # alias
|
|
|
|
|
|
2025-11-13 11:34:09 +04:00
|
|
|
func config*(self: CodexServer): CodexConf =
|
|
|
|
|
return self.config
|
|
|
|
|
|
|
|
|
|
func node*(self: CodexServer): CodexNodeRef =
|
|
|
|
|
return self.codexNode
|
|
|
|
|
|
|
|
|
|
func repoStore*(self: CodexServer): RepoStore =
|
|
|
|
|
return self.repoStore
|
|
|
|
|
|
2022-05-19 14:56:03 -05:00
|
|
|
proc start*(s: CodexServer) {.async.} =
|
2025-11-13 11:34:09 +04:00
|
|
|
if s.isStarted:
|
2025-12-18 18:23:09 +01:00
|
|
|
warn "Storage server already started, skipping"
|
2025-11-13 11:34:09 +04:00
|
|
|
return
|
2022-12-02 18:00:55 -06:00
|
|
|
|
2025-12-18 18:23:09 +01:00
|
|
|
trace "Starting Storage node", config = $s.config
|
2022-12-02 18:00:55 -06:00
|
|
|
await s.repoStore.start()
|
2025-11-13 11:34:09 +04:00
|
|
|
|
2023-03-08 16:04:54 +01:00
|
|
|
s.maintenance.start()
|
2022-01-10 09:32:56 -06:00
|
|
|
|
2023-09-04 11:12:20 +02:00
|
|
|
await s.codexNode.switch.start()
|
|
|
|
|
|
2025-01-09 23:41:22 +05:30
|
|
|
let (announceAddrs, discoveryAddrs) = nattedAddress(
|
|
|
|
|
s.config.nat, s.codexNode.switch.peerInfo.addrs, s.config.discoveryPort
|
|
|
|
|
)
|
2022-11-01 18:58:41 -06:00
|
|
|
|
|
|
|
|
s.codexNode.discovery.updateAnnounceRecord(announceAddrs)
|
2025-01-09 23:41:22 +05:30
|
|
|
s.codexNode.discovery.updateDhtRecord(discoveryAddrs)
|
2022-11-01 18:58:41 -06:00
|
|
|
|
2023-09-04 11:12:20 +02:00
|
|
|
await s.codexNode.start()
|
2025-11-13 11:34:09 +04:00
|
|
|
|
|
|
|
|
if s.restServer != nil:
|
|
|
|
|
s.restServer.start()
|
|
|
|
|
|
|
|
|
|
s.isStarted = true
|
2023-09-04 11:12:20 +02:00
|
|
|
|
2022-05-19 14:56:03 -05:00
|
|
|
proc stop*(s: CodexServer) {.async.} =
|
2025-11-13 11:34:09 +04:00
|
|
|
if not s.isStarted:
|
2025-12-18 18:23:09 +01:00
|
|
|
warn "Storage is not started"
|
2025-11-13 11:34:09 +04:00
|
|
|
return
|
|
|
|
|
|
2025-12-18 18:23:09 +01:00
|
|
|
notice "Stopping Storage node"
|
2022-12-02 18:00:55 -06:00
|
|
|
|
2025-11-13 11:34:09 +04:00
|
|
|
var futures =
|
2025-03-13 08:33:15 -06:00
|
|
|
@[
|
|
|
|
|
s.codexNode.switch.stop(),
|
|
|
|
|
s.codexNode.stop(),
|
|
|
|
|
s.repoStore.stop(),
|
|
|
|
|
s.maintenance.stop(),
|
|
|
|
|
]
|
2025-11-13 11:34:09 +04:00
|
|
|
|
|
|
|
|
if s.restServer != nil:
|
|
|
|
|
futures.add(s.restServer.stop())
|
|
|
|
|
|
|
|
|
|
let res = await noCancel allFinishedFailed[void](futures)
|
2022-01-10 09:32:56 -06:00
|
|
|
|
2025-03-13 08:33:15 -06:00
|
|
|
if res.failure.len > 0:
|
2025-12-18 18:23:09 +01:00
|
|
|
error "Failed to stop Storage node", failures = res.failure.len
|
|
|
|
|
raiseAssert "Failed to stop Storage node"
|
2025-03-13 08:33:15 -06:00
|
|
|
|
2025-11-13 11:34:09 +04:00
|
|
|
proc close*(s: CodexServer) {.async.} =
|
|
|
|
|
var futures = @[s.codexNode.close(), s.repoStore.close()]
|
|
|
|
|
|
|
|
|
|
let res = await noCancel allFinishedFailed[void](futures)
|
|
|
|
|
|
2025-06-13 01:19:42 +03:00
|
|
|
if not s.taskpool.isNil:
|
2025-11-13 11:34:09 +04:00
|
|
|
try:
|
|
|
|
|
s.taskpool.shutdown()
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
error "Failed to stop the taskpool", failures = res.failure.len
|
|
|
|
|
raiseAssert("Failure in taskpool shutdown:" & exc.msg)
|
|
|
|
|
|
|
|
|
|
if res.failure.len > 0:
|
2025-12-18 18:23:09 +01:00
|
|
|
error "Failed to close Storage node", failures = res.failure.len
|
|
|
|
|
raiseAssert "Failed to close Storage node"
|
2025-11-13 11:34:09 +04:00
|
|
|
|
|
|
|
|
proc shutdown*(server: CodexServer) {.async.} =
|
|
|
|
|
await server.stop()
|
|
|
|
|
await server.close()
|
2025-06-13 01:19:42 +03:00
|
|
|
|
2023-06-21 15:02:05 -07:00
|
|
|
proc new*(
|
2024-01-15 10:45:04 -06:00
|
|
|
T: type CodexServer, config: CodexConf, privateKey: CodexPrivateKey
|
|
|
|
|
): CodexServer =
|
2023-06-21 15:02:05 -07:00
|
|
|
## create CodexServer including setting up datastore, repostore, etc
|
2022-01-10 09:32:56 -06:00
|
|
|
let switch = SwitchBuilder
|
|
|
|
|
.new()
|
2022-04-13 18:32:35 +02:00
|
|
|
.withPrivateKey(privateKey)
|
2022-10-27 07:44:56 -06:00
|
|
|
.withAddresses(config.listenAddrs)
|
2025-05-29 20:37:38 -03:00
|
|
|
.withRng(random.Rng.instance())
|
2022-01-10 09:32:56 -06:00
|
|
|
.withNoise()
|
|
|
|
|
.withMplex(5.minutes, 5.minutes)
|
|
|
|
|
.withMaxConnections(config.maxPeers)
|
|
|
|
|
.withAgentVersion(config.agentString)
|
2022-04-13 18:32:35 +02:00
|
|
|
.withSignedPeerRecord(true)
|
2025-11-13 07:47:02 +02:00
|
|
|
.withTcpTransport({ServerFlags.ReuseAddr, ServerFlags.TcpNoDelay})
|
2022-01-10 09:32:56 -06:00
|
|
|
.build()
|
|
|
|
|
|
2025-02-12 23:26:26 +05:30
|
|
|
var
|
|
|
|
|
cache: CacheStore = nil
|
|
|
|
|
taskpool: Taskpool
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
if config.numThreads == ThreadCount(0):
|
|
|
|
|
taskpool = Taskpool.new(numThreads = min(countProcessors(), 16))
|
|
|
|
|
else:
|
|
|
|
|
taskpool = Taskpool.new(numThreads = int(config.numThreads))
|
|
|
|
|
info "Threadpool started", numThreads = taskpool.numThreads
|
|
|
|
|
except CatchableError as exc:
|
|
|
|
|
raiseAssert("Failure in taskpool initialization:" & exc.msg)
|
2022-08-04 18:51:05 -05:00
|
|
|
|
2023-07-06 16:23:27 -07:00
|
|
|
if config.cacheSize > 0'nb:
|
|
|
|
|
cache = CacheStore.new(cacheSize = config.cacheSize)
|
2023-03-08 16:04:54 +01:00
|
|
|
## Is unused?
|
2022-03-03 03:30:42 +11:00
|
|
|
|
2022-12-02 18:00:55 -06:00
|
|
|
let discoveryDir = config.dataDir / CodexDhtNamespace
|
|
|
|
|
|
|
|
|
|
if io2.createPath(discoveryDir).isErr:
|
|
|
|
|
trace "Unable to create discovery directory for block store",
|
|
|
|
|
discoveryDir = discoveryDir
|
|
|
|
|
raise (ref Defect)(
|
|
|
|
|
msg: "Unable to create discovery directory for block store: " & discoveryDir
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
let
|
|
|
|
|
discoveryStore = Datastore(
|
2024-05-30 08:57:10 +02:00
|
|
|
LevelDbDatastore.new(config.dataDir / CodexDhtProvidersNamespace).expect(
|
2022-12-02 18:00:55 -06:00
|
|
|
"Should create discovery datastore!"
|
|
|
|
|
)
|
2025-01-21 21:54:46 +01:00
|
|
|
)
|
2022-10-27 07:44:56 -06:00
|
|
|
|
2022-11-01 18:58:41 -06:00
|
|
|
discovery = Discovery.new(
|
2022-10-27 07:44:56 -06:00
|
|
|
switch.peerInfo.privateKey,
|
2022-11-01 18:58:41 -06:00
|
|
|
announceAddrs = config.listenAddrs,
|
|
|
|
|
bindPort = config.discoveryPort,
|
2022-10-27 07:44:56 -06:00
|
|
|
bootstrapNodes = config.bootstrapNodes,
|
|
|
|
|
store = discoveryStore,
|
|
|
|
|
)
|
2022-04-13 18:32:35 +02:00
|
|
|
|
2022-01-10 09:32:56 -06:00
|
|
|
network = BlockExcNetwork.new(switch)
|
2022-08-08 16:42:05 -05:00
|
|
|
|
2023-03-14 18:32:15 -04:00
|
|
|
repoData =
|
|
|
|
|
case config.repoKind
|
|
|
|
|
of repoFS:
|
|
|
|
|
Datastore(
|
|
|
|
|
FSDatastore.new($config.dataDir, depth = 5).expect(
|
|
|
|
|
"Should create repo file data store!"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
of repoSQLite:
|
|
|
|
|
Datastore(
|
|
|
|
|
SQLiteDatastore.new($config.dataDir).expect(
|
|
|
|
|
"Should create repo SQLite data store!"
|
|
|
|
|
)
|
2024-05-30 08:57:10 +02:00
|
|
|
)
|
|
|
|
|
of repoLevelDb:
|
|
|
|
|
Datastore(
|
|
|
|
|
LevelDbDatastore.new($config.dataDir).expect(
|
|
|
|
|
"Should create repo LevelDB data store!"
|
|
|
|
|
)
|
2025-01-21 21:54:46 +01:00
|
|
|
)
|
2023-03-14 18:32:15 -04:00
|
|
|
|
2022-12-02 18:00:55 -06:00
|
|
|
repoStore = RepoStore.new(
|
2023-03-14 18:32:15 -04:00
|
|
|
repoDs = repoData,
|
2024-05-30 08:57:10 +02:00
|
|
|
metaDs = LevelDbDatastore.new(config.dataDir / CodexMetaNamespace).expect(
|
|
|
|
|
"Should create metadata store!"
|
|
|
|
|
),
|
2024-06-21 00:46:06 +02:00
|
|
|
quotaMaxBytes = config.storageQuota,
|
2023-07-06 16:23:27 -07:00
|
|
|
blockTtl = config.blockTtl,
|
|
|
|
|
)
|
2023-03-08 16:04:54 +01:00
|
|
|
|
|
|
|
|
maintenance = BlockMaintainer.new(
|
|
|
|
|
repoStore,
|
2023-07-06 16:23:27 -07:00
|
|
|
interval = config.blockMaintenanceInterval,
|
2023-03-08 16:04:54 +01:00
|
|
|
numberOfBlocksPerInterval = config.blockMaintenanceNumberOfBlocks,
|
|
|
|
|
)
|
2022-08-08 16:42:05 -05:00
|
|
|
|
2022-05-18 20:29:15 -06:00
|
|
|
peerStore = PeerCtxStore.new()
|
2025-11-13 11:34:09 +04:00
|
|
|
pendingBlocks = PendingBlocksManager.new(retries = config.blockRetries)
|
2024-08-26 15:18:59 +02:00
|
|
|
advertiser = Advertiser.new(repoStore, discovery)
|
2022-12-02 18:00:55 -06:00
|
|
|
blockDiscovery =
|
|
|
|
|
DiscoveryEngine.new(repoStore, peerStore, network, discovery, pendingBlocks)
|
2024-08-26 15:18:59 +02:00
|
|
|
engine = BlockExcEngine.new(
|
2025-12-17 15:20:48 +11:00
|
|
|
repoStore, network, blockDiscovery, advertiser, peerStore, pendingBlocks
|
2024-08-26 15:18:59 +02:00
|
|
|
)
|
2022-12-02 18:00:55 -06:00
|
|
|
store = NetworkStore.new(engine, repoStore)
|
2024-02-19 12:12:10 -06:00
|
|
|
|
|
|
|
|
codexNode = CodexNodeRef.new(
|
|
|
|
|
switch = switch,
|
|
|
|
|
networkStore = store,
|
|
|
|
|
engine = engine,
|
2024-03-23 10:56:35 +01:00
|
|
|
discovery = discovery,
|
2025-02-12 23:26:26 +05:30
|
|
|
taskPool = taskpool,
|
2025-01-10 15:12:37 +01:00
|
|
|
)
|
2025-01-21 21:54:46 +01:00
|
|
|
|
2025-11-13 11:34:09 +04:00
|
|
|
var restServer: RestServerRef = nil
|
|
|
|
|
|
|
|
|
|
if config.apiBindAddress.isSome:
|
2022-01-10 09:32:56 -06:00
|
|
|
restServer = RestServerRef
|
|
|
|
|
.new(
|
2024-06-17 21:33:21 +10:00
|
|
|
codexNode.initRestApi(config, repoStore, config.apiCorsAllowedOrigin),
|
2025-11-13 11:34:09 +04:00
|
|
|
initTAddress(config.apiBindAddress.get(), config.apiPort),
|
2022-01-10 09:32:56 -06:00
|
|
|
bufferSize = (1024 * 64),
|
|
|
|
|
maxRequestBodySize = int.high,
|
|
|
|
|
)
|
2025-02-24 15:01:23 -06:00
|
|
|
.expect("Should create rest server!")
|
2022-01-10 09:32:56 -06:00
|
|
|
|
|
|
|
|
switch.mount(network)
|
2023-06-21 15:02:05 -07:00
|
|
|
|
2023-06-22 08:11:18 -07:00
|
|
|
CodexServer(
|
2022-01-10 09:32:56 -06:00
|
|
|
config: config,
|
2022-05-19 14:56:03 -05:00
|
|
|
codexNode: codexNode,
|
2022-12-02 18:00:55 -06:00
|
|
|
restServer: restServer,
|
2023-03-08 16:04:54 +01:00
|
|
|
repoStore: repoStore,
|
2025-01-10 15:12:37 +01:00
|
|
|
maintenance: maintenance,
|
2025-06-13 01:19:42 +03:00
|
|
|
taskpool: taskpool,
|
2025-01-10 15:12:37 +01:00
|
|
|
)
|