import math, times, sequtils, strutils, options import nimcrypto import results import leopard import chronicles # External dependencies (still needed) # import protobuf # Nim protobuf library (e.g., protobuf-nim) # SegmentMessage type (unchanged) type SegmentMessage* = ref object entireMessageHash*: seq[byte] index*: uint32 segmentsCount*: uint32 paritySegmentIndex*: uint32 paritySegmentsCount*: uint32 payload*: seq[byte] # Placeholder types (unchanged) type WakuNewMessage* = object payload*: seq[byte] # Add other fields as needed StatusMessage* = object transportLayer*: TransportLayer TransportLayer* = object hash*: seq[byte] payload*: seq[byte] sigPubKey*: seq[byte] Persistence = object completedMessages: Table[seq[byte], bool] # Mock storage for completed message hashes segments: Table[(seq[byte], seq[byte]), seq[SegmentMessage]] # Stores segments by (hash, sigPubKey) # Error definitions (unchanged) const ErrMessageSegmentsIncomplete = "message segments incomplete" ErrMessageSegmentsAlreadyCompleted = "message segments already completed" ErrMessageSegmentsInvalidCount = "invalid segments count" ErrMessageSegmentsHashMismatch = "hash of entire payload does not match" ErrMessageSegmentsInvalidParity = "invalid parity segments" # Constants (unchanged) const SegmentsParityRate = 0.125 SegmentsReedsolomonMaxCount = 256 # Validation methods (unchanged) proc isValid*(s: SegmentMessage): bool = s.segmentsCount >= 2 or s.paritySegmentsCount > 0 proc isParityMessage*(s: SegmentMessage): bool = s.segmentsCount == 0 and s.paritySegmentsCount > 0 # MessageSender type (unchanged) type MessageSender* = ref object messaging*: Messaging persistence*: Persistence Messaging* = object maxMessageSize*: int proc initPersistence*(): Persistence = Persistence( completedMessages: initTable[seq[byte], bool](), segments: initTable[(seq[byte], seq[byte]), seq[SegmentMessage]]() ) proc isMessageAlreadyCompleted(p: Persistence, hash: seq[byte]): Result[bool, string] = return ok(p.completedMessages.getOrDefault(hash, false)) proc saveMessageSegment(p: var Persistence, segment: SegmentMessage, sigPubKey: seq[byte], timestamp: int64): Result[void, string] = let key = (segment.entireMessageHash, sigPubKey) # Initialize or append to the segments list if not p.segments.hasKey(key): p.segments[key] = @[] p.segments[key].add(segment) return ok() proc getMessageSegments(p: Persistence, hash: seq[byte], sigPubKey: seq[byte]): Result[seq[SegmentMessage], string] = let key = (hash, sigPubKey) return ok(p.segments.getOrDefault(key, @[])) proc completeMessageSegments(p: var Persistence, hash: seq[byte], sigPubKey: seq[byte], timestamp: int64): Result[void, string] = p.completedMessages[hash] = true return ok() # Replicate message (unchanged) proc replicateMessageWithNewPayload(message: WakuNewMessage, payload: seq[byte]): Result[WakuNewMessage, string] = var copiedMessage = WakuNewMessage(payload: payload) return ok(copiedMessage) proc protoMarshal(msg: SegmentMessage): Result[seq[byte], string] = # Fake serialization (index + payload length) TODO return ok(@[byte(msg.index)] & msg.payload) proc protoUnmarshal(data: seq[byte], msg: var SegmentMessage): Result[void, string] = # Fake deserialization (reconstruct index and payload) if data.len < 1: return err("data too short") msg.index = uint32(data[0]) msg.payload = data[1..^1] msg.segmentsCount = 2 msg.entireMessageHash = @[byte 1, 2, 3] # Dummy hash return ok() # Segment message into smaller chunks (updated with nim-leopard) proc segmentMessageInternal(newMessage: WakuNewMessage, segmentSize: int): Result[seq[WakuNewMessage], string] = if newMessage.payload.len <= segmentSize: return ok(@[newMessage]) let entireMessageHash = keccak256.digest(newMessage.payload) let entirePayloadSize = newMessage.payload.len let segmentsCount = int(ceil(entirePayloadSize.float / segmentSize.float)) let paritySegmentsCount = int(floor(segmentsCount.float * SegmentsParityRate)) var segmentPayloads = newSeq[seq[byte]](segmentsCount + paritySegmentsCount) var segmentMessages = newSeq[WakuNewMessage](segmentsCount) for i in 0.. entirePayloadSize: endIndex = entirePayloadSize let segmentPayload = newMessage.payload[start.. SegmentsReedsolomonMaxCount: return ok(segmentMessages) # Align last segment payload for Reed-Solomon (leopard requires fixed-size shards) let lastSegmentPayload = segmentPayloads[segmentsCount-1] segmentPayloads[segmentsCount-1] = newSeq[byte](segmentSize) segmentPayloads[segmentsCount-1][0.. 0: payloads[firstSegmentMessage.segmentsCount - 1] = lastNonParitySegmentPayload # Combine payload var entirePayload = newSeq[byte]() for i in 0..