nwaku/tests/wakunode_rest/test_rest_store.nim
Simon-Pierre Vivier f54ba10bc7
chore(archive): archive and drivers refactor (#2761)
* queue driver refactor (#2753)
* chore(archive): archive refactor (#2752)
* chore(archive): sqlite driver refactor (#2754)
* chore(archive): postgres driver refactor (#2755)
* chore(archive): renaming & copies (#2751)
* posgres legacy: stop using the storedAt field
* migration script 6: we still need the id column
  The id column is needed because it contains the message digest
  which is used in store v2, and we need to keep support to
  store v2 for a while
* legacy archive: set target migration version to 6
* waku_node: try to use wakuLegacyArchive if wakuArchive is nil
* node_factory, waku_node: mount legacy and future store simultaneously
  We want the nwaku node to simultaneously support store-v2
  requests and store-v3 requests.
  Only the legacy archive is in charge of archiving messages, and the
  archived information is suitable to fulfill both store-v2 and
  store-v3 needs.
* postgres_driver: adding temporary code until store-v2 is removed

---------

Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com>
Co-authored-by: gabrielmer <101006718+gabrielmer@users.noreply.github.com>
Co-authored-by: Ivan Folgueira Bande <ivansete@status.im>
2024-07-12 18:19:12 +02:00

873 lines
28 KiB
Nim

{.used.}
import
std/[options, sugar],
stew/shims/net as stewNet,
chronicles,
chronos/timer,
testutils/unittests,
eth/keys,
presto,
presto/client as presto_client,
libp2p/crypto/crypto
import
waku/[
waku_core/message,
waku_core/message/digest,
waku_core/topics,
waku_core/time,
waku_node,
node/peer_manager,
waku_api/rest/server,
waku_api/rest/client,
waku_api/rest/responses,
waku_api/rest/store/handlers as store_api,
waku_api/rest/store/client as store_api_client,
waku_api/rest/store/types,
waku_archive,
waku_archive/driver/queue_driver,
waku_archive/driver/sqlite_driver,
common/databases/db_sqlite,
waku_archive/driver/postgres_driver,
waku_store as waku_store,
],
../testlib/wakucore,
../testlib/wakunode
logScope:
topics = "waku node rest store_api test"
proc put(
store: ArchiveDriver, pubsubTopic: PubsubTopic, message: WakuMessage
): Future[Result[void, string]] =
let msgHash = computeMessageHash(pubsubTopic, message)
store.put(msgHash, pubsubTopic, message)
# Creates a new WakuNode
proc testWakuNode(): WakuNode =
let
privkey = generateSecp256k1Key()
bindIp = parseIpAddress("0.0.0.0")
extIp = parseIpAddress("127.0.0.1")
port = Port(0)
return newTestWakuNode(privkey, bindIp, port, some(extIp), some(port))
################################################################################
# Beginning of the tests
################################################################################
procSuite "Waku Rest API - Store v3":
asyncTest "MessageHash <-> string conversions":
# Validate MessageHash conversion from a WakuMessage obj
let wakuMsg = WakuMessage(
contentTopic: "Test content topic", payload: @[byte('H'), byte('i'), byte('!')]
)
let messageHash = computeMessageHash(DefaultPubsubTopic, wakuMsg)
let restMsgHash = some(messageHash.toRestStringWakuMessageHash())
let parsedMsgHashRes = parseHash(restMsgHash)
assert parsedMsgHashRes.isOk(), $parsedMsgHashRes.error
check:
messageHash == parsedMsgHashRes.get().get()
# Random validation. Obtained the raw values manually
let expected = some("f6za9OzG1xSiEZagZc2b3litRbkd3zRl61rezDd3pgQ%3D")
let msgHashRes = parseHash(expected)
assert msgHashRes.isOk(), $msgHashRes.error
check:
expected.get() == msgHashRes.get().get().toRestStringWakuMessageHash()
asyncTest "invalid cursor":
let node = testWakuNode()
await node.start()
await node.mountRelay()
var restPort = Port(0)
let restAddress = parseIpAddress("0.0.0.0")
let restServer = WakuRestServerRef.init(restAddress, restPort).tryGet()
restPort = restServer.httpServer.address.port # update with bound port for client use
installStoreApiHandlers(restServer.router, node)
restServer.start()
# WakuStore setup
let db: SqliteDatabase =
SqliteDatabase.new(string.none().get(":memory:")).expect("valid DB")
let driver: ArchiveDriver = SqliteDriver.new(db).expect("valid driver")
let mountArchiveRes = node.mountArchive(driver)
assert mountArchiveRes.isOk(), mountArchiveRes.error
await node.mountStore()
node.mountStoreClient()
let key = generateEcdsaKey()
var peerSwitch = newStandardSwitch(some(key))
await peerSwitch.start()
peerSwitch.mount(node.wakuStore)
await sleepAsync(1.seconds())
# Now prime it with some history before tests
let msgList =
@[
fakeWakuMessage(@[byte 0], contentTopic = ContentTopic("ct1"), ts = 0),
fakeWakuMessage(@[byte 1], ts = 1),
fakeWakuMessage(@[byte 1, byte 2], ts = 2),
fakeWakuMessage(@[byte 1], ts = 3),
fakeWakuMessage(@[byte 1], ts = 4),
fakeWakuMessage(@[byte 1], ts = 5),
fakeWakuMessage(@[byte 1], ts = 6),
fakeWakuMessage(@[byte 9], contentTopic = ContentTopic("c2"), ts = 9),
]
for msg in msgList:
require (await driver.put(DefaultPubsubTopic, msg)).isOk()
let client = newRestHttpClient(initTAddress(restAddress, restPort))
let remotePeerInfo = peerSwitch.peerInfo.toRemotePeerInfo()
let fullAddr = $remotePeerInfo.addrs[0] & "/p2p/" & $remotePeerInfo.peerId
await sleepAsync(1.seconds())
let fakeCursor = computeMessageHash(DefaultPubsubTopic, fakeWakuMessage())
let encodedCursor = fakeCursor.toRestStringWakuMessageHash()
# Apply filter by start and end timestamps
var response = await client.getStoreMessagesV3(
encodeUrl(fullAddr),
"true", # include data
"", # pubsub topic
"ct1,c2", # empty content topics.
"", # start time
"", # end time
"", # hashes
encodedCursor, # base64-encoded hash
"true", # ascending
"5", # empty implies default page size
)
check:
response.status == 200
$response.contentType == $MIMETYPE_JSON
response.data.messages.len == 0
await restServer.stop()
await restServer.closeWait()
await node.stop()
asyncTest "Filter by start and end time":
let node = testWakuNode()
await node.start()
await node.mountRelay()
var restPort = Port(0)
let restAddress = parseIpAddress("0.0.0.0")
let restServer = WakuRestServerRef.init(restAddress, restPort).tryGet()
restPort = restServer.httpServer.address.port # update with bound port for client use
installStoreApiHandlers(restServer.router, node)
restServer.start()
# WakuStore setup
let driver: ArchiveDriver = QueueDriver.new()
let mountArchiveRes = node.mountArchive(driver)
assert mountArchiveRes.isOk(), mountArchiveRes.error
await node.mountStore()
node.mountStoreClient()
let key = generateEcdsaKey()
var peerSwitch = newStandardSwitch(some(key))
await peerSwitch.start()
peerSwitch.mount(node.wakuStore)
# Now prime it with some history before tests
let msgList =
@[
fakeWakuMessage(@[byte 0], contentTopic = ContentTopic("ct1"), ts = 0),
fakeWakuMessage(@[byte 1], ts = 1),
fakeWakuMessage(@[byte 1, byte 2], ts = 2),
fakeWakuMessage(@[byte 1], ts = 3),
fakeWakuMessage(@[byte 1], ts = 4),
fakeWakuMessage(@[byte 1], ts = 5),
fakeWakuMessage(@[byte 1], ts = 6),
fakeWakuMessage(@[byte 9], contentTopic = ContentTopic("c2"), ts = 9),
]
for msg in msgList:
require (await driver.put(DefaultPubsubTopic, msg)).isOk()
let client = newRestHttpClient(initTAddress(restAddress, restPort))
let remotePeerInfo = peerSwitch.peerInfo.toRemotePeerInfo()
let fullAddr = $remotePeerInfo.addrs[0] & "/p2p/" & $remotePeerInfo.peerId
# Apply filter by start and end timestamps
var response = await client.getStoreMessagesV3(
encodeUrl(fullAddr),
"true", # include data
encodeUrl(DefaultPubsubTopic),
"", # empty content topics. Don't filter by this field
"3", # start time
"6", # end time
"", # hashes
"", # base64-encoded hash
"true", # ascending
"", # empty implies default page size
)
check:
response.status == 200
$response.contentType == $MIMETYPE_JSON
response.data.messages.len == 4
await restServer.stop()
await restServer.closeWait()
await node.stop()
asyncTest "Store node history response - forward pagination":
# Test adapted from the analogous present at waku_store/test_wakunode_store.nim
let node = testWakuNode()
await node.start()
var restPort = Port(0)
let restAddress = parseIpAddress("0.0.0.0")
let restServer = WakuRestServerRef.init(restAddress, restPort).tryGet()
restPort = restServer.httpServer.address.port # update with bound port for client use
installStoreApiHandlers(restServer.router, node)
restServer.start()
# WakuStore setup
let driver: ArchiveDriver = QueueDriver.new()
let mountArchiveRes = node.mountArchive(driver)
assert mountArchiveRes.isOk(), mountArchiveRes.error
await node.mountStore()
node.mountStoreClient()
let key = generateEcdsaKey()
var peerSwitch = newStandardSwitch(some(key))
await peerSwitch.start()
peerSwitch.mount(node.wakuStore)
# Now prime it with some history before tests
let timeOrigin = wakucore.now()
let msgList =
@[
fakeWakuMessage(@[byte 00], ts = ts(00, timeOrigin)),
fakeWakuMessage(@[byte 01], ts = ts(10, timeOrigin)),
fakeWakuMessage(@[byte 02], ts = ts(20, timeOrigin)),
fakeWakuMessage(@[byte 03], ts = ts(30, timeOrigin)),
fakeWakuMessage(@[byte 04], ts = ts(40, timeOrigin)),
fakeWakuMessage(@[byte 05], ts = ts(50, timeOrigin)),
fakeWakuMessage(@[byte 06], ts = ts(60, timeOrigin)),
fakeWakuMessage(@[byte 07], ts = ts(70, timeOrigin)),
fakeWakuMessage(@[byte 08], ts = ts(80, timeOrigin)),
fakeWakuMessage(@[byte 09], ts = ts(90, timeOrigin)),
]
for msg in msgList:
require (await driver.put(DefaultPubsubTopic, msg)).isOk()
let client = newRestHttpClient(initTAddress(restAddress, restPort))
let remotePeerInfo = peerSwitch.peerInfo.toRemotePeerInfo()
let fullAddr = $remotePeerInfo.addrs[0] & "/p2p/" & $remotePeerInfo.peerId
var pages = newSeq[seq[WakuMessage]](2)
var reqHash = none(WakuMessageHash)
for i in 0 ..< 2:
let response = await client.getStoreMessagesV3(
encodeUrl(fullAddr),
"true", # include data
encodeUrl(DefaultPubsubTopic),
"", # content topics. Empty ignores the field.
"", # start time. Empty ignores the field.
"", # end time. Empty ignores the field.
"", # hashes
if reqHash.isSome():
reqHash.get().toRestStringWakuMessageHash()
else:
""
, # base64-encoded digest. Empty ignores the field.
"true", # ascending
"7", # page size. Empty implies default page size.
)
let wakuMessages = collect(newSeq):
for element in response.data.messages:
if element.message.isSome():
element.message.get()
pages[i] = wakuMessages
# populate the cursor for next page
if response.data.paginationCursor.isSome():
reqHash = some(response.data.paginationCursor.get())
check:
response.status == 200
$response.contentType == $MIMETYPE_JSON
check:
pages[0] == msgList[0 .. 6]
pages[1] == msgList[7 .. 9]
await restServer.stop()
await restServer.closeWait()
await node.stop()
asyncTest "query a node and retrieve historical messages filtered by pubsub topic":
# Given
let node = testWakuNode()
await node.start()
await node.mountRelay()
var restPort = Port(0)
let restAddress = parseIpAddress("0.0.0.0")
let restServer = WakuRestServerRef.init(restAddress, restPort).tryGet()
restPort = restServer.httpServer.address.port # update with bound port for client use
installStoreApiHandlers(restServer.router, node)
restServer.start()
# WakuStore setup
let driver: ArchiveDriver = QueueDriver.new()
let mountArchiveRes = node.mountArchive(driver)
assert mountArchiveRes.isOk(), mountArchiveRes.error
await node.mountStore()
node.mountStoreClient()
let key = generateEcdsaKey()
var peerSwitch = newStandardSwitch(some(key))
await peerSwitch.start()
peerSwitch.mount(node.wakuStore)
# Now prime it with some history before tests
let msgList =
@[
fakeWakuMessage(@[byte 0], contentTopic = ContentTopic("2"), ts = 0),
fakeWakuMessage(@[byte 1], ts = 1),
fakeWakuMessage(@[byte 9], contentTopic = ContentTopic("2"), ts = 9),
]
for msg in msgList:
require (await driver.put(DefaultPubsubTopic, msg)).isOk()
let client = newRestHttpClient(initTAddress(restAddress, restPort))
let remotePeerInfo = peerSwitch.peerInfo.toRemotePeerInfo()
let fullAddr = $remotePeerInfo.addrs[0] & "/p2p/" & $remotePeerInfo.peerId
# Filtering by a known pubsub topic
var response = await client.getStoreMessagesV3(
encodeUrl($fullAddr), "true", encodeUrl(DefaultPubsubTopic)
)
check:
response.status == 200
$response.contentType == $MIMETYPE_JSON
response.data.messages.len == 3
# Get all the messages by specifying an empty pubsub topic
response = await client.getStoreMessagesV3(encodeUrl($fullAddr), "true")
check:
response.status == 200
$response.contentType == $MIMETYPE_JSON
response.data.messages.len == 3
# Receiving no messages by filtering with a random pubsub topic
response = await client.getStoreMessagesV3(
encodeUrl($fullAddr), "true", encodeUrl("random pubsub topic")
)
check:
response.status == 200
$response.contentType == $MIMETYPE_JSON
response.data.messages.len == 0
await restServer.stop()
await restServer.closeWait()
await node.stop()
asyncTest "retrieve historical messages from a provided store node address":
# Given
let node = testWakuNode()
await node.start()
await node.mountRelay()
var restPort = Port(0)
let restAddress = parseIpAddress("0.0.0.0")
let restServer = WakuRestServerRef.init(restAddress, restPort).tryGet()
restPort = restServer.httpServer.address.port # update with bound port for client use
installStoreApiHandlers(restServer.router, node)
restServer.start()
# WakuStore setup
let driver: ArchiveDriver = QueueDriver.new()
let mountArchiveRes = node.mountArchive(driver)
assert mountArchiveRes.isOk(), mountArchiveRes.error
await node.mountStore()
node.mountStoreClient()
let key = generateEcdsaKey()
var peerSwitch = newStandardSwitch(some(key))
await peerSwitch.start()
peerSwitch.mount(node.wakuStore)
# Now prime it with some history before tests
let msgList =
@[
fakeWakuMessage(@[byte 0], contentTopic = ContentTopic("ct1"), ts = 0),
fakeWakuMessage(@[byte 1], ts = 1),
fakeWakuMessage(@[byte 9], contentTopic = ContentTopic("ct2"), ts = 9),
]
for msg in msgList:
require (await driver.put(DefaultPubsubTopic, msg)).isOk()
let client = newRestHttpClient(initTAddress(restAddress, restPort))
let remotePeerInfo = peerSwitch.peerInfo.toRemotePeerInfo()
let fullAddr = $remotePeerInfo.addrs[0] & "/p2p/" & $remotePeerInfo.peerId
# Filtering by a known pubsub topic.
# We also pass the store-node address in the request.
var response = await client.getStoreMessagesV3(
encodeUrl(fullAddr), "true", encodeUrl(DefaultPubsubTopic)
)
check:
response.status == 200
$response.contentType == $MIMETYPE_JSON
response.data.messages.len == 3
# Get all the messages by specifying an empty pubsub topic
# We also pass the store-node address in the request.
response =
await client.getStoreMessagesV3(encodeUrl(fullAddr), "true", encodeUrl(""))
check:
response.status == 200
$response.contentType == $MIMETYPE_JSON
response.data.messages.len == 3
# Receiving no messages by filtering with a random pubsub topic
# We also pass the store-node address in the request.
response = await client.getStoreMessagesV3(
encodeUrl(fullAddr), "true", encodeUrl("random pubsub topic")
)
check:
response.status == 200
$response.contentType == $MIMETYPE_JSON
response.data.messages.len == 0
# Receiving 400 response if setting wrong store-node address
response = await client.getStoreMessagesV3(
encodeUrl("incorrect multi address format"),
"true",
encodeUrl("random pubsub topic"),
)
check:
response.status == 400
$response.contentType == $MIMETYPE_TEXT
response.data.messages.len == 0
response.data.statusDesc ==
"Failed parsing remote peer info [MultiAddress.init [multiaddress: Invalid MultiAddress, must start with `/`]]"
await restServer.stop()
await restServer.closeWait()
await node.stop()
asyncTest "filter historical messages by content topic":
# Given
let node = testWakuNode()
await node.start()
await node.mountRelay()
var restPort = Port(0)
let restAddress = parseIpAddress("0.0.0.0")
let restServer = WakuRestServerRef.init(restAddress, restPort).tryGet()
restPort = restServer.httpServer.address.port # update with bound port for client use
installStoreApiHandlers(restServer.router, node)
restServer.start()
# WakuStore setup
let driver: ArchiveDriver = QueueDriver.new()
let mountArchiveRes = node.mountArchive(driver)
assert mountArchiveRes.isOk(), mountArchiveRes.error
await node.mountStore()
node.mountStoreClient()
let key = generateEcdsaKey()
var peerSwitch = newStandardSwitch(some(key))
await peerSwitch.start()
peerSwitch.mount(node.wakuStore)
# Now prime it with some history before tests
let msgList =
@[
fakeWakuMessage(@[byte 0], contentTopic = ContentTopic("ct1"), ts = 0),
fakeWakuMessage(@[byte 1], ts = 1),
fakeWakuMessage(@[byte 9], contentTopic = ContentTopic("ct2"), ts = 9),
]
for msg in msgList:
require (await driver.put(DefaultPubsubTopic, msg)).isOk()
let client = newRestHttpClient(initTAddress(restAddress, restPort))
let remotePeerInfo = peerSwitch.peerInfo.toRemotePeerInfo()
let fullAddr = $remotePeerInfo.addrs[0] & "/p2p/" & $remotePeerInfo.peerId
# Filtering by content topic
let response = await client.getStoreMessagesV3(
encodeUrl(fullAddr), "true", encodeUrl(DefaultPubsubTopic), encodeUrl("ct1,ct2")
)
check:
response.status == 200
$response.contentType == $MIMETYPE_JSON
response.data.messages.len == 2
await restServer.stop()
await restServer.closeWait()
await node.stop()
asyncTest "precondition failed":
# Given
let node = testWakuNode()
await node.start()
await node.mountRelay()
var restPort = Port(0)
let restAddress = parseIpAddress("0.0.0.0")
let restServer = WakuRestServerRef.init(restAddress, restPort).tryGet()
restPort = restServer.httpServer.address.port # update with bound port for client use
installStoreApiHandlers(restServer.router, node)
restServer.start()
node.mountStoreClient()
let key = generateEcdsaKey()
var peerSwitch = newStandardSwitch(some(key))
await peerSwitch.start()
let client = newRestHttpClient(initTAddress(restAddress, restPort))
let remotePeerInfo = peerSwitch.peerInfo.toRemotePeerInfo()
# Sending no peer-store node address
var response = await client.getStoreMessagesV3(
encodeUrl(""), "true", encodeUrl(DefaultPubsubTopic)
)
check:
response.status == 412
$response.contentType == $MIMETYPE_TEXT
response.data.messages.len == 0
response.data.statusDesc == NoPeerNoDiscError.errobj.message
# Now add the storenode from "config"
node.peerManager.addServicePeer(remotePeerInfo, WakuStoreCodec)
# WakuStore setup
let driver: ArchiveDriver = QueueDriver.new()
let mountArchiveRes = node.mountArchive(driver)
assert mountArchiveRes.isOk(), mountArchiveRes.error
await node.mountStore()
# Now prime it with some history before tests
let msgList =
@[
fakeWakuMessage(@[byte 0], contentTopic = ContentTopic("ct1"), ts = 0),
fakeWakuMessage(@[byte 1], ts = 1),
fakeWakuMessage(@[byte 9], contentTopic = ContentTopic("ct2"), ts = 9),
]
for msg in msgList:
require (await driver.put(DefaultPubsubTopic, msg)).isOk()
# Sending no peer-store node address
response = await client.getStoreMessagesV3(
encodeUrl(""), "true", encodeUrl(DefaultPubsubTopic)
)
check:
response.status == 200
$response.contentType == $MIMETYPE_JSON
response.data.messages.len == 3
await restServer.stop()
await restServer.closeWait()
await node.stop()
asyncTest "retrieve historical messages from a self-store-node":
## This test aims to validate the correct message retrieval for a store-node which exposes
## a REST server.
# Given
let node = testWakuNode()
await node.start()
var restPort = Port(0)
let restAddress = parseIpAddress("0.0.0.0")
let restServer = WakuRestServerRef.init(restAddress, restPort).tryGet()
restPort = restServer.httpServer.address.port # update with bound port for client use
installStoreApiHandlers(restServer.router, node)
restServer.start()
# WakuStore setup
let driver: ArchiveDriver = QueueDriver.new()
let mountArchiveRes = node.mountArchive(driver)
assert mountArchiveRes.isOk(), mountArchiveRes.error
await node.mountStore()
# Now prime it with some history before tests
let msgList =
@[
fakeWakuMessage(
@[byte 0], contentTopic = ContentTopic("ct1"), ts = 0, meta = (@[byte 8])
),
fakeWakuMessage(@[byte 1], ts = 1),
fakeWakuMessage(@[byte 9], contentTopic = ContentTopic("ct2"), ts = 9),
]
for msg in msgList:
require (await driver.put(DefaultPubsubTopic, msg)).isOk()
let client = newRestHttpClient(initTAddress(restAddress, restPort))
# Filtering by a known pubsub topic.
var response = await client.getStoreMessagesV3(
includeData = "true", pubsubTopic = encodeUrl(DefaultPubsubTopic)
)
check:
response.status == 200
$response.contentType == $MIMETYPE_JSON
response.data.messages.len == 3
# Get all the messages by specifying an empty pubsub topic
response =
await client.getStoreMessagesV3(includeData = "true", pubsubTopic = encodeUrl(""))
check:
response.status == 200
$response.contentType == $MIMETYPE_JSON
response.data.messages.len == 3
# Receiving no messages by filtering with a random pubsub topic
response = await client.getStoreMessagesV3(
includeData = "true", pubsubTopic = encodeUrl("random pubsub topic")
)
check:
response.status == 200
$response.contentType == $MIMETYPE_JSON
response.data.messages.len == 0
asyncTest "correct message fields are returned":
# Given
let node = testWakuNode()
await node.start()
var restPort = Port(0)
let restAddress = parseIpAddress("0.0.0.0")
let restServer = WakuRestServerRef.init(restAddress, restPort).tryGet()
restPort = restServer.httpServer.address.port # update with bound port for client use
installStoreApiHandlers(restServer.router, node)
restServer.start()
# WakuStore setup
let driver: ArchiveDriver = QueueDriver.new()
let mountArchiveRes = node.mountArchive(driver)
assert mountArchiveRes.isOk(), mountArchiveRes.error
await node.mountStore()
# Now prime it with some history before tests
let msg = fakeWakuMessage(
@[byte 0], contentTopic = ContentTopic("ct1"), ts = 0, meta = (@[byte 8])
)
require (await driver.put(DefaultPubsubTopic, msg)).isOk()
let client = newRestHttpClient(initTAddress(restAddress, restPort))
# Filtering by a known pubsub topic.
var response = await client.getStoreMessagesV3(
includeData = "true", pubsubTopic = encodeUrl(DefaultPubsubTopic)
)
check:
response.status == 200
$response.contentType == $MIMETYPE_JSON
response.data.messages.len == 1
let storeMessage = response.data.messages[0].message.get()
check:
storeMessage.payload == msg.payload
storeMessage.contentTopic == msg.contentTopic
storeMessage.version == msg.version
storeMessage.timestamp == msg.timestamp
storeMessage.ephemeral == msg.ephemeral
storeMessage.meta == msg.meta
asyncTest "Rate limit store node store query":
# Test adapted from the analogous present at waku_store/test_wakunode_store.nim
let node = testWakuNode()
await node.start()
var restPort = Port(0)
let restAddress = parseIpAddress("0.0.0.0")
let restServer = WakuRestServerRef.init(restAddress, restPort).tryGet()
restPort = restServer.httpServer.address.port # update with bound port for client use
installStoreApiHandlers(restServer.router, node)
restServer.start()
# WakuStore setup
let driver: ArchiveDriver = QueueDriver.new()
let mountArchiveRes = node.mountArchive(driver)
assert mountArchiveRes.isOk(), mountArchiveRes.error
await node.mountStore((2, 500.millis))
node.mountStoreClient()
let key = generateEcdsaKey()
var peerSwitch = newStandardSwitch(some(key))
await peerSwitch.start()
peerSwitch.mount(node.wakuStore)
# Now prime it with some history before tests
let timeOrigin = wakucore.now()
let msgList =
@[
fakeWakuMessage(@[byte 00], ts = ts(00, timeOrigin)),
fakeWakuMessage(@[byte 01], ts = ts(10, timeOrigin)),
fakeWakuMessage(@[byte 02], ts = ts(20, timeOrigin)),
fakeWakuMessage(@[byte 03], ts = ts(30, timeOrigin)),
fakeWakuMessage(@[byte 04], ts = ts(40, timeOrigin)),
fakeWakuMessage(@[byte 05], ts = ts(50, timeOrigin)),
fakeWakuMessage(@[byte 06], ts = ts(60, timeOrigin)),
fakeWakuMessage(@[byte 07], ts = ts(70, timeOrigin)),
fakeWakuMessage(@[byte 08], ts = ts(80, timeOrigin)),
fakeWakuMessage(@[byte 09], ts = ts(90, timeOrigin)),
]
for msg in msgList:
require (await driver.put(DefaultPubsubTopic, msg)).isOk()
let client = newRestHttpClient(initTAddress(restAddress, restPort))
let remotePeerInfo = peerSwitch.peerInfo.toRemotePeerInfo()
let fullAddr = $remotePeerInfo.addrs[0] & "/p2p/" & $remotePeerInfo.peerId
var pages = newSeq[seq[WakuMessage]](2)
var reqPubsubTopic = DefaultPubsubTopic
var reqHash = none(WakuMessageHash)
for i in 0 ..< 2:
let response = await client.getStoreMessagesV3(
encodeUrl(fullAddr),
"true", # include data
encodeUrl(reqPubsubTopic),
"", # content topics. Empty ignores the field.
"", # start time. Empty ignores the field.
"", # end time. Empty ignores the field.
"", # hashes
if reqHash.isSome():
reqHash.get().toRestStringWakuMessageHash()
else:
""
, # base64-encoded digest. Empty ignores the field.
"true", # ascending
"3", # page size. Empty implies default page size.
)
let wakuMessages = collect(newSeq):
for element in response.data.messages:
if element.message.isSome():
element.message.get()
pages[i] = wakuMessages
# populate the cursor for next page
if response.data.paginationCursor.isSome():
reqHash = response.data.paginationCursor
check:
response.status == 200
$response.contentType == $MIMETYPE_JSON
check:
pages[0] == msgList[0 .. 2]
pages[1] == msgList[3 .. 5]
# request last third will lead to rate limit rejection
var response = await client.getStoreMessagesV3(
encodeUrl(fullAddr),
"true", # include data
encodeUrl(reqPubsubTopic),
"", # content topics. Empty ignores the field.
"", # start time. Empty ignores the field.
"", # end time. Empty ignores the field.
"", # hashes
if reqHash.isSome():
reqHash.get().toRestStringWakuMessageHash()
else:
""
, # base64-encoded digest. Empty ignores the field.
)
check:
response.status == 429
$response.contentType == $MIMETYPE_TEXT
response.data.statusDesc == "Request rate limit reached"
await sleepAsync(500.millis)
# retry after respective amount of time shall succeed
response = await client.getStoreMessagesV3(
encodeUrl(fullAddr),
"true", # include data
encodeUrl(reqPubsubTopic),
"", # content topics. Empty ignores the field.
"", # start time. Empty ignores the field.
"", # end time. Empty ignores the field.
"", # hashes
if reqHash.isSome():
reqHash.get().toRestStringWakuMessageHash()
else:
""
, # base64-encoded digest. Empty ignores the field.
"true", # ascending
"5", # page size. Empty implies default page size.
)
check:
response.status == 200
$response.contentType == $MIMETYPE_JSON
let wakuMessages = collect(newSeq):
for element in response.data.messages:
if element.message.isSome():
element.message.get()
check wakuMessages == msgList[6 .. 9]
await restServer.stop()
await restServer.closeWait()
await node.stop()