Chrysostomos Nanakos 34b111f7dc
chore: nph formatting
Part of https://github.com/logos-storage/logos-storage-nim/issues/1366

Signed-off-by: Chrysostomos Nanakos <chris@include.gr>
2026-02-27 12:43:54 +02:00

323 lines
10 KiB
Nim

import std/[sequtils, options]
import pkg/chronos
import pkg/storage/rng
import pkg/storage/blockexchange
import pkg/storage/stores
import pkg/storage/chunker
import pkg/storage/discovery
import pkg/storage/blocktype
import pkg/storage/merkletree
import pkg/storage/blockexchange/utils
import pkg/storage/blockexchange/engine/activedownload {.all.}
import pkg/storage/blockexchange/engine/downloadmanager {.all.}
import ../../../asynctest
import ../../helpers
import ../../examples
asyncchecksuite "NetworkStore engine handlers":
var
peerId: PeerId
chunker: Chunker
blockDiscovery: Discovery
peerStore: PeerContextStore
downloadManager: DownloadManager
network: BlockExcNetwork
engine: BlockExcEngine
discovery: DiscoveryEngine
advertiser: Advertiser
peerCtx: PeerContext
localStore: BlockStore
blocks: seq[Block]
setup:
chunker = RandomChunker.new(Rng.instance(), size = 1024'nb, chunkSize = 256'nb)
while true:
let chunk = await chunker.getBytes()
if chunk.len <= 0:
break
blocks.add(Block.new(chunk).tryGet())
peerId = PeerId.example
blockDiscovery = Discovery.new()
peerStore = PeerContextStore.new()
downloadManager = DownloadManager.new()
localStore = CacheStore.new()
network = BlockExcNetwork()
discovery = DiscoveryEngine.new(localStore, peerStore, network, blockDiscovery)
advertiser = Advertiser.new(localStore, blockDiscovery)
engine = BlockExcEngine.new(
localStore, network, discovery, advertiser, peerStore, downloadManager
)
peerCtx = PeerContext(id: peerId)
engine.peers.add(peerCtx)
test "Should handle want list":
let
tree = StorageMerkleTree.init(blocks.mapIt(it.cid)).tryGet
rootCid = tree.rootCid.tryGet()
for i, blk in blocks:
(await localStore.putBlock(blk)).tryGet()
(await localStore.putCidAndProof(rootCid, i, blk.cid, tree.getProof(i).tryGet())).tryGet()
let
done = newFuture[void]()
wantList = makeWantList(rootCid, blocks.len)
proc sendPresence(
peerId: PeerId, presence: seq[BlockPresence]
) {.async: (raises: [CancelledError]).} =
check presence.mapIt(it.address) == wantList.entries.mapIt(it.address)
for p in presence:
check p.kind in {BlockPresenceType.HaveRange, BlockPresenceType.Complete}
done.complete()
engine.network =
BlockExcNetwork(request: BlockExcRequest(sendPresence: sendPresence))
await engine.wantListHandler(peerId, wantList)
await done
test "Should handle want list - `dont-have`":
let
done = newFuture[void]()
treeCid = Cid.example
wantList = makeWantList(treeCid, blocks.len, sendDontHave = true)
proc sendPresence(
peerId: PeerId, presence: seq[BlockPresence]
) {.async: (raises: [CancelledError]).} =
check presence.mapIt(it.address) == wantList.entries.mapIt(it.address)
for p in presence:
check:
p.kind == BlockPresenceType.DontHave
done.complete()
engine.network =
BlockExcNetwork(request: BlockExcRequest(sendPresence: sendPresence))
await engine.wantListHandler(peerId, wantList)
await done
test "Should handle want list - `dont-have` some blocks":
let
tree = StorageMerkleTree.init(blocks.mapIt(it.cid)).tryGet
rootCid = tree.rootCid.tryGet()
for i in 0 ..< 2:
(await engine.localStore.putBlock(blocks[i])).tryGet()
(
await engine.localStore.putCidAndProof(
rootCid, i, blocks[i].cid, tree.getProof(i).tryGet()
)
).tryGet()
let
done = newFuture[void]()
wantList = makeWantList(rootCid, blocks.len, sendDontHave = true)
proc sendPresence(
peerId: PeerId, presence: seq[BlockPresence]
) {.async: (raises: [CancelledError]).} =
for p in presence:
if p.address.index >= 2:
check p.kind == BlockPresenceType.DontHave
else:
check p.kind in {BlockPresenceType.HaveRange, BlockPresenceType.Complete}
done.complete()
engine.network =
BlockExcNetwork(request: BlockExcRequest(sendPresence: sendPresence))
await engine.wantListHandler(peerId, wantList)
await done
test "Should handle block presence":
proc sendWantList(
id: PeerId,
addresses: seq[BlockAddress],
priority: int32 = 0,
cancel: bool = false,
wantType: WantType = WantType.WantHave,
full: bool = false,
sendDontHave: bool = false,
rangeCount: uint64 = 0,
downloadId: uint64 = 0,
) {.async: (raises: [CancelledError]).} =
discard
engine.network =
BlockExcNetwork(request: BlockExcRequest(sendWantList: sendWantList))
let
blockCid = blocks[0].cid
address = BlockAddress(treeCid: blockCid, index: 0)
desc = toDownloadDesc(address, DefaultBlockSize.uint32)
download = engine.downloadManager.startDownload(desc)
discard download.getWantHandle(address)
await engine.blockPresenceHandler(
peerId,
@[
BlockPresence(
address: address, kind: BlockPresenceType.Complete, downloadId: download.id
)
],
)
let
swarm = download.getSwarm()
peerOpt = swarm.getPeer(peerId)
check peerOpt.isSome
test "Should handle range want list":
let
done = newFuture[void]()
treeCid = Cid.example
tree = StorageMerkleTree.init(blocks.mapIt(it.cid)).tryGet
rootCid = tree.rootCid.tryGet()
for i, blk in blocks:
(await localStore.putBlock(blk)).tryGet()
let proof = tree.getProof(i).tryGet()
(await localStore.putCidAndProof(rootCid, i, blk.cid, proof)).tryGet()
let wantList = WantList(
entries: @[
WantListEntry(
address: BlockAddress(treeCid: rootCid, index: 0),
priority: 0,
cancel: false,
wantType: WantType.WantHave,
sendDontHave: false,
rangeCount: blocks.len.uint64,
)
],
full: false,
)
proc sendPresence(
peerId: PeerId, presence: seq[BlockPresence]
) {.async: (raises: [CancelledError]).} =
check presence.len == 1
check presence[0].kind == BlockPresenceType.HaveRange
check presence[0].ranges.len > 0
done.complete()
engine.network =
BlockExcNetwork(request: BlockExcRequest(sendPresence: sendPresence))
await engine.wantListHandler(peerId, wantList)
await done
test "Should not send presence for blocks not in range":
let
done = newFuture[void]()
treeCid = Cid.example
tree = StorageMerkleTree.init(blocks.mapIt(it.cid)).tryGet
rootCid = tree.rootCid.tryGet()
for i in 0 ..< 2:
(await localStore.putBlock(blocks[i])).tryGet()
let proof = tree.getProof(i).tryGet()
(await localStore.putCidAndProof(rootCid, i, blocks[i].cid, proof)).tryGet()
let wantList = WantList(
entries: @[
WantListEntry(
address: BlockAddress(treeCid: rootCid, index: 0),
priority: 0,
cancel: false,
wantType: WantType.WantHave,
sendDontHave: false,
rangeCount: blocks.len.uint64,
)
],
full: false,
)
proc sendPresence(
peerId: PeerId, presence: seq[BlockPresence]
) {.async: (raises: [CancelledError]).} =
check presence.len == 1
check presence[0].kind == BlockPresenceType.HaveRange
for (start, count) in presence[0].ranges:
check start < 2
done.complete()
engine.network =
BlockExcNetwork(request: BlockExcRequest(sendPresence: sendPresence))
await engine.wantListHandler(peerId, wantList)
await done
suite "IsIndexInRanges":
test "Empty ranges returns false":
let ranges: seq[(uint64, uint64)] = @[]
check not isIndexInRanges(0, ranges)
check not isIndexInRanges(100, ranges)
test "Single range - index inside":
let ranges = @[(10'u64, 5'u64)]
check isIndexInRanges(10, ranges, sortedRanges = true)
check isIndexInRanges(12, ranges, sortedRanges = true)
check isIndexInRanges(14, ranges, sortedRanges = true)
test "Single range - index outside":
let ranges = @[(10'u64, 5'u64)]
check not isIndexInRanges(9, ranges, sortedRanges = true)
check not isIndexInRanges(15, ranges, sortedRanges = true)
check not isIndexInRanges(100, ranges, sortedRanges = true)
test "Multiple sorted ranges - index in each":
let ranges = @[(0'u64, 3'u64), (10'u64, 5'u64), (100'u64, 10'u64)]
check isIndexInRanges(0, ranges, sortedRanges = true)
check isIndexInRanges(2, ranges, sortedRanges = true)
check isIndexInRanges(10, ranges, sortedRanges = true)
check isIndexInRanges(14, ranges, sortedRanges = true)
check isIndexInRanges(100, ranges, sortedRanges = true)
check isIndexInRanges(109, ranges, sortedRanges = true)
test "Multiple ranges - index in gaps":
let ranges = @[(0'u64, 3'u64), (10'u64, 5'u64), (100'u64, 10'u64)]
check not isIndexInRanges(3, ranges, sortedRanges = true)
check not isIndexInRanges(9, ranges, sortedRanges = true)
check not isIndexInRanges(15, ranges, sortedRanges = true)
check not isIndexInRanges(99, ranges, sortedRanges = true)
check not isIndexInRanges(110, ranges, sortedRanges = true)
test "Unsorted ranges with sortedRanges=false":
let ranges = @[(100'u64, 10'u64), (0'u64, 3'u64), (10'u64, 5'u64)]
check isIndexInRanges(0, ranges, sortedRanges = false)
check isIndexInRanges(2, ranges, sortedRanges = false)
check isIndexInRanges(10, ranges, sortedRanges = false)
check isIndexInRanges(105, ranges, sortedRanges = false)
check not isIndexInRanges(50, ranges, sortedRanges = false)
test "Adjacent ranges":
let ranges = @[(0'u64, 5'u64), (5'u64, 5'u64), (10'u64, 5'u64)]
for i in 0'u64 ..< 15:
check isIndexInRanges(i, ranges, sortedRanges = true)
check not isIndexInRanges(15, ranges, sortedRanges = true)
test "Large range values":
let ranges = @[(1_000_000_000'u64, 1_000_000'u64)]
check isIndexInRanges(1_000_000_000, ranges, sortedRanges = true)
check isIndexInRanges(1_000_500_000, ranges, sortedRanges = true)
check not isIndexInRanges(999_999_999, ranges, sortedRanges = true)
check not isIndexInRanges(1_001_000_000, ranges, sortedRanges = true)