2022-05-19 19:56:03 +00:00
|
|
|
## Nim-Codex
|
2021-02-26 00:23:22 +00:00
|
|
|
## Copyright (c) 2021 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-04-05 00:46:13 +00:00
|
|
|
import std/tables
|
|
|
|
export tables
|
|
|
|
|
2022-03-18 22:17:51 +00:00
|
|
|
import pkg/upraises
|
|
|
|
|
|
|
|
push: {.upraises: [].}
|
2021-02-26 00:23:22 +00:00
|
|
|
|
2021-08-30 19:25:20 +00:00
|
|
|
import pkg/libp2p
|
|
|
|
import pkg/stew/byteutils
|
2022-01-11 02:25:13 +00:00
|
|
|
import pkg/questionable
|
|
|
|
import pkg/questionable/results
|
|
|
|
|
|
|
|
import ./errors
|
2021-02-26 00:23:22 +00:00
|
|
|
|
2022-07-28 00:39:17 +00:00
|
|
|
const
|
2022-09-08 09:26:46 +00:00
|
|
|
BlockSize* = 65536 # block size
|
2022-07-28 00:39:17 +00:00
|
|
|
|
|
|
|
type
|
|
|
|
Block* = ref object of RootObj
|
|
|
|
cid*: Cid
|
|
|
|
data*: seq[byte]
|
|
|
|
|
2022-08-19 00:56:36 +00:00
|
|
|
BlockNotFoundError* = object of CodexError
|
|
|
|
|
2022-04-05 00:46:13 +00:00
|
|
|
template EmptyCid*: untyped =
|
|
|
|
var
|
|
|
|
emptyCid {.global, threadvar.}:
|
|
|
|
array[CIDv0..CIDv1, Table[MultiCodec, Cid]]
|
|
|
|
|
|
|
|
once:
|
|
|
|
emptyCid = [
|
|
|
|
CIDv0: {
|
|
|
|
multiCodec("sha2-256"): Cid
|
|
|
|
.init("QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n")
|
|
|
|
.get()
|
|
|
|
}.toTable,
|
|
|
|
CIDv1: {
|
|
|
|
multiCodec("sha2-256"): Cid
|
|
|
|
.init("bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku")
|
|
|
|
.get()
|
|
|
|
}.toTable,
|
|
|
|
]
|
|
|
|
|
|
|
|
emptyCid
|
|
|
|
|
|
|
|
template EmptyDigests*: untyped =
|
|
|
|
var
|
|
|
|
emptyDigests {.global, threadvar.}:
|
|
|
|
array[CIDv0..CIDv1, Table[MultiCodec, MultiHash]]
|
|
|
|
|
|
|
|
once:
|
|
|
|
emptyDigests = [
|
|
|
|
CIDv0: {
|
|
|
|
multiCodec("sha2-256"): EmptyCid[CIDv0]
|
|
|
|
.catch
|
|
|
|
.get()[multiCodec("sha2-256")]
|
|
|
|
.catch
|
|
|
|
.get()
|
|
|
|
.mhash
|
|
|
|
.get()
|
|
|
|
}.toTable,
|
|
|
|
CIDv1: {
|
2022-05-24 05:24:15 +00:00
|
|
|
multiCodec("sha2-256"): EmptyCid[CIDv1]
|
2022-04-05 00:46:13 +00:00
|
|
|
.catch
|
|
|
|
.get()[multiCodec("sha2-256")]
|
|
|
|
.catch
|
|
|
|
.get()
|
|
|
|
.mhash
|
|
|
|
.get()
|
|
|
|
}.toTable,
|
|
|
|
]
|
|
|
|
|
|
|
|
emptyDigests
|
|
|
|
|
|
|
|
template EmptyBlock*: untyped =
|
|
|
|
var
|
|
|
|
emptyBlock {.global, threadvar.}:
|
|
|
|
array[CIDv0..CIDv1, Table[MultiCodec, Block]]
|
|
|
|
|
|
|
|
once:
|
|
|
|
emptyBlock = [
|
|
|
|
CIDv0: {
|
|
|
|
multiCodec("sha2-256"): Block(
|
2022-07-29 20:04:12 +00:00
|
|
|
cid: EmptyCid[CIDv0][multiCodec("sha2-256")])
|
2022-04-05 00:46:13 +00:00
|
|
|
}.toTable,
|
|
|
|
CIDv1: {
|
|
|
|
multiCodec("sha2-256"): Block(
|
|
|
|
cid: EmptyCid[CIDv1][multiCodec("sha2-256")])
|
|
|
|
}.toTable,
|
|
|
|
]
|
|
|
|
|
|
|
|
emptyBlock
|
|
|
|
|
|
|
|
proc isEmpty*(cid: Cid): bool =
|
|
|
|
cid == EmptyCid[cid.cidver]
|
|
|
|
.catch
|
|
|
|
.get()[cid.mhash.get().mcodec]
|
|
|
|
.catch
|
|
|
|
.get()
|
|
|
|
|
|
|
|
proc isEmpty*(blk: Block): bool =
|
|
|
|
blk.cid.isEmpty
|
|
|
|
|
|
|
|
proc emptyBlock*(cid: Cid): Block =
|
|
|
|
EmptyBlock[cid.cidver]
|
|
|
|
.catch
|
|
|
|
.get()[cid.mhash.get().mcodec]
|
|
|
|
.catch
|
|
|
|
.get()
|
|
|
|
|
2021-02-26 00:23:22 +00:00
|
|
|
proc `$`*(b: Block): string =
|
|
|
|
result &= "cid: " & $b.cid
|
|
|
|
result &= "\ndata: " & string.fromBytes(b.data)
|
|
|
|
|
2022-03-18 19:50:53 +00:00
|
|
|
func new*(
|
2021-08-30 19:25:20 +00:00
|
|
|
T: type Block,
|
|
|
|
data: openArray[byte] = [],
|
|
|
|
version = CIDv1,
|
2022-01-11 02:25:13 +00:00
|
|
|
mcodec = multiCodec("sha2-256"),
|
|
|
|
codec = multiCodec("raw")): ?!T =
|
|
|
|
|
|
|
|
let
|
|
|
|
hash = ? MultiHash.digest($mcodec, data).mapFailure
|
|
|
|
cid = ? Cid.init(version, codec, hash).mapFailure
|
|
|
|
|
2022-03-15 18:47:31 +00:00
|
|
|
# TODO: If the hash is `>=` to the data,
|
|
|
|
# use the Cid as a container!
|
|
|
|
Block(
|
2022-01-11 02:25:13 +00:00
|
|
|
cid: cid,
|
2022-03-15 18:47:31 +00:00
|
|
|
data: @data).success
|
2021-08-30 19:25:20 +00:00
|
|
|
|
2022-03-18 19:50:53 +00:00
|
|
|
func new*(
|
2021-02-26 00:23:22 +00:00
|
|
|
T: type Block,
|
|
|
|
cid: Cid,
|
2022-01-11 02:25:13 +00:00
|
|
|
data: openArray[byte],
|
2022-03-15 18:47:31 +00:00
|
|
|
verify: bool = true): ?!T =
|
2022-01-11 02:25:13 +00:00
|
|
|
|
|
|
|
let
|
|
|
|
mhash = ? cid.mhash.mapFailure
|
2022-03-18 19:50:53 +00:00
|
|
|
b = ? Block.new(
|
2022-01-11 02:25:13 +00:00
|
|
|
data = @data,
|
|
|
|
version = cid.cidver,
|
|
|
|
codec = cid.mcodec,
|
|
|
|
mcodec = mhash.mcodec)
|
|
|
|
|
|
|
|
if verify and cid != b.cid:
|
2022-04-05 00:46:13 +00:00
|
|
|
return "Cid and content don't match!".failure
|
2022-01-11 02:25:13 +00:00
|
|
|
|
|
|
|
success b
|