Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
184 commits
Select commit Hold shift + click to select a range
912cb3d
wip
dryajov Jan 29, 2026
78d1eea
fix(nimble): use submodules instead of nimble dependencies
markspanbroek Jan 29, 2026
a95d06a
wip: reworking with kvstore and overlays
dryajov Feb 4, 2026
708ef6d
feat: fixing bugs and minor cleanup
dryajov Feb 5, 2026
e3e81e9
wip
dryajov Feb 9, 2026
bb5ff9a
feat: add overlay operations
dryajov Feb 10, 2026
2231438
rename keys
dryajov Feb 10, 2026
eb667c7
feat: add putLeafsAndBlocks support
dryajov Feb 10, 2026
def4dc5
misc
dryajov Feb 10, 2026
8de7164
add hash support for block types
dryajov Feb 10, 2026
fd2d4ef
wip tests
dryajov Feb 10, 2026
4c26b81
use cid for hashing
dryajov Feb 11, 2026
a9eaf77
feat: handle bitseqs and duplicate blocks with different leafs
dryajov Feb 11, 2026
3f8b5da
mic cleanup
dryajov Feb 11, 2026
ccc9526
feat: expose new putLeafAndBlock methods on network store, fix minor …
dryajov Feb 11, 2026
f41e19f
feat: migrate to kvstore, drop leveldb and nim-datastore
dryajov Feb 11, 2026
a1516e3
chore: remove TempLevelDb and CacheStore from tests, use in-memory SQ…
dryajov Feb 11, 2026
e67c815
fix: missing poseidon2digest import in builder, restore marketplace t…
dryajov Feb 11, 2026
615fe33
feat: overlay tests
dryajov Feb 11, 2026
a3ef5f0
rebasing main
dryajov Feb 11, 2026
c3a9a38
bump submodules
dryajov Feb 11, 2026
b357f85
ignore files
dryajov Feb 11, 2026
28f771c
feat: remove datastore deps
dryajov Feb 11, 2026
aa81487
refactor: migrate chunker to result-based api and update callers
dryajov Feb 11, 2026
deb61d3
feat: add bitseq combineSafe utility
dryajov Feb 12, 2026
ddbb8cf
refactor: simplify treehelper error handling
dryajov Feb 12, 2026
7bae0d3
refactor: improve overlay and repostore operations
dryajov Feb 12, 2026
14bfc22
feat: migrate node to overlay semantics
dryajov Feb 12, 2026
146d7c4
feat: migrate erasure to overlay semantics
dryajov Feb 12, 2026
826cb9e
feat: migrate slot builder to overlay semantics
dryajov Feb 12, 2026
ed79c49
refactor: update test helpers for overlay migration
dryajov Feb 12, 2026
3b68b6b
refactor: update tests for overlay migration
dryajov Feb 12, 2026
4df5672
fix: update call sites for dual-store overlay semantics
dryajov Feb 12, 2026
46ab602
refactor: remove manifest param and ensureExpiry, simplify overlay si…
dryajov Feb 12, 2026
3ef34ac
fix: handle uninitialized bitseq in combineSafe and overlay creation
dryajov Feb 12, 2026
3e5a0d9
chore: checkpoint overlay and erasure migration
dryajov Feb 14, 2026
a452e29
feat: implement withTmpOverlay dataset store
dryajov Feb 14, 2026
7285c01
misc: proper casts
dryajov Feb 14, 2026
312300f
fix: put proofs under the correct tree on upload
dryajov Feb 14, 2026
7dc8f07
misc: added todo in engine
dryajov Feb 14, 2026
d02805c
misc: formatting
dryajov Feb 14, 2026
9b46793
fix: tidy up overlay decoding lifecycle
dryajov Feb 14, 2026
07f9985
feat: proper upsert for availability
dryajov Feb 14, 2026
2ad06a5
fix: shutdown sequence
dryajov Feb 14, 2026
244f637
fix: avoid sigsegv on shutdowns
dryajov Feb 14, 2026
e80e068
fix: don't crash on nil proof
dryajov Feb 14, 2026
569b9ef
feat: do proper leaf merge
dryajov Feb 14, 2026
d813542
fix: proper nil type result handling
dryajov Feb 14, 2026
948dc81
feat: handle cancellations better in overlays
dryajov Feb 14, 2026
e739431
fix purchasing tests
dryajov Feb 14, 2026
aa719bd
feat: updated expiry handling
dryajov Feb 14, 2026
e22da22
fix: re-enable and fix failing tests
dryajov Feb 14, 2026
a88fa6a
format
dryajov Feb 14, 2026
7c5427c
debug: allow all jobs to complete
dryajov Feb 14, 2026
6a9cf60
feat: handle deletes with overlays (first pass)
dryajov Feb 14, 2026
220243a
feat: remove old expiry handling from node
dryajov Feb 14, 2026
237cfe1
feat: return proper error on missing dataset delete
dryajov Feb 14, 2026
6ee349d
re-enable import (do we need it?)
dryajov Feb 14, 2026
3518bd3
feat: use putLeafAndBlock in engine
dryajov Feb 14, 2026
121dbc7
feat: remplement maintenance and avoid concurrent deletes
dryajov Feb 15, 2026
c8bc042
fix: test maintenance with overlays
dryajov Feb 15, 2026
a7eeafa
feat: make sure download overlay is tracked
dryajov Feb 15, 2026
12a2080
feat: remove expiry from download flow
dryajov Feb 15, 2026
5a971e5
feat: rework repostore type serde with pb
dryajov Feb 15, 2026
1761e83
feat: use protobuf for speed in codecs
dryajov Feb 15, 2026
a1f7c77
feat: store manifest cid in overlay for easy manifest retrieval
dryajov Feb 15, 2026
b376760
fix: avoid sigsegv during shutdown
dryajov Feb 15, 2026
6b19152
fix: close stream on comple in node.store
dryajov Feb 15, 2026
53bea50
feat: re-enable common tests
dryajov Feb 15, 2026
95cd5a8
feat: initial blocks bitmap optimizations
dryajov Feb 15, 2026
df268d4
feat: cleanup block bitmap handling and more tests
dryajov Feb 15, 2026
5510f8c
misc: get rid of asyncchecksuit
dryajov Feb 15, 2026
f688d2a
feat: properly merge overlay data on updates
dryajov Feb 16, 2026
a849b92
fix: remove unused import
dryajov Feb 16, 2026
ff38a92
bump deps
dryajov Feb 16, 2026
bac5368
feat: consolidate overlay case putorupdate
dryajov Feb 16, 2026
34dc1df
format
dryajov Feb 16, 2026
edab387
format
dryajov Feb 16, 2026
85fcbec
bump kvstore
dryajov Feb 16, 2026
5c025ab
Fix nimgroth16 zero-proof bug: assert -> doAssert in converters.nim
dryajov Feb 17, 2026
cfdd639
bump metrics and kvstore
dryajov Feb 17, 2026
4ae36ed
bump kvstore after format
dryajov Feb 17, 2026
523a63d
feat: use batched versions to put proofs
dryajov Feb 17, 2026
61581ed
misc: formatting
dryajov Feb 17, 2026
3798ed5
feat: make finilize safe
dryajov Feb 17, 2026
c5eacb5
feat: remove size from block meta
dryajov Feb 17, 2026
25bc6d9
feat: add downloading type to distinguish from storing
dryajov Feb 17, 2026
0d0bf86
feat: remove size from block meta
dryajov Feb 17, 2026
5e1e422
feat: rename update to sync and syncUnsafe
dryajov Feb 17, 2026
62172ee
feat: use syncModules & syncUnsafe - to avoid clashing with nimble bu…
dryajov Feb 17, 2026
43ed736
misc: format
dryajov Feb 17, 2026
7dc802e
misc: bump kvstore
dryajov Feb 17, 2026
d322da1
misc: move sync tasks to the bottom
dryajov Feb 17, 2026
fdb6bcf
Add E2E testing infrastructure
dryajov Feb 16, 2026
ead1301
Update E2E infrastructure: fix test script, prometheus config, add da…
dryajov Feb 17, 2026
47773f2
Add kvstore metrics and update E2E monitoring config
dryajov Feb 17, 2026
0390129
Update Grafana dashboard with comprehensive kvstore metrics
dryajov Feb 17, 2026
34f54ae
replace oid with rng
dryajov Feb 18, 2026
ff5c0fd
feat: properly handle re-upload with same treeCid (same data) in fini…
dryajov Feb 18, 2026
c0c931e
feat: properly track slots with overlays
dryajov Feb 18, 2026
746e488
misc: update grafana dashboard
dryajov Feb 18, 2026
fbac395
bump kvstore
dryajov Feb 18, 2026
8b43740
feat: standardize manifest tracking and dataset deletion
dryajov Feb 19, 2026
0734058
feat: delete dataset safely during cleanup for temp overlays
dryajov Feb 19, 2026
7e778d1
misc: cleanup tests
dryajov Feb 19, 2026
c124057
feat: adding grafana, prometheus and updating metrics
dryajov Feb 16, 2026
db82e4d
misc: drop unneeded test files
dryajov Feb 19, 2026
9584873
feat: dispose listBlocks iterator in discovery
dryajov Feb 19, 2026
cd4337f
fix: drop overlay with refcount reconsiliation
dryajov Feb 20, 2026
7bb2166
bump kvstore
dryajov Feb 20, 2026
9aa220f
bump kvstore
dryajov Feb 20, 2026
acf87c6
feat: added batching for downloads
dryajov Feb 21, 2026
9bc6b0b
feat: remove blockaddress type - constrain to blockexchange engine only
dryajov Feb 21, 2026
ac20cd5
feat: speed up download by reading more bytes from storestream
dryajov Feb 21, 2026
42554f8
feat: avoid excessive string allocation
dryajov Feb 21, 2026
a19f288
feat: add batched get block
dryajov Feb 21, 2026
0dee08f
feat: batched getblocks
dryajov Feb 21, 2026
78cfda7
remove blockaddress methods from the store
dryajov Feb 21, 2026
243e18e
feat: avoid excessive string & key reallocations
dryajov Feb 21, 2026
d49ecfa
feat: batch block reads - use getBlocks
dryajov Feb 21, 2026
088e39a
feat: use batched downloads with getBlocks
dryajov Feb 21, 2026
4360adf
misc: small cleanup
dryajov Feb 21, 2026
648356b
perf: replace per-block hasBlock with single bitmap fetch in fetchBat…
dryajov Feb 21, 2026
58140fd
feat: fix storestream hanging on no blocks
dryajov Feb 23, 2026
95aa72e
bump nim-kvstore
dryajov Feb 23, 2026
048a345
feat: add fsds options
dryajov Feb 24, 2026
e9892d9
feat: add overlay caching
dryajov Feb 25, 2026
3c37e39
wip
dryajov Feb 25, 2026
bddf8d3
feat: passthrough fsstore args
dryajov Feb 25, 2026
7b32d08
feat: ignore default circuit locations during tests
dryajov Feb 25, 2026
4eec4c1
bump kvstore
dryajov Feb 25, 2026
001d320
fix: make sure cache and middleware updates are consistent
dryajov Feb 25, 2026
551aa91
fix: don't override block bits in middleware
dryajov Feb 26, 2026
5f7ff39
fix: overlay cache eviction order
dryajov Feb 26, 2026
324fb01
feat: add upload batching
dryajov Feb 26, 2026
87d0129
misc: debug helper comment
dryajov Feb 26, 2026
9d53e4d
bump kvstore
dryajov Feb 26, 2026
1cfa464
bump kvstore
dryajov Feb 26, 2026
bf6b9b8
bump kvstore
dryajov Feb 27, 2026
7034496
feat: cleanup and consolidation of blockstore public api with all cal…
dryajov Feb 27, 2026
258ccb3
feat: add tests for batched operations
dryajov Feb 27, 2026
1350159
feat: use new blockstore api
dryajov Feb 27, 2026
d2dac51
feat: skip non-manifest blocks
dryajov Feb 27, 2026
080af2f
feat: adding metrics
dryajov Feb 27, 2026
b6e5800
feat: add overlay helpers to tests
dryajov Feb 27, 2026
9c425bd
feat: run install.nims before test tasks to build deps
dryajov Feb 27, 2026
eebdf97
bump kvstore
dryajov Feb 27, 2026
f7745ff
fix tests
dryajov Feb 27, 2026
ead2080
feat: expose getBlocksAndProof on netowork engine and minor cleanup
dryajov Feb 27, 2026
5b541b6
format
dryajov Feb 27, 2026
409ba23
bump kvstore
dryajov Feb 28, 2026
593cc70
Update archivist/blockexchange/engine/advertiser.nim
dryajov Mar 5, 2026
faa3721
Update archivist/blockexchange/engine/advertiser.nim
dryajov Mar 5, 2026
44ddedf
Update archivist/blockexchange/engine/advertiser.nim
dryajov Mar 5, 2026
a3a756f
Update tests/archivist/marketplace/sales/mockstorage.nim
dryajov Mar 5, 2026
8ea4437
Update archivist/blockexchange/engine/engine.nim
dryajov Mar 5, 2026
bc0ad02
feat: fixup grafana dashboard
dryajov Mar 1, 2026
6c82ec9
fix: fixup metrics
dryajov Mar 2, 2026
2b1eb69
addressing review comments
dryajov Mar 5, 2026
1d02ba2
addressing review comments
dryajov Mar 5, 2026
5ef0176
remove log statments
dryajov Mar 5, 2026
8836dfb
feat: move verifyBlockBitState to test helpers
dryajov Mar 5, 2026
db2b848
feat: use checkBitmask more consistently
dryajov Mar 5, 2026
ed75e2d
feat: move to test helpers
dryajov Mar 5, 2026
c8dc6f4
formatting
dryajov Mar 5, 2026
7758afe
feat: batch proofItems
dryajov Mar 6, 2026
1471da2
feat: add catchAsync to correctly propagate cancellations
dryajov Mar 6, 2026
ea54aad
bump kvstore
dryajov Mar 6, 2026
025f3ba
feat: don't doublecount batches
dryajov Mar 7, 2026
587d56b
fix: store the recovered data under the correct treeCid
dryajov Mar 7, 2026
cf93215
fix: don't decode invalid status enum vals
dryajov Mar 7, 2026
766a426
fix: don't decode invalid Naturals & enum vals
dryajov Mar 7, 2026
abf71db
fix: invalidate cache and use catchAsync
dryajov Mar 7, 2026
186f27b
feat: delete only when refCount == 0
dryajov Mar 7, 2026
3aa9a9a
feat: don't allow putting blocks for an overlay that is deleted
dryajov Mar 7, 2026
3ce6d92
feat: refactor repostore tests
dryajov Mar 7, 2026
5d35901
fix: delete manifest blocks from repoDs directly.
dryajov Mar 7, 2026
f7c9050
bump archivist dht
dryajov Mar 12, 2026
9005c7b
fix: circuitDir now properly uses the runtime datDir
dryajov Mar 13, 2026
89f3d0f
merigin main
dryajov Mar 13, 2026
c52bb6a
bumping archivistdht
dryajov Mar 13, 2026
fd91f7d
rename block cli options to overlay
dryajov Mar 16, 2026
00aa9b8
feat: add 404 param when cid not found locally
dryajov Mar 16, 2026
54c1283
fix: use overlay terminology instead of block
dryajov Mar 16, 2026
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
1 change: 1 addition & 0 deletions .github/workflows/ci-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ env:
jobs:
build:
strategy:
fail-fast: false
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Probably a left-over from testing? I would not disable fail-fast in general, because we have too few github runners to use them on jobs in PRs that are failing anyway.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yeah, I'll clean it up before merge, but I need this to be able to see what breaks on which platform.

matrix:
include: ${{ fromJson(inputs.matrix) }}

Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,9 @@ docker/prometheus-data
data/
nimbledeps
logs/
.grepai/
*.log
CLAUDE.md
AGENTS.md
.claude
.opencode
13 changes: 7 additions & 6 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,6 @@
[submodule "vendor/nimble/sqlite3_abi"]
path = vendor/nimble/sqlite3_abi
url = https://github.com/arnetheduck/nim-sqlite3-abi
[submodule "vendor/nimble/leveldbstatic"]
path = vendor/nimble/leveldbstatic
url = https://github.com/durability-labs/nim-leveldbstatic
[submodule "vendor/nimble/datastore"]
path = vendor/nimble/datastore
url = https://github.com/durability-labs/nim-datastore
[submodule "vendor/nimble/archivistdht"]
path = vendor/nimble/archivistdht
url = https://github.com/durability-labs/archivist-dht
Expand Down Expand Up @@ -159,3 +153,10 @@
[submodule "vendor/nimble/zippy"]
path = vendor/nimble/zippy
url = https://github.com/guzba/zippy
[submodule "vendor/nimble/nim-kvstore"]
path = vendor/nimble/nim-kvstore
url = git@github.com:durability-labs/nim-kvstore.git
url = https://github.com/durability-labs/nim-kvstore.git
[submodule "vendor/nimble/threading"]
path = vendor/nimble/threading
url = https://github.com/nim-lang/threading.git
2 changes: 2 additions & 0 deletions archivist.nim
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ when isMainModule:
chronos.poll()
except Exception as exc:
error "Unhandled exception in async proc, aborting", msg = exc.msg
# raise exc # uncomment for stack trace
quit QuitFailure

try:
Expand All @@ -155,6 +156,7 @@ when isMainModule:
waitFor shutdown
except CatchableError as error:
error "Archivist Node didn't shutdown correctly", error = error.msg
# raise exc # uncomment for stacktrace
quit QuitFailure

notice "Exited Archivist Node"
2 changes: 2 additions & 0 deletions archivist.nim.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
--define:"chronicles_sinks=textlines[dynamic],json[dynamic],textlines[dynamic]"
# enable metrics collection
--define:metrics
# bypass Nim TLSF allocator to avoid cross-thread free accumulation
--define:useMalloc
24 changes: 15 additions & 9 deletions archivist.nimble
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,18 @@ import "./vendor/nimble/deps.nims"
before build:
exec "nim vendor" / "nimble" / "install.nims"

task update, "Sync submodules to pinned commits (safe)":
exec "git submodule sync --recursive"
exec "git submodule update --init --recursive"

task updateUnsafe, "Reset and clean submodules to pinned commits (destructive)":
exec "git submodule sync --recursive"
exec "git submodule foreach --recursive 'git reset --hard'"
exec "git submodule foreach --recursive 'git clean -fdx'"
exec "git submodule update --init --recursive --force"
before test:
exec "nim vendor" / "nimble" / "install.nims"

task test, "Run node tests":
exec "nim c -r tests" / "testNode"

task testContracts, "Run contract tests":
exec "nim c -r tests" / "testContracts"

before testIntegration:
exec "nim vendor" / "nimble" / "install.nims"

task testIntegration, "Run integration tests":
exec "nim c" &
" --define:release" &
Expand All @@ -52,6 +48,16 @@ task format, "Format code using NPH":
exec findExe("nph") & " tests/"
exec findExe("nph") & " tools/"

task syncModules, "Sync submodules to pinned commits (safe)":
exec "git submodule sync --recursive"
exec "git submodule update --init --recursive"

task syncUnsafe, "Reset and clean submodules to pinned commits (destructive)":
exec "git submodule sync --recursive"
exec "git submodule foreach --recursive 'git reset --hard'"
exec "git submodule foreach --recursive 'git clean -fdx'"
exec "git submodule update --init --recursive --force"

task addDep, "Add vendored Nim dependency (git submodule)":
addDepTask(thisDir())

Expand Down
40 changes: 21 additions & 19 deletions archivist/archivist.nim
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import pkg/confutils
import pkg/confutils/defs
import pkg/nitro
import pkg/stew/io2
import pkg/datastore
import pkg/kvstore
import pkg/ethers except Rng

import ./node
Expand Down Expand Up @@ -168,8 +168,8 @@ proc new*(
)

let
discoveryStore = Datastore(
LevelDbDatastore.new(config.dataDir / ArchivistDhtProvidersNamespace).expect(
discoveryStore = KVStore(
SQLiteKVStore.new(config.dataDir / ArchivistDhtProvidersNamespace, tp).expect(
"Should create discovery datastore!"
)
)
Expand All @@ -185,40 +185,41 @@ proc new*(
wallet = WalletRef.new(EthPrivateKey.random())
network = BlockExcNetwork.new(switch)

repoData =
repoData: KVStore =
case config.repoKind
of repoFS:
Datastore(
FSDatastore.new($config.dataDir, depth = 5).expect(
"Should create repo file data store!"
KVStore(
FSKVStore
.new(
$config.dataDir,
tp,
depth = 5,
directIO = config.fsDirectIO,
fsyncFile = config.fsFsyncFile,
fsyncDir = config.fsFsyncDir,
)
.expect("Should create repo file data store!")
)
of repoSQLite:
Datastore(
SQLiteDatastore.new($config.dataDir).expect(
KVStore(
SQLiteKVStore.new($config.dataDir, tp).expect(
"Should create repo SQLite data store!"
)
)
of repoLevelDb:
Datastore(
LevelDbDatastore.new($config.dataDir).expect(
"Should create repo LevelDB data store!"
)
)

repoStore = RepoStore.new(
repoDs = repoData,
metaDs = LevelDbDatastore.new(config.dataDir / ArchivistMetaNamespace).expect(
metaDs = SQLiteKVStore.new(config.dataDir / ArchivistMetaNamespace, tp).expect(
"Should create metadata store!"
),
quotaMaxBytes = config.storageQuota,
blockTtl = config.blockTtl,
overlayTtl = config.overlayTtl.seconds,
)

maintenance = BlockMaintainer.new(
repoStore,
interval = config.blockMaintenanceInterval,
numberOfBlocksPerInterval = config.blockMaintenanceNumberOfBlocks,
interval = config.overlayMaintenanceInterval,
numberOfBlocksPerInterval = config.overlayMaintenanceNumberOfBlocks,
)

peerStore = PeerCtxStore.new()
Expand All @@ -240,6 +241,7 @@ proc new*(
archivistNode = ArchivistNodeRef.new(
switch = switch,
networkStore = store,
repoStore = repoStore,
engine = engine,
discovery = discovery,
prover = prover,
Expand Down
23 changes: 16 additions & 7 deletions archivist/blockexchange/engine/advertiser.nim
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,21 @@ proc advertiseBlock(b: Advertiser, cid: Cid) {.async: (raises: [CancelledError])
proc advertiseLocalStoreLoop(b: Advertiser) {.async: (raises: []).} =
try:
while b.advertiserRunning:
if cidsIter =? await b.localStore.listBlocks(blockType = BlockType.Manifest):
trace "Advertiser begins iterating blocks..."
for c in cidsIter:
if cid =? await c:
await b.advertiseBlock(cid)
trace "Advertiser iterating blocks finished."
without cidsIter =? await b.localStore.listBlocks(blockType = BlockType.Manifest),
err:
trace "Error retrieving manifest iterator, advertising skipped!", err = err.msg
await sleepAsync(b.advertiseLocalStoreLoopSleep)
continue

defer:
if err =? (await cidsIter.dispose()).errorOption:
warn "Error disposing manifest iterator", err = err.msg

trace "Advertiser begins iterating blocks..."
for c in cidsIter:
if cid =? await c:
await b.advertiseBlock(cid)
trace "Advertiser iterating blocks finished."

await sleepAsync(b.advertiseLocalStoreLoopSleep)
except CancelledError:
Expand Down Expand Up @@ -126,7 +135,7 @@ proc start*(b: Advertiser) {.async: (raises: []).} =

# The advertiser is expected to be started only once.
if b.advertiserRunning:
raiseAssert "Advertiser can only be started once this should not happen"
raiseAssert "Advertiser can only be started once - this should not happen"

proc onBlock(cid: Cid) {.async: (raises: []).} =
try:
Expand Down
68 changes: 49 additions & 19 deletions archivist/blockexchange/engine/engine.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import std/sets
import std/options
import std/algorithm
import std/sugar
import std/tables

import pkg/chronos
import pkg/libp2p/[cid, switch, multihash, multicodec]
Expand Down Expand Up @@ -396,10 +397,17 @@ proc validateBlockDelivery(self: BlockExcEngine, bd: BlockDelivery): ?!void =

proc blocksDeliveryHandler*(
self: BlockExcEngine, peer: PeerId, blocksDelivery: seq[BlockDelivery]
) {.async: (raises: []).} =
) {.async: (raises: [CancelledError]).} =
# TODO: this should not be here, the engine should just resolve the future,
# and let the caller do the validation and storing
trace "Received blocks from peer", peer, blocks = (blocksDelivery.mapIt(it.address))

var validatedBlocksDelivery: seq[BlockDelivery]
# Validate all deliveries and separate leaf vs non-leaf
var
validatedBlocksDelivery: seq[BlockDelivery]
leafByTree: Table[Cid, seq[(Block, Natural, ArchivistProof)]]
nonLeafDeliveries: seq[BlockDelivery]

for bd in blocksDelivery:
logScope:
peer = peer
Expand All @@ -410,36 +418,54 @@ proc blocksDeliveryHandler*(
warn "Block validation failed", msg = err.msg
continue

if err =? (await self.localStore.putBlock(bd.blk)).errorOption:
error "Unable to store block", err = err.msg
continue

if bd.address.leaf:
without proof =? bd.proof:
warn "Proof expected for a leaf block delivery"
continue
if err =? (
await self.localStore.putCidAndProof(
bd.address.treeCid, bd.address.index, bd.blk.cid, proof
)
).errorOption:
warn "Unable to store proof and cid for a block"
continue

leafByTree.withValue(bd.address.treeCid, slot):
slot[].add((bd.blk, bd.address.index, proof))
do:
leafByTree[bd.address.treeCid] = @[(bd.blk, bd.address.index, proof)]
else:
nonLeafDeliveries.add(bd)
except CatchableError as exc:
warn "Error handling block delivery", error = exc.msg
continue

validatedBlocksDelivery.add(bd)

# Batch write leaf blocks grouped by treeCid
for treeCid, items in leafByTree:
if err =? (await self.localStore.putBlocks(treeCid, items)).errorOption:
error "Unable to store leaf blocks", treeCid, err = err.msg
# Remove failed leaves from validatedBlocksDelivery
validatedBlocksDelivery.keepItIf(
not (it.address.leaf and it.address.treeCid == treeCid)
)

# Write non-leaf blocks sequentially - this should only be manifests after #94
for bd in nonLeafDeliveries:
without isManifest =? bd.blk.cid.isManifest, err:
error "Received a non-leaf block that isn't a manifest!", err = err.msg
validatedBlocksDelivery.keepItIf(it.address.cid != bd.address.cid)
continue

# TODO: The putBlock here should be replace by something like -
# storeManifestBlock(...)
if err =? (await self.localStore.putBlock(bd.blk)).errorOption:
error "Unable to store block", err = err.msg
validatedBlocksDelivery.keepItIf(it.address.cid != bd.address.cid)

archivist_block_exchange_blocks_received.inc(validatedBlocksDelivery.len.int64)

let peerCtx = self.peers.get(peer)
if peerCtx != nil:
if err =? catch(await self.payForBlocks(peerCtx, blocksDelivery)).errorOption:
if err =? catchAsync(await self.payForBlocks(peerCtx, blocksDelivery)).errorOption:
warn "Error paying for blocks", err = err.msg
return

if err =? catch(await self.resolveBlocks(validatedBlocksDelivery)).errorOption:
if err =? catchAsync(await self.resolveBlocks(validatedBlocksDelivery)).errorOption:
warn "Error resolving blocks", err = err.msg
return

Expand Down Expand Up @@ -470,7 +496,11 @@ proc wantListHandler*(
let
have =
try:
await e.address in self.localStore
if e.address.leaf:
(await self.localStore.hasBlock(e.address.treeCid, e.address.index)) |?
false
else:
(await self.localStore.hasBlock(e.address.cid)) |? false
Comment on lines +499 to +503
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Might be nice to create a hasBlock() overload that takes a BlockAddress

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I intentionally removed the BlockAddress api from the BlockStore abstraction, because there was way too much noice. I also thought that I'd go the other way around, and use BlockAddress exclusively, alas I found it to be very clunky compared to the treeCid, indices one...

except CatchableError:
# TODO: should not be necessary once we have proper exception tracking on the BlockStore interface
false
Expand Down Expand Up @@ -612,13 +642,13 @@ proc taskHandler*(
proc localLookup(e: WantListEntry): Future[?!BlockDelivery] {.async.} =
if e.address.leaf:
(await self.localStore.getBlockAndProof(e.address.treeCid, e.address.index)).map(
(blkAndProof: (Block, ArchivistProof)) =>
(blkAndProof: (Natural, Block, ArchivistProof)) =>
BlockDelivery(
address: e.address, blk: blkAndProof[0], proof: blkAndProof[1].some
address: e.address, blk: blkAndProof[1], proof: blkAndProof[2].some
)
)
else:
(await self.localStore.getBlock(e.address)).map(
(await self.localStore.getBlock(e.address.cid)).map(
(blk: Block) =>
BlockDelivery(address: e.address, blk: blk, proof: ArchivistProof.none)
)
Expand Down
Loading
Loading