Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
dba938d
Init library
2-towns Sep 9, 2025
1ea8e0b
Define pragma raises
2-towns Sep 9, 2025
11c868c
Move the updateLogLevel in the main file in order to avoid gcsafe error
2-towns Sep 9, 2025
c6b2578
Catch exception when shutting down taskpool
2-towns Sep 9, 2025
869759b
Refactor the config in order to share parse functions with json parse
2-towns Sep 9, 2025
75803af
Set dynamic build as default
2-towns Sep 11, 2025
e5fd789
Log fatal when command line argument cannot be parsed
2-towns Sep 11, 2025
3bb2bd0
Define raises pragma for the whole file
2-towns Sep 11, 2025
fcdb0df
Avoid raising errors in the spawn threads
2-towns Sep 11, 2025
f28f6a3
Simplify a bit by removing handleRequest func
2-towns Sep 11, 2025
6f9557b
Add limitation doc
2-towns Sep 11, 2025
820d535
Use await keyword as soon as possible to yield to the event event loop
2-towns Sep 12, 2025
e1f6977
Replace version git command to get the last tag
2-towns Sep 12, 2025
c9670e8
Return the Codex version
2-towns Sep 12, 2025
fc5d069
Add codex revision
2-towns Sep 12, 2025
8fe29c6
Provide a better API with ACK and OK differenciation
2-towns Sep 12, 2025
aa2128d
Add repo and fix pointer freeing memory
2-towns Sep 16, 2025
e9da685
Remove ACK and CODEX_CALL in order to return the first RET value in t…
2-towns Sep 16, 2025
2d578f9
Add async method with callabck for Codex start
2-towns Sep 16, 2025
5ea6081
Expose config and node via getters
2-towns Sep 16, 2025
d124146
Add debug feature
2-towns Sep 16, 2025
c6febf2
Add spr
2-towns Sep 16, 2025
d4958f2
Add peer id and add debug request
2-towns Sep 17, 2025
899a194
Add log level
2-towns Sep 17, 2025
0ed1d5a
Remove log level from the conf because the log level has to be set wi…
2-towns Sep 17, 2025
1000a14
Add peer connect
2-towns Sep 17, 2025
f6b0f7c
Add peer debug
2-towns Sep 17, 2025
4eda7c7
Add upload feature
2-towns Sep 18, 2025
f02d4b2
Refactoring
2-towns Sep 18, 2025
8119a1d
Fix empty codex version and revision empty
2-towns Sep 18, 2025
5b57739
Add method to upload from a reader
2-towns Sep 18, 2025
2e76aeb
Update chunk size to uint32
2-towns Sep 18, 2025
614684c
Add upload file API
2-towns Sep 19, 2025
378dbfe
Add progress callback for upload
2-towns Sep 22, 2025
c01c913
Cap the percent to 100 because of the difference between the block si…
2-towns Sep 22, 2025
5d56a45
Use cancelSoon instead of cancel
2-towns Sep 22, 2025
d9cb745
Add async version for file upload
2-towns Sep 22, 2025
1cd6a94
Use faststream, provide better cleanup and comments
2-towns Sep 23, 2025
4f40be4
Provide better comments
2-towns Sep 23, 2025
3333e91
Add more comment
2-towns Sep 23, 2025
9a86c48
Provide better api for progress, fix memory pointer issues and improv…
2-towns Sep 25, 2025
e6330e2
Provide better logs (hopefully)
2-towns Sep 25, 2025
3535b21
Rename OnBlockStored
2-towns Sep 29, 2025
56cf2d4
Remove dead code
2-towns Sep 29, 2025
792ba0e
Refactore upload for better memory management with thread and avoid s…
2-towns Sep 29, 2025
56b01d5
Refactor to avoid memory issues and add download local
2-towns Sep 30, 2025
8bee7ec
Add download streaming mode
2-towns Sep 30, 2025
421c88b
Add comments
2-towns Sep 30, 2025
f883bba
Add manifest
2-towns Oct 1, 2025
f9aa69a
Add storage list
2-towns Oct 1, 2025
e4d1d22
Add node storage fetch (network download to local node)
2-towns Oct 1, 2025
007f92c
Add node space
2-towns Oct 1, 2025
74e7f08
Add storage delete (block or dataset delete)
2-towns Oct 1, 2025
ffae046
Define raises for async pragma for waitUntil
2-towns Oct 2, 2025
1d24d1a
Cancel the download in the example to avoid to keep a future and stre…
2-towns Oct 2, 2025
eb562bc
Fix log message
2-towns Oct 2, 2025
db5109a
Fix mock clock
2-towns Oct 2, 2025
40cc019
Make rest api server optional
2-towns Oct 2, 2025
fe7e9b3
Reraise cancelled error
2-towns Oct 3, 2025
95a562e
Add chronicles build args to filter logs
2-towns Oct 6, 2025
56d5db1
Add chronicles logging configuration
2-towns Oct 6, 2025
2784c88
Separate stop and close features for restartability
2-towns Oct 7, 2025
c028073
Export shutdown proc
2-towns Oct 7, 2025
5531c78
Pass build parameters to the task build library
2-towns Oct 7, 2025
34b19cf
Add p2p build argument
2-towns Oct 7, 2025
0285ac8
Add missing peerAddresses
2-towns Oct 7, 2025
bb81405
Add blockRetries parameter
2-towns Oct 8, 2025
c6652af
Split close and destroy in separate functions
2-towns Oct 9, 2025
76772fb
Add dll library build for windows
2-towns Oct 10, 2025
847136f
Add specific chronicles_sinks for windows
2-towns Oct 10, 2025
3bf2161
Fix missing &
2-towns Oct 10, 2025
2bc5371
Remove skipParentCfg build param
2-towns Oct 10, 2025
263767d
Fib lib name on windows
2-towns Oct 10, 2025
7ada6af
Fix lib name on windows
2-towns Oct 10, 2025
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
26 changes: 26 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ format:
$(NPH) *.nim
$(NPH) codex/
$(NPH) tests/
$(NPH) library/

clean-nph:
rm -f $(NPH)
Expand All @@ -242,4 +243,29 @@ print-nph-path:

clean: | clean-nph

################
## C Bindings ##
################
.PHONY: libcodex

STATIC ?= 0

ifneq ($(strip $(CODEX_LIB_PARAMS)),)
NIM_PARAMS := $(NIM_PARAMS) $(CODEX_LIB_PARAMS)
endif

libcodex:
$(MAKE) deps
rm -f build/libcodex*

ifeq ($(STATIC), 1)
echo -e $(BUILD_MSG) "build/$@.a" && \
$(ENV_SCRIPT) nim libcodexStatic $(NIM_PARAMS) codex.nims
else ifeq ($(detected_OS),Windows)
echo -e $(BUILD_MSG) "build/$@.dll" && \
$(ENV_SCRIPT) nim libcodexDynamic $(NIM_PARAMS) codex.nims
else
echo -e $(BUILD_MSG) "build/$@.so" && \
$(ENV_SCRIPT) nim libcodexDynamic $(NIM_PARAMS) codex.nims
endif
endif # "variables.mk" was not included
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,56 @@ To get acquainted with Codex, consider:

The client exposes a REST API that can be used to interact with the clients. Overview of the API can be found on [api.codex.storage](https://api.codex.storage).

## Bindings

Codex provides a C API that can be wrapped by other languages. The bindings is located in the `library` folder.
Currently, only a Go binding is included.

### Build the C library

```bash
make libcodex
```

This produces the shared library under `build/`.

### Run the Go example

Build the Go example:

```bash
go build -o codex-go examples/golang/codex.go
```

Export the library path:

```bash
export LD_LIBRARY_PATH=build
```

Run the example:

```bash
./codex-go
```

### Static vs Dynamic build

By default, Codex builds a dynamic library (`libcodex.so`), which you can load at runtime.
If you prefer a static library (`libcodex.a`), set the `STATIC` flag:

### Limitation

Callbacks must be fast and non-blocking; otherwise, the working thread will hang and prevent other requests from being processed.

```bash
# Build dynamic (default)
make libcodex

# Build static
make STATIC=1 libcodex
```

## Contributing and development

Feel free to dive in, contributions are welcomed! Open an issue or submit PRs.
Expand Down
41 changes: 41 additions & 0 deletions build.nims
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,27 @@ proc buildBinary(name: string, srcDir = "./", params = "", lang = "c") =

exec(cmd)

proc buildLibrary(name: string, srcDir = "./", params = "", `type` = "dynamic") =
if not dirExists "build":
mkDir "build"

if `type` == "dynamic":
let lib_name = (when defined(windows): name & ".dll" else: name & ".so")
exec "nim c" & " --out:build/" & lib_name & " --threads:on --app:lib --opt:size --noMain --mm:refc --header --d:metrics " &
"--nimMainPrefix:libcodex -d:noSignalHandler " &
"-d:LeopardExtraCompilerFlags=-fPIC " &
"-d:chronicles_runtime_filtering " &
"-d:chronicles_log_level=TRACE " &
params & " " & srcDir & name & ".nim"
else:
exec "nim c" & " --out:build/" & name &
".a --threads:on --app:staticlib --opt:size --noMain --mm:refc --header --d:metrics " &
"--nimMainPrefix:libcodex -d:noSignalHandler " &
"-d:LeopardExtraCompilerFlags=-fPIC " &
"-d:chronicles_runtime_filtering " &
"-d:chronicles_log_level=TRACE " &
params & " " & srcDir & name & ".nim"

proc test(name: string, srcDir = "tests/", params = "", lang = "c") =
buildBinary name, srcDir, params
exec "build/" & name
Expand Down Expand Up @@ -121,3 +142,23 @@ task showCoverage, "open coverage html":
echo " ======== Opening HTML coverage report in browser... ======== "
if findExe("open") != "":
exec("open coverage/report/index.html")

task libcodexDynamic, "Generate bindings":
var params = ""
when compiles(commandLineParams):
for param in commandLineParams():
if param.len > 0 and param.startsWith("-"):
params.add " " & param

let name = "libcodex"
buildLibrary name, "library/", params, "dynamic"

task libcodextatic, "Generate bindings":
var params = ""
when compiles(commandLineParams):
for param in commandLineParams():
if param.len > 0 and param.startsWith("-"):
params.add " " & param

let name = "libcodex"
buildLibrary name, "library/", params, "static"
12 changes: 11 additions & 1 deletion codex.nim
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ when isMainModule:
,
)
config.setupLogging()

try:
updateLogLevel(config.logLevel)
except ValueError as err:
try:
stderr.write "Invalid value for --log-level. " & err.msg & "\n"
except IOError:
echo "Invalid value for --log-level. " & err.msg
quit QuitFailure
Comment on lines +58 to +65
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't this already called in setupLogging?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I removed it from the setupLogging because the compiler was complaining about gcsafe issue.


config.setupMetrics()

if not (checkAndCreateDataDir((config.dataDir).string)):
Expand Down Expand Up @@ -94,7 +104,7 @@ when isMainModule:

## Ctrl+C handling
proc doShutdown() =
shutdown = server.stop()
shutdown = server.shutdown()
state = CodexStatus.Stopping

notice "Stopping Codex"
Expand Down
6 changes: 5 additions & 1 deletion codex/clock.nim
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{.push raises: [].}

import pkg/chronos
import pkg/stew/endians2
import pkg/upraises
Expand All @@ -11,7 +13,9 @@ type
method now*(clock: Clock): SecondsSince1970 {.base, gcsafe, upraises: [].} =
raiseAssert "not implemented"

method waitUntil*(clock: Clock, time: SecondsSince1970) {.base, async.} =
method waitUntil*(
clock: Clock, time: SecondsSince1970
) {.base, async: (raises: [CancelledError]).} =
raiseAssert "not implemented"

method start*(clock: Clock) {.base, async.} =
Expand Down
50 changes: 42 additions & 8 deletions codex/codex.nim
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ type
CodexPrivateKey* = libp2p.PrivateKey # alias
EthWallet = ethers.Wallet

func config*(self: CodexServer): CodexConf =
return self.config

func node*(self: CodexServer): CodexNodeRef =
return self.codexNode

func repoStore*(self: CodexServer): RepoStore =
return self.repoStore

proc waitForSync(provider: Provider): Future[void] {.async.} =
var sleepTime = 1
trace "Checking sync state of Ethereum provider..."
Expand Down Expand Up @@ -160,8 +169,8 @@ proc bootstrapInteractions(s: CodexServer): Future[void] {.async.} =

proc start*(s: CodexServer) {.async.} =
trace "Starting codex node", config = $s.config

await s.repoStore.start()

s.maintenance.start()

await s.codexNode.switch.start()
Expand All @@ -175,27 +184,49 @@ proc start*(s: CodexServer) {.async.} =

await s.bootstrapInteractions()
await s.codexNode.start()
s.restServer.start()

if s.restServer != nil:
s.restServer.start()

proc stop*(s: CodexServer) {.async.} =
notice "Stopping codex node"

let res = await noCancel allFinishedFailed[void](
var futures =
@[
s.restServer.stop(),
s.codexNode.switch.stop(),
s.codexNode.stop(),
s.repoStore.stop(),
s.maintenance.stop(),
]
)

if s.restServer != nil:
futures.add(s.restServer.stop())

let res = await noCancel allFinishedFailed[void](futures)

if res.failure.len > 0:
error "Failed to stop codex node", failures = res.failure.len
raiseAssert "Failed to stop codex node"

proc close*(s: CodexServer) {.async.} =
var futures = @[s.codexNode.close(), s.repoStore.close()]

let res = await noCancel allFinishedFailed[void](futures)

if not s.taskpool.isNil:
s.taskpool.shutdown()
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:
error "Failed to close codex node", failures = res.failure.len
raiseAssert "Failed to close codex node"

proc shutdown*(server: CodexServer) {.async.} =
await server.stop()
await server.close()

proc new*(
T: type CodexServer, config: CodexConf, privateKey: CodexPrivateKey
Expand Down Expand Up @@ -295,7 +326,7 @@ proc new*(
)

peerStore = PeerCtxStore.new()
pendingBlocks = PendingBlocksManager.new()
pendingBlocks = PendingBlocksManager.new(retries = config.blockRetries)
advertiser = Advertiser.new(repoStore, discovery)
blockDiscovery =
DiscoveryEngine.new(repoStore, peerStore, network, discovery, pendingBlocks)
Expand All @@ -320,10 +351,13 @@ proc new*(
taskPool = taskpool,
)

var restServer: RestServerRef = nil

if config.apiBindAddress.isSome:
restServer = RestServerRef
.new(
codexNode.initRestApi(config, repoStore, config.apiCorsAllowedOrigin),
initTAddress(config.apiBindAddress, config.apiPort),
initTAddress(config.apiBindAddress.get(), config.apiPort),
bufferSize = (1024 * 64),
maxRequestBodySize = int.high,
)
Expand Down
Loading
Loading