mirror of
https://github.com/logos-messaging/nim-sds.git
synced 2026-07-22 23:59:27 +00:00
96 lines
3.7 KiB
Nim
96 lines
3.7 KiB
Nim
## Verifies the SDS message wire stays backward-compatible with pre-SDS-R nodes
|
|
## (v0.2.x/v0.3.x): causalHistory is a repeated string of message IDs in field 3,
|
|
## and the richer per-entry metadata (senderId, retrievalHint) rides in the
|
|
## additive field 8, which older nodes skip.
|
|
|
|
import std/unittest
|
|
import protobuf_serialization
|
|
import protobuf_serialization/pkg/results
|
|
import ../sds/protobuf
|
|
import ../sds/types/[sds_message, history_entry, sds_message_id]
|
|
|
|
converter toParticipantID(s: string): SdsParticipantID =
|
|
s.SdsParticipantID
|
|
|
|
func toStr(b: seq[byte]): string =
|
|
result = newString(b.len)
|
|
if b.len > 0:
|
|
copyMem(addr result[0], unsafeAddr b[0], b.len)
|
|
|
|
func toBytes(s: string): seq[byte] =
|
|
result = newSeq[byte](s.len)
|
|
if s.len > 0:
|
|
copyMem(addr result[0], unsafeAddr s[0], s.len)
|
|
|
|
# How a pre-SDS-R node sees the message: field 3 is a repeated string of message
|
|
# IDs; it knows nothing of the additive field 8.
|
|
type OldSdsMessagePB {.proto3.} = object
|
|
messageId {.fieldNumber: 1.}: Opt[seq[byte]]
|
|
causalHistory {.fieldNumber: 3.}: seq[seq[byte]]
|
|
channelId {.fieldNumber: 4.}: Opt[seq[byte]]
|
|
content {.fieldNumber: 5.}: Opt[seq[byte]]
|
|
|
|
suite "SDS v0.4 wire backward-compatibility":
|
|
test "old node reads causal history IDs from a v0.4-encoded message":
|
|
let msg = SdsMessage.init(
|
|
messageId = "0xdeadbeef",
|
|
lamportTimestamp = 7,
|
|
causalHistory = @[
|
|
HistoryEntry.init("0xaaa", @[byte 1, 2, 3], "0xsender".SdsParticipantID),
|
|
HistoryEntry.init("0xbbb"),
|
|
],
|
|
channelId = "0xchannel",
|
|
content = @[byte 9, 9, 9],
|
|
bloomFilter = @[],
|
|
senderId = "0xmsgsender".SdsParticipantID,
|
|
repairRequest = @[],
|
|
)
|
|
|
|
let wire = serializeMessage(msg).get()
|
|
|
|
# An old node recovers the EXACT message IDs from field 3 and never sees the
|
|
# senderId/hint that ride in field 8.
|
|
let old = Protobuf.decode(wire, OldSdsMessagePB)
|
|
check old.causalHistory.len == 2
|
|
check old.causalHistory[0].toStr == "0xaaa"
|
|
check old.causalHistory[1].toStr == "0xbbb"
|
|
check old.channelId.get(@[]).toStr == "0xchannel"
|
|
check old.content.get(@[]) == @[byte 9, 9, 9]
|
|
|
|
test "v0.4 round-trips message IDs, hints and senderIds":
|
|
let msg = SdsMessage.init(
|
|
messageId = "0xfeed",
|
|
lamportTimestamp = 3,
|
|
causalHistory = @[
|
|
HistoryEntry.init("0xaaa", @[byte 1, 2, 3], "0xsender".SdsParticipantID),
|
|
HistoryEntry.init("0xbbb"),
|
|
],
|
|
channelId = "0xchannel",
|
|
content = @[byte 1],
|
|
bloomFilter = @[],
|
|
)
|
|
|
|
let decoded = deserializeMessage(serializeMessage(msg).get()).get()
|
|
check decoded.causalHistory.len == 2
|
|
check decoded.causalHistory[0].messageId == "0xaaa"
|
|
check decoded.causalHistory[0].retrievalHint == @[byte 1, 2, 3]
|
|
check decoded.causalHistory[0].senderId.string == "0xsender"
|
|
check decoded.causalHistory[1].messageId == "0xbbb"
|
|
check decoded.causalHistory[1].retrievalHint.len == 0
|
|
check decoded.causalHistory[1].senderId.string.len == 0
|
|
|
|
test "v0.4 decodes a legacy message (field 3 IDs only, no field 8)":
|
|
# Build a message the way a pre-SDS-R node would: field 3 = bare ID strings.
|
|
let legacy = OldSdsMessagePB(
|
|
messageId: Opt.some("0xlegacy".toBytes),
|
|
causalHistory: @["0xaaa".toBytes, "0xbbb".toBytes],
|
|
channelId: Opt.some("0xchannel".toBytes),
|
|
content: Opt.some(@[byte 5]),
|
|
)
|
|
let decoded = deserializeMessage(Protobuf.encode(legacy)).get()
|
|
check decoded.causalHistory.len == 2
|
|
check decoded.causalHistory[0].messageId == "0xaaa"
|
|
check decoded.causalHistory[0].retrievalHint.len == 0
|
|
check decoded.causalHistory[0].senderId.string.len == 0
|
|
check decoded.causalHistory[1].messageId == "0xbbb"
|