2022-05-19 19:56:03 +00:00
|
|
|
## Nim-Codex
|
2022-03-14 16:06:36 +00:00
|
|
|
## Copyright (c) 2022 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-08-24 12:15:59 +00:00
|
|
|
# This module defines all operations on Manifest
|
|
|
|
|
2022-03-18 22:17:51 +00:00
|
|
|
import pkg/upraises
|
|
|
|
|
|
|
|
push: {.upraises: [].}
|
2022-03-14 16:06:36 +00:00
|
|
|
|
|
|
|
import pkg/libp2p/protobuf/minprotobuf
|
2023-12-22 12:04:01 +00:00
|
|
|
import pkg/libp2p/[cid, multihash, multicodec]
|
2022-03-14 16:06:36 +00:00
|
|
|
import pkg/questionable/results
|
|
|
|
|
|
|
|
import ../errors
|
2022-08-24 12:15:59 +00:00
|
|
|
import ../utils
|
2023-11-09 08:47:09 +00:00
|
|
|
import ../utils/json
|
2023-07-06 23:23:27 +00:00
|
|
|
import ../units
|
2022-03-15 18:47:31 +00:00
|
|
|
import ../blocktype
|
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 07:35:03 +00:00
|
|
|
import ../logutils
|
2023-07-06 23:23:27 +00:00
|
|
|
|
2023-07-19 14:06:59 +00:00
|
|
|
type
|
|
|
|
Manifest* = ref object of RootObj
|
2023-11-14 17:52:27 +00:00
|
|
|
treeCid {.serialize.}: Cid # Root of the merkle tree
|
|
|
|
datasetSize {.serialize.}: NBytes # Total size of all blocks
|
|
|
|
blockSize {.serialize.}: NBytes # Size of each contained block (might not be needed if blocks are len-prefixed)
|
2023-12-21 06:41:43 +00:00
|
|
|
codec: MultiCodec # Dataset codec
|
2023-11-14 17:52:27 +00:00
|
|
|
hcodec: MultiCodec # Multihash codec
|
2023-12-21 06:41:43 +00:00
|
|
|
version: CidVersion # Cid version
|
2023-11-14 17:52:27 +00:00
|
|
|
case protected {.serialize.}: bool # Protected datasets have erasure coded info
|
2023-07-19 14:06:59 +00:00
|
|
|
of true:
|
2023-11-14 17:52:27 +00:00
|
|
|
ecK: int # Number of blocks to encode
|
|
|
|
ecM: int # Number of resulting parity blocks
|
|
|
|
originalTreeCid: Cid # The original root of the dataset being erasure coded
|
2023-11-14 12:02:17 +00:00
|
|
|
originalDatasetSize: NBytes
|
2023-12-12 08:11:54 +00:00
|
|
|
case verifiable {.serialize.}: bool # Verifiable datasets can be used to generate storage proofs
|
|
|
|
of true:
|
2024-01-11 16:45:23 +00:00
|
|
|
verifyRoot: Cid # Root of the top level merkle tree built from slot roots
|
|
|
|
slotRoots: seq[Cid] # Individual slot root built from the original dataset blocks
|
2023-12-12 08:11:54 +00:00
|
|
|
else:
|
|
|
|
discard
|
2023-07-19 14:06:59 +00:00
|
|
|
else:
|
|
|
|
discard
|
|
|
|
|
|
|
|
############################################################
|
|
|
|
# Accessors
|
|
|
|
############################################################
|
|
|
|
|
|
|
|
proc blockSize*(self: Manifest): NBytes =
|
|
|
|
self.blockSize
|
|
|
|
|
2023-11-14 12:02:17 +00:00
|
|
|
proc datasetSize*(self: Manifest): NBytes =
|
|
|
|
self.datasetSize
|
2023-07-19 14:06:59 +00:00
|
|
|
|
|
|
|
proc version*(self: Manifest): CidVersion =
|
|
|
|
self.version
|
|
|
|
|
|
|
|
proc hcodec*(self: Manifest): MultiCodec =
|
|
|
|
self.hcodec
|
|
|
|
|
|
|
|
proc codec*(self: Manifest): MultiCodec =
|
|
|
|
self.codec
|
|
|
|
|
|
|
|
proc protected*(self: Manifest): bool =
|
|
|
|
self.protected
|
|
|
|
|
|
|
|
proc ecK*(self: Manifest): int =
|
|
|
|
self.ecK
|
|
|
|
|
|
|
|
proc ecM*(self: Manifest): int =
|
|
|
|
self.ecM
|
|
|
|
|
2023-11-14 12:02:17 +00:00
|
|
|
proc originalTreeCid*(self: Manifest): Cid =
|
|
|
|
self.originalTreeCid
|
2023-07-19 14:06:59 +00:00
|
|
|
|
2023-11-14 12:02:17 +00:00
|
|
|
proc originalBlocksCount*(self: Manifest): int =
|
|
|
|
divUp(self.originalDatasetSize.int, self.blockSize.int)
|
2023-07-19 14:06:59 +00:00
|
|
|
|
2023-11-14 12:02:17 +00:00
|
|
|
proc originalDatasetSize*(self: Manifest): NBytes =
|
|
|
|
self.originalDatasetSize
|
2022-03-14 16:06:36 +00:00
|
|
|
|
2023-11-14 12:02:17 +00:00
|
|
|
proc treeCid*(self: Manifest): Cid =
|
|
|
|
self.treeCid
|
2022-03-14 16:06:36 +00:00
|
|
|
|
2023-11-14 12:02:17 +00:00
|
|
|
proc blocksCount*(self: Manifest): int =
|
|
|
|
divUp(self.datasetSize.int, self.blockSize.int)
|
2022-03-14 16:06:36 +00:00
|
|
|
|
2023-12-12 08:11:54 +00:00
|
|
|
proc verifiable*(self: Manifest): bool =
|
|
|
|
self.verifiable
|
|
|
|
|
2024-01-11 16:45:23 +00:00
|
|
|
proc verifyRoot*(self: Manifest): Cid =
|
|
|
|
self.verifyRoot
|
2023-12-12 08:11:54 +00:00
|
|
|
|
|
|
|
proc slotRoots*(self: Manifest): seq[Cid] =
|
|
|
|
self.slotRoots
|
|
|
|
|
2024-01-08 22:52:46 +00:00
|
|
|
proc numSlots*(self: Manifest): int =
|
|
|
|
if not self.protected:
|
|
|
|
0
|
|
|
|
else:
|
|
|
|
self.ecK + self.ecM
|
2024-01-11 16:45:23 +00:00
|
|
|
|
2023-11-14 12:02:17 +00:00
|
|
|
############################################################
|
|
|
|
# Operations on block list
|
|
|
|
############################################################
|
2022-03-14 16:06:36 +00:00
|
|
|
|
2022-12-03 00:00:55 +00:00
|
|
|
func isManifest*(cid: Cid): ?!bool =
|
2023-12-22 12:04:01 +00:00
|
|
|
success (ManifestCodec == ? cid.contentType().mapFailure(CodexError))
|
2022-12-03 00:00:55 +00:00
|
|
|
|
|
|
|
func isManifest*(mc: MultiCodec): ?!bool =
|
2023-12-22 12:04:01 +00:00
|
|
|
success mc == ManifestCodec
|
2022-12-03 00:00:55 +00:00
|
|
|
|
2022-08-24 12:15:59 +00:00
|
|
|
############################################################
|
|
|
|
# Various sizes and verification
|
|
|
|
############################################################
|
|
|
|
|
2023-07-06 23:23:27 +00:00
|
|
|
func bytes*(self: Manifest, pad = true): NBytes =
|
2022-08-24 12:15:59 +00:00
|
|
|
## Compute how many bytes corresponding StoreStream(Manifest, pad) will return
|
|
|
|
if pad or self.protected:
|
2023-11-14 12:02:17 +00:00
|
|
|
self.blocksCount.NBytes * self.blockSize
|
2022-08-24 12:15:59 +00:00
|
|
|
else:
|
2023-11-14 12:02:17 +00:00
|
|
|
self.datasetSize
|
2022-08-24 12:15:59 +00:00
|
|
|
|
|
|
|
func rounded*(self: Manifest): int =
|
|
|
|
## Number of data blocks in *protected* manifest including padding at the end
|
2023-11-14 12:02:17 +00:00
|
|
|
roundUp(self.originalBlocksCount, self.ecK)
|
2022-08-24 12:15:59 +00:00
|
|
|
|
|
|
|
func steps*(self: Manifest): int =
|
|
|
|
## Number of EC groups in *protected* manifest
|
2023-11-14 12:02:17 +00:00
|
|
|
divUp(self.originalBlocksCount, self.ecK)
|
2022-08-24 12:15:59 +00:00
|
|
|
|
|
|
|
func verify*(self: Manifest): ?!void =
|
|
|
|
## Check manifest correctness
|
|
|
|
##
|
|
|
|
|
2023-11-14 12:02:17 +00:00
|
|
|
if self.protected and (self.blocksCount != self.steps * (self.ecK + self.ecM)):
|
|
|
|
return failure newException(CodexError, "Broken manifest: wrong originalBlocksCount")
|
2022-08-24 12:15:59 +00:00
|
|
|
|
|
|
|
return success()
|
|
|
|
|
2023-11-14 12:02:17 +00:00
|
|
|
proc cid*(self: Manifest): ?!Cid {.deprecated: "use treeCid instead".} =
|
|
|
|
self.treeCid.success
|
|
|
|
|
|
|
|
proc `==`*(a, b: Manifest): bool =
|
|
|
|
(a.treeCid == b.treeCid) and
|
|
|
|
(a.datasetSize == b.datasetSize) and
|
|
|
|
(a.blockSize == b.blockSize) and
|
|
|
|
(a.version == b.version) and
|
|
|
|
(a.hcodec == b.hcodec) and
|
|
|
|
(a.codec == b.codec) and
|
|
|
|
(a.protected == b.protected) and
|
|
|
|
(if a.protected:
|
|
|
|
(a.ecK == b.ecK) and
|
|
|
|
(a.ecM == b.ecM) and
|
|
|
|
(a.originalTreeCid == b.originalTreeCid) and
|
2023-12-12 08:11:54 +00:00
|
|
|
(a.originalDatasetSize == b.originalDatasetSize) and
|
|
|
|
(a.verifiable == b.verifiable) and
|
|
|
|
(if a.verifiable:
|
2024-01-11 16:45:23 +00:00
|
|
|
(a.verifyRoot == b.verifyRoot) and
|
2023-12-12 08:11:54 +00:00
|
|
|
(a.slotRoots == b.slotRoots)
|
|
|
|
else:
|
|
|
|
true)
|
2023-11-14 12:02:17 +00:00
|
|
|
else:
|
|
|
|
true)
|
|
|
|
|
|
|
|
proc `$`*(self: Manifest): string =
|
|
|
|
"treeCid: " & $self.treeCid &
|
|
|
|
", datasetSize: " & $self.datasetSize &
|
|
|
|
", blockSize: " & $self.blockSize &
|
|
|
|
", version: " & $self.version &
|
|
|
|
", hcodec: " & $self.hcodec &
|
|
|
|
", codec: " & $self.codec &
|
|
|
|
", protected: " & $self.protected &
|
|
|
|
(if self.protected:
|
|
|
|
", ecK: " & $self.ecK &
|
|
|
|
", ecM: " & $self.ecM &
|
|
|
|
", originalTreeCid: " & $self.originalTreeCid &
|
2023-12-12 08:11:54 +00:00
|
|
|
", originalDatasetSize: " & $self.originalDatasetSize &
|
|
|
|
", verifiable: " & $self.verifiable &
|
|
|
|
(if self.verifiable:
|
2024-01-11 16:45:23 +00:00
|
|
|
", verifyRoot: " & $self.verifyRoot &
|
2023-12-12 08:11:54 +00:00
|
|
|
", slotRoots: " & $self.slotRoots
|
|
|
|
else:
|
|
|
|
"")
|
2023-11-14 12:02:17 +00:00
|
|
|
else:
|
|
|
|
"")
|
2022-08-24 12:15:59 +00:00
|
|
|
|
|
|
|
############################################################
|
|
|
|
# Constructors
|
|
|
|
############################################################
|
|
|
|
|
2022-03-17 13:56:46 +00:00
|
|
|
proc new*(
|
2023-12-21 06:41:43 +00:00
|
|
|
T: type Manifest,
|
|
|
|
treeCid: Cid,
|
|
|
|
blockSize: NBytes,
|
|
|
|
datasetSize: NBytes,
|
|
|
|
version: CidVersion = CIDv1,
|
2023-12-22 12:04:01 +00:00
|
|
|
hcodec = Sha256HashCodec,
|
|
|
|
codec = BlockCodec,
|
2023-12-21 06:41:43 +00:00
|
|
|
protected = false): Manifest =
|
2022-03-14 16:06:36 +00:00
|
|
|
|
|
|
|
T(
|
2023-11-14 12:02:17 +00:00
|
|
|
treeCid: treeCid,
|
|
|
|
blockSize: blockSize,
|
|
|
|
datasetSize: datasetSize,
|
2022-03-14 16:06:36 +00:00
|
|
|
version: version,
|
|
|
|
codec: codec,
|
|
|
|
hcodec: hcodec,
|
2023-11-14 12:02:17 +00:00
|
|
|
protected: protected)
|
2022-04-05 00:46:13 +00:00
|
|
|
|
|
|
|
proc new*(
|
2023-12-21 06:41:43 +00:00
|
|
|
T: type Manifest,
|
|
|
|
manifest: Manifest,
|
|
|
|
treeCid: Cid,
|
|
|
|
datasetSize: NBytes,
|
|
|
|
ecK, ecM: int): Manifest =
|
2022-04-05 00:46:13 +00:00
|
|
|
## Create an erasure protected dataset from an
|
2023-11-14 12:02:17 +00:00
|
|
|
## unprotected one
|
2022-04-05 00:46:13 +00:00
|
|
|
##
|
2023-12-21 06:41:43 +00:00
|
|
|
|
2023-11-14 12:02:17 +00:00
|
|
|
Manifest(
|
|
|
|
treeCid: treeCid,
|
|
|
|
datasetSize: datasetSize,
|
|
|
|
version: manifest.version,
|
|
|
|
codec: manifest.codec,
|
|
|
|
hcodec: manifest.hcodec,
|
|
|
|
blockSize: manifest.blockSize,
|
|
|
|
protected: true,
|
|
|
|
ecK: ecK, ecM: ecM,
|
|
|
|
originalTreeCid: manifest.treeCid,
|
|
|
|
originalDatasetSize: manifest.datasetSize)
|
2022-04-05 00:46:13 +00:00
|
|
|
|
2023-11-14 12:02:17 +00:00
|
|
|
proc new*(
|
2023-12-21 06:41:43 +00:00
|
|
|
T: type Manifest,
|
|
|
|
manifest: Manifest): Manifest =
|
2023-11-14 12:02:17 +00:00
|
|
|
## Create an unprotected dataset from an
|
|
|
|
## erasure protected one
|
|
|
|
##
|
2023-12-22 12:04:01 +00:00
|
|
|
|
2023-11-14 12:02:17 +00:00
|
|
|
Manifest(
|
|
|
|
treeCid: manifest.originalTreeCid,
|
|
|
|
datasetSize: manifest.originalDatasetSize,
|
|
|
|
version: manifest.version,
|
|
|
|
codec: manifest.codec,
|
|
|
|
hcodec: manifest.hcodec,
|
|
|
|
blockSize: manifest.blockSize,
|
|
|
|
protected: false)
|
2022-03-15 18:47:31 +00:00
|
|
|
|
2022-03-17 13:56:46 +00:00
|
|
|
proc new*(
|
2022-03-15 18:47:31 +00:00
|
|
|
T: type Manifest,
|
2023-12-22 12:04:01 +00:00
|
|
|
data: openArray[byte]): ?!Manifest =
|
2023-06-22 15:11:18 +00:00
|
|
|
## Create a manifest instance from given data
|
2023-07-19 14:06:59 +00:00
|
|
|
##
|
2023-12-21 06:41:43 +00:00
|
|
|
|
2023-12-22 12:04:01 +00:00
|
|
|
Manifest.decode(data)
|
2023-07-19 14:06:59 +00:00
|
|
|
|
|
|
|
proc new*(
|
|
|
|
T: type Manifest,
|
2023-11-14 12:02:17 +00:00
|
|
|
treeCid: Cid,
|
|
|
|
datasetSize: NBytes,
|
2023-07-19 14:06:59 +00:00
|
|
|
blockSize: NBytes,
|
|
|
|
version: CidVersion,
|
|
|
|
hcodec: MultiCodec,
|
|
|
|
codec: MultiCodec,
|
|
|
|
ecK: int,
|
|
|
|
ecM: int,
|
2023-11-14 12:02:17 +00:00
|
|
|
originalTreeCid: Cid,
|
2023-12-21 06:41:43 +00:00
|
|
|
originalDatasetSize: NBytes): Manifest =
|
|
|
|
|
2023-07-19 14:06:59 +00:00
|
|
|
Manifest(
|
2023-11-14 12:02:17 +00:00
|
|
|
treeCid: treeCid,
|
|
|
|
datasetSize: datasetSize,
|
2023-07-19 14:06:59 +00:00
|
|
|
blockSize: blockSize,
|
|
|
|
version: version,
|
|
|
|
hcodec: hcodec,
|
|
|
|
codec: codec,
|
|
|
|
protected: true,
|
|
|
|
ecK: ecK,
|
|
|
|
ecM: ecM,
|
2023-11-14 12:02:17 +00:00
|
|
|
originalTreeCid: originalTreeCid,
|
|
|
|
originalDatasetSize: originalDatasetSize
|
2023-07-19 14:06:59 +00:00
|
|
|
)
|
2023-12-12 08:11:54 +00:00
|
|
|
|
|
|
|
proc new*(
|
2023-12-21 06:41:43 +00:00
|
|
|
T: type Manifest,
|
|
|
|
manifest: Manifest,
|
2024-01-11 16:45:23 +00:00
|
|
|
verifyRoot: Cid,
|
|
|
|
slotRoots: openArray[Cid]): ?!Manifest =
|
2023-12-12 08:11:54 +00:00
|
|
|
## Create a verifiable dataset from an
|
|
|
|
## protected one
|
|
|
|
##
|
2024-01-11 16:45:23 +00:00
|
|
|
|
2023-12-12 08:11:54 +00:00
|
|
|
if not manifest.protected:
|
2024-01-11 16:45:23 +00:00
|
|
|
return failure newException(
|
|
|
|
CodexError, "Can create verifiable manifest only from protected manifest.")
|
|
|
|
|
|
|
|
if slotRoots.len != manifest.numSlots:
|
|
|
|
return failure newException(
|
|
|
|
CodexError, "Wrong number of slot roots.")
|
2023-12-12 08:11:54 +00:00
|
|
|
|
2024-01-11 16:45:23 +00:00
|
|
|
success Manifest(
|
2023-12-12 08:11:54 +00:00
|
|
|
treeCid: manifest.treeCid,
|
|
|
|
datasetSize: manifest.datasetSize,
|
|
|
|
version: manifest.version,
|
|
|
|
codec: manifest.codec,
|
|
|
|
hcodec: manifest.hcodec,
|
|
|
|
blockSize: manifest.blockSize,
|
|
|
|
protected: true,
|
|
|
|
ecK: manifest.ecK,
|
|
|
|
ecM: manifest.ecM,
|
|
|
|
originalTreeCid: manifest.treeCid,
|
|
|
|
originalDatasetSize: manifest.originalDatasetSize,
|
|
|
|
verifiable: true,
|
2024-01-11 16:45:23 +00:00
|
|
|
verifyRoot: verifyRoot,
|
|
|
|
slotRoots: @slotRoots)
|