mirror of
https://github.com/logos-storage/logos-storage-nim.git
synced 2026-05-12 14:29:39 +00:00
189 lines
5.4 KiB
Nim
189 lines
5.4 KiB
Nim
# Protocol of data exchange between Logos Storage nodes
|
|
# and Protobuf encoder/decoder for these messages.
|
|
#
|
|
# Eventually all this code should be auto-generated from message.proto.
|
|
import std/sugar
|
|
|
|
import pkg/libp2p/protobuf/minprotobuf
|
|
import pkg/libp2p/cid
|
|
|
|
import pkg/questionable
|
|
|
|
import ../../merkletree
|
|
import ../../blocktype
|
|
|
|
type
|
|
WantType* = enum
|
|
WantHave = 0 # Presence query - the only type used with batch transfer protocol
|
|
|
|
WantListEntry* = object
|
|
address*: BlockAddress
|
|
priority*: int32 # The priority (normalized). default to 1
|
|
cancel*: bool # Whether this revokes an entry
|
|
wantType*: WantType # Defaults to WantHave (only type supported)
|
|
sendDontHave*: bool # Note: defaults to false
|
|
rangeCount*: uint64
|
|
# For range queries: number of sequential blocks starting from address.index (0 = single block)
|
|
downloadId*: uint64 # Unique download ID for request/response correlation
|
|
|
|
WantList* = object
|
|
entries*: seq[WantListEntry] # A list of wantList entries
|
|
full*: bool # Whether this is the full wantList. default to false
|
|
|
|
BlockDelivery* = object
|
|
blk*: Block
|
|
address*: BlockAddress
|
|
proof*: ?StorageMerkleProof
|
|
|
|
BlockPresenceType* = enum
|
|
DontHave = 0
|
|
HaveRange = 1
|
|
Complete = 2
|
|
|
|
BlockPresence* = object
|
|
address*: BlockAddress
|
|
kind*: BlockPresenceType
|
|
ranges*: seq[tuple[start: uint64, count: uint64]]
|
|
downloadId*: uint64 # echoed for request/response correlation
|
|
|
|
Message* = object
|
|
wantList*: WantList
|
|
blockPresences*: seq[BlockPresence]
|
|
|
|
#
|
|
# Encoding Message into seq[byte] in Protobuf format
|
|
#
|
|
|
|
proc write*(pb: var ProtoBuffer, field: int, value: BlockAddress) =
|
|
var ipb = initProtoBuffer()
|
|
ipb.write(1, value.treeCid.data.buffer)
|
|
ipb.write(2, value.index.uint64)
|
|
ipb.finish()
|
|
pb.write(field, ipb)
|
|
|
|
proc write*(pb: var ProtoBuffer, field: int, value: WantListEntry) =
|
|
var ipb = initProtoBuffer()
|
|
ipb.write(1, value.address)
|
|
ipb.write(2, value.priority.uint64)
|
|
ipb.write(3, value.cancel.uint)
|
|
ipb.write(4, value.wantType.uint)
|
|
ipb.write(5, value.sendDontHave.uint)
|
|
ipb.write(6, value.rangeCount)
|
|
ipb.write(7, value.downloadId)
|
|
ipb.finish()
|
|
pb.write(field, ipb)
|
|
|
|
proc write*(pb: var ProtoBuffer, field: int, value: WantList) =
|
|
var ipb = initProtoBuffer()
|
|
for v in value.entries:
|
|
ipb.write(1, v)
|
|
ipb.write(2, value.full.uint)
|
|
ipb.finish()
|
|
pb.write(field, ipb)
|
|
|
|
proc write*(pb: var ProtoBuffer, field: int, value: BlockPresence) =
|
|
var ipb = initProtoBuffer()
|
|
ipb.write(1, value.address)
|
|
ipb.write(2, value.kind.uint)
|
|
# Encode ranges if present
|
|
for (start, count) in value.ranges:
|
|
var rangePb = initProtoBuffer()
|
|
rangePb.write(1, start)
|
|
rangePb.write(2, count)
|
|
rangePb.finish()
|
|
ipb.write(3, rangePb)
|
|
ipb.write(4, value.downloadId)
|
|
ipb.finish()
|
|
pb.write(field, ipb)
|
|
|
|
proc protobufEncode*(value: Message): seq[byte] =
|
|
var ipb = initProtoBuffer()
|
|
ipb.write(1, value.wantList)
|
|
for v in value.blockPresences:
|
|
ipb.write(4, v)
|
|
ipb.finish()
|
|
ipb.buffer
|
|
|
|
#
|
|
# Decoding Message from seq[byte] in Protobuf format
|
|
#
|
|
proc decode*(_: type BlockAddress, pb: ProtoBuffer): ProtoResult[BlockAddress] =
|
|
var
|
|
value: BlockAddress
|
|
field: uint64
|
|
cidBuf = newSeq[byte]()
|
|
|
|
if ?pb.getField(1, cidBuf):
|
|
value.treeCid = ?Cid.init(cidBuf).mapErr(x => ProtoError.IncorrectBlob)
|
|
if ?pb.getField(2, field):
|
|
value.index = field
|
|
|
|
ok(value)
|
|
|
|
proc decode*(_: type WantListEntry, pb: ProtoBuffer): ProtoResult[WantListEntry] =
|
|
var
|
|
value = WantListEntry()
|
|
field: uint64
|
|
ipb: ProtoBuffer
|
|
if ?pb.getField(1, ipb):
|
|
value.address = ?BlockAddress.decode(ipb)
|
|
if ?pb.getField(2, field):
|
|
value.priority = int32(field)
|
|
if ?pb.getField(3, field):
|
|
value.cancel = bool(field)
|
|
if ?pb.getField(4, field):
|
|
value.wantType = WantType(field)
|
|
if ?pb.getField(5, field):
|
|
value.sendDontHave = bool(field)
|
|
if ?pb.getField(6, field):
|
|
value.rangeCount = field
|
|
if ?pb.getField(7, field):
|
|
value.downloadId = field
|
|
ok(value)
|
|
|
|
proc decode*(_: type WantList, pb: ProtoBuffer): ProtoResult[WantList] =
|
|
var
|
|
value = WantList()
|
|
field: uint64
|
|
sublist: seq[seq[byte]]
|
|
if ?pb.getRepeatedField(1, sublist):
|
|
for item in sublist:
|
|
value.entries.add(?WantListEntry.decode(initProtoBuffer(item)))
|
|
if ?pb.getField(2, field):
|
|
value.full = bool(field)
|
|
ok(value)
|
|
|
|
proc decode*(_: type BlockPresence, pb: ProtoBuffer): ProtoResult[BlockPresence] =
|
|
var
|
|
value = BlockPresence()
|
|
field: uint64
|
|
ipb: ProtoBuffer
|
|
rangelist: seq[seq[byte]]
|
|
if ?pb.getField(1, ipb):
|
|
value.address = ?BlockAddress.decode(ipb)
|
|
if ?pb.getField(2, field):
|
|
value.kind = BlockPresenceType(field)
|
|
if ?pb.getRepeatedField(3, rangelist):
|
|
for item in rangelist:
|
|
var rangePb = initProtoBuffer(item)
|
|
var start, count: uint64
|
|
discard ?rangePb.getField(1, start)
|
|
discard ?rangePb.getField(2, count)
|
|
value.ranges.add((start, count))
|
|
if ?pb.getField(4, field):
|
|
value.downloadId = field
|
|
ok(value)
|
|
|
|
proc protobufDecode*(_: type Message, msg: seq[byte]): ProtoResult[Message] =
|
|
var
|
|
value = Message()
|
|
pb = initProtoBuffer(msg)
|
|
ipb: ProtoBuffer
|
|
sublist: seq[seq[byte]]
|
|
if ?pb.getField(1, ipb):
|
|
value.wantList = ?WantList.decode(ipb)
|
|
if ?pb.getRepeatedField(4, sublist):
|
|
for item in sublist:
|
|
value.blockPresences.add(?BlockPresence.decode(initProtoBuffer(item)))
|
|
ok(value)
|