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 implements serialization and deserialization of Manifest
|
|
|
|
|
2022-03-18 22:17:51 +00:00
|
|
|
import pkg/upraises
|
2024-10-25 13:43:19 +00:00
|
|
|
import times
|
2022-03-18 22:17:51 +00:00
|
|
|
|
|
|
|
push: {.upraises: [].}
|
2022-03-14 16:06:36 +00:00
|
|
|
|
|
|
|
import std/tables
|
2023-12-12 08:11:54 +00:00
|
|
|
import std/sequtils
|
2022-03-14 16:06:36 +00:00
|
|
|
|
|
|
|
import pkg/libp2p
|
|
|
|
import pkg/questionable
|
|
|
|
import pkg/questionable/results
|
|
|
|
import pkg/chronos
|
|
|
|
|
2022-03-15 18:47:31 +00:00
|
|
|
import ./manifest
|
2022-03-14 16:06:36 +00:00
|
|
|
import ../errors
|
2022-07-29 20:04:12 +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
|
2024-02-07 20:54:57 +00:00
|
|
|
import ../indexingstrategy
|
2022-03-15 18:47:31 +00:00
|
|
|
|
2023-12-22 12:04:01 +00:00
|
|
|
proc encode*(manifest: Manifest): ?!seq[byte] =
|
2022-03-14 16:06:36 +00:00
|
|
|
## Encode the manifest into a ``ManifestCodec``
|
|
|
|
## multicodec container (Dag-pb) for now
|
|
|
|
##
|
|
|
|
|
2022-08-24 12:15:59 +00:00
|
|
|
? manifest.verify()
|
2022-03-14 16:06:36 +00:00
|
|
|
var pbNode = initProtoBuffer()
|
|
|
|
|
2022-03-15 18:47:31 +00:00
|
|
|
# NOTE: The `Data` field in the the `dag-pb`
|
|
|
|
# contains the following protobuf `Message`
|
|
|
|
#
|
|
|
|
# ```protobuf
|
2023-12-12 08:11:54 +00:00
|
|
|
# Message VerificationInfo {
|
2024-01-11 16:45:23 +00:00
|
|
|
# bytes verifyRoot = 1; # Decimal encoded field-element
|
2023-12-12 08:11:54 +00:00
|
|
|
# repeated bytes slotRoots = 2; # Decimal encoded field-elements
|
|
|
|
# }
|
2022-04-05 00:46:13 +00:00
|
|
|
# Message ErasureInfo {
|
2023-12-12 08:11:54 +00:00
|
|
|
# optional uint32 ecK = 1; # number of encoded blocks
|
|
|
|
# optional uint32 ecM = 2; # number of parity blocks
|
|
|
|
# optional bytes originalTreeCid = 3; # cid of the original dataset
|
|
|
|
# optional uint32 originalDatasetSize = 4; # size of the original dataset
|
|
|
|
# optional VerificationInformation verification = 5; # verification information
|
2022-04-05 00:46:13 +00:00
|
|
|
# }
|
2023-12-22 12:04:01 +00:00
|
|
|
#
|
2022-03-15 18:47:31 +00:00
|
|
|
# Message Header {
|
2023-11-14 12:02:17 +00:00
|
|
|
# optional bytes treeCid = 1; # cid (root) of the tree
|
2022-04-05 00:46:13 +00:00
|
|
|
# optional uint32 blockSize = 2; # size of a single block
|
2023-11-14 12:02:17 +00:00
|
|
|
# optional uint64 datasetSize = 3; # size of the dataset
|
2023-12-21 06:41:43 +00:00
|
|
|
# optional codec: MultiCodec = 4; # Dataset codec
|
|
|
|
# optional hcodec: MultiCodec = 5 # Multihash codec
|
|
|
|
# optional version: CidVersion = 6; # Cid version
|
|
|
|
# optional ErasureInfo erasure = 7; # erasure coding info
|
2024-10-25 13:43:19 +00:00
|
|
|
# optional filename: ?string = 8; # original filename
|
|
|
|
# optional mimetype: ?string = 9; # original mimetype
|
|
|
|
# optional uploadedAt: ?int64 = 10; # original uploadedAt
|
2022-03-15 18:47:31 +00:00
|
|
|
# }
|
|
|
|
# ```
|
|
|
|
#
|
2023-11-14 12:02:17 +00:00
|
|
|
# var treeRootVBuf = initVBuffer()
|
2022-03-15 18:47:31 +00:00
|
|
|
var header = initProtoBuffer()
|
2023-11-14 12:02:17 +00:00
|
|
|
header.write(1, manifest.treeCid.data.buffer)
|
2022-03-15 18:47:31 +00:00
|
|
|
header.write(2, manifest.blockSize.uint32)
|
2024-04-30 15:27:17 +00:00
|
|
|
header.write(3, manifest.datasetSize.uint64)
|
2023-12-21 06:41:43 +00:00
|
|
|
header.write(4, manifest.codec.uint32)
|
|
|
|
header.write(5, manifest.hcodec.uint32)
|
|
|
|
header.write(6, manifest.version.uint32)
|
2024-10-25 13:43:19 +00:00
|
|
|
|
2022-04-05 00:46:13 +00:00
|
|
|
if manifest.protected:
|
|
|
|
var erasureInfo = initProtoBuffer()
|
2023-03-10 07:02:54 +00:00
|
|
|
erasureInfo.write(1, manifest.ecK.uint32)
|
|
|
|
erasureInfo.write(2, manifest.ecM.uint32)
|
2023-11-14 12:02:17 +00:00
|
|
|
erasureInfo.write(3, manifest.originalTreeCid.data.buffer)
|
2024-04-30 15:27:17 +00:00
|
|
|
erasureInfo.write(4, manifest.originalDatasetSize.uint64)
|
2024-02-07 20:54:57 +00:00
|
|
|
erasureInfo.write(5, manifest.protectedStrategy.uint32)
|
2022-04-05 00:46:13 +00:00
|
|
|
|
2023-12-12 08:11:54 +00:00
|
|
|
if manifest.verifiable:
|
|
|
|
var verificationInfo = initProtoBuffer()
|
2024-01-11 16:45:23 +00:00
|
|
|
verificationInfo.write(1, manifest.verifyRoot.data.buffer)
|
2023-12-12 08:11:54 +00:00
|
|
|
for slotRoot in manifest.slotRoots:
|
|
|
|
verificationInfo.write(2, slotRoot.data.buffer)
|
2024-02-07 20:54:57 +00:00
|
|
|
verificationInfo.write(3, manifest.cellSize.uint32)
|
|
|
|
verificationInfo.write(4, manifest.verifiableStrategy.uint32)
|
|
|
|
erasureInfo.write(6, verificationInfo)
|
2023-12-12 08:11:54 +00:00
|
|
|
|
|
|
|
erasureInfo.finish()
|
2023-12-21 06:41:43 +00:00
|
|
|
header.write(7, erasureInfo)
|
2022-03-15 18:47:31 +00:00
|
|
|
|
2024-10-25 13:43:19 +00:00
|
|
|
if manifest.filename.isSome:
|
|
|
|
header.write(8, manifest.filename.get())
|
|
|
|
|
|
|
|
if manifest.mimetype.isSome:
|
|
|
|
header.write(9, manifest.mimetype.get())
|
|
|
|
|
|
|
|
if manifest.uploadedAt.isSome:
|
|
|
|
header.write(10, manifest.uploadedAt.get().uint64)
|
|
|
|
|
2023-11-14 12:02:17 +00:00
|
|
|
pbNode.write(1, header) # set the treeCid as the data field
|
2022-03-14 16:06:36 +00:00
|
|
|
pbNode.finish()
|
|
|
|
|
|
|
|
return pbNode.buffer.success
|
|
|
|
|
2023-12-22 12:04:01 +00:00
|
|
|
proc decode*(_: type Manifest, data: openArray[byte]): ?!Manifest =
|
2022-03-14 16:06:36 +00:00
|
|
|
## Decode a manifest from a data blob
|
|
|
|
##
|
|
|
|
|
|
|
|
var
|
|
|
|
pbNode = initProtoBuffer(data)
|
2022-03-15 18:47:31 +00:00
|
|
|
pbHeader: ProtoBuffer
|
2022-04-05 00:46:13 +00:00
|
|
|
pbErasureInfo: ProtoBuffer
|
2023-12-12 08:11:54 +00:00
|
|
|
pbVerificationInfo: ProtoBuffer
|
2023-11-14 12:02:17 +00:00
|
|
|
treeCidBuf: seq[byte]
|
|
|
|
originalTreeCid: seq[byte]
|
2024-04-30 15:27:17 +00:00
|
|
|
datasetSize: uint64
|
2023-12-21 06:41:43 +00:00
|
|
|
codec: uint32
|
|
|
|
hcodec: uint32
|
|
|
|
version: uint32
|
2022-03-15 18:47:31 +00:00
|
|
|
blockSize: uint32
|
2024-04-30 15:27:17 +00:00
|
|
|
originalDatasetSize: uint64
|
2023-03-10 07:02:54 +00:00
|
|
|
ecK, ecM: uint32
|
2024-02-07 20:54:57 +00:00
|
|
|
protectedStrategy: uint32
|
2024-01-11 16:45:23 +00:00
|
|
|
verifyRoot: seq[byte]
|
2023-12-12 08:11:54 +00:00
|
|
|
slotRoots: seq[seq[byte]]
|
2024-02-07 20:54:57 +00:00
|
|
|
cellSize: uint32
|
|
|
|
verifiableStrategy: uint32
|
2024-10-25 13:43:19 +00:00
|
|
|
filename: string
|
|
|
|
mimetype: string
|
|
|
|
uploadedAt: uint64
|
2022-03-14 16:06:36 +00:00
|
|
|
|
2022-03-15 18:47:31 +00:00
|
|
|
# Decode `Header` message
|
|
|
|
if pbNode.getField(1, pbHeader).isErr:
|
|
|
|
return failure("Unable to decode `Header` from dag-pb manifest!")
|
|
|
|
|
|
|
|
# Decode `Header` contents
|
2023-11-14 12:02:17 +00:00
|
|
|
if pbHeader.getField(1, treeCidBuf).isErr:
|
|
|
|
return failure("Unable to decode `treeCid` from manifest!")
|
2022-03-15 18:47:31 +00:00
|
|
|
|
|
|
|
if pbHeader.getField(2, blockSize).isErr:
|
|
|
|
return failure("Unable to decode `blockSize` from manifest!")
|
2022-03-14 16:06:36 +00:00
|
|
|
|
2023-11-14 12:02:17 +00:00
|
|
|
if pbHeader.getField(3, datasetSize).isErr:
|
|
|
|
return failure("Unable to decode `datasetSize` from manifest!")
|
2022-08-24 12:15:59 +00:00
|
|
|
|
2023-12-21 06:41:43 +00:00
|
|
|
if pbHeader.getField(4, codec).isErr:
|
|
|
|
return failure("Unable to decode `codec` from manifest!")
|
|
|
|
|
|
|
|
if pbHeader.getField(5, hcodec).isErr:
|
|
|
|
return failure("Unable to decode `hcodec` from manifest!")
|
|
|
|
|
|
|
|
if pbHeader.getField(6, version).isErr:
|
|
|
|
return failure("Unable to decode `version` from manifest!")
|
|
|
|
|
|
|
|
if pbHeader.getField(7, pbErasureInfo).isErr:
|
2022-04-05 00:46:13 +00:00
|
|
|
return failure("Unable to decode `erasureInfo` from manifest!")
|
|
|
|
|
2024-10-25 13:43:19 +00:00
|
|
|
if pbHeader.getField(8, filename).isErr:
|
|
|
|
return failure("Unable to decode `filename` from manifest!")
|
|
|
|
|
|
|
|
if pbHeader.getField(9, mimetype).isErr:
|
|
|
|
return failure("Unable to decode `mimetype` from manifest!")
|
|
|
|
|
|
|
|
if pbHeader.getField(10, uploadedAt).isErr:
|
|
|
|
return failure("Unable to decode `uploadedAt` from manifest!")
|
|
|
|
|
2023-11-14 12:02:17 +00:00
|
|
|
let protected = pbErasureInfo.buffer.len > 0
|
2023-12-12 08:11:54 +00:00
|
|
|
var verifiable = false
|
2023-11-14 12:02:17 +00:00
|
|
|
if protected:
|
2023-03-10 07:02:54 +00:00
|
|
|
if pbErasureInfo.getField(1, ecK).isErr:
|
2022-04-05 00:46:13 +00:00
|
|
|
return failure("Unable to decode `K` from manifest!")
|
|
|
|
|
2023-03-10 07:02:54 +00:00
|
|
|
if pbErasureInfo.getField(2, ecM).isErr:
|
2022-04-05 00:46:13 +00:00
|
|
|
return failure("Unable to decode `M` from manifest!")
|
|
|
|
|
2023-11-14 12:02:17 +00:00
|
|
|
if pbErasureInfo.getField(3, originalTreeCid).isErr:
|
|
|
|
return failure("Unable to decode `originalTreeCid` from manifest!")
|
2022-04-05 00:46:13 +00:00
|
|
|
|
2023-11-14 12:02:17 +00:00
|
|
|
if pbErasureInfo.getField(4, originalDatasetSize).isErr:
|
|
|
|
return failure("Unable to decode `originalDatasetSize` from manifest!")
|
2022-03-14 16:06:36 +00:00
|
|
|
|
2024-02-07 20:54:57 +00:00
|
|
|
if pbErasureInfo.getField(5, protectedStrategy).isErr:
|
|
|
|
return failure("Unable to decode `protectedStrategy` from manifest!")
|
|
|
|
|
|
|
|
if pbErasureInfo.getField(6, pbVerificationInfo).isErr:
|
2023-12-12 08:11:54 +00:00
|
|
|
return failure("Unable to decode `verificationInfo` from manifest!")
|
|
|
|
|
|
|
|
verifiable = pbVerificationInfo.buffer.len > 0
|
|
|
|
if verifiable:
|
2024-01-11 16:45:23 +00:00
|
|
|
if pbVerificationInfo.getField(1, verifyRoot).isErr:
|
|
|
|
return failure("Unable to decode `verifyRoot` from manifest!")
|
2022-03-14 16:06:36 +00:00
|
|
|
|
2023-12-12 08:11:54 +00:00
|
|
|
if pbVerificationInfo.getRequiredRepeatedField(2, slotRoots).isErr:
|
|
|
|
return failure("Unable to decode `slotRoots` from manifest!")
|
|
|
|
|
2024-02-07 20:54:57 +00:00
|
|
|
if pbVerificationInfo.getField(3, cellSize).isErr:
|
|
|
|
return failure("Unable to decode `cellSize` from manifest!")
|
|
|
|
|
|
|
|
if pbVerificationInfo.getField(4, verifiableStrategy).isErr:
|
|
|
|
return failure("Unable to decode `verifiableStrategy` from manifest!")
|
|
|
|
|
2023-12-12 08:11:54 +00:00
|
|
|
let
|
2023-11-14 12:02:17 +00:00
|
|
|
treeCid = ? Cid.init(treeCidBuf).mapFailure
|
2022-03-15 18:47:31 +00:00
|
|
|
|
2024-10-25 13:43:19 +00:00
|
|
|
var filenameOption = if filename.len == 0: string.none else: filename.some
|
|
|
|
var mimetypeOption = if mimetype.len == 0: string.none else: mimetype.some
|
|
|
|
var uploadedAtOption = if uploadedAt == 0: int64.none else: uploadedAt.int64.some
|
|
|
|
|
2023-07-19 14:06:59 +00:00
|
|
|
let
|
2023-11-14 12:02:17 +00:00
|
|
|
self = if protected:
|
2023-07-19 14:06:59 +00:00
|
|
|
Manifest.new(
|
2023-11-14 12:02:17 +00:00
|
|
|
treeCid = treeCid,
|
|
|
|
datasetSize = datasetSize.NBytes,
|
2023-07-19 14:06:59 +00:00
|
|
|
blockSize = blockSize.NBytes,
|
2023-12-21 06:41:43 +00:00
|
|
|
version = CidVersion(version),
|
|
|
|
hcodec = hcodec.MultiCodec,
|
|
|
|
codec = codec.MultiCodec,
|
2023-07-19 14:06:59 +00:00
|
|
|
ecK = ecK.int,
|
|
|
|
ecM = ecM.int,
|
2023-11-14 12:02:17 +00:00
|
|
|
originalTreeCid = ? Cid.init(originalTreeCid).mapFailure,
|
2024-02-07 20:54:57 +00:00
|
|
|
originalDatasetSize = originalDatasetSize.NBytes,
|
2024-10-25 13:43:19 +00:00
|
|
|
strategy = StrategyType(protectedStrategy),
|
|
|
|
filename = filenameOption,
|
|
|
|
mimetype = mimetypeOption,
|
|
|
|
uploadedAt = uploadedAtOption)
|
2023-07-19 14:06:59 +00:00
|
|
|
else:
|
|
|
|
Manifest.new(
|
2023-11-14 12:02:17 +00:00
|
|
|
treeCid = treeCid,
|
|
|
|
datasetSize = datasetSize.NBytes,
|
2023-07-19 14:06:59 +00:00
|
|
|
blockSize = blockSize.NBytes,
|
2023-12-21 06:41:43 +00:00
|
|
|
version = CidVersion(version),
|
|
|
|
hcodec = hcodec.MultiCodec,
|
2024-10-25 13:43:19 +00:00
|
|
|
codec = codec.MultiCodec,
|
|
|
|
filename = filenameOption,
|
|
|
|
mimetype = mimetypeOption,
|
|
|
|
uploadedAt = uploadedAtOption)
|
2022-04-05 00:46:13 +00:00
|
|
|
|
2022-08-24 12:15:59 +00:00
|
|
|
? self.verify()
|
2023-12-12 08:11:54 +00:00
|
|
|
|
|
|
|
if verifiable:
|
|
|
|
let
|
2024-01-11 16:45:23 +00:00
|
|
|
verifyRootCid = ? Cid.init(verifyRoot).mapFailure
|
2023-12-12 08:11:54 +00:00
|
|
|
slotRootCids = slotRoots.mapIt(? Cid.init(it).mapFailure)
|
|
|
|
|
|
|
|
return Manifest.new(
|
|
|
|
manifest = self,
|
2024-01-11 16:45:23 +00:00
|
|
|
verifyRoot = verifyRootCid,
|
2024-02-07 20:54:57 +00:00
|
|
|
slotRoots = slotRootCids,
|
|
|
|
cellSize = cellSize.NBytes,
|
|
|
|
strategy = StrategyType(verifiableStrategy)
|
2023-12-12 08:11:54 +00:00
|
|
|
)
|
|
|
|
|
2022-04-05 00:46:13 +00:00
|
|
|
self.success
|
|
|
|
|
2022-07-29 20:04:12 +00:00
|
|
|
func decode*(_: type Manifest, blk: Block): ?!Manifest =
|
2022-12-03 00:00:55 +00:00
|
|
|
## Decode a manifest using `decoder`
|
|
|
|
##
|
|
|
|
|
|
|
|
if not ? blk.cid.isManifest:
|
|
|
|
return failure "Cid not a manifest codec"
|
|
|
|
|
2023-12-22 12:04:01 +00:00
|
|
|
Manifest.decode(blk.data)
|