logos-delivery/tests/waku_archive/test_driver_sqlite.nim
darshankabariya 3accb291c9 feat: persist RLN proofs in the archive so synced history stays verifiable
Live messages carry an RLN proof, but archives dropped it at insert
time - so history handed over via store-sync transfer or store resume
arrived proofless and had to be accepted on faith, sidestepping the
spam limiter exactly where it should be load-bearing. A malicious peer
could invent 'history you missed' and a victim would swallow and
re-serve it.

- archive: proof column (sqlite schema v11, postgres v8; nullable, so
  existing rows migrate as a no-op and in-memory archives need no
  migration); insert/select thread message.proof through both drivers;
  the queue driver stores whole messages and needed no change
- transfer and store resume serve proof-bearing messages automatically
  (the wire codecs already carry the field) and both re-verify the
  original author's proof on arrival: the receiving node's FIRST
  verification of a message it missed on relay, not a repeat - same
  work the relay path would have done, deferred to catch-up
- store resume gains the same validator the sync transfer uses, since
  a store node could also serve invented history
- new --store-sync-require-proof flag (default off): the rollout lever;
  once the fleet persists and serves proofs, flipping it makes nodes
  reject proofless synced history when RLN is enabled
- reconciliation untouched: proofs are not part of the message hash,
  so identity, fingerprints and cursors are unchanged

Tested end-to-end: a proof survives full-node -> full-node sync
transfer and the store-query -> resume -> archive trip intact.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 01:42:26 +05:30

85 lines
2.2 KiB
Nim

{.used.}
import std/sequtils, testutils/unittests, chronos
import
logos_delivery/waku/[waku_archive, waku_archive/driver/sqlite_driver, waku_core],
../waku_archive/archive_utils,
../testlib/wakucore
suite "SQLite driver":
test "init driver and database":
## Given
let database = newSqliteDatabase()
## When
let driverRes = SqliteDriver.new(database)
## Then
check:
driverRes.isOk()
let driver: ArchiveDriver = driverRes.tryGet()
check:
not driver.isNil()
## Cleanup
(waitFor driver.close()).expect("driver to close")
test "insert a message":
## Given
const contentTopic = "test-content-topic"
const meta = "test meta"
let driver = newSqliteArchiveDriver()
let msg = fakeWakuMessage(contentTopic = contentTopic, meta = meta)
let msgHash = computeMessageHash(DefaultPubsubTopic, msg)
## When
let putRes = waitFor driver.put(msgHash, DefaultPubsubTopic, msg)
## Then
check:
putRes.isOk()
let storedMsg = (waitFor driver.getAllMessages()).tryGet()
check:
storedMsg.len == 1
storedMsg.all do(item: auto) -> bool:
let (hash, pubsubTopic, actualMsg) = item
actualMsg.contentTopic == contentTopic and pubsubTopic == DefaultPubsubTopic and
hash == msgHash and msg.meta == actualMsg.meta
## Cleanup
(waitFor driver.close()).expect("driver to close")
test "insert a message with a proof and read it back":
## The original author's RLN proof must survive archiving so that
## history served via store-sync transfer stays verifiable.
let driver = newSqliteArchiveDriver()
let proof = @[byte 1, 2, 3, 4]
let msg = fakeWakuMessage(proof = proof)
let msgHash = computeMessageHash(DefaultPubsubTopic, msg)
## When
let putRes = waitFor driver.put(msgHash, DefaultPubsubTopic, msg)
## Then
check:
putRes.isOk()
let allRows = (waitFor driver.getAllMessages()).tryGet()
check:
allRows.len == 1
allRows[0][2].proof == proof
let queried =
(waitFor driver.getMessages(includeData = true, hashes = @[msgHash])).tryGet()
check:
queried.len == 1
queried[0][2].proof == proof
## Cleanup
(waitFor driver.close()).expect("driver to close")