From 0a19473a3b04444bf9add33402c2bf7347bf8d48 Mon Sep 17 00:00:00 2001 From: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> Date: Thu, 16 Jul 2026 16:56:12 +0200 Subject: [PATCH 1/9] fix: don't apply reconnect backoff to discovered relay peers (#4029) --- .../waku/node/peer_manager/peer_manager.nim | 38 +++++++++------ logos_delivery/waku/waku_core/peers.nim | 1 + tests/node/test_wakunode_peer_manager.nim | 5 ++ tests/test_peer_manager.nim | 48 +++++++++++++++++++ 4 files changed, 78 insertions(+), 14 deletions(-) diff --git a/logos_delivery/waku/node/peer_manager/peer_manager.nim b/logos_delivery/waku/node/peer_manager/peer_manager.nim index 31c6133ab..5ffc185b0 100644 --- a/logos_delivery/waku/node/peer_manager/peer_manager.nim +++ b/logos_delivery/waku/node/peer_manager/peer_manager.nim @@ -223,7 +223,10 @@ proc loadFromStorage(pm: PeerManager) {.gcsafe.} = pm.switch.peerStore[ConnectionBook][peerId] = NotConnected # Reset connectedness state pm.switch.peerStore[DisconnectBook][peerId] = remotePeerInfo.disconnectTime - pm.switch.peerStore[SourceBook][peerId] = remotePeerInfo.origin + # Mark as Cache so it is distinguishable from live-discovered peers. If the + # same peer is later rediscovered, addPeer overrides this with the live + # origin, and reconnect backoff no longer applies to it. + pm.switch.peerStore[SourceBook][peerId] = Cache if remotePeerInfo.enr.isSome(): pm.switch.peerStore[ENRBook][peerId] = remotePeerInfo.enr.get() @@ -695,21 +698,28 @@ proc reconnectPeers*( info "Reconnecting peers", proto = proto - # Proto is not persisted, we need to iterate over all peers. - for peerInfo in pm.switch.peerStore.peers(protocolMatcher(proto)): - # Check that the peer can be connected - if peerInfo.connectedness == CannotConnect: - error "Not reconnecting to unreachable or non-existing peer", - peerId = peerInfo.peerId - continue + # Only reconnect peers that come from persistent storage (Cache). Freshly + # discovered peers must not be delayed by the reconnect backoff: they are + # connected right away by the relay connectivity loop. Rediscovered peers get + # their origin overridden by addPeer, so they naturally drop out of this set. + let peersToReconnect = pm.switch.peerStore.peers(protocolMatcher(proto)).filterIt( + it.origin == Cache and it.connectedness != CannotConnect + ) - if backoffTime > ZeroDuration: - info "Backing off before reconnect", - peerId = peerInfo.peerId, backoffTime = backoffTime - # We disconnected recently and still need to wait for a backoff period before connecting - await sleepAsync(backoffTime) + if peersToReconnect.len == 0: + return - await pm.connectToNodes(@[peerInfo]) + # We disconnected recently and still need to wait a backoff period before + # reconnecting. The wait is shared across all peers rather than applied once + # per peer, so reconnection can't stall behind a slow/unreachable peer and + # keep the node from taking on freshly discovered ones. + if backoffTime > ZeroDuration: + info "Backing off before reconnect", backoffTime = backoffTime + await sleepAsync(backoffTime) + + # Dial all reconnectable peers in parallel; a single slow dial must not delay + # the rest. + await allFutures(peersToReconnect.mapIt(pm.connectToNodes(@[it]))) proc getNumStreams*(pm: PeerManager, protocol: string): (int, int) = var diff --git a/logos_delivery/waku/waku_core/peers.nim b/logos_delivery/waku/waku_core/peers.nim index 6e23c848f..c28ae5427 100644 --- a/logos_delivery/waku/waku_core/peers.nim +++ b/logos_delivery/waku/waku_core/peers.nim @@ -40,6 +40,7 @@ type PeerExchange Dns Kademlia + Cache # Loaded from persistent peer storage (not a live discovery source) PeerDirection* = enum UnknownDirection diff --git a/tests/node/test_wakunode_peer_manager.nim b/tests/node/test_wakunode_peer_manager.nim index 0f85d61fe..73ccfe2b9 100644 --- a/tests/node/test_wakunode_peer_manager.nim +++ b/tests/node/test_wakunode_peer_manager.nim @@ -614,6 +614,11 @@ suite "Peer Manager": serverPeerStore.getPeer(clientPeerId).connectedness == Connectedness.CanConnect + # reconnectPeers only acts on peers restored from persistent storage, + # so tag the server as such. Peers coming from live discovery are + # deliberately left out of the reconnect (and its backoff) path. + client.peerManager.addPeer(serverRemotePeerInfo, origin = Cache) + # When triggering the reconnection await client.peerManager.reconnectPeers(WakuRelayCodec) diff --git a/tests/test_peer_manager.nim b/tests/test_peer_manager.nim index b364fc8c3..1dc42d4ce 100644 --- a/tests/test_peer_manager.nim +++ b/tests/test_peer_manager.nim @@ -300,6 +300,54 @@ procSuite "Peer Manager": await allFutures(nodes.mapIt(it.stop())) + asyncTest "reconnectPeers only reconnects persisted (Cache) peers": + ## Regression: freshly discovered relay peers were wrongly swept into the + ## reconnect backoff path. reconnectPeers must act only on peers loaded from + ## persistent storage (origin == Cache); discovered peers are left for the + ## connectivity loop to dial without any backoff. + let node = newTestWakuNode(generateSecp256k1Key()) + await node.start() + + let basePeerId = "QmeuZJbXrszW2jdT7GdduSjQskPU3S7vvGWKtKgDfkDvW" + var cachePeerId, discoveredPeerId: PeerId + require cachePeerId.init(basePeerId & "1") + require discoveredPeerId.init(basePeerId & "2") + + # Both peers advertise relay and point at an unreachable address, so a dial + # attempt fails fast and is observable via the failed-connection counter. + let unreachableAddr = MultiAddress.init("/ip4/127.0.0.1/tcp/1").tryGet() + + node.peerManager.addPeer( + RemotePeerInfo.init( + peerId = cachePeerId, addrs = @[unreachableAddr], protocols = @[WakuRelayCodec] + ), + origin = Cache, + ) + node.peerManager.addPeer( + RemotePeerInfo.init( + peerId = discoveredPeerId, + addrs = @[unreachableAddr], + protocols = @[WakuRelayCodec], + ), + origin = Discv5, + ) + + # Default backoff is zero, so the test stays fast; the origin filter is what + # we are validating here. + await node.peerManager.reconnectPeers(WakuRelayCodec) + + let peerStore = node.peerManager.switch.peerStore + check: + # The Cache peer was dialed (and failed against the unreachable address). + peerStore[NumberFailedConnBook][cachePeerId] == 1 + peerStore.connectedness(cachePeerId) == CannotConnect + + # The discovered peer was never touched by reconnectPeers. + peerStore[NumberFailedConnBook][discoveredPeerId] == 0 + peerStore.connectedness(discoveredPeerId) == NotConnected + + await node.stop() + asyncTest "Peer manager can use persistent storage and survive restarts": let database = SqliteDatabase.new(":memory:")[] From 1c83c32397c90c17767cc52fd3b45e501781fad4 Mon Sep 17 00:00:00 2001 From: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> Date: Thu, 16 Jul 2026 18:38:05 +0200 Subject: [PATCH 2/9] feat(channels): add channelExists to reliable channels API (#4045) --- library/channels_api/channel_api.nim | 15 +++++++ library/liblogosdelivery.h | 7 ++++ .../api/reliable_channel_manager_api.nim | 1 + .../channels/api/channel_lifecycle.nim | 6 +++ tests/channels/test_all.nim | 1 + tests/channels/test_channel_lifecycle.nim | 39 +++++++++++++++++++ 6 files changed, 69 insertions(+) create mode 100644 tests/channels/test_channel_lifecycle.nim diff --git a/library/channels_api/channel_api.nim b/library/channels_api/channel_api.nim index c9b96312f..6468804d7 100644 --- a/library/channels_api/channel_api.nim +++ b/library/channels_api/channel_api.nim @@ -30,6 +30,21 @@ proc logosdelivery_channel_create( return ok(string(id)) +proc logosdelivery_channel_exists( + ctx: ptr FFIContext[LogosDelivery], + callback: FFICallBack, + userData: pointer, + channelIdStr: cstring, +) {.ffi.} = + ## Returns `"true"` or `"false"`; a missing channel is not an error. + requireInitializedNode(ctx, "ChannelExists"): + return err(errMsg) + + requireChannels(ctx, "ChannelExists"): + return err(errMsg) + + return ok($ctx.myLib[].reliableChannelManager.channelExists(ChannelId($channelIdStr))) + proc logosdelivery_channel_send( ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, diff --git a/library/liblogosdelivery.h b/library/liblogosdelivery.h index 21d8890d2..f06ef4ae5 100644 --- a/library/liblogosdelivery.h +++ b/library/liblogosdelivery.h @@ -86,6 +86,13 @@ extern "C" const char *contentTopic, const char *senderId); + // Check whether a reliable channel is currently open. Returns "true" or + // "false"; an unknown channel id is not an error. + int logosdelivery_channel_exists(void *ctx, + FFICallBack callback, + void *userData, + const char *channelId); + // Send a message on a reliable channel. // messageJson: { "payload": "base64-encoded-payload", "ephemeral": false } // Returns a request ID that can be used to track delivery. diff --git a/logos_delivery/api/reliable_channel_manager_api.nim b/logos_delivery/api/reliable_channel_manager_api.nim index 8d3f63ff3..a43670665 100644 --- a/logos_delivery/api/reliable_channel_manager_api.nim +++ b/logos_delivery/api/reliable_channel_manager_api.nim @@ -10,6 +10,7 @@ type ReliableChannelApi* = concept c createReliableChannel( c, channelId = ChannelId, contentTopic = ContentTopic, senderId = SdsParticipantID ) is Result[ChannelId, string] + channelExists(c, channelId = ChannelId) is bool closeChannel(c, channelId = ChannelId) is Future[Result[void, string]] send(c, channelId = ChannelId, appPayload = seq[byte]) is Future[Result[RequestId, string]] diff --git a/logos_delivery/channels/api/channel_lifecycle.nim b/logos_delivery/channels/api/channel_lifecycle.nim index d110ceb72..bacce83d8 100644 --- a/logos_delivery/channels/api/channel_lifecycle.nim +++ b/logos_delivery/channels/api/channel_lifecycle.nim @@ -74,6 +74,12 @@ proc createReliableChannel*( self.channels[channelId] = chn return ok(channelId) +proc channelExists*(self: ReliableChannelManager, channelId: ChannelId): bool = + ## True while the channel is held by the manager, i.e. between a successful + ## `createReliableChannel` and `closeChannel`. Persisted SDS state for a + ## closed channel does not count as existing. + return self.channels.hasKey(channelId) + proc closeChannel*( self: ReliableChannelManager, channelId: ChannelId ): Future[Result[void, string]] {.async: (raises: []).} = diff --git a/tests/channels/test_all.nim b/tests/channels/test_all.nim index 04b448707..0c0855278 100644 --- a/tests/channels/test_all.nim +++ b/tests/channels/test_all.nim @@ -1,3 +1,4 @@ {.used.} +import ./test_channel_lifecycle import ./test_reliable_channel_send_receive diff --git a/tests/channels/test_channel_lifecycle.nim b/tests/channels/test_channel_lifecycle.nim new file mode 100644 index 000000000..c5cf810cf --- /dev/null +++ b/tests/channels/test_channel_lifecycle.nim @@ -0,0 +1,39 @@ +{.used.} + +import chronos, testutils/unittests +import brokers/broker_context + +import ../testlib/[common, testasync] + +import logos_delivery/api/conf/channels_conf +import logos_delivery/channels/reliable_channel_manager +import logos_delivery/channels/api/channel_lifecycle +import logos_delivery/channels/encryption/noop_encryption + +suite "Reliable Channel - lifecycle": + asyncTest "channelExists tracks create and close": + const + channelId = ChannelId("lifecycle-channel") + contentTopic = ContentTopic("/reliable-channel/test/proto") + + var manager: ReliableChannelManager + lockNewGlobalBrokerContext: + manager = ReliableChannelManager.new(ReliableChannelManagerConf()).expect( + "ReliableChannelManager.new" + ) + setNoopEncryption() + + check not manager.channelExists(channelId) + + discard manager + .createReliableChannel(channelId, contentTopic, SdsParticipantID("local")) + .expect("createReliableChannel") + + check manager.channelExists(channelId) + + ## An unrelated id must not be reported as existing. + check not manager.channelExists(ChannelId("other-channel")) + + (await manager.closeChannel(channelId)).expect("closeChannel") + + check not manager.channelExists(channelId) From ce918b081921f364fa984806b49899c467a72b4e Mon Sep 17 00:00:00 2001 From: Fabiana Cecin Date: Thu, 16 Jul 2026 14:02:17 -0300 Subject: [PATCH 3/9] chore: replace Option with Opt (#4035) * change all usage of std.options.Option[T] to results.Opt[T] * fix broken apps and examples (to validate refactor) * removed all std/options code added for libp2p v2 migration * add broker Opt codec to persistency/backend_comm.nim * add a readValue overload for Opt[T] in tools/confutils/cli_args.nim * keep Option where required (Presto, confutils' config_file.nim) * Change generateRlnProof error handling * Fix imports --- apps/benchmarks/benchmarks.nim | 3 +- apps/chat2/chat2.nim | 26 +-- apps/chat2/config_chat2.nim | 9 +- apps/chat2bridge/chat2bridge.nim | 11 +- apps/chat2bridge/config_chat2bridge.nim | 4 +- apps/chat2mix/chat2mix.nim | 40 ++--- apps/chat2mix/config_chat2mix.nim | 8 +- .../diagnose_connections.nim | 2 +- apps/liteprotocoltester/legacy_publisher.nim | 4 +- .../liteprotocoltester/liteprotocoltester.nim | 7 +- apps/liteprotocoltester/publisher.nim | 2 +- apps/liteprotocoltester/receiver.nim | 5 +- .../service_peer_management.nim | 21 +-- apps/liteprotocoltester/statistics.nim | 14 +- apps/liteprotocoltester/tester_config.nim | 2 +- apps/liteprotocoltester/tester_message.nim | 31 ++-- apps/liteprotocoltester/v3_publisher.nim | 8 +- apps/networkmonitor/networkmonitor.nim | 16 +- apps/wakucanary/wakucanary.nim | 7 +- apps/wakunode2/wakunode2.nim | 2 +- examples/api_example/api_example.nim | 3 - examples/filter_subscriber.nim | 4 +- .../lightpush_mix/lightpush_publisher_mix.nim | 11 +- examples/lightpush_publisher.nim | 6 +- examples/publisher.nim | 13 +- examples/subscriber.nim | 11 +- examples/wakustealthcommitments/node_spec.nim | 19 +- .../stealth_commitment_protocol.nim | 4 +- examples/wakustealthcommitments/wire_spec.nim | 54 +++--- library/kernel_api/protocols/store_api.nim | 14 +- library/liblogosdelivery.nim | 3 +- library/utils.nim | 8 +- logos_delivery/api/conf/channels_conf.nim | 20 +-- .../api/conf/logos_delivery_conf.nim | 11 +- .../api/conf/logos_delivery_conf_json.nim | 6 +- logos_delivery/api/conf/messaging_conf.nim | 66 ++++--- logos_delivery/api/types.nim | 4 +- .../channels/api/channel_lifecycle.nim | 10 +- logos_delivery/channels/reliable_channel.nim | 12 +- .../scalable_data_sync/scalable_data_sync.nim | 4 +- .../channels/segmentation/segmentation.nim | 7 +- logos_delivery/logos_delivery.nim | 9 +- .../recv_service/recv_service.nim | 9 +- .../send_service/delivery_task.nim | 7 +- .../send_service/lightpush_processor.nim | 7 +- .../send_service/relay_processor.nim | 6 +- .../send_service/send_service.nim | 3 +- logos_delivery/messaging/messaging_client.nim | 1 - logos_delivery/waku/api/filter.nim | 7 +- logos_delivery/waku/api/lightpush.nim | 1 - logos_delivery/waku/api/peer_manager.nim | 2 +- logos_delivery/waku/api/publish.nim | 8 +- logos_delivery/waku/api/store.nim | 1 - .../common/databases/db_postgres/dbconn.nim | 1 - .../databases/db_postgres/pgasyncpool.nim | 1 - .../waku/common/databases/db_sqlite.nim | 7 +- logos_delivery/waku/common/enr/builder.nim | 20 +-- .../waku/common/enr/typed_record.nim | 42 ++--- logos_delivery/waku/common/paging.nim | 6 +- logos_delivery/waku/common/protobuf.nim | 4 +- .../common/rate_limit/per_peer_limiter.nim | 8 +- .../common/rate_limit/request_limiter.nim | 19 +- .../common/rate_limit/service_metrics.nim | 5 +- .../waku/common/rate_limit/setting.nim | 2 +- .../rate_limit/single_token_limiter.nim | 16 +- .../waku/common/utils/matterbridge_client.nim | 2 +- logos_delivery/waku/common/utils/nat.nim | 19 +- .../waku/common/utils/parse_size_units.nim | 1 - logos_delivery/waku/compat/option_valueor.nim | 32 ---- .../waku/discovery/autonat_service.nim | 2 +- logos_delivery/waku/discovery/waku_discv5.nim | 35 ++-- .../waku/discovery/waku_dnsdisc.nim | 3 +- .../waku/discovery/waku_kademlia.nim | 23 ++- logos_delivery/waku/factory/builder.nim | 68 +++---- .../conf_builder/discv5_conf_builder.nim | 34 ++-- .../dns_discovery_conf_builder.nim | 14 +- .../filter_service_conf_builder.nim | 26 +-- .../kademlia_discovery_conf_builder.nim | 26 ++- .../metrics_server_conf_builder.nim | 26 +-- .../factory/conf_builder/mix_conf_builder.nim | 29 +-- .../conf_builder/quic_conf_builder.nim | 18 +- .../conf_builder/rate_limit_conf_builder.nim | 12 +- .../conf_builder/rest_server_conf_builder.nim | 30 ++-- .../conf_builder/rln_relay_conf_builder.nim | 54 +++--- .../store_service_conf_builder.nim | 34 ++-- .../conf_builder/store_sync_conf_builder.nim | 24 +-- .../conf_builder/waku_conf_builder.nim | 169 +++++++++-------- .../conf_builder/web_socket_conf_builder.nim | 38 ++-- .../waku/factory/internal_config.nim | 27 ++- logos_delivery/waku/factory/node_factory.nim | 26 +-- logos_delivery/waku/factory/waku_conf.nim | 46 ++--- .../waku/incentivization/common.nim | 6 +- .../incentivization/eligibility_manager.nim | 5 +- .../incentivization/reputation_manager.nim | 26 ++- logos_delivery/waku/incentivization/rpc.nim | 6 +- .../waku/incentivization/rpc_codec.nim | 11 +- logos_delivery/waku/net/net_config.nim | 79 ++++---- .../health_monitor/node_health_monitor.nim | 13 +- .../node/health_monitor/protocol_health.nim | 21 +-- .../waku/node/peer_manager/peer_manager.nim | 50 +++--- .../peer_store/waku_peer_storage.nim | 9 +- .../node/peer_manager/waku_peer_store.nim | 12 +- .../waku/node/subscription_manager.nim | 6 +- logos_delivery/waku/node/waku_metrics.nim | 1 - logos_delivery/waku/node/waku_node.nim | 17 +- logos_delivery/waku/node/waku_node/filter.nim | 9 +- .../waku/node/waku_node/lightpush.nim | 45 ++--- .../waku/node/waku_node/peer_exchange.nim | 9 +- logos_delivery/waku/node/waku_node/ping.nim | 2 - logos_delivery/waku/node/waku_node/relay.nim | 17 +- logos_delivery/waku/node/waku_node/store.nim | 8 +- logos_delivery/waku/node/waku_switch.nim | 12 +- .../waku/persistency/backend_comm.nim | 38 +++- .../waku/persistency/backend_sqlite.nim | 7 +- .../waku/persistency/backend_thread.nim | 2 +- .../waku/persistency/persistency.nim | 7 +- .../waku/persistency/sds_persistency.nim | 2 +- .../waku/requests/node_requests.nim | 5 +- .../waku/rest_api/endpoint/admin/handlers.nim | 7 +- .../waku/rest_api/endpoint/admin/types.nim | 60 +++---- .../waku/rest_api/endpoint/builder.nim | 19 +- .../waku/rest_api/endpoint/debug/client.nim | 2 +- .../waku/rest_api/endpoint/debug/handlers.nim | 1 - .../waku/rest_api/endpoint/debug/types.nim | 18 +- .../waku/rest_api/endpoint/filter/client.nim | 2 +- .../rest_api/endpoint/filter/handlers.nim | 19 +- .../waku/rest_api/endpoint/filter/types.nim | 115 ++++++------ .../rest_api/endpoint/health/handlers.nim | 1 - .../waku/rest_api/endpoint/health/types.nim | 28 ++- .../endpoint/legacy_lightpush/handlers.nim | 7 +- .../endpoint/legacy_lightpush/types.nim | 17 +- .../rest_api/endpoint/lightpush/client.nim | 2 +- .../rest_api/endpoint/lightpush/handlers.nim | 13 +- .../rest_api/endpoint/lightpush/types.nim | 29 +-- .../waku/rest_api/endpoint/origin_handler.nim | 28 ++- .../waku/rest_api/endpoint/relay/handlers.nim | 10 +- .../waku/rest_api/endpoint/relay/types.nim | 57 +++--- .../waku/rest_api/endpoint/rest_serdes.nim | 4 +- .../waku/rest_api/endpoint/serdes.nim | 2 +- .../waku/rest_api/endpoint/server.nim | 9 +- .../waku/rest_api/endpoint/store/client.nim | 8 +- .../waku/rest_api/endpoint/store/handlers.nim | 78 ++++---- .../waku/rest_api/endpoint/store/types.nim | 50 +++--- logos_delivery/waku/rest_api/handlers.nim | 11 +- .../waku/rest_api/message_cache.nim | 14 +- logos_delivery/waku/rln/config.nim | 8 +- .../rln/group_manager/group_manager_base.nim | 18 +- .../group_manager/on_chain/group_manager.nim | 44 ++--- .../group_manager/on_chain/rpc_wrapper.nim | 1 + logos_delivery/waku/rln/proof.nim | 27 ++- logos_delivery/waku/rln/protocol_types.nim | 2 +- logos_delivery/waku/rln/rln.nim | 14 +- logos_delivery/waku/rln/rln/rln_interface.nim | 4 +- logos_delivery/waku/rln/rln/wrappers.nim | 15 +- logos_delivery/waku/waku.nim | 3 +- logos_delivery/waku/waku_archive/archive.nim | 7 +- logos_delivery/waku/waku_archive/common.nim | 13 +- logos_delivery/waku/waku_archive/driver.nim | 10 +- .../waku/waku_archive/driver/builder.nim | 1 - .../driver/postgres_driver/migrations.nim | 1 - .../postgres_driver/postgres_driver.nim | 47 +++-- .../driver/queue_driver/queue_driver.nim | 17 +- .../driver/sqlite_driver/queries.nim | 82 ++++----- .../driver/sqlite_driver/sqlite_driver.nim | 11 +- .../waku_archive/retention_policy/builder.nim | 13 +- .../retention_policy_capacity.nim | 1 - logos_delivery/waku/waku_core/peers.nim | 25 ++- .../waku/waku_core/topics/content_topic.nim | 11 +- .../waku/waku_core/topics/sharding.nim | 3 +- logos_delivery/waku/waku_enr/capabilities.nim | 12 +- logos_delivery/waku/waku_enr/multiaddr.nim | 11 +- logos_delivery/waku/waku_enr/sharding.nim | 29 ++- logos_delivery/waku/waku_filter_v2/client.nim | 6 +- .../waku/waku_filter_v2/protocol.nim | 14 +- logos_delivery/waku/waku_filter_v2/rpc.nim | 16 +- .../waku/waku_filter_v2/rpc_codec.nim | 11 +- .../waku/waku_filter_v2/subscriptions.nim | 3 +- .../waku/waku_keystore/keystore.nim | 3 +- .../waku/waku_lightpush/callbacks.nim | 1 - logos_delivery/waku/waku_lightpush/client.nim | 13 +- logos_delivery/waku/waku_lightpush/common.nim | 26 +-- .../waku/waku_lightpush/protocol.nim | 37 ++-- logos_delivery/waku/waku_lightpush/rpc.nim | 9 +- .../waku/waku_lightpush/rpc_codec.nim | 15 +- .../waku/waku_lightpush/self_req_handler.nim | 4 +- .../waku/waku_lightpush_legacy/client.nim | 5 +- .../waku/waku_lightpush_legacy/protocol.nim | 13 +- .../waku/waku_lightpush_legacy/rpc.nim | 9 +- .../waku/waku_lightpush_legacy/rpc_codec.nim | 15 +- .../self_req_handler.nim | 4 +- .../waku/waku_metadata/protocol.nim | 7 +- logos_delivery/waku/waku_metadata/rpc.nim | 14 +- logos_delivery/waku/waku_mix/protocol.nim | 5 +- .../waku/waku_peer_exchange/client.nim | 27 +-- .../waku/waku_peer_exchange/protocol.nim | 23 ++- .../waku/waku_peer_exchange/rpc.nim | 8 +- .../waku/waku_peer_exchange/rpc_codec.nim | 7 +- logos_delivery/waku/waku_relay/protocol.nim | 1 - .../waku/waku_rendezvous/client.nim | 5 +- .../waku/waku_rendezvous/common.nim | 7 +- .../waku/waku_rendezvous/protocol.nim | 3 +- logos_delivery/waku/waku_store/client.nim | 5 +- logos_delivery/waku/waku_store/common.nim | 28 +-- logos_delivery/waku/waku_store/protocol.nim | 7 +- logos_delivery/waku/waku_store/resume.nim | 13 +- logos_delivery/waku/waku_store/rpc_codec.nim | 34 ++-- .../waku/waku_store/self_req_handler.nim | 1 - .../waku/waku_store_sync/common.nim | 2 +- .../waku/waku_store_sync/reconciliation.nim | 21 +-- .../waku_store_sync/storage/seq_storage.nim | 14 +- .../waku/waku_store_sync/transfer.nim | 1 - tests/api/test_api_health.nim | 8 +- tests/api/test_api_receive.nim | 8 +- tests/api/test_api_send.nim | 4 +- tests/api/test_api_subscription.nim | 12 +- tests/api/test_conf.nim | 71 ++++---- tests/api/test_entry_nodes.nim | 2 +- tests/api/test_node_conf.nim | 2 +- .../test_reliable_channel_send_receive.nim | 4 +- tests/common/test_enr_builder.nim | 36 ++-- tests/common/test_ratelimit_setting.nim | 2 +- tests/common/test_requestratelimiter.nim | 8 +- tests/factory/test_node_factory.nim | 5 +- tests/factory/test_waku_conf.nim | 4 +- .../incentivization/test_poc_eligibility.nim | 18 +- tests/incentivization/test_poc_reputation.nim | 21 +-- tests/incentivization/test_rpc_codec.nim | 4 +- .../peer_store/test_migrations.nim | 2 +- .../peer_store/test_waku_peer_storage.nim | 2 +- tests/node/peer_manager/peer_store/utils.nim | 4 +- tests/node/peer_manager/test_peer_manager.nim | 4 +- tests/node/test_wakunode_filter.nim | 55 +++--- tests/node/test_wakunode_health_monitor.nim | 23 ++- tests/node/test_wakunode_legacy_lightpush.nim | 24 +-- tests/node/test_wakunode_lightpush.nim | 36 ++-- tests/node/test_wakunode_peer_exchange.nim | 15 +- tests/node/test_wakunode_peer_manager.nim | 15 +- tests/node/test_wakunode_relay_rln.nim | 34 ++-- tests/node/test_wakunode_restart.nim | 1 - tests/node/test_wakunode_sharding.nim | 84 ++++----- tests/node/test_wakunode_store.nim | 170 +++++++++--------- tests/node/utils.nim | 2 +- tests/persistency/test_backend.nim | 4 +- tests/persistency/test_encoding.nim | 4 +- tests/persistency/test_facade.nim | 2 +- tests/persistency/test_lifecycle.nim | 2 +- tests/persistency/test_sds_persistency.nim | 2 +- tests/persistency/test_string_lookup.nim | 2 +- tests/test_peer_manager.nim | 42 ++--- tests/test_peer_storage.nim | 6 +- tests/test_relay_peer_exchange.nim | 11 +- tests/test_waku.nim | 8 +- tests/test_waku_enr.nim | 2 +- tests/test_waku_metadata.nim | 2 +- tests/test_waku_netconfig.nim | 70 ++++---- tests/test_waku_protobufs.nim | 6 +- tests/test_waku_rendezvous.nim | 6 +- tests/test_wakunode.nim | 33 ++-- tests/testlib/tables.nim | 2 +- tests/testlib/wakucore.nim | 4 +- tests/testlib/wakunode.nim | 33 ++-- tests/tools/test_confutils_envvar.nim | 13 +- tests/waku_archive/archive_utils.nim | 4 +- tests/waku_archive/test_driver_postgres.nim | 7 +- .../test_driver_postgres_query.nim | 99 +++++----- tests/waku_archive/test_driver_queue.nim | 2 +- .../test_driver_queue_pagination.nim | 46 ++--- .../waku_archive/test_driver_queue_query.nim | 86 ++++----- .../waku_archive/test_driver_sqlite_query.nim | 86 ++++----- tests/waku_archive/test_waku_archive.nim | 36 ++-- tests/waku_core/test_namespaced_topics.nim | 8 +- tests/waku_core/test_peers.nim | 7 +- tests/waku_core/topics/test_pubsub_topic.nim | 2 +- tests/waku_core/topics/test_sharding.nim | 14 +- tests/waku_discv5/test_waku_discv5.nim | 22 +-- tests/waku_discv5/utils.nim | 6 +- tests/waku_enr/utils.nim | 15 +- tests/waku_filter_v2/test_waku_client.nim | 2 +- .../test_waku_filter_dos_protection.nim | 45 ++--- tests/waku_filter_v2/waku_filter_utils.nim | 4 +- tests/waku_kademlia/test_waku_kademlia.nim | 2 +- tests/waku_kademlia/utils.nim | 2 +- tests/waku_lightpush/lightpush_utils.nim | 10 +- tests/waku_lightpush/test_client.nim | 50 +++--- tests/waku_lightpush/test_ratelimit.nim | 20 ++- .../waku_lightpush_legacy/lightpush_utils.nim | 4 +- tests/waku_lightpush_legacy/test_client.nim | 2 +- .../waku_lightpush_legacy/test_ratelimit.nim | 6 +- tests/waku_peer_exchange/test_protocol.nim | 32 ++-- tests/waku_peer_exchange/test_rpc_codec.nim | 2 +- tests/waku_peer_exchange/utils.nim | 7 +- tests/waku_relay/test_protocol.nim | 2 +- tests/waku_relay/test_wakunode_relay.nim | 19 +- tests/waku_relay/utils.nim | 7 +- .../rln/waku_rln_relay_utils.nim | 5 +- .../test_rln_contract_deployment.nim | 5 +- .../test_rln_group_manager_onchain.nim | 22 +-- tests/waku_rln_relay/test_waku_rln_relay.nim | 5 +- .../test_wakunode_rln_relay.nim | 33 ++-- tests/waku_rln_relay/utils.nim | 2 +- tests/waku_rln_relay/utils_offchain.nim | 13 +- tests/waku_rln_relay/utils_onchain.nim | 20 +-- tests/waku_store/store_utils.nim | 2 +- tests/waku_store/test_client.nim | 40 ++--- tests/waku_store/test_resume.nim | 2 +- tests/waku_store/test_rpc_codec.nim | 18 +- tests/waku_store/test_waku_store.nim | 6 +- tests/waku_store/test_wakunode_store.nim | 31 ++-- tests/waku_store_sync/sync_utils.nim | 2 +- tests/waku_store_sync/test_codec.nim | 2 +- tests/waku_store_sync/test_protocol.nim | 37 ++-- tests/waku_store_sync/test_storage.nim | 4 +- tests/wakunode2/test_app.nim | 1 - tests/wakunode2/test_cli_args.nim | 2 +- tests/wakunode2/test_validators.nim | 19 +- tests/wakunode_rest/test_rest_cors.nim | 132 +++++++------- tests/wakunode_rest/test_rest_debug.nim | 4 +- .../wakunode_rest/test_rest_debug_serdes.nim | 3 +- tests/wakunode_rest/test_rest_filter.nim | 20 +-- tests/wakunode_rest/test_rest_health.nim | 13 +- tests/wakunode_rest/test_rest_lightpush.nim | 26 +-- .../test_rest_lightpush_legacy.nim | 18 +- tests/wakunode_rest/test_rest_relay.nim | 43 ++--- .../wakunode_rest/test_rest_relay_serdes.nim | 9 +- tests/wakunode_rest/test_rest_store.nim | 17 +- tools/confutils/cli_args.nim | 77 ++++---- tools/confutils/conf_from_json.nim | 11 +- .../confutils/envvar_serialization/reader.nim | 23 ++- .../confutils/envvar_serialization/writer.nim | 5 +- .../rln_keystore_generator.nim | 6 +- 330 files changed, 2837 insertions(+), 2856 deletions(-) delete mode 100644 logos_delivery/waku/compat/option_valueor.nim diff --git a/apps/benchmarks/benchmarks.nim b/apps/benchmarks/benchmarks.nim index eb1efe98d..f97b64f7e 100644 --- a/apps/benchmarks/benchmarks.nim +++ b/apps/benchmarks/benchmarks.nim @@ -1,5 +1,4 @@ -import - std/[strutils, times, sequtils, osproc], math, results, options, testutils/unittests +import std/[strutils, times, sequtils, osproc], math, results, testutils/unittests import logos_delivery/waku/[ diff --git a/apps/chat2/chat2.nim b/apps/chat2/chat2.nim index 647667b0c..2e57fc015 100644 --- a/apps/chat2/chat2.nim +++ b/apps/chat2/chat2.nim @@ -6,7 +6,7 @@ when not (compileOption("threads")): {.push raises: [].} -import std/[strformat, strutils, times, options, random, sequtils] +import std/[strformat, strutils, times, random, sequtils] import confutils, chronicles, @@ -48,7 +48,7 @@ import ./config_chat2 import libp2p/protocols/pubsub/rpc/messages, libp2p/protocols/pubsub/pubsub -import ../../logos_delivery/waku/rln +import logos_delivery/waku/rln const Help = """ Commands: /[?|help|connect|nick|exit] @@ -215,10 +215,10 @@ proc publish(c: Chat, line: string) = try: if not c.node.wakuLegacyLightPush.isNil(): # Attempt lightpush - (waitFor c.node.legacyLightpushPublish(some(DefaultPubsubTopic), message)).isOkOr: + (waitFor c.node.legacyLightpushPublish(Opt.some(DefaultPubsubTopic), message)).isOkOr: error "failed to publish lightpush message", error = error else: - (waitFor c.node.publish(some(DefaultPubsubTopic), message)).isOkOr: + (waitFor c.node.publish(Opt.some(DefaultPubsubTopic), message)).isOkOr: error "failed to publish message", error = error except CatchableError: error "caught error publishing message: ", error = getCurrentExceptionMsg() @@ -383,25 +383,25 @@ proc processInput(rfd: AsyncFD, rng: crypto.Rng) {.async.} = echo "Connecting to static peers..." await connectToNodes(chat, conf.staticnodes) - var dnsDiscoveryUrl = none(string) + var dnsDiscoveryUrl = Opt.none(string) if conf.fleet != Fleet.none: # Use DNS discovery to connect to selected fleet echo "Connecting to " & $conf.fleet & " fleet using DNS discovery..." if conf.fleet == Fleet.test: - dnsDiscoveryUrl = some( + dnsDiscoveryUrl = Opt.some( "enrtree://AOGYWMBYOUIMOENHXCHILPKY3ZRFEULMFI4DOM442QSZ73TT2A7VI@test.waku.nodes.status.im" ) else: # Connect to sandbox by default - dnsDiscoveryUrl = some( + dnsDiscoveryUrl = Opt.some( "enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im" ) elif conf.dnsDiscoveryUrl != "": # No pre-selected fleet. Discover nodes via DNS using user config info "Discovering nodes using Waku DNS discovery", url = conf.dnsDiscoveryUrl - dnsDiscoveryUrl = some(conf.dnsDiscoveryUrl) + dnsDiscoveryUrl = Opt.some(conf.dnsDiscoveryUrl) var discoveredNodes: seq[RemotePeerInfo] @@ -437,17 +437,17 @@ proc processInput(rfd: AsyncFD, rng: crypto.Rng) {.async.} = if (conf.storenode != "") or (conf.store == true): await node.mountStore() - var storenode: Option[RemotePeerInfo] + var storenode: Opt[RemotePeerInfo] if conf.storenode != "": let peerInfo = parsePeerInfo(conf.storenode) if peerInfo.isOk(): - storenode = some(peerInfo.value) + storenode = Opt.some(peerInfo.value) else: error "Incorrect conf.storenode", error = peerInfo.error elif discoveredNodes.len > 0: echo "Store enabled, but no store nodes configured. Choosing one at random from discovered peers" - storenode = some(discoveredNodes[rand(0 .. len(discoveredNodes) - 1)]) + storenode = Opt.some(discoveredNodes[rand(0 .. len(discoveredNodes) - 1)]) if storenode.isSome(): # We have a viable storenode. Let's query it for historical messages. @@ -537,14 +537,14 @@ proc processInput(rfd: AsyncFD, rng: crypto.Rng) {.async.} = credIndex: conf.rlnRelayCredIndex, chainId: UInt256.fromBytesBE(conf.rlnRelayChainId.toBytesBE()), ethClientUrls: conf.ethClientUrls.mapIt(string(it)), - creds: some( + creds: Opt.some( RlnCreds(path: conf.rlnRelayCredPath, password: conf.rlnRelayCredPassword) ), userMessageLimit: conf.rlnRelayUserMessageLimit, epochSizeSec: conf.rlnEpochSizeSec, ) - waitFor node.setRlnValidator(rlnConf, spamHandler = some(spamHandler)) + waitFor node.setRlnValidator(rlnConf, spamHandler = Opt.some(spamHandler)) let membershipIndex = node.rln.groupManager.membershipIndex.get() let identityCredential = node.rln.groupManager.idCredentials.get() diff --git a/apps/chat2/config_chat2.nim b/apps/chat2/config_chat2.nim index dfb26eb56..a60f9a7a9 100644 --- a/apps/chat2/config_chat2.nim +++ b/apps/chat2/config_chat2.nim @@ -1,4 +1,5 @@ import + results, chronicles, chronos, confutils, @@ -26,7 +27,7 @@ type .}: LogLevel nodekey* {.desc: "P2P node private key as 64 char hex string.", name: "nodekey".}: - Option[crypto.PrivateKey] + Opt[crypto.PrivateKey] listenAddress* {. defaultValue: defaultListenAddress(config), @@ -234,7 +235,7 @@ type rlnRelayCredIndex* {. desc: "the index of the onchain commitment to use", name: "rln-relay-cred-index" - .}: Option[uint] + .}: Opt[uint] rlnRelayDynamic* {. desc: "Enable waku-rln-relay with on-chain dynamic group management: true|false", @@ -317,9 +318,9 @@ proc parseCmdArg*(T: type Port, p: string): T = proc completeCmdArg*(T: type Port, val: string): seq[string] = return @[] -proc parseCmdArg*(T: type Option[uint], p: string): T = +proc parseCmdArg*(T: type Opt[uint], p: string): T = try: - some(parseUint(p)) + Opt.some(parseUint(p)) except CatchableError: raise newException(ValueError, "Invalid unsigned integer") diff --git a/apps/chat2bridge/chat2bridge.nim b/apps/chat2bridge/chat2bridge.nim index e97eba033..097735c7a 100644 --- a/apps/chat2bridge/chat2bridge.nim +++ b/apps/chat2bridge/chat2bridge.nim @@ -1,7 +1,8 @@ {.push raises: [].} import - std/[tables, times, strutils, hashes, sequtils, json, options], + results, + std/[tables, times, strutils, hashes, sequtils, json], chronos, confutils, chronicles, @@ -102,7 +103,7 @@ proc toChat2(cmb: Chat2MatterBridge, jsonNode: JsonNode) {.async.} = chat2_mb_transfers.inc(labelValues = ["mb_to_chat2"]) - (await cmb.nodev2.publish(some(DefaultPubsubTopic), msg)).isOkOr: + (await cmb.nodev2.publish(Opt.some(DefaultPubsubTopic), msg)).isOkOr: error "failed to publish message", error = error proc toMatterbridge( @@ -156,8 +157,8 @@ proc new*( nodev2Key: crypto.PrivateKey, nodev2BindIp: IpAddress, nodev2BindPort: Port, - nodev2ExtIp = none[IpAddress](), - nodev2ExtPort = none[Port](), + nodev2ExtIp = Opt.none(IpAddress), + nodev2ExtPort = Opt.none(Port), contentTopic: string, ): T {. raises: [Defect, ValueError, KeyError, TLSStreamProtocolError, IOError, LPError] @@ -264,7 +265,7 @@ when isMainModule: ## config, the external port is the same as the bind port. let extPort = if nodev2ExtIp.isSome() and nodev2ExtPort.isNone(): - some(Port(uint16(conf.libp2pTcpPort) + conf.portsShift)) + Opt.some(Port(uint16(conf.libp2pTcpPort) + conf.portsShift)) else: nodev2ExtPort diff --git a/apps/chat2bridge/config_chat2bridge.nim b/apps/chat2bridge/config_chat2bridge.nim index 048fc4d87..0884ff89a 100644 --- a/apps/chat2bridge/config_chat2bridge.nim +++ b/apps/chat2bridge/config_chat2bridge.nim @@ -1,5 +1,5 @@ import - std/options, + results, confutils, confutils/defs, confutils/std/net, @@ -64,7 +64,7 @@ type Chat2MatterbridgeConf* = object nodekey* {. desc: "P2P node private key as hex", defaultValueDesc: "random", name: "nodekey" - .}: Option[crypto.PrivateKey] + .}: Opt[crypto.PrivateKey] store* {. desc: "Flag whether to start store protocol", defaultValue: true, name: "store" diff --git a/apps/chat2mix/chat2mix.nim b/apps/chat2mix/chat2mix.nim index f5d864a8f..4d2d08837 100644 --- a/apps/chat2mix/chat2mix.nim +++ b/apps/chat2mix/chat2mix.nim @@ -6,7 +6,7 @@ when not (compileOption("threads")): {.push raises: [].} -import std/[strformat, strutils, times, options, random, sequtils] +import std/[strformat, strutils, times, random, sequtils, sets] import confutils, chronicles, @@ -31,9 +31,8 @@ import protocols/kademlia/types, protocols/service_discovery/types as sd_types, nameresolving/dnsresolver, - protocols/mix/curve25519, - protocols/mix/mix_protocol, ] # define DNS resolution +import libp2p_mix/[curve25519, mix_protocol] import logos_delivery/waku/[ waku_core, @@ -216,9 +215,9 @@ proc publish(c: Chat, line: string) {.async.} = ( waitFor c.node.lightpushPublish( - some(c.conf.getPubsubTopic(c.node, c.contentTopic)), + Opt.some(c.conf.getPubsubTopic(c.node, c.contentTopic)), message, - none(RemotePeerInfo), + Opt.none(RemotePeerInfo), true, ) ).isOkOr: @@ -312,7 +311,7 @@ proc readInput(wfd: AsyncFD) {.thread, raises: [Defect, CatchableError].} = var alreadyUsedServicePeers {.threadvar.}: seq[RemotePeerInfo] proc selectRandomServicePeer*( - pm: PeerManager, actualPeer: Option[RemotePeerInfo], codec: string + pm: PeerManager, actualPeer: Opt[RemotePeerInfo], codec: string ): Result[RemotePeerInfo, void] = if actualPeer.isSome(): alreadyUsedServicePeers.add(actualPeer.get()) @@ -355,7 +354,7 @@ proc maintainSubscription( let subscribeErr = ( await wakuNode.filterSubscribe( - some(filterPubsubTopic), filterContentTopic, actualFilterPeer + Opt.some(filterPubsubTopic), filterContentTopic, actualFilterPeer ) ).errorOr: await sleepAsync(SubscriptionMaintenance) @@ -377,7 +376,7 @@ proc maintainSubscription( elif not preventPeerSwitch: # try again with new peer without delay let actualFilterPeer = selectRandomServicePeer( - wakuNode.peerManager, some(actualFilterPeer), WakuFilterSubscribeCodec + wakuNode.peerManager, Opt.some(actualFilterPeer), WakuFilterSubscribeCodec ).valueOr: error "Failed to find new service peer. Exiting." noFailedServiceNodeSwitches += 1 @@ -463,10 +462,9 @@ proc processInput(rfd: AsyncFD, rng: crypto.Rng) {.async.} = if conf.kadBootstrapNodes.len > 0: var kadBootstrapPeers: seq[(PeerId, seq[MultiAddress])] for nodeStr in conf.kadBootstrapNodes: - let (peerId, ma) = block: - parseFullAddress(nodeStr).isOkOr: - error "Failed to parse kademlia bootstrap node", node = nodeStr, error - continue + let (peerId, ma) = parseFullAddress(nodeStr).valueOr: + error "Failed to parse kademlia bootstrap node", node = nodeStr, error = error + continue kadBootstrapPeers.add((peerId, @[ma])) @@ -474,7 +472,7 @@ proc processInput(rfd: AsyncFD, rng: crypto.Rng) {.async.} = node.mountKademlia( KademliaDiscoveryConf( bootstrapNodes: kadBootstrapPeers, - servicesToDiscover: @[MixProtocolID], + servicesToDiscover: toHashSet([MixProtocolID]), randomLookupInterval: chronos.seconds(60), serviceLookupInterval: chronos.seconds(60), kadDhtConfig: KadDHTConfig.new(), @@ -511,25 +509,25 @@ proc processInput(rfd: AsyncFD, rng: crypto.Rng) {.async.} = conf: conf, ) - var dnsDiscoveryUrl = none(string) + var dnsDiscoveryUrl = Opt.none(string) if conf.fleet != Fleet.none: # Use DNS discovery to connect to selected fleet echo "Connecting to " & $conf.fleet & " fleet using DNS discovery..." if conf.fleet == Fleet.test: - dnsDiscoveryUrl = some( + dnsDiscoveryUrl = Opt.some( "enrtree://AOGYWMBYOUIMOENHXCHILPKY3ZRFEULMFI4DOM442QSZ73TT2A7VI@test.waku.nodes.status.im" ) else: # Connect to sandbox by default - dnsDiscoveryUrl = some( + dnsDiscoveryUrl = Opt.some( "enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im" ) elif conf.dnsDiscoveryUrl != "": # No pre-selected fleet. Discover nodes via DNS using user config info "Discovering nodes using Waku DNS discovery", url = conf.dnsDiscoveryUrl - dnsDiscoveryUrl = some(conf.dnsDiscoveryUrl) + dnsDiscoveryUrl = Opt.some(conf.dnsDiscoveryUrl) var discoveredNodes: seq[RemotePeerInfo] @@ -565,17 +563,17 @@ proc processInput(rfd: AsyncFD, rng: crypto.Rng) {.async.} = if (conf.storenode != "") or (conf.store == true): await node.mountStore() - var storenode: Option[RemotePeerInfo] + var storenode: Opt[RemotePeerInfo] if conf.storenode != "": let peerInfo = parsePeerInfo(conf.storenode) if peerInfo.isOk(): - storenode = some(peerInfo.value) + storenode = Opt.some(peerInfo.value) else: error "Incorrect conf.storenode", error = peerInfo.error elif discoveredNodes.len > 0: echo "Store enabled, but no store nodes configured. Choosing one at random from discovered peers" - storenode = some(discoveredNodes[rand(0 .. len(discoveredNodes) - 1)]) + storenode = Opt.some(discoveredNodes[rand(0 .. len(discoveredNodes) - 1)]) if storenode.isSome(): # We have a viable storenode. Let's query it for historical messages. @@ -620,7 +618,7 @@ proc processInput(rfd: AsyncFD, rng: crypto.Rng) {.async.} = if servicePeerInfo == nil or $servicePeerInfo.peerId == "": # Assuming that service node supports all services servicePeerInfo = selectRandomServicePeer( - node.peerManager, none(RemotePeerInfo), WakuLightpushCodec + node.peerManager, Opt.none(RemotePeerInfo), WakuLightpushCodec ).valueOr: error "Couldn't find any service peer" quit(QuitFailure) diff --git a/apps/chat2mix/config_chat2mix.nim b/apps/chat2mix/config_chat2mix.nim index f77a729f4..ed7d5c045 100644 --- a/apps/chat2mix/config_chat2mix.nim +++ b/apps/chat2mix/config_chat2mix.nim @@ -1,4 +1,4 @@ -import chronicles, chronos, std/strutils, regex +import results, chronicles, chronos, std/strutils, regex import eth/keys, @@ -32,7 +32,7 @@ type .}: LogLevel nodekey* {.desc: "P2P node private key as 64 char hex string.", name: "nodekey".}: - Option[crypto.PrivateKey] + Opt[crypto.PrivateKey] listenAddress* {. defaultValue: defaultListenAddress(config), @@ -287,9 +287,9 @@ proc parseCmdArg*(T: type Port, p: string): T = proc completeCmdArg*(T: type Port, val: string): seq[string] = return @[] -proc parseCmdArg*(T: type Option[uint], p: string): T = +proc parseCmdArg*(T: type Opt[uint], p: string): T = try: - some(parseUint(p)) + Opt.some(parseUint(p)) except CatchableError: raise newException(ValueError, "Invalid unsigned integer") diff --git a/apps/liteprotocoltester/diagnose_connections.nim b/apps/liteprotocoltester/diagnose_connections.nim index 1b5b79b4b..77eec268e 100644 --- a/apps/liteprotocoltester/diagnose_connections.nim +++ b/apps/liteprotocoltester/diagnose_connections.nim @@ -4,7 +4,7 @@ else: {.push raises: [].} import - std/[options, net, strformat], + std/[net, strformat], chronicles, chronos, metrics, diff --git a/apps/liteprotocoltester/legacy_publisher.nim b/apps/liteprotocoltester/legacy_publisher.nim index c2b729b8b..d950faee2 100644 --- a/apps/liteprotocoltester/legacy_publisher.nim +++ b/apps/liteprotocoltester/legacy_publisher.nim @@ -1,4 +1,4 @@ -import chronos, results, options +import chronos, results import logos_delivery/waku/[waku_node, waku_core] import publisher_base @@ -18,7 +18,7 @@ method send*( ): Future[Result[void, string]] {.async.} = # when error it must return original error desc due the text is used for distinction between error types in metrics. discard ( - await self.wakuNode.legacyLightpushPublish(some(topic), message, servicePeer) + await self.wakuNode.legacyLightpushPublish(Opt.some(topic), message, servicePeer) ).valueOr: return err(error) return ok() diff --git a/apps/liteprotocoltester/liteprotocoltester.nim b/apps/liteprotocoltester/liteprotocoltester.nim index 124d09173..b1e7bab1e 100644 --- a/apps/liteprotocoltester/liteprotocoltester.nim +++ b/apps/liteprotocoltester/liteprotocoltester.nim @@ -1,7 +1,8 @@ {.push raises: [].} import - std/[options, strutils, os, sequtils, net], + results, + std/[strutils, os, sequtils, net], chronicles, chronos, metrics, @@ -95,7 +96,7 @@ when isMainModule: wakuNodeConf.shards = @[conf.shard] wakuNodeConf.contentTopics = conf.contentTopics - wakuNodeConf.clusterId = some(conf.clusterId) + wakuNodeConf.clusterId = Opt.some(conf.clusterId) ## TODO: Depending on the tester needs we might extend here with shards, clusterId, etc... wakuNodeConf.metricsServer = true @@ -190,7 +191,7 @@ when isMainModule: quit(QuitFailure) serviceNodePeerInfo = selectRandomServicePeer( - waku.node.peerManager, none(RemotePeerInfo), codec + waku.node.peerManager, Opt.none(RemotePeerInfo), codec ).valueOr: error "Service node selection failed" quit(QuitFailure) diff --git a/apps/liteprotocoltester/publisher.nim b/apps/liteprotocoltester/publisher.nim index cbd36ce68..4bfd6aed3 100644 --- a/apps/liteprotocoltester/publisher.nim +++ b/apps/liteprotocoltester/publisher.nim @@ -188,7 +188,7 @@ proc publishMessages( if not preventPeerSwitch and noFailedPush > maxFailedPush: info "Max push failure limit reached, Try switching peer." actualServicePeer = selectRandomServicePeer( - wakuNode.peerManager, some(actualServicePeer), WakuLightPushCodec + wakuNode.peerManager, Opt.some(actualServicePeer), WakuLightPushCodec ).valueOr: error "Failed to find new service peer. Exiting." noFailedServiceNodeSwitches += 1 diff --git a/apps/liteprotocoltester/receiver.nim b/apps/liteprotocoltester/receiver.nim index 457626af6..e9151b101 100644 --- a/apps/liteprotocoltester/receiver.nim +++ b/apps/liteprotocoltester/receiver.nim @@ -2,7 +2,6 @@ ## subscribe to messages without relay import - std/options, system/ansi_c, chronicles, chronos, @@ -74,7 +73,7 @@ proc maintainSubscription( let subscribeErr = ( await wakuNode.filterSubscribe( - some(filterPubsubTopic), filterContentTopic, actualFilterPeer + Opt.some(filterPubsubTopic), filterContentTopic, actualFilterPeer ) ).errorOr: await sleepAsync(SubscriptionMaintenanceMs) @@ -99,7 +98,7 @@ proc maintainSubscription( elif not preventPeerSwitch: # try again with new peer without delay actualFilterPeer = selectRandomServicePeer( - wakuNode.peerManager, some(actualFilterPeer), WakuFilterSubscribeCodec + wakuNode.peerManager, Opt.some(actualFilterPeer), WakuFilterSubscribeCodec ).valueOr: error "Failed to find new service peer. Exiting." noFailedServiceNodeSwitches += 1 diff --git a/apps/liteprotocoltester/service_peer_management.nim b/apps/liteprotocoltester/service_peer_management.nim index 6198bc448..aa7041116 100644 --- a/apps/liteprotocoltester/service_peer_management.nim +++ b/apps/liteprotocoltester/service_peer_management.nim @@ -1,7 +1,8 @@ {.push raises: [].} import - std/[options, net, sysrand, random, strformat, strutils, sequtils], + results, + std/[net, sysrand, random, strformat, strutils, sequtils], chronicles, chronos, metrics, @@ -53,7 +54,7 @@ proc translateToRemotePeerInfo*(peerAddress: string): Result[RemotePeerInfo, voi ## Note: This is kept for future use. proc selectRandomCapablePeer*( pm: PeerManager, codec: string, pubsubTopic: PubsubTopic -): Future[Option[RemotePeerInfo]] {.async.} = +): Future[Opt[RemotePeerInfo]] {.async.} = var cap = Capabilities.Filter if codec.contains("lightpush"): cap = Capabilities.Lightpush @@ -65,9 +66,9 @@ proc selectRandomCapablePeer*( trace "Found supportive peers count", count = supportivePeers.len() trace "Found supportive peers", supportivePeers = $supportivePeers if supportivePeers.len == 0: - return none(RemotePeerInfo) + return Opt.none(RemotePeerInfo) - var found = none(RemotePeerInfo) + var found = Opt.none(RemotePeerInfo) while found.isNone() and supportivePeers.len > 0: let rndPeerIndex = rand(0 .. supportivePeers.len - 1) let randomPeer = supportivePeers[rndPeerIndex] @@ -80,7 +81,7 @@ proc selectRandomCapablePeer*( let connOpt = pm.dialPeer(randomPeer, codec) if (await connOpt.withTimeout(10.seconds)): if connOpt.value().isSome(): - found = some(randomPeer) + found = Opt.some(randomPeer) info "Dialing successful", peer = constructMultiaddrStr(randomPeer), codec = codec else: @@ -94,7 +95,7 @@ proc selectRandomCapablePeer*( # Debugging PX gathered peers connectivity proc tryCallAllPxPeers*( pm: PeerManager, codec: string, pubsubTopic: PubsubTopic -): Future[Option[seq[RemotePeerInfo]]] {.async.} = +): Future[Opt[seq[RemotePeerInfo]]] {.async.} = var capability = Capabilities.Filter if codec.contains("lightpush"): capability = Capabilities.Lightpush @@ -107,7 +108,7 @@ proc tryCallAllPxPeers*( info "Found supportive peers count", count = supportivePeers.len() info "Found supportive peers", supportivePeers = $supportivePeers if supportivePeers.len == 0: - return none(seq[RemotePeerInfo]) + return Opt.none(seq[RemotePeerInfo]) var okPeers: seq[RemotePeerInfo] = @[] @@ -152,7 +153,7 @@ proc tryCallAllPxPeers*( echo "PX returned peers found callable for " & codec & " / " & $capability & ":\n" echo okPeersStr - return some(okPeers) + return Opt.some(okPeers) proc pxLookupServiceNode*( node: WakuNode, conf: LiteProtocolTesterConf @@ -168,7 +169,7 @@ proc pxLookupServiceNode*( node.peerManager.addServicePeer(peerExchangeNode, WakuPeerExchangeCodec) try: - await node.mountPeerExchange(some(conf.clusterId)) + await node.mountPeerExchange(Opt.some(conf.clusterId)) except CatchableError: error "failed to mount waku peer-exchange protocol", error = getCurrentExceptionMsg() @@ -207,7 +208,7 @@ var alreadyUsedServicePeers {.threadvar.}: seq[RemotePeerInfo] ## Select service peers by codec from peer store randomly. proc selectRandomServicePeer*( - pm: PeerManager, actualPeer: Option[RemotePeerInfo], codec: string + pm: PeerManager, actualPeer: Opt[RemotePeerInfo], codec: string ): Result[RemotePeerInfo, void] = if actualPeer.isSome(): alreadyUsedServicePeers.add(actualPeer.get()) diff --git a/apps/liteprotocoltester/statistics.nim b/apps/liteprotocoltester/statistics.nim index 7feebd4cf..0a3a975d7 100644 --- a/apps/liteprotocoltester/statistics.nim +++ b/apps/liteprotocoltester/statistics.nim @@ -1,7 +1,7 @@ {.push raises: [].} import - std/[sets, tables, sequtils, options, strformat], + std/[sets, tables, sequtils, strformat], chronos/timer as chtimer, chronicles, chronos, @@ -123,10 +123,10 @@ proc addMessage*( lpt_receiver_sender_peer_count.set(value = self.len) -proc lastMessageArrivedAt*(self: Statistics): Option[Moment] = +proc lastMessageArrivedAt*(self: Statistics): Opt[Moment] = if self.receivedMessages > 0: - return some(self.helper.prevArrivedAt) - return none(Moment) + return Opt.some(self.helper.prevArrivedAt) + return Opt.none(Moment) proc lossCount*(self: Statistics): uint32 = self.helper.maxIndex - self.receivedMessages @@ -271,7 +271,7 @@ proc jsonStats*(self: PerPeerStatistics): string = "{\"result:\": \"Error while generating json stats: " & getCurrentExceptionMsg() & "\"}" -proc lastMessageArrivedAt*(self: PerPeerStatistics): Option[Moment] = +proc lastMessageArrivedAt*(self: PerPeerStatistics): Opt[Moment] = var lastArrivedAt = Moment.init(0, Millisecond) for stat in self.values: let lastMsgFromPeerAt = stat.lastMessageArrivedAt().valueOr: @@ -281,9 +281,9 @@ proc lastMessageArrivedAt*(self: PerPeerStatistics): Option[Moment] = lastArrivedAt = lastMsgFromPeerAt if lastArrivedAt == Moment.init(0, Millisecond): - return none(Moment) + return Opt.none(Moment) - return some(lastArrivedAt) + return Opt.some(lastArrivedAt) proc checkIfAllMessagesReceived*( self: PerPeerStatistics, maxWaitForLastMessage: Duration diff --git a/apps/liteprotocoltester/tester_config.nim b/apps/liteprotocoltester/tester_config.nim index 79fc6bf1d..2150d1188 100644 --- a/apps/liteprotocoltester/tester_config.nim +++ b/apps/liteprotocoltester/tester_config.nim @@ -37,7 +37,7 @@ type LiteProtocolTesterConf* = object desc: "Loads configuration from a TOML file (cmd-line parameters take precedence) for the light waku node", name: "config-file" - .}: Option[InputFile] + .}: Opt[InputFile] ## Log configuration logLevel* {. diff --git a/apps/liteprotocoltester/tester_message.nim b/apps/liteprotocoltester/tester_message.nim index 1a169db04..70eb65147 100644 --- a/apps/liteprotocoltester/tester_message.nim +++ b/apps/liteprotocoltester/tester_message.nim @@ -1,9 +1,10 @@ {.push raises: [].} import + results, chronicles, json_serialization, - json_serialization/std/options, + json_serialization/pkg/results, json_serialization/lexer import logos_delivery/waku/rest_api/endpoint/serdes @@ -34,13 +35,13 @@ proc readValue*( reader: var JsonReader[RestJson], value: var ProtocolTesterMessage ) {.gcsafe, raises: [SerializationError, IOError].} = var - sender: Option[string] - index: Option[uint32] - count: Option[uint32] - startedAt: Option[int64] - sinceStart: Option[int64] - sincePrev: Option[int64] - size: Option[uint64] + sender: Opt[string] + index: Opt[uint32] + count: Opt[uint32] + startedAt: Opt[int64] + sinceStart: Opt[int64] + sincePrev: Opt[int64] + size: Opt[uint64] for fieldName in readObjectFields(reader): case fieldName @@ -49,43 +50,43 @@ proc readValue*( reader.raiseUnexpectedField( "Multiple `sender` fields found", "ProtocolTesterMessage" ) - sender = some(reader.readValue(string)) + sender = Opt.some(reader.readValue(string)) of "index": if index.isSome(): reader.raiseUnexpectedField( "Multiple `index` fields found", "ProtocolTesterMessage" ) - index = some(reader.readValue(uint32)) + index = Opt.some(reader.readValue(uint32)) of "count": if count.isSome(): reader.raiseUnexpectedField( "Multiple `count` fields found", "ProtocolTesterMessage" ) - count = some(reader.readValue(uint32)) + count = Opt.some(reader.readValue(uint32)) of "startedAt": if startedAt.isSome(): reader.raiseUnexpectedField( "Multiple `startedAt` fields found", "ProtocolTesterMessage" ) - startedAt = some(reader.readValue(int64)) + startedAt = Opt.some(reader.readValue(int64)) of "sinceStart": if sinceStart.isSome(): reader.raiseUnexpectedField( "Multiple `sinceStart` fields found", "ProtocolTesterMessage" ) - sinceStart = some(reader.readValue(int64)) + sinceStart = Opt.some(reader.readValue(int64)) of "sincePrev": if sincePrev.isSome(): reader.raiseUnexpectedField( "Multiple `sincePrev` fields found", "ProtocolTesterMessage" ) - sincePrev = some(reader.readValue(int64)) + sincePrev = Opt.some(reader.readValue(int64)) of "size": if size.isSome(): reader.raiseUnexpectedField( "Multiple `size` fields found", "ProtocolTesterMessage" ) - size = some(reader.readValue(uint64)) + size = Opt.some(reader.readValue(uint64)) else: unrecognizedFieldWarning(value) diff --git a/apps/liteprotocoltester/v3_publisher.nim b/apps/liteprotocoltester/v3_publisher.nim index bdfea75ec..db9f957f1 100644 --- a/apps/liteprotocoltester/v3_publisher.nim +++ b/apps/liteprotocoltester/v3_publisher.nim @@ -1,4 +1,4 @@ -import results, options, chronos +import results, chronos import logos_delivery/waku/[waku_node, waku_core, waku_lightpush, waku_lightpush/common] import publisher_base @@ -18,10 +18,12 @@ method send*( ): Future[Result[void, string]] {.async.} = # when error it must return original error desc due the text is used for distinction between error types in metrics. discard ( - await self.wakuNode.lightpushPublish(some(topic), message, some(servicePeer)) + await self.wakuNode.lightpushPublish( + Opt.some(topic), message, Opt.some(servicePeer) + ) ).valueOr: if error.code == LightPushErrorCode.NO_PEERS_TO_RELAY and - error.desc != some("No peers for topic, skipping publish"): + error.desc != Opt.some("No peers for topic, skipping publish"): # TODO: We need better separation of errors happening on the client side or the server side.- return err("dial_failure") else: diff --git a/apps/networkmonitor/networkmonitor.nim b/apps/networkmonitor/networkmonitor.nim index a23c778ef..7bdf41469 100644 --- a/apps/networkmonitor/networkmonitor.nim +++ b/apps/networkmonitor/networkmonitor.nim @@ -422,7 +422,7 @@ proc initAndStartApp( let # some hardcoded parameters - rng = keys.newRng() + rng = crypto.newRng() key = crypto.PrivateKey.random(Secp256k1, rng)[] nodeTcpPort = Port(60000) nodeUdpPort = Port(9000) @@ -433,7 +433,9 @@ proc initAndStartApp( var builder = EnrBuilder.init(key) builder.withIpAddressAndPorts( - ipAddr = some(extIp), tcpPort = some(nodeTcpPort), udpPort = some(nodeUdpPort) + ipAddr = Opt.some(extIp), + tcpPort = Opt.some(nodeTcpPort), + udpPort = Opt.some(nodeUdpPort), ) builder.withWakuCapabilities(flags) @@ -450,7 +452,7 @@ proc initAndStartApp( nodeBuilder.withNodeKey(key) nodeBuilder.withRecord(record) - nodeBuilder.withSwitchConfiguration(maxConnections = some(MaxConnectedPeers)) + nodeBuilder.withSwitchConfiguration(maxConnections = Opt.some(MaxConnectedPeers)) nodeBuilder.withPeerManagerConfig( maxConnections = MaxConnectedPeers, @@ -473,7 +475,7 @@ proc initAndStartApp( # discv5 let discv5Conf = WakuDiscoveryV5Config( - discv5Config: none(DiscoveryConfig), + discv5Config: Opt.none(DiscoveryConfig), address: bindIp, port: nodeUdpPort, privateKey: keys.PrivateKey(key.skkey), @@ -481,7 +483,7 @@ proc initAndStartApp( autoupdateRecord: false, ) - let wakuDiscv5 = WakuDiscoveryV5.new(node.rng, discv5Conf, some(record)) + let wakuDiscv5 = WakuDiscoveryV5.new(node.rng, discv5Conf, Opt.some(record)) try: wakuDiscv5.protocol.open() @@ -610,11 +612,11 @@ when isMainModule: if conf.rlnRelay and conf.rlnRelayEthContractAddress != "": let rlnConf = WakuRlnConfig( dynamic: conf.rlnRelayDynamic, - credIndex: some(uint(0)), + credIndex: Opt.some(uint(0)), ethContractAddress: conf.rlnRelayEthContractAddress, ethClientUrls: conf.ethClientUrls.mapIt(string(it)), epochSizeSec: conf.rlnEpochSizeSec, - creds: none(RlnCreds), + creds: Opt.none(RlnCreds), onFatalErrorAction: onFatalErrorAction, ) diff --git a/apps/wakucanary/wakucanary.nim b/apps/wakucanary/wakucanary.nim index 44a3548d6..2ada1ac26 100644 --- a/apps/wakucanary/wakucanary.nim +++ b/apps/wakucanary/wakucanary.nim @@ -1,4 +1,5 @@ import + results, std/[strutils, sequtils, tables, strformat], confutils, chronos, @@ -215,7 +216,7 @@ proc main(rng: Rng): Future[int] {.async.} = let netConfig = NetConfig.init( bindIp = bindIp, bindPort = nodeTcpPort, - wsBindPort = some(wsBindPort), + wsBindPort = Opt.some(wsBindPort), wsEnabled = isWs, wssEnabled = isWss, ) @@ -244,7 +245,9 @@ proc main(rng: Rng): Future[int] {.async.} = builder.withRecord(record) builder.withNetworkConfiguration(netConfig.tryGet()) builder.withSwitchConfiguration( - secureKey = some(keyPath), secureCert = some(certPath), nameResolver = resolver + secureKey = Opt.some(keyPath), + secureCert = Opt.some(certPath), + nameResolver = resolver, ) let node = builder.build().tryGet() diff --git a/apps/wakunode2/wakunode2.nim b/apps/wakunode2/wakunode2.nim index a75b472ec..914e8e3ad 100644 --- a/apps/wakunode2/wakunode2.nim +++ b/apps/wakunode2/wakunode2.nim @@ -1,7 +1,7 @@ {.push raises: [].} import - std/[options, strutils, sequtils, net], + std/[strutils, sequtils, net], chronicles, chronos, metrics, diff --git a/examples/api_example/api_example.nim b/examples/api_example/api_example.nim index 8c8759191..024809032 100644 --- a/examples/api_example/api_example.nim +++ b/examples/api_example/api_example.nim @@ -1,4 +1,3 @@ -import std/options import chronos, results, confutils, confutils/defs import logos_delivery @@ -67,11 +66,9 @@ when isMainModule: if args.ethRpcEndpoint == "": # Create a basic configuration for the Waku node # No RLN as we don't have an ETH RPC Endpoint - conf.mode = Core conf.preset = "logos.dev" else: # Connect to TWN, use ETH RPC Endpoint for RLN - conf.mode = Core conf.preset = "twn" conf.ethClientUrls = @[EthRpcUrl(args.ethRpcEndpoint)] diff --git a/examples/filter_subscriber.nim b/examples/filter_subscriber.nim index 5fa47d976..e5555f3c0 100644 --- a/examples/filter_subscriber.nim +++ b/examples/filter_subscriber.nim @@ -43,13 +43,13 @@ proc messagePushHandler( contentTopic = message.contentTopic, timestamp = message.timestamp -proc setupAndSubscribe(rng: ref HmacDrbgContext) {.async.} = +proc setupAndSubscribe(rng: crypto.Rng) {.async.} = # use notice to filter all waku messaging setupLog(logging.LogLevel.NOTICE, logging.LogFormat.TEXT) notice "starting subscriber", wakuPort = wakuPort let - nodeKey = crypto.PrivateKey.random(Secp256k1, rng[])[] + nodeKey = crypto.PrivateKey.random(Secp256k1, rng)[] ip = parseIpAddress("0.0.0.0") flags = CapabilitiesBitfield.init(relay = true) diff --git a/examples/lightpush_mix/lightpush_publisher_mix.nim b/examples/lightpush_mix/lightpush_publisher_mix.nim index 573d6549e..133f80881 100644 --- a/examples/lightpush_mix/lightpush_publisher_mix.nim +++ b/examples/lightpush_mix/lightpush_publisher_mix.nim @@ -48,13 +48,13 @@ proc splitPeerIdAndAddr(maddr: string): (string, string) = peerId = parts[1] return (address, peerId) -proc setupAndPublish(rng: ref HmacDrbgContext, conf: LightPushMixConf) {.async.} = +proc setupAndPublish(rng: crypto.Rng, conf: LightPushMixConf) {.async.} = # use notice to filter all waku messaging setupLog(logging.LogLevel.DEBUG, logging.LogFormat.TEXT) notice "starting publisher", wakuPort = conf.port let - nodeKey = crypto.PrivateKey.random(Secp256k1, rng[]).get() + nodeKey = crypto.PrivateKey.random(Secp256k1, rng).get() ip = parseIpAddress("0.0.0.0") flags = CapabilitiesBitfield.init(relay = true) @@ -84,7 +84,7 @@ proc setupAndPublish(rng: ref HmacDrbgContext, conf: LightPushMixConf) {.async.} ) node.mountLightPushClient() try: - await node.mountPeerExchange(some(uint16(clusterId))) + await node.mountPeerExchange(Opt.some(uint16(clusterId))) except CatchableError: error "failed to mount waku peer-exchange protocol", error = getCurrentExceptionMsg() @@ -164,8 +164,9 @@ proc setupAndPublish(rng: ref HmacDrbgContext, conf: LightPushMixConf) {.async.} timestamp: getNowInNanosecondTime(), ) # current timestamp - let res = - await node.wakuLightpushClient.publish(some(LightpushPubsubTopic), message, conn) + let res = await node.wakuLightpushClient.publish( + Opt.some(LightpushPubsubTopic), message, conn + ) let startTime = getNowInNanosecondTime() diff --git a/examples/lightpush_publisher.nim b/examples/lightpush_publisher.nim index fe4134072..c7bf73124 100644 --- a/examples/lightpush_publisher.nim +++ b/examples/lightpush_publisher.nim @@ -35,13 +35,13 @@ const LightpushPubsubTopic = PubsubTopic("/waku/2/rs/1/0") LightpushContentTopic = ContentTopic("/examples/1/light-pubsub-example/proto") -proc setupAndPublish(rng: ref HmacDrbgContext) {.async.} = +proc setupAndPublish(rng: crypto.Rng) {.async.} = # use notice to filter all waku messaging setupLog(logging.LogLevel.NOTICE, logging.LogFormat.TEXT) notice "starting publisher", wakuPort = wakuPort let - nodeKey = crypto.PrivateKey.random(Secp256k1, rng[]).get() + nodeKey = crypto.PrivateKey.random(Secp256k1, rng).get() ip = parseIpAddress("0.0.0.0") flags = CapabilitiesBitfield.init(relay = true) @@ -87,7 +87,7 @@ proc setupAndPublish(rng: ref HmacDrbgContext) {.async.} = quit(QuitFailure) let res = await node.legacyLightpushPublish( - some(LightpushPubsubTopic), message, lightpushPeer + Opt.some(LightpushPubsubTopic), message, lightpushPeer ) if res.isOk: diff --git a/examples/publisher.nim b/examples/publisher.nim index edae12157..81b66e53c 100644 --- a/examples/publisher.nim +++ b/examples/publisher.nim @@ -1,4 +1,5 @@ import + results, std/[tables, times, sequtils], stew/byteutils, chronicles, @@ -37,13 +38,13 @@ const bootstrapNode = const wakuPort = 60000 const discv5Port = 9000 -proc setupAndPublish(rng: ref HmacDrbgContext) {.async.} = +proc setupAndPublish(rng: crypto.Rng) {.async.} = # use notice to filter all waku messaging setupLog(logging.LogLevel.NOTICE, logging.LogFormat.TEXT) notice "starting publisher", wakuPort = wakuPort, discv5Port = discv5Port let - nodeKey = crypto.PrivateKey.random(Secp256k1, rng[]).get() + nodeKey = crypto.PrivateKey.random(Secp256k1, rng).get() ip = parseIpAddress("0.0.0.0") flags = CapabilitiesBitfield.init(relay = true) @@ -63,7 +64,7 @@ proc setupAndPublish(rng: ref HmacDrbgContext) {.async.} = discard bootstrapNodeEnr.fromURI(bootstrapNode) let discv5Conf = WakuDiscoveryV5Config( - discv5Config: none(DiscoveryConfig), + discv5Config: Opt.none(DiscoveryConfig), address: ip, port: Port(discv5Port), privateKey: keys.PrivateKey(nodeKey.skkey), @@ -75,8 +76,8 @@ proc setupAndPublish(rng: ref HmacDrbgContext) {.async.} = let wakuDiscv5 = WakuDiscoveryV5.new( node.rng, discv5Conf, - some(node.enr), - some(node.peerManager), + Opt.some(node.enr), + Opt.some(node.peerManager), node.topicSubscriptionQueue, ) @@ -119,7 +120,7 @@ proc setupAndPublish(rng: ref HmacDrbgContext) {.async.} = timestamp: now(), ) # current timestamp - let res = await node.publish(some(pubSubTopic), message) + let res = await node.publish(Opt.some(pubSubTopic), message) if res.isOk: notice "published message", diff --git a/examples/subscriber.nim b/examples/subscriber.nim index 541d3ddec..febbd1a65 100644 --- a/examples/subscriber.nim +++ b/examples/subscriber.nim @@ -1,4 +1,5 @@ import + results, std/[tables, sequtils], stew/byteutils, chronicles, @@ -35,13 +36,13 @@ const bootstrapNode = const wakuPort = 50000 const discv5Port = 8000 -proc setupAndSubscribe(rng: ref HmacDrbgContext) {.async.} = +proc setupAndSubscribe(rng: crypto.Rng) {.async.} = # use notice to filter all waku messaging setupLog(logging.LogLevel.NOTICE, logging.LogFormat.TEXT) notice "starting subscriber", wakuPort = wakuPort, discv5Port = discv5Port let - nodeKey = crypto.PrivateKey.random(Secp256k1, rng[])[] + nodeKey = crypto.PrivateKey.random(Secp256k1, rng)[] ip = parseIpAddress("0.0.0.0") flags = CapabilitiesBitfield.init(relay = true) @@ -61,7 +62,7 @@ proc setupAndSubscribe(rng: ref HmacDrbgContext) {.async.} = discard bootstrapNodeEnr.fromURI(bootstrapNode) let discv5Conf = WakuDiscoveryV5Config( - discv5Config: none(DiscoveryConfig), + discv5Config: Opt.none(DiscoveryConfig), address: ip, port: Port(discv5Port), privateKey: keys.PrivateKey(nodeKey.skkey), @@ -73,8 +74,8 @@ proc setupAndSubscribe(rng: ref HmacDrbgContext) {.async.} = let wakuDiscv5 = WakuDiscoveryV5.new( node.rng, discv5Conf, - some(node.enr), - some(node.peerManager), + Opt.some(node.enr), + Opt.some(node.peerManager), node.topicSubscriptionQueue, ) diff --git a/examples/wakustealthcommitments/node_spec.nim b/examples/wakustealthcommitments/node_spec.nim index e8e0a2062..5cc2124e4 100644 --- a/examples/wakustealthcommitments/node_spec.nim +++ b/examples/wakustealthcommitments/node_spec.nim @@ -3,15 +3,16 @@ import tools/confutils/cli_args import logos_delivery/waku/[common/logging, waku, factory/networks_config] import - std/[options, strutils, os, sequtils], + results, + std/[strutils, os, sequtils], chronicles, chronos, metrics, libp2p/crypto/crypto export - networks_config, waku, logging, options, strutils, os, sequtils, stewNet, chronicles, - chronos, metrics, crypto + networks_config, waku, logging, strutils, os, sequtils, stewNet, chronicles, chronos, + metrics, crypto proc setup*(): Waku = const versionString = "version / git commit hash: " & waku.git_version @@ -29,18 +30,18 @@ proc setup*(): Waku = # Override configuration conf.maxMessageSize = twnNetworkConf.maxMessageSize - conf.clusterId = some(twnNetworkConf.clusterId) + conf.clusterId = Opt.some(twnNetworkConf.clusterId) conf.rlnRelayEthContractAddress = twnNetworkConf.rlnRelayEthContractAddress - conf.rlnRelayDynamic = some(twnNetworkConf.rlnRelayDynamic) - conf.discv5Discovery = some(twnNetworkConf.discv5Discovery) + conf.rlnRelayDynamic = Opt.some(twnNetworkConf.rlnRelayDynamic) + conf.discv5Discovery = Opt.some(twnNetworkConf.discv5Discovery) conf.discv5BootstrapNodes = conf.discv5BootstrapNodes & twnNetworkConf.discv5BootstrapNodes - conf.rlnEpochSizeSec = some(twnNetworkConf.rlnEpochSizeSec) - conf.rlnRelayUserMessageLimit = some(twnNetworkConf.rlnRelayUserMessageLimit) + conf.rlnEpochSizeSec = Opt.some(twnNetworkConf.rlnEpochSizeSec) + conf.rlnRelayUserMessageLimit = Opt.some(twnNetworkConf.rlnRelayUserMessageLimit) # Only set rlnRelay to true if relay is configured if conf.relay: - conf.rlnRelay = some(twnNetworkConf.rlnRelay) + conf.rlnRelay = Opt.some(twnNetworkConf.rlnRelay) info "Starting node" var waku = (waitFor Waku.new(conf)).valueOr: diff --git a/examples/wakustealthcommitments/stealth_commitment_protocol.nim b/examples/wakustealthcommitments/stealth_commitment_protocol.nim index 097994126..f14ed7043 100644 --- a/examples/wakustealthcommitments/stealth_commitment_protocol.nim +++ b/examples/wakustealthcommitments/stealth_commitment_protocol.nim @@ -51,7 +51,7 @@ proc sendThruWaku*( ).valueOr: return err("could not append rate limit proof to the message: " & error) - (await self.waku.node.publish(some(DefaultPubsubTopic), message)).isOkOr: + (await self.waku.node.publish(Opt.some(DefaultPubsubTopic), message)).isOkOr: return err("failed to publish message: " & $error) info "rate limit proof is appended to the message" @@ -182,7 +182,7 @@ proc new*( except CatchableError: error "could not handle SCP message: ", err = getCurrentExceptionMsg() - waku.node.subscribe((kind: PubsubSub, topic: DefaultPubsubTopic), some(handler)).isOkOr: + waku.node.subscribe((kind: PubsubSub, topic: DefaultPubsubTopic), Opt.some(handler)).isOkOr: error "could not subscribe to pubsub topic: ", err = $error return err("could not subscribe to pubsub topic: " & $error) return ok(SCP) diff --git a/examples/wakustealthcommitments/wire_spec.nim b/examples/wakustealthcommitments/wire_spec.nim index cd32d24a8..fdaa4d8f3 100644 --- a/examples/wakustealthcommitments/wire_spec.nim +++ b/examples/wakustealthcommitments/wire_spec.nim @@ -1,22 +1,20 @@ -import std/[times, options] +import std/times import confutils, chronicles, chronos, results import logos_delivery/waku/[waku_core, common/protobuf] import libp2p/protobuf/minprotobuf -export - times, options, confutils, chronicles, chronos, results, waku_core, protobuf, - minprotobuf +export times, confutils, chronicles, chronos, results, waku_core, protobuf, minprotobuf type SerializedKey* = seq[byte] type WakuStealthCommitmentMsg* = object request*: bool - spendingPubKey*: Option[SerializedKey] - viewingPubKey*: Option[SerializedKey] - ephemeralPubKey*: Option[SerializedKey] - stealthCommitment*: Option[SerializedKey] - viewTag*: Option[uint64] + spendingPubKey*: Opt[SerializedKey] + viewingPubKey*: Opt[SerializedKey] + ephemeralPubKey*: Opt[SerializedKey] + stealthCommitment*: Opt[SerializedKey] + viewTag*: Opt[uint64] proc decode*(T: type WakuStealthCommitmentMsg, buffer: seq[byte]): ProtoResult[T] = var msg = WakuStealthCommitmentMsg() @@ -29,20 +27,20 @@ proc decode*(T: type WakuStealthCommitmentMsg, buffer: seq[byte]): ProtoResult[T discard ?pb.getField(2, spendingPubKey) msg.spendingPubKey = if spendingPubKey.len > 0: - some(spendingPubKey) + Opt.some(spendingPubKey) else: - none(SerializedKey) + Opt.none(SerializedKey) var viewingPubKey = newSeq[byte]() discard ?pb.getField(3, viewingPubKey) msg.viewingPubKey = if viewingPubKey.len > 0: - some(viewingPubKey) + Opt.some(viewingPubKey) else: - none(SerializedKey) + Opt.none(SerializedKey) if msg.spendingPubKey.isSome() and msg.viewingPubKey.isSome(): - msg.stealthCommitment = none(SerializedKey) - msg.viewTag = none(uint64) + msg.stealthCommitment = Opt.none(SerializedKey) + msg.viewTag = Opt.none(uint64) return ok(msg) if msg.spendingPubKey.isSome() and msg.viewingPubKey.isNone(): return err(ProtoError.RequiredFieldMissing) @@ -55,25 +53,25 @@ proc decode*(T: type WakuStealthCommitmentMsg, buffer: seq[byte]): ProtoResult[T discard ?pb.getField(4, stealthCommitment) msg.stealthCommitment = if stealthCommitment.len > 0: - some(stealthCommitment) + Opt.some(stealthCommitment) else: - none(SerializedKey) + Opt.none(SerializedKey) var ephemeralPubKey = newSeq[byte]() discard ?pb.getField(5, ephemeralPubKey) msg.ephemeralPubKey = if ephemeralPubKey.len > 0: - some(ephemeralPubKey) + Opt.some(ephemeralPubKey) else: - none(SerializedKey) + Opt.none(SerializedKey) var viewTag: uint64 discard ?pb.getField(6, viewTag) msg.viewTag = if viewTag != 0: - some(viewTag) + Opt.some(viewTag) else: - none(uint64) + Opt.none(uint64) if msg.stealthCommitment.isNone() and msg.viewTag.isNone() and msg.ephemeralPubKey.isNone(): @@ -86,8 +84,8 @@ proc decode*(T: type WakuStealthCommitmentMsg, buffer: seq[byte]): ProtoResult[T return err(ProtoError.RequiredFieldMissing) if msg.stealthCommitment.isSome() and msg.viewTag.isSome(): - msg.spendingPubKey = none(SerializedKey) - msg.viewingPubKey = none(SerializedKey) + msg.spendingPubKey = Opt.none(SerializedKey) + msg.viewingPubKey = Opt.none(SerializedKey) ok(msg) @@ -118,8 +116,8 @@ proc constructRequest*( ): WakuStealthCommitmentMsg = WakuStealthCommitmentMsg( request: true, - spendingPubKey: some(spendingPubKey), - viewingPubKey: some(viewingPubKey), + spendingPubKey: Opt.some(spendingPubKey), + viewingPubKey: Opt.some(viewingPubKey), ) proc constructResponse*( @@ -127,7 +125,7 @@ proc constructResponse*( ): WakuStealthCommitmentMsg = WakuStealthCommitmentMsg( request: false, - stealthCommitment: some(stealthCommitment), - ephemeralPubKey: some(ephemeralPubKey), - viewTag: some(viewTag), + stealthCommitment: Opt.some(stealthCommitment), + ephemeralPubKey: Opt.some(ephemeralPubKey), + viewTag: Opt.some(viewTag), ) diff --git a/library/kernel_api/protocols/store_api.nim b/library/kernel_api/protocols/store_api.nim index 75d43fee1..3f47fcc66 100644 --- a/library/kernel_api/protocols/store_api.nim +++ b/library/kernel_api/protocols/store_api.nim @@ -1,4 +1,4 @@ -import std/[json, sugar, options] +import std/[json, sugar] import chronos, chronicles, results, ffi import logos_delivery, @@ -24,17 +24,17 @@ func fromJsonNode(jsonContent: JsonNode): Result[StoreQueryRequest, string] = let pubsubTopic = if jsonContent.contains("pubsubTopic"): - some(jsonContent["pubsubTopic"].getStr()) + Opt.some(jsonContent["pubsubTopic"].getStr()) else: - none(string) + Opt.none(string) let paginationCursor = if jsonContent.contains("paginationCursor"): let hash = jsonContent["paginationCursor"].getStr().hexToHash().valueOr: return err("Failed converting paginationCursor hex string to bytes: " & error) - some(hash) + Opt.some(hash) else: - none(WakuMessageHash) + Opt.none(WakuMessageHash) let paginationForwardBool = jsonContent["paginationForward"].getBool() let paginationForward = @@ -42,9 +42,9 @@ func fromJsonNode(jsonContent: JsonNode): Result[StoreQueryRequest, string] = let paginationLimit = if jsonContent.contains("paginationLimit"): - some(uint64(jsonContent["paginationLimit"].getInt())) + Opt.some(uint64(jsonContent["paginationLimit"].getInt())) else: - none(uint64) + Opt.none(uint64) let startTime = ?jsonContent.getProtoInt64("timeStart") let endTime = ?jsonContent.getProtoInt64("timeEnd") diff --git a/library/liblogosdelivery.nim b/library/liblogosdelivery.nim index d3753da63..57279c189 100644 --- a/library/liblogosdelivery.nim +++ b/library/liblogosdelivery.nim @@ -1,5 +1,4 @@ -import logos_delivery/waku/compat/option_valueor -import std/[atomics, options, macros] +import std/[atomics, macros] import chronicles, chronos, chronos/threadsync, ffi import logos_delivery/waku/waku_core/message/message, diff --git a/library/utils.nim b/library/utils.nim index 926ec4e88..005b725f4 100644 --- a/library/utils.nim +++ b/library/utils.nim @@ -1,7 +1,7 @@ -import std/[json, options, strutils] +import std/[json, strutils] import results -proc getProtoInt64*(node: JsonNode, key: string): Result[Option[int64], string] = +proc getProtoInt64*(node: JsonNode, key: string): Result[Opt[int64], string] = try: let (value, ok) = if node.hasKey(key): @@ -13,8 +13,8 @@ proc getProtoInt64*(node: JsonNode, key: string): Result[Option[int64], string] (0, false) if ok: - return ok(some(value)) + return ok(Opt.some(value)) - return ok(none(int64)) + return ok(Opt.none(int64)) except CatchableError: return err("Invalid int64 value in `" & key & "`") diff --git a/logos_delivery/api/conf/channels_conf.nim b/logos_delivery/api/conf/channels_conf.nim index 5d19e802a..9bef68942 100644 --- a/logos_delivery/api/conf/channels_conf.nim +++ b/logos_delivery/api/conf/channels_conf.nim @@ -1,15 +1,15 @@ -import std/options +import results type ReliableChannelManagerConf* = object - ## All-`Option` partial; unset fields fall back to `createReliableChannel` defaults. - segmentationEnableReedSolomon*: Option[bool] + ## All-`Opt` partial; unset fields fall back to `createReliableChannel` defaults. + segmentationEnableReedSolomon*: Opt[bool] ## Add Reed-Solomon parity segments for recovery of lost segments. - segmentationSegmentSizeBytes*: Option[int] ## Maximum segment size in bytes. - sdsAcknowledgementTimeoutMs*: Option[int] + segmentationSegmentSizeBytes*: Opt[int] ## Maximum segment size in bytes. + sdsAcknowledgementTimeoutMs*: Opt[int] ## Time to wait before retransmitting an unacknowledged message. - sdsMaxRetransmissions*: Option[int] + sdsMaxRetransmissions*: Opt[int] ## Maximum retransmission attempts before delivery fails. - sdsCausalHistorySize*: Option[int] ## Number of message ids kept in causal history. - rateLimitEnabled*: Option[bool] ## Enable rate limiting. - rateLimitEpochPeriodSec*: Option[int] ## Rate-limit epoch length in seconds. - rateLimitMessagesPerEpoch*: Option[int] ## Messages allowed per rate-limit epoch. + sdsCausalHistorySize*: Opt[int] ## Number of message ids kept in causal history. + rateLimitEnabled*: Opt[bool] ## Enable rate limiting. + rateLimitEpochPeriodSec*: Opt[int] ## Rate-limit epoch length in seconds. + rateLimitMessagesPerEpoch*: Opt[int] ## Messages allowed per rate-limit epoch. diff --git a/logos_delivery/api/conf/logos_delivery_conf.nim b/logos_delivery/api/conf/logos_delivery_conf.nim index e5ac7432a..bec9f9a78 100644 --- a/logos_delivery/api/conf/logos_delivery_conf.nim +++ b/logos_delivery/api/conf/logos_delivery_conf.nim @@ -1,19 +1,18 @@ {.push raises: [].} -import std/options import results import logos_delivery/api/conf/messaging_conf import logos_delivery/api/conf/channels_conf -export options, messaging_conf, channels_conf +export messaging_conf, channels_conf type LogosDeliveryConf* = object ## Aggregates the per-layer config objects. A layer is mounted iff its config ## is present. kernelConf*: KernelConf - messagingConf*: Option[MessagingClientConf] - channelsConf*: Option[ReliableChannelManagerConf] + messagingConf*: Opt[MessagingClientConf] + channelsConf*: Opt[ReliableChannelManagerConf] proc init*(T: type LogosDeliveryConf, kernelConf: KernelConf): LogosDeliveryConf = return LogosDeliveryConf(kernelConf: kernelConf) @@ -31,8 +30,8 @@ proc init*( return ok( LogosDeliveryConf( kernelConf: KernelConf(kernelConf), - messagingConf: some(merged), - channelsConf: some(channelsOverrides), + messagingConf: Opt.some(merged), + channelsConf: Opt.some(channelsOverrides), ) ) diff --git a/logos_delivery/api/conf/logos_delivery_conf_json.nim b/logos_delivery/api/conf/logos_delivery_conf_json.nim index e5df174e4..6440a63ac 100644 --- a/logos_delivery/api/conf/logos_delivery_conf_json.nim +++ b/logos_delivery/api/conf/logos_delivery_conf_json.nim @@ -1,6 +1,6 @@ {.push raises: [].} -import std/[json, options, strutils, tables] +import std/[json, strutils, tables] import results import tools/confutils/conf_from_json @@ -82,8 +82,8 @@ proc parseFlatConf( return ok( LogosDeliveryConf( kernelConf: KernelConf(kernel), - messagingConf: some(messaging), - channelsConf: some(ReliableChannelManagerConf()), + messagingConf: Opt.some(messaging), + channelsConf: Opt.some(ReliableChannelManagerConf()), ) ) diff --git a/logos_delivery/api/conf/messaging_conf.nim b/logos_delivery/api/conf/messaging_conf.nim index 86a73575b..a8c91acd7 100644 --- a/logos_delivery/api/conf/messaging_conf.nim +++ b/logos_delivery/api/conf/messaging_conf.nim @@ -1,7 +1,5 @@ -import std/options import std/net -import results -import libp2p/crypto/crypto +import results, libp2p/crypto/crypto import logos_delivery/api/conf/kernel_conf import logos_delivery/waku/common/logging @@ -15,44 +13,44 @@ type LogosDeliveryMode* {.pure.} = enum Fleet # kernel-only node from a raw kernel config type MessagingClientConf* = object - clusterId* {.name: "cluster-id".}: Option[uint16] ## Network cluster id. - numShardsInCluster* {.name: "num-shards-in-network".}: Option[uint16] + clusterId* {.name: "cluster-id".}: Opt[uint16] ## Network cluster id. + numShardsInCluster* {.name: "num-shards-in-network".}: Opt[uint16] ## Number of shards in the cluster. - p2pTcpPort* {.name: "tcp-port".}: Option[Port] ## TCP listening port. - discv5UdpPort* {.name: "discv5-udp-port".}: Option[Port] ## discv5 UDP port. - websocketSupport* {.name: "websocket-support".}: Option[bool] + p2pTcpPort* {.name: "tcp-port".}: Opt[Port] ## TCP listening port. + discv5UdpPort* {.name: "discv5-udp-port".}: Opt[Port] ## discv5 UDP port. + websocketSupport* {.name: "websocket-support".}: Opt[bool] ## Enable the websocket transport. - websocketPort* {.name: "websocket-port".}: Option[Port] ## Websocket listening port. - quicSupport* {.name: "quic-support".}: Option[bool] ## Enable the QUIC transport. - quicPort* {.name: "quic-port".}: Option[Port] ## QUIC (UDP) listening port. - listenIpv4* {.name: "listen-address".}: Option[IpAddress] ## Inbound bind address. - maxMessageSize* {.name: "max-msg-size".}: Option[string] + websocketPort* {.name: "websocket-port".}: Opt[Port] ## Websocket listening port. + quicSupport* {.name: "quic-support".}: Opt[bool] ## Enable the QUIC transport. + quicPort* {.name: "quic-port".}: Opt[Port] ## QUIC (UDP) listening port. + listenIpv4* {.name: "listen-address".}: Opt[IpAddress] ## Inbound bind address. + maxMessageSize* {.name: "max-msg-size".}: Opt[string] ## Maximum accepted message size (e.g. "150 KiB"). - entryNodes* {.name: "entry-node".}: Option[seq[string]] + entryNodes* {.name: "entry-node".}: Opt[seq[string]] ## Bootstrap / connectivity nodes (enrtree or multiaddr). - ethRpcEndpoints* {.name: "rln-relay-eth-client-address".}: Option[seq[EthRpcUrl]] + ethRpcEndpoints* {.name: "rln-relay-eth-client-address".}: Opt[seq[EthRpcUrl]] ## Ethereum RPC endpoints (required for RLN validation); multiple for fail-over. - rlnContractAddress* {.name: "rln-relay-eth-contract-address".}: Option[string] + rlnContractAddress* {.name: "rln-relay-eth-contract-address".}: Opt[string] ## RLN contract address; when set, RLN validation is enabled. - rlnChainId* {.name: "rln-relay-chain-id".}: Option[uint] + rlnChainId* {.name: "rln-relay-chain-id".}: Opt[uint] ## Chain id the RLN contract is deployed on. - rlnEpochSizeSec* {.name: "rln-relay-epoch-sec".}: Option[uint] + rlnEpochSizeSec* {.name: "rln-relay-epoch-sec".}: Opt[uint] ## RLN epoch size, in seconds. - reliabilityEnabled* {.name: "reliability".}: Option[bool] + reliabilityEnabled* {.name: "reliability".}: Opt[bool] ## Enable store-based send reliability. - store*: Option[bool] ## Enable the store protocol. - storenode* {.name: "storenode".}: Option[string] - storeMessageDbUrl* {.name: "store-message-db-url".}: Option[string] + store*: Opt[bool] ## Enable the store protocol. + storenode* {.name: "storenode".}: Opt[string] + storeMessageDbUrl* {.name: "store-message-db-url".}: Opt[string] ## Database connection URL for the store service's persistent storage. - storeMessageRetentionPolicy* {.name: "store-message-retention-policy".}: - Option[string] ## Store retention policy (e.g. "time:3600;size:1GB"). - storeMaxNumDbConnections* {.name: "store-max-num-db-connections".}: Option[int] + storeMessageRetentionPolicy* {.name: "store-message-retention-policy".}: Opt[string] + ## Store retention policy (e.g. "time:3600;size:1GB"). + storeMaxNumDbConnections* {.name: "store-max-num-db-connections".}: Opt[int] ## Maximum number of simultaneous store database connections. - logLevel* {.name: "log-level".}: Option[logging.LogLevel] + logLevel* {.name: "log-level".}: Opt[logging.LogLevel] ## Process log level (TRACE..FATAL); applied by the kernel on node creation. - logFormat* {.name: "log-format".}: Option[logging.LogFormat] + logFormat* {.name: "log-format".}: Opt[logging.LogFormat] ## Process log format (TEXT or JSON); applied by the kernel on node creation. - nodeKey* {.name: "nodekey".}: Option[crypto.PrivateKey] + nodeKey* {.name: "nodekey".}: Opt[crypto.PrivateKey] ## P2P node private key (64-char hex): stable identity / peerId across restarts. proc applyMode*(conf: var WakuNodeConf, mode: LogosDeliveryMode): ConfResult[void] = @@ -62,7 +60,7 @@ proc applyMode*(conf: var WakuNodeConf, mode: LogosDeliveryMode): ConfResult[voi conf.relay = true conf.filter = true conf.lightpush = true - conf.discv5Discovery = some(true) + conf.discv5Discovery = Opt.some(true) conf.peerExchange = true conf.rendezvous = true of LogosDeliveryMode.Edge: @@ -108,11 +106,11 @@ proc toWakuNodeConf*( conf.ethClientUrls = self.ethRpcEndpoints.get() if self.rlnContractAddress.isSome(): conf.rlnRelayEthContractAddress = self.rlnContractAddress.get() - conf.rlnRelay = some(true) + conf.rlnRelay = Opt.some(true) if self.rlnChainId.isSome(): conf.rlnRelayChainId = self.rlnChainId.get() if self.rlnEpochSizeSec.isSome(): - conf.rlnEpochSizeSec = some(self.rlnEpochSizeSec.get().uint64) + conf.rlnEpochSizeSec = Opt.some(self.rlnEpochSizeSec.get().uint64) if self.logLevel.isSome(): conf.logLevel = self.logLevel.get() if self.logFormat.isSome(): @@ -132,7 +130,7 @@ proc toWakuNodeConf*( proc merge*(base, overrides: MessagingClientConf): MessagingClientConf = var m = base for _, mField, oField in fieldPairs(m, overrides): - when oField is Option: + when oField is Opt: if oField.isSome(): mField = oField return m @@ -140,8 +138,8 @@ proc merge*(base, overrides: MessagingClientConf): MessagingClientConf = proc resolvePreset*(preset: string): ConfResult[MessagingClientConf] = ## Preset to messaging-only fields. Kernel-mirrored fields stay unset; the ## kernel resolves those from `conf.preset`. - let npcOpt = ?toNetworkPresetConf(preset, none(uint16)) + let npcOpt = ?toNetworkPresetConf(preset, Opt.none(uint16)) if npcOpt.isNone(): return ok(MessagingClientConf()) let npc = npcOpt.get() - return ok(MessagingClientConf(reliabilityEnabled: some(npc.p2pReliability))) + return ok(MessagingClientConf(reliabilityEnabled: Opt.some(npc.p2pReliability))) diff --git a/logos_delivery/api/types.nim b/logos_delivery/api/types.nim index 97e7a11c9..e21d1c3d0 100644 --- a/logos_delivery/api/types.nim +++ b/logos_delivery/api/types.nim @@ -1,8 +1,6 @@ -import logos_delivery/waku/compat/option_valueor -import libp2p/crypto/crypto {.push raises: [].} -import bearssl/rand, std/times, chronos +import libp2p/crypto/crypto, bearssl/rand, std/times, chronos import stew/byteutils import logos_delivery/waku/utils/requests as request_utils import logos_delivery/waku/waku_core/[topics/content_topic, message/message, time] diff --git a/logos_delivery/channels/api/channel_lifecycle.nim b/logos_delivery/channels/api/channel_lifecycle.nim index bacce83d8..0d32e2acf 100644 --- a/logos_delivery/channels/api/channel_lifecycle.nim +++ b/logos_delivery/channels/api/channel_lifecycle.nim @@ -1,6 +1,6 @@ ## Reliable Channel layer API — channel lifecycle ## (createReliableChannel / closeChannel). -import std/[options, tables] +import std/tables import results, chronos, chronicles import logos_delivery/api/types @@ -15,17 +15,17 @@ const SdsJobId = "sds" ## One persistency job shared by every channel's SDS state; rows are ## keyed by channelId. -proc sdsPersistence(): Option[Persistence] = +proc sdsPersistence(): Opt[Persistence] = ## SDS backend from the Persistency singleton; memory-only fallback when ## it is unavailable (e.g. unit tests). let p = Persistency.instance().valueOr: info "SDS persistence disabled, running memory-only", reason = $error - return none(Persistence) + return Opt.none(Persistence) let job = p.openJob(SdsJobId).valueOr: warn "SDS persistence disabled, could not open persistency job", jobId = SdsJobId, reason = $error - return none(Persistence) - return some(newSdsPersistence(job)) + return Opt.none(Persistence) + return Opt.some(newSdsPersistence(job)) proc createReliableChannel*( self: ReliableChannelManager, diff --git a/logos_delivery/channels/reliable_channel.nim b/logos_delivery/channels/reliable_channel.nim index 4daf8a1e2..ca74f9df4 100644 --- a/logos_delivery/channels/reliable_channel.nim +++ b/logos_delivery/channels/reliable_channel.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor ## Reliable Channel type. ## ## A `ReliableChannel` orchestrates segmentation, SDS (end-to-end @@ -14,9 +13,8 @@ import logos_delivery/waku/compat/option_valueor ## ## See: https://lip.logos.co/messaging/raw/reliable-channel-api.html -import std/[options, tables] -import results -import chronos +import std/tables +import results, chronos import bearssl/rand import stew/byteutils import libp2p/crypto/crypto as libp2p_crypto @@ -160,17 +158,17 @@ type ClaimedSegment = object channelReqId: RequestId isEphemeral: bool -proc claimAwaitingChannelReq(self: ReliableChannel): Option[ClaimedSegment] = +proc claimAwaitingChannelReq(self: ReliableChannel): Opt[ClaimedSegment] = for channelReqId, state in self.channelReqs.mpairs: if state.awaitingDispatch > 0: state.awaitingDispatch.dec() - return some( + return Opt.some( ClaimedSegment( channelReqId: channelReqId, isEphemeral: state.persistenceReqType == MessagePersistence.Ephemeral, ) ) - return none(ClaimedSegment) + return Opt.none(ClaimedSegment) type MessagingOutcome {.pure.} = enum Sent diff --git a/logos_delivery/channels/scalable_data_sync/scalable_data_sync.nim b/logos_delivery/channels/scalable_data_sync/scalable_data_sync.nim index 8da0c8530..81e1f6ac9 100644 --- a/logos_delivery/channels/scalable_data_sync/scalable_data_sync.nim +++ b/logos_delivery/channels/scalable_data_sync/scalable_data_sync.nim @@ -8,7 +8,7 @@ {.push raises: [].} -import std/[options, tables] +import std/tables from std/times import initDuration, getTime, toUnix, nanosecond import results, chronos, chronicles import nimcrypto/keccak @@ -37,7 +37,7 @@ type acknowledgementTimeoutMs*: int maxRetransmissions*: int causalHistorySize*: int - persistence*: Option[Persistence] + persistence*: Opt[Persistence] ## Durability backend. `none` runs memory-only: reliability still ## works, state does not survive a restart. diff --git a/logos_delivery/channels/segmentation/segmentation.nim b/logos_delivery/channels/segmentation/segmentation.nim index 9fc7964c0..148a6e08c 100644 --- a/logos_delivery/channels/segmentation/segmentation.nim +++ b/logos_delivery/channels/segmentation/segmentation.nim @@ -9,8 +9,7 @@ ## ## See: https://lip.logos.co/messaging/raw/reliable-channel-api.html -import std/options -import ./segment_message_proto +import results, ./segment_message_proto import ./segmentation_persistence export segment_message_proto, segmentation_persistence @@ -54,12 +53,12 @@ proc performSegmentation*( proc handleIncomingSegment*( self: SegmentationHandler, segmentBytes: seq[byte] -): Option[ReassemblyResult] = +): Opt[ReassemblyResult] = ## Skeleton behaviour: every segment is already a complete message ## (since `performSegmentation` always emits one), so just hand the ## payload straight back. let segment = SegmentMessageProto.decode(segmentBytes) - return some( + return Opt.some( ReassemblyResult( payload: segment.payload, entireMessageHash: segment.entireMessageHash ) diff --git a/logos_delivery/logos_delivery.nim b/logos_delivery/logos_delivery.nim index 0e1f77104..35e9f6a97 100644 --- a/logos_delivery/logos_delivery.nim +++ b/logos_delivery/logos_delivery.nim @@ -9,7 +9,6 @@ {.push raises: [].} -import std/options import results, chronos, chronicles # Each layer has a core module (type + new/start/stop) and an api/ folder whose @@ -111,8 +110,8 @@ proc new*( return await LogosDelivery.new( LogosDeliveryConf( kernelConf: KernelConf(conf), - messagingConf: some(MessagingClientConf()), - channelsConf: some(ReliableChannelManagerConf()), + messagingConf: Opt.some(MessagingClientConf()), + channelsConf: Opt.some(ReliableChannelManagerConf()), ), appCallbacks, ) @@ -136,8 +135,8 @@ proc new*( return await LogosDelivery.new( LogosDeliveryConf( kernelConf: kernelConf, - messagingConf: some(messagingOverrides), - channelsConf: some(channelsOverrides), + messagingConf: Opt.some(messagingOverrides), + channelsConf: Opt.some(channelsOverrides), ), appCallbacks, ) diff --git a/logos_delivery/messaging/delivery_service/recv_service/recv_service.nim b/logos_delivery/messaging/delivery_service/recv_service/recv_service.nim index d2c369d46..57c7f1c4f 100644 --- a/logos_delivery/messaging/delivery_service/recv_service/recv_service.nim +++ b/logos_delivery/messaging/delivery_service/recv_service/recv_service.nim @@ -1,9 +1,8 @@ -import logos_delivery/waku/compat/option_valueor ## This module is in charge of taking care of the messages that this node is expecting to ## receive and is backed by store-v3 requests to get an additional degree of certainty ## -import std/[tables, sequtils, options, sets] +import results, std/[tables, sequtils, sets] import chronos, chronicles, libp2p/utility import brokers/broker_context import @@ -112,10 +111,10 @@ proc checkStore*(self: RecvService) {.async.} = await self.waku.storeQueryToAny( StoreQueryRequest( includeData: false, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: toSeq(contentTopics), - startTime: some(self.startTimeToCheck - DelayExtra.nanos), - endTime: some(self.endTimeToCheck + DelayExtra.nanos), + startTime: Opt.some(self.startTimeToCheck - DelayExtra.nanos), + endTime: Opt.some(self.endTimeToCheck + DelayExtra.nanos), ) ) ).valueOr: diff --git a/logos_delivery/messaging/delivery_service/send_service/delivery_task.nim b/logos_delivery/messaging/delivery_service/send_service/delivery_task.nim index 1f76078fe..f0c9d9942 100644 --- a/logos_delivery/messaging/delivery_service/send_service/delivery_task.nim +++ b/logos_delivery/messaging/delivery_service/send_service/delivery_task.nim @@ -1,5 +1,4 @@ -import logos_delivery/waku/compat/option_valueor -import std/[options, times], chronos +import results, std/times, chronos import brokers/broker_context import logos_delivery/waku/waku_core, @@ -24,7 +23,7 @@ type DeliveryTask* = ref object tryCount*: int state*: DeliveryState deliveryTime*: Moment - firstPropagatedTime*: Option[Moment] + firstPropagatedTime*: Opt[Moment] ## Set once on the first successful propagation; never reset on re-publish. ## Anchors the store-validation time cap (see propagationAge). propagateEventEmitted*: bool @@ -39,7 +38,7 @@ proc new*( let msg = envelop.toWakuMessage() # TODO: use sync request for such as soon as available let relayShardRes = ( - RequestRelayShard.request(brokerCtx, none[PubsubTopic](), envelop.contentTopic) + RequestRelayShard.request(brokerCtx, Opt.none(PubsubTopic), envelop.contentTopic) ).valueOr: error "RequestRelayShard.request failed", error = error return err("Failed create DeliveryTask: " & $error) diff --git a/logos_delivery/messaging/delivery_service/send_service/lightpush_processor.nim b/logos_delivery/messaging/delivery_service/send_service/lightpush_processor.nim index fa199774b..58ffc3d70 100644 --- a/logos_delivery/messaging/delivery_service/send_service/lightpush_processor.nim +++ b/logos_delivery/messaging/delivery_service/send_service/lightpush_processor.nim @@ -1,7 +1,4 @@ -import logos_delivery/waku/compat/option_valueor -import chronicles, chronos, results -import std/options -import brokers/broker_context +import chronicles, chronos, results, brokers/broker_context import logos_delivery/waku/waku_core, logos_delivery/waku/waku import logos_delivery/waku/api/publish @@ -54,7 +51,7 @@ method sendImpl*( task.state = DeliveryState.SuccessfullyPropagated task.deliveryTime = Moment.now() if task.firstPropagatedTime.isNone(): - task.firstPropagatedTime = some(Moment.now()) + task.firstPropagatedTime = Opt.some(Moment.now()) # TODO: with a simple retry processor it might be more accurate to say `Sent` else: # Controversial state, publish says ok but no peer. It should not happen. diff --git a/logos_delivery/messaging/delivery_service/send_service/relay_processor.nim b/logos_delivery/messaging/delivery_service/send_service/relay_processor.nim index dc40b797d..cc53d0fb3 100644 --- a/logos_delivery/messaging/delivery_service/send_service/relay_processor.nim +++ b/logos_delivery/messaging/delivery_service/send_service/relay_processor.nim @@ -1,6 +1,4 @@ -import logos_delivery/waku/compat/option_valueor -import std/options -import chronos, chronicles +import results, chronos, chronicles import brokers/broker_context import logos_delivery/waku/[waku_core], logos_delivery/waku/waku_lightpush/[common, rpc] import logos_delivery/waku/requests/health_requests @@ -77,7 +75,7 @@ method sendImpl*(self: RelaySendProcessor, task: DeliveryTask) {.async.} = task.state = DeliveryState.SuccessfullyPropagated task.deliveryTime = Moment.now() if task.firstPropagatedTime.isNone(): - task.firstPropagatedTime = some(Moment.now()) + task.firstPropagatedTime = Opt.some(Moment.now()) else: # It shall not happen, but still covering it task.state = self.fallbackStateToSet diff --git a/logos_delivery/messaging/delivery_service/send_service/send_service.nim b/logos_delivery/messaging/delivery_service/send_service/send_service.nim index 037ad879b..097bb0752 100644 --- a/logos_delivery/messaging/delivery_service/send_service/send_service.nim +++ b/logos_delivery/messaging/delivery_service/send_service/send_service.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor ## This module reinforces the publish operation with regular store-v3 requests. ## -import std/[sequtils, tables, options, typetraits] +import std/[sequtils, tables, typetraits] import chronos, chronicles, libp2p/utility import brokers/broker_context import diff --git a/logos_delivery/messaging/messaging_client.nim b/logos_delivery/messaging/messaging_client.nim index 1044122d3..d883878fb 100644 --- a/logos_delivery/messaging/messaging_client.nim +++ b/logos_delivery/messaging/messaging_client.nim @@ -1,7 +1,6 @@ ## Messaging layer core: the `MessagingClient` type plus its construction and ## lifecycle. The public operations (subscribe / unsubscribe / send) live in ## `messaging/api.nim`. -import std/options import results, chronos, chronicles import logos_delivery/api/conf/messaging_conf, diff --git a/logos_delivery/waku/api/filter.nim b/logos_delivery/waku/api/filter.nim index 06c78213f..4305aceb8 100644 --- a/logos_delivery/waku/api/filter.nim +++ b/logos_delivery/waku/api/filter.nim @@ -1,8 +1,6 @@ ## Waku layer API — filter (light client) operations. -import logos_delivery/waku/compat/option_valueor {.push raises: [].} -import std/options import results, chronos, chronicles import logos_delivery/waku/waku @@ -36,7 +34,7 @@ proc filterSubscribe*( let peer = self.node.peerManager.selectPeer(WakuFilterSubscribeCodec).valueOr: return err("could not find peer with WakuFilterSubscribeCodec when subscribing") - let subFut = self.node.filterSubscribe(some(pubsubTopic), contentTopics, peer) + let subFut = self.node.filterSubscribe(Opt.some(pubsubTopic), contentTopics, peer) if not await subFut.withTimeout(FilterOpTimeout): return err("filter subscription timed out") subFut.read().isOkOr: @@ -57,7 +55,8 @@ proc filterUnsubscribe*( let peer = self.node.peerManager.selectPeer(WakuFilterSubscribeCodec).valueOr: return err("could not find peer with WakuFilterSubscribeCodec when unsubscribing") - let unsubFut = self.node.filterUnsubscribe(some(pubsubTopic), contentTopics, peer) + let unsubFut = + self.node.filterUnsubscribe(Opt.some(pubsubTopic), contentTopics, peer) if not await unsubFut.withTimeout(FilterOpTimeout): return err("filter un-subscription timed out") unsubFut.read().isOkOr: diff --git a/logos_delivery/waku/api/lightpush.nim b/logos_delivery/waku/api/lightpush.nim index 6208a2643..34ffca85f 100644 --- a/logos_delivery/waku/api/lightpush.nim +++ b/logos_delivery/waku/api/lightpush.nim @@ -1,5 +1,4 @@ ## Waku layer API — lightpush (light client publish) operations. -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import results, chronos, chronicles diff --git a/logos_delivery/waku/api/peer_manager.nim b/logos_delivery/waku/api/peer_manager.nim index 3a73051b8..054c94dae 100644 --- a/logos_delivery/waku/api/peer_manager.nim +++ b/logos_delivery/waku/api/peer_manager.nim @@ -1,7 +1,7 @@ ## Waku layer API — peer management operations. {.push raises: [].} -import std/[options, sequtils, strutils] +import std/[sequtils, strutils] import results, chronos, chronicles import libp2p/[peerid, peerstore] diff --git a/logos_delivery/waku/api/publish.nim b/logos_delivery/waku/api/publish.nim index f9f3229f6..d1dffd5a0 100644 --- a/logos_delivery/waku/api/publish.nim +++ b/logos_delivery/waku/api/publish.nim @@ -5,10 +5,8 @@ ## `WakuLightPushResult` (status code + description) that the send processors ## branch on for their retry decisions, and expose relay/lightpush availability ## so the messaging layer never inspects `waku.node` directly. -import logos_delivery/waku/compat/option_valueor {.push raises: [].} -import std/options import results, chronos import logos_delivery/waku/waku @@ -46,7 +44,7 @@ proc relayPushHandler*(self: Waku): PushMessageHandler = proc lightpushPeerAvailable*(self: Waku, shard: PubsubTopic): bool = ## True if a lightpush service peer is available for `shard`. - return self.node.peerManager.selectPeer(WakuLightPushCodec, some(shard)).isSome() + return self.node.peerManager.selectPeer(WakuLightPushCodec, Opt.some(shard)).isSome() proc lightpushPublishToAny*( self: Waku, shard: PubsubTopic, message: WakuMessage @@ -55,9 +53,9 @@ proc lightpushPublishToAny*( ## through the node's lightpush flow, which attaches an RLN proof per ## attempt when RLN is mounted. Returns SERVICE_NOT_AVAILABLE when no peer ## is available. - let peer = self.node.peerManager.selectPeer(WakuLightPushCodec, some(shard)).valueOr: + let peer = self.node.peerManager.selectPeer(WakuLightPushCodec, Opt.some(shard)).valueOr: return lightpushResultServiceUnavailable("no lightpush peer available for shard") try: - return await self.node.lightpushPublish(some(shard), message, some(peer)) + return await self.node.lightpushPublish(Opt.some(shard), message, Opt.some(peer)) except CatchableError as e: return lightpushResultInternalError(e.msg) diff --git a/logos_delivery/waku/api/store.nim b/logos_delivery/waku/api/store.nim index a54ebe1f3..0154e3b3c 100644 --- a/logos_delivery/waku/api/store.nim +++ b/logos_delivery/waku/api/store.nim @@ -1,7 +1,6 @@ ## Waku layer API — store (historical query) operations. {.push raises: [].} -import std/options import results, chronos, chronicles import logos_delivery/waku/waku diff --git a/logos_delivery/waku/common/databases/db_postgres/dbconn.nim b/logos_delivery/waku/common/databases/db_postgres/dbconn.nim index ce0eaa213..f24f3d4dd 100644 --- a/logos_delivery/waku/common/databases/db_postgres/dbconn.nim +++ b/logos_delivery/waku/common/databases/db_postgres/dbconn.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor import std/[times, strutils, os, sets, strformat, tables], results, diff --git a/logos_delivery/waku/common/databases/db_postgres/pgasyncpool.nim b/logos_delivery/waku/common/databases/db_postgres/pgasyncpool.nim index b04319a65..0b298084e 100644 --- a/logos_delivery/waku/common/databases/db_postgres/pgasyncpool.nim +++ b/logos_delivery/waku/common/databases/db_postgres/pgasyncpool.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor # Simple async pool driver for postgress. # Inspired by: https://github.com/treeform/pg/ {.push raises: [].} diff --git a/logos_delivery/waku/common/databases/db_sqlite.nim b/logos_delivery/waku/common/databases/db_sqlite.nim index e8237bfe6..5af1e038c 100644 --- a/logos_delivery/waku/common/databases/db_sqlite.nim +++ b/logos_delivery/waku/common/databases/db_sqlite.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} # The code in this file is an adaptation of the Sqlite KV Store found in nim-eth. # https://github.com/status-im/nim-eth/blob/master/eth/db/kvstore_sqlite3.nim @@ -172,11 +171,11 @@ proc exec*[P](s: SqliteStmt[P, void], params: P): DatabaseResult[void] = res template readResult(s: RawStmtPtr, column: cint, T: type): auto = - when T is Option: + when T is Opt: if sqlite3_column_type(s, column) == SQLITE_NULL: - none(typeof(default(T).get())) + Opt.none(typeof(default(T).get())) else: - some(readSimpleResult(s, column, typeof(default(T).get()))) + Opt.some(readSimpleResult(s, column, typeof(default(T).get()))) else: readSimpleResult(s, column, T) diff --git a/logos_delivery/waku/common/enr/builder.nim b/logos_delivery/waku/common/enr/builder.nim index 3c5455d52..906a9e92a 100644 --- a/logos_delivery/waku/common/enr/builder.nim +++ b/logos_delivery/waku/common/enr/builder.nim @@ -1,7 +1,7 @@ {.push raises: [].} import - std/[options, net], + std/net, results, eth/keys as eth_keys, eth/p2p/discoveryv5/enr, @@ -62,22 +62,22 @@ proc build*(builder: EnrBuilder): EnrResult[enr.Record] = ## Builder extension: IP address and TCP/UDP ports proc addAddressAndPorts( - builder: var EnrBuilder, ip: IpAddress, tcpPort, udpPort: Option[Port] + builder: var EnrBuilder, ip: IpAddress, tcpPort, udpPort: Opt[Port] ) = builder.ipAddress = Opt.some(ip) - builder.tcpPort = tcpPort.toOpt() - builder.udpPort = udpPort.toOpt() + builder.tcpPort = tcpPort + builder.udpPort = udpPort -proc addPorts(builder: var EnrBuilder, tcp, udp: Option[Port]) = +proc addPorts(builder: var EnrBuilder, tcp, udp: Opt[Port]) = # Based on: https://github.com/status-im/nim-eth/blob/4b22fcd/eth/p2p/discoveryv5/enr.nim#L166 - builder.tcpPort = tcp.toOpt() - builder.udpPort = udp.toOpt() + builder.tcpPort = tcp + builder.udpPort = udp proc withIpAddressAndPorts*( builder: var EnrBuilder, - ipAddr = none(IpAddress), - tcpPort = none(Port), - udpPort = none(Port), + ipAddr = Opt.none(IpAddress), + tcpPort = Opt.none(Port), + udpPort = Opt.none(Port), ) = if ipAddr.isSome(): addAddressAndPorts(builder, ipAddr.get(), tcpPort, udpPort) diff --git a/logos_delivery/waku/common/enr/typed_record.nim b/logos_delivery/waku/common/enr/typed_record.nim index 94353d01d..5c619d84c 100644 --- a/logos_delivery/waku/common/enr/typed_record.nim +++ b/logos_delivery/waku/common/enr/typed_record.nim @@ -1,23 +1,9 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} -import std/options, results, eth/keys as eth_keys, libp2p/crypto/crypto as libp2p_crypto +import results, eth/keys as eth_keys, libp2p/crypto/crypto as libp2p_crypto import eth/p2p/discoveryv5/enr except TypedRecord, toTypedRecord -## Since enr changed to result.Opt[T] from Option[T] for intercompatibility introduce a conversion between -func toOpt*[T](o: Option[T]): Opt[T] = - if o.isSome(): - return Opt.some(o.get()) - else: - return Opt.none(T) - -func toOption*[T](o: Opt[T]): Option[T] = - if o.isSome(): - return some(o.get()) - else: - return none(T) - ## ENR typed record # Record identity scheme @@ -44,8 +30,8 @@ type TypedRecord* = object proc init(T: type TypedRecord, record: Record): T = TypedRecord(raw: record) -proc tryGet*(record: TypedRecord, field: string, T: type): Option[T] = - return record.raw.tryGet(field, T).toOption() +proc tryGet*(record: TypedRecord, field: string, T: type): Opt[T] = + return record.raw.tryGet(field, T) func toTyped*(record: Record): EnrResult[TypedRecord] = let tr = TypedRecord.init(record) @@ -61,38 +47,38 @@ func toTyped*(record: Record): EnrResult[TypedRecord] = # Typed record field accessors -func id*(record: TypedRecord): Option[RecordId] = +func id*(record: TypedRecord): Opt[RecordId] = let fieldOpt = record.tryGet("id", string) if fieldOpt.isNone(): - return none(RecordId) + return Opt.none(RecordId) let field = toRecordId(fieldOpt.get()).valueOr: - return none(RecordId) + return Opt.none(RecordId) - return some(field) + return Opt.some(field) -func secp256k1*(record: TypedRecord): Option[array[33, byte]] = +func secp256k1*(record: TypedRecord): Opt[array[33, byte]] = record.tryGet("secp256k1", array[33, byte]) -func ip*(record: TypedRecord): Option[array[4, byte]] = +func ip*(record: TypedRecord): Opt[array[4, byte]] = record.tryGet("ip", array[4, byte]) -func ip6*(record: TypedRecord): Option[array[16, byte]] = +func ip6*(record: TypedRecord): Opt[array[16, byte]] = record.tryGet("ip6", array[16, byte]) -func tcp*(record: TypedRecord): Option[uint16] = +func tcp*(record: TypedRecord): Opt[uint16] = record.tryGet("tcp", uint16) -func tcp6*(record: TypedRecord): Option[uint16] = +func tcp6*(record: TypedRecord): Opt[uint16] = let port = record.tryGet("tcp6", uint16) if port.isNone(): return record.tcp() return port -func udp*(record: TypedRecord): Option[uint16] = +func udp*(record: TypedRecord): Opt[uint16] = record.tryGet("udp", uint16) -func udp6*(record: TypedRecord): Option[uint16] = +func udp6*(record: TypedRecord): Opt[uint16] = let port = record.tryGet("udp6", uint16) if port.isNone(): return record.udp() diff --git a/logos_delivery/waku/common/paging.nim b/logos_delivery/waku/common/paging.nim index c963a24bc..0cbcb625e 100644 --- a/logos_delivery/waku/common/paging.nim +++ b/logos_delivery/waku/common/paging.nim @@ -1,4 +1,4 @@ -import std/options +import results type PagingDirection* {.pure.} = enum ## PagingDirection determines the direction of pagination @@ -11,7 +11,7 @@ proc default*(): PagingDirection {.inline.} = proc into*(b: bool): PagingDirection = PagingDirection(b) -proc into*(b: Option[bool]): PagingDirection = +proc into*(b: Opt[bool]): PagingDirection = if b.isNone(): return default() b.get().into() @@ -19,7 +19,7 @@ proc into*(b: Option[bool]): PagingDirection = proc into*(d: PagingDirection): bool = d == PagingDirection.FORWARD -proc into*(d: Option[PagingDirection]): bool = +proc into*(d: Opt[PagingDirection]): bool = if d.isNone(): return false d.get().into() diff --git a/logos_delivery/waku/common/protobuf.nim b/logos_delivery/waku/common/protobuf.nim index 767bdaea3..a47fb7435 100644 --- a/logos_delivery/waku/common/protobuf.nim +++ b/logos_delivery/waku/common/protobuf.nim @@ -2,7 +2,7 @@ {.push raises: [].} -import std/options, libp2p/protobuf/minprotobuf, libp2p/varint +import results, libp2p/protobuf/minprotobuf, libp2p/varint export minprotobuf, varint @@ -39,7 +39,7 @@ proc invalidLengthField*(T: type ProtobufError, field: string): T = ## Extension methods proc write3*(proto: var ProtoBuffer, field: int, value: auto) = - when value is Option: + when value is Opt: if value.isSome(): proto.write(field, value.get()) else: diff --git a/logos_delivery/waku/common/rate_limit/per_peer_limiter.nim b/logos_delivery/waku/common/rate_limit/per_peer_limiter.nim index 16b6bf065..886a8f9b2 100644 --- a/logos_delivery/waku/common/rate_limit/per_peer_limiter.nim +++ b/logos_delivery/waku/common/rate_limit/per_peer_limiter.nim @@ -6,19 +6,19 @@ {.push raises: [].} -import std/[options, tables], libp2p/stream/connection +import results, std/tables, libp2p/stream/connection import ./[single_token_limiter, service_metrics], ../../utils/tableutils export token_bucket, setting, service_metrics type PerPeerRateLimiter* = ref object of RootObj - setting*: Option[RateLimitSetting] - peerBucket: Table[PeerId, Option[TokenBucket]] + setting*: Opt[RateLimitSetting] + peerBucket: Table[PeerId, Opt[TokenBucket]] proc mgetOrPut( perPeerRateLimiter: var PerPeerRateLimiter, peerId: PeerId -): var Option[TokenBucket] = +): var Opt[TokenBucket] = return perPeerRateLimiter.peerBucket.mgetOrPut( peerId, newTokenBucket(perPeerRateLimiter.setting, ReplenishMode.Continuous) ) diff --git a/logos_delivery/waku/common/rate_limit/request_limiter.nim b/logos_delivery/waku/common/rate_limit/request_limiter.nim index 9fccf1c29..68e5e3120 100644 --- a/logos_delivery/waku/common/rate_limit/request_limiter.nim +++ b/logos_delivery/waku/common/rate_limit/request_limiter.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor ## RequestRateLimiter ## ## RequestRateLimiter is a general service protection mechanism. @@ -17,11 +16,7 @@ import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[options, math], - chronicles, - chronos/timer, - libp2p/stream/connection, - libp2p/utility + results, std/math, chronicles, chronos/timer, libp2p/stream/connection, libp2p/utility import std/times except TimeInterval, Duration, seconds, minutes @@ -41,7 +36,7 @@ const MINUTES_RATIO = 2 type RequestRateLimiter* = ref object of RootObj tokenBucket: TokenBucket - setting*: Option[RateLimitSetting] + setting*: Opt[RateLimitSetting] mainBucketSetting: RateLimitSetting ratio: int peerBucketSetting*: RateLimitSetting @@ -80,7 +75,7 @@ proc mgetOrPut( requestRateLimiter: var RequestRateLimiter, peerId: PeerId, now: Moment ): var TokenBucket = let bucketForNew = newTokenBucket( - some(requestRateLimiter.peerBucketSetting), Discrete, now + Opt.some(requestRateLimiter.peerBucketSetting), Discrete, now ).valueOr: raiseAssert "This branch is not allowed to be reached as it will not be called if the setting is None." @@ -137,7 +132,7 @@ template checkUsageLimit*( bodyRejected # TODO: review these ratio assumptions! Debatable! -func calcPeriodRatio(settingOpt: Option[RateLimitSetting]): int = +func calcPeriodRatio(settingOpt: Opt[RateLimitSetting]): int = settingOpt.withValue(setting): if setting.isUnlimited(): return UNLIMITED_RATIO @@ -155,7 +150,7 @@ func calcPeriodRatio(settingOpt: Option[RateLimitSetting]): int = # calculates peer cache items timeout # effectively if a peer does not issue any requests for this amount of time will be forgotten. -func calcCacheTimeout(settingOpt: Option[RateLimitSetting], ratio: int): Duration = +func calcCacheTimeout(settingOpt: Opt[RateLimitSetting], ratio: int): Duration = settingOpt.withValue(setting): if setting.isUnlimited(): return UNLIMITED_TIMEOUT @@ -167,7 +162,7 @@ func calcCacheTimeout(settingOpt: Option[RateLimitSetting], ratio: int): Duratio return UNLIMITED_TIMEOUT func calcPeerTokenSetting( - setting: Option[RateLimitSetting], ratio: int + setting: Opt[RateLimitSetting], ratio: int ): RateLimitSetting = let s = setting.valueOr: return (0, 0.minutes) @@ -178,7 +173,7 @@ func calcPeerTokenSetting( return (peerVolume, peerPeriod) -proc newRequestRateLimiter*(setting: Option[RateLimitSetting]): RequestRateLimiter = +proc newRequestRateLimiter*(setting: Opt[RateLimitSetting]): RequestRateLimiter = let ratio = calcPeriodRatio(setting) let isLimited = setting.isSome() and not setting.get().isUnlimited() let mainBucketSetting = diff --git a/logos_delivery/waku/common/rate_limit/service_metrics.nim b/logos_delivery/waku/common/rate_limit/service_metrics.nim index 4453dc5bd..47c66f7ae 100644 --- a/logos_delivery/waku/common/rate_limit/service_metrics.nim +++ b/logos_delivery/waku/common/rate_limit/service_metrics.nim @@ -1,7 +1,6 @@ {.push raises: [].} -import std/options -import metrics, setting +import results, metrics, setting export metrics @@ -14,7 +13,7 @@ declarePublicCounter waku_service_requests, declarePublicCounter waku_service_network_bytes, "total incoming traffic of specific waku services", labels = ["service", "direction"] -proc setServiceLimitMetric*(service: string, limit: Option[RateLimitSetting]) = +proc setServiceLimitMetric*(service: string, limit: Opt[RateLimitSetting]) = if limit.isSome() and not limit.get().isUnlimited(): waku_service_requests_limit.set( limit.get().calculateLimitPerSecond(), labelValues = [service] diff --git a/logos_delivery/waku/common/rate_limit/setting.nim b/logos_delivery/waku/common/rate_limit/setting.nim index 66ff79d17..e3669ebd6 100644 --- a/logos_delivery/waku/common/rate_limit/setting.nim +++ b/logos_delivery/waku/common/rate_limit/setting.nim @@ -1,6 +1,6 @@ {.push raises: [].} -import chronos/timer, std/[tables, strutils, options], regex, results +import chronos/timer, std/[tables, strutils], regex, results # Setting for TokenBucket defined as volume over period of time type RateLimitSetting* = tuple[volume: int, period: Duration] diff --git a/logos_delivery/waku/common/rate_limit/single_token_limiter.nim b/logos_delivery/waku/common/rate_limit/single_token_limiter.nim index fc4b0acd5..954c8445f 100644 --- a/logos_delivery/waku/common/rate_limit/single_token_limiter.nim +++ b/logos_delivery/waku/common/rate_limit/single_token_limiter.nim @@ -2,7 +2,7 @@ {.push raises: [].} -import std/[options], chronos/timer, libp2p/stream/connection, libp2p/utility +import results, chronos/timer, libp2p/stream/connection, libp2p/utility import std/times except TimeInterval, Duration @@ -12,17 +12,17 @@ import ./[setting, service_metrics] export token_bucket, setting, service_metrics proc newTokenBucket*( - setting: Option[RateLimitSetting], + setting: Opt[RateLimitSetting], replenishMode: static[ReplenishMode] = ReplenishMode.Continuous, startTime: Moment = Moment.now(), -): Option[TokenBucket] = +): Opt[TokenBucket] = if setting.isNone(): - return none[TokenBucket]() + return Opt.none(TokenBucket) if setting.get().isUnlimited(): - return none[TokenBucket]() + return Opt.none(TokenBucket) - return some( + return Opt.some( TokenBucket.new( capacity = setting.get().volume, fillDuration = setting.get().period, @@ -40,7 +40,7 @@ proc checkUsage( return true proc checkUsage( - t: var Option[TokenBucket], proto: string, now = Moment.now() + t: var Opt[TokenBucket], proto: string, now = Moment.now() ): bool {.raises: [].} = if t.isNone(): return true @@ -49,7 +49,7 @@ proc checkUsage( return checkUsage(tokenBucket, proto, now) template checkUsageLimit*( - t: var Option[TokenBucket] | var TokenBucket, + t: var Opt[TokenBucket] | var TokenBucket, proto: string, conn: Connection, bodyWithinLimit, bodyRejected: untyped, diff --git a/logos_delivery/waku/common/utils/matterbridge_client.nim b/logos_delivery/waku/common/utils/matterbridge_client.nim index e8593aeff..841d49b9a 100644 --- a/logos_delivery/waku/common/utils/matterbridge_client.nim +++ b/logos_delivery/waku/common/utils/matterbridge_client.nim @@ -1,6 +1,6 @@ {.push raises: [].} -import std/[httpclient, json, uri, options], results +import std/[httpclient, json, uri], results const # Resource locators diff --git a/logos_delivery/waku/common/utils/nat.nim b/logos_delivery/waku/common/utils/nat.nim index 125a48935..6a258278f 100644 --- a/logos_delivery/waku/common/utils/nat.nim +++ b/logos_delivery/waku/common/utils/nat.nim @@ -1,6 +1,6 @@ {.push raises: [].} -import std/[options, strutils, net] +import std/[strutils, net] import chronicles, eth/net/nat, results, nativesockets logScope: @@ -18,9 +18,9 @@ var singletonNat: bool = false # TODO: pass `NatStrategy`, not a string proc setupNat*( natConf, clientId: string, tcpPort, udpPort: Port -): Result[ - tuple[ip: Option[IpAddress], tcpPort: Option[Port], udpPort: Option[Port]], string -] {.gcsafe.} = +): Result[tuple[ip: Opt[IpAddress], tcpPort: Opt[Port], udpPort: Opt[Port]], string] {. + gcsafe +.} = let strategy = case natConf.toLowerAscii() of "any": NatAny @@ -29,8 +29,7 @@ proc setupNat*( of "pmp": NatPmp else: NatNone - var endpoint: - tuple[ip: Option[IpAddress], tcpPort: Option[Port], udpPort: Option[Port]] + var endpoint: tuple[ip: Opt[IpAddress], tcpPort: Opt[Port], udpPort: Opt[Port]] if strategy != NatNone: ## Only initialize the NAT module once @@ -47,7 +46,7 @@ proc setupNat*( warn "exception in setupNat", error = getCurrentExceptionMsg() if extIP.isSome(): - endpoint.ip = some(extIp.get()) + endpoint.ip = Opt.some(extIp.get()) # RedirectPorts in considered a gcsafety violation # because it obtains the address of a non-gcsafe proc? var extPorts: Opt[(Port, Port)] @@ -65,15 +64,15 @@ proc setupNat*( if extPorts.isSome(): let (extTcpPort, extUdpPort) = extPorts.get() - endpoint.tcpPort = some(extTcpPort) - endpoint.udpPort = some(extUdpPort) + endpoint.tcpPort = Opt.some(extTcpPort) + endpoint.udpPort = Opt.some(extUdpPort) else: # NatNone if not natConf.startsWith("extip:"): return err("not a valid NAT mechanism: " & $natConf) try: # any required port redirection is assumed to be done by hand - endpoint.ip = some(parseIpAddress(natConf[6 ..^ 1])) + endpoint.ip = Opt.some(parseIpAddress(natConf[6 ..^ 1])) except ValueError: return err("not a valid IP address: " & $natConf[6 ..^ 1]) diff --git a/logos_delivery/waku/common/utils/parse_size_units.nim b/logos_delivery/waku/common/utils/parse_size_units.nim index 3b8c1d1a7..14f41a933 100644 --- a/logos_delivery/waku/common/utils/parse_size_units.nim +++ b/logos_delivery/waku/common/utils/parse_size_units.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor import std/[strutils, math], results, regex proc parseMsgSize*(input: string): Result[uint64, string] = diff --git a/logos_delivery/waku/compat/option_valueor.nim b/logos_delivery/waku/compat/option_valueor.nim deleted file mode 100644 index 96a9276d5..000000000 --- a/logos_delivery/waku/compat/option_valueor.nim +++ /dev/null @@ -1,32 +0,0 @@ -## Polyfill: `valueOr` / `withValue` templates for `std/options.Option[T]`. -## -## Previously provided transitively by `libp2p/utility`, removed in -## nim-libp2p PR #2162 (commit 8a9943145). logos-delivery uses these -## templates pervasively on `Option[T]`. - -{.push raises: [].} - -import std/[macros, options] - -template valueOr*[T](self: Option[T], body: untyped): untyped = - let temp = (self) - if temp.isSome: - temp.get() - else: - body - -template withValue*[T](self: Option[T], value, body: untyped): untyped = - let temp = (self) - if temp.isSome: - let `value` {.inject.} = temp.get() - body - -macro withValue*[T](self: Option[T], value, body, elseStmt: untyped): untyped = - let elseBody = elseStmt[0] - quote: - let temp = (`self`) - if temp.isSome: - let `value` {.inject.} = temp.get() - `body` - else: - `elseBody` diff --git a/logos_delivery/waku/discovery/autonat_service.nim b/logos_delivery/waku/discovery/autonat_service.nim index 9f6ecaafd..b09efd49f 100644 --- a/logos_delivery/waku/discovery/autonat_service.nim +++ b/logos_delivery/waku/discovery/autonat_service.nim @@ -1,4 +1,4 @@ -import libp2p/crypto/crypto +import results, libp2p/crypto/crypto import chronos, chronicles, diff --git a/logos_delivery/waku/discovery/waku_discv5.nim b/logos_delivery/waku/discovery/waku_discv5.nim index 5f831730d..24fbffc83 100644 --- a/logos_delivery/waku/discovery/waku_discv5.nim +++ b/logos_delivery/waku/discovery/waku_discv5.nim @@ -1,10 +1,9 @@ import libp2p/crypto/crypto import libp2p/crypto/rng -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[sequtils, strutils, options, sets, net, json], + std/[sequtils, strutils, sets, net, json], results, chronos, chronicles, @@ -40,7 +39,7 @@ type Discv5Conf* {.requiresInit.} = object enrAutoUpdate*: bool type WakuDiscoveryV5Config* = object - discv5Config*: Option[DiscoveryConfig] + discv5Config*: Opt[DiscoveryConfig] address*: IpAddress port*: Port privateKey*: eth_keys.PrivateKey @@ -56,21 +55,21 @@ type WakuDiscoveryV5* = ref object conf: WakuDiscoveryV5Config protocol*: protocol.Protocol listening*: bool - predicate: Option[WakuDiscv5Predicate] - peerManager: Option[PeerManager] + predicate: Opt[WakuDiscv5Predicate] + peerManager: Opt[PeerManager] topicSubscriptionQueue: AsyncEventQueue[SubscriptionEvent] proc shardingPredicate*( record: Record, bootnodes: seq[Record] = @[] -): Option[WakuDiscv5Predicate] = +): Opt[WakuDiscv5Predicate] = ## Filter peers based on relay sharding information let typedRecord = record.toTyped().valueOr: info "peer filtering failed", reason = error - return none(WakuDiscv5Predicate) + return Opt.none(WakuDiscv5Predicate) let nodeShard = typedRecord.relaySharding().valueOr: info "no relay sharding information, peer filtering disabled" - return none(WakuDiscv5Predicate) + return Opt.none(WakuDiscv5Predicate) info "peer filtering updated" @@ -81,14 +80,14 @@ proc shardingPredicate*( nodeShard.shardIds.anyIt(record.containsShard(nodeShard.clusterId, it)) ) #RFC 64 guideline - return some(predicate) + return Opt.some(predicate) proc new*( T: type WakuDiscoveryV5, rng: crypto.Rng, conf: WakuDiscoveryV5Config, - record: Option[waku_enr.Record], - peerManager: Option[PeerManager] = none(PeerManager), + record: Opt[waku_enr.Record], + peerManager: Opt[PeerManager] = Opt.none(PeerManager), queue: AsyncEventQueue[SubscriptionEvent] = newAsyncEventQueue[SubscriptionEvent](30), ): T = @@ -100,7 +99,7 @@ proc new*( privKey = conf.privateKey, bootstrapRecords = conf.bootstrapRecords, enrAutoUpdate = conf.autoupdateRecord, - previousRecord = record.toOpt(), + previousRecord = record, enrIp = Opt.none(IpAddress), enrTcpPort = Opt.none(Port), enrUdpPort = Opt.none(Port), @@ -110,7 +109,7 @@ proc new*( if record.isSome(): shardingPredicate(record.get(), conf.bootstrapRecords) else: - none(WakuDiscv5Predicate) + Opt.none(WakuDiscv5Predicate) WakuDiscoveryV5( conf: conf, @@ -221,7 +220,7 @@ proc logDiscv5FoundPeers(discoveredRecords: seq[waku_enr.Record]) = addrs = addrs, enr = recordUri, capabilities = capabilities, shards = shardsStr proc findRandomPeers*( - wd: WakuDiscoveryV5, overridePred = none(WakuDiscv5Predicate) + wd: WakuDiscoveryV5, overridePred = Opt.none(WakuDiscv5Predicate) ): Future[seq[waku_enr.Record]] {.async.} = ## Find random peers to connect to using Discovery v5 let discoveredNodes = await wd.protocol.queryRandom() @@ -445,7 +444,7 @@ proc setupDiscoveryV5*( let discv5UdpPort = conf.udpPort let discv5Conf = WakuDiscoveryV5Config( - discv5Config: some(discv5Config), + discv5Config: Opt.some(discv5Config), address: p2pListenAddress, port: discv5UdpPort, privateKey: eth_keys.PrivateKey(key.skkey), @@ -455,7 +454,11 @@ proc setupDiscoveryV5*( return ok( WakuDiscoveryV5.new( - rng, discv5Conf, some(myENR), some(nodePeerManager), nodeTopicSubscriptionQueue + rng, + discv5Conf, + Opt.some(myENR), + Opt.some(nodePeerManager), + nodeTopicSubscriptionQueue, ) ) diff --git a/logos_delivery/waku/discovery/waku_dnsdisc.nim b/logos_delivery/waku/discovery/waku_dnsdisc.nim index d0167de06..acd31c866 100644 --- a/logos_delivery/waku/discovery/waku_dnsdisc.nim +++ b/logos_delivery/waku/discovery/waku_dnsdisc.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} ## A set of utilities to integrate EIP-1459 DNS-based discovery @@ -7,7 +6,7 @@ import logos_delivery/waku/compat/option_valueor ## EIP-1459 is defined in https://eips.ethereum.org/EIPS/eip-1459 import - std/[options, net, sequtils, sugar], + std/[net, sequtils, sugar], chronicles, chronos, metrics, diff --git a/logos_delivery/waku/discovery/waku_kademlia.nim b/logos_delivery/waku/discovery/waku_kademlia.nim index e6775530c..78ff31f65 100644 --- a/logos_delivery/waku/discovery/waku_kademlia.nim +++ b/logos_delivery/waku/discovery/waku_kademlia.nim @@ -1,7 +1,6 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} -import std/[options, sequtils, sets] +import std/[sequtils, sets] import chronos, chronicles, @@ -51,45 +50,45 @@ type KademliaDiscoveryConf* = object clientMode*: bool xprPublishing*: bool -proc extractMixPubKey*(service: ServiceInfo): Option[Curve25519Key] = +proc extractMixPubKey*(service: ServiceInfo): Opt[Curve25519Key] = if service.id != MixProtocolID: - return none(Curve25519Key) + return Opt.none(Curve25519Key) if service.data.len != Curve25519KeySize: trace "invalid mix pub key length", expected = Curve25519KeySize, actual = service.data.len, dataHex = byteutils.toHex(service.data) - return none(Curve25519Key) + return Opt.none(Curve25519Key) let key = intoCurve25519Key(service.data) - return some(key) + return Opt.some(key) -proc remotePeerInfoFrom*(record: ExtendedPeerRecord): Option[RemotePeerInfo] = +proc remotePeerInfoFrom*(record: ExtendedPeerRecord): Opt[RemotePeerInfo] = if record.addresses.len == 0: trace "missing addresses", peerId = record.peerId - return none(RemotePeerInfo) + return Opt.none(RemotePeerInfo) let addrs = record.addresses.mapIt(it.address) if addrs.len == 0: trace "no dialable addresses", peerId = record.peerId - return none(RemotePeerInfo) + return Opt.none(RemotePeerInfo) let protocols = record.services.mapIt(it.id) - var mixPubKey: Option[Curve25519Key] = none(Curve25519Key) + var mixPubKey: Opt[Curve25519Key] = Opt.none(Curve25519Key) for service in record.services: let key = extractMixPubKey(service).valueOr: continue - mixPubKey = some(key) + mixPubKey = Opt.some(key) trace "successfully extracted mix pub key", peerId = record.peerId, keyHex = byteutils.toHex(mixPubKey.get()) break - return some( + return Opt.some( RemotePeerInfo.init( record.peerId, addrs = addrs, diff --git a/logos_delivery/waku/factory/builder.nim b/logos_delivery/waku/factory/builder.nim index 3ca6313e0..a1e5a637b 100644 --- a/logos_delivery/waku/factory/builder.nim +++ b/logos_delivery/waku/factory/builder.nim @@ -1,7 +1,7 @@ {.push raises: [].} import - std/[options, net, math], + std/[net, math], results, chronicles, libp2p/crypto/crypto, @@ -23,14 +23,14 @@ import type WakuNodeBuilder* = object # General - nodeRng: Option[crypto.Rng] - nodeKey: Option[crypto.PrivateKey] - netConfig: Option[NetConfig] - record: Option[enr.Record] + nodeRng: Opt[crypto.Rng] + nodeKey: Opt[crypto.PrivateKey] + netConfig: Opt[NetConfig] + record: Opt[enr.Record] # Peer storage and peer manager - peerStorage: Option[PeerStorage] - peerStorageCapacity: Option[int] + peerStorage: Opt[PeerStorage] + peerStorageCapacity: Opt[int] # Peer manager config maxRelayPeers: int @@ -39,16 +39,16 @@ type shardAware: bool # Libp2p switch - switchMaxConnections: Option[int] - switchNameResolver: Option[NameResolver] - switchAgentString: Option[string] - switchSslSecureKey: Option[string] - switchSslSecureCert: Option[string] - switchSendSignedPeerRecord: Option[bool] + switchMaxConnections: Opt[int] + switchNameResolver: Opt[NameResolver] + switchAgentString: Opt[string] + switchSslSecureKey: Opt[string] + switchSslSecureCert: Opt[string] + switchSendSignedPeerRecord: Opt[bool] circuitRelay: Relay # Rate limit configs for non-relay req-resp protocols - rateLimitSettings: Option[ProtocolRateLimitSettings] + rateLimitSettings: Opt[ProtocolRateLimitSettings] WakuNodeBuilderResult* = Result[void, string] @@ -60,29 +60,29 @@ proc init*(T: type WakuNodeBuilder): WakuNodeBuilder = ## General proc withRng*(builder: var WakuNodeBuilder, rng: crypto.Rng) = - builder.nodeRng = some(rng) + builder.nodeRng = Opt.some(rng) proc withNodeKey*(builder: var WakuNodeBuilder, nodeKey: crypto.PrivateKey) = - builder.nodeKey = some(nodeKey) + builder.nodeKey = Opt.some(nodeKey) proc withRecord*(builder: var WakuNodeBuilder, record: enr.Record) = - builder.record = some(record) + builder.record = Opt.some(record) proc withNetworkConfiguration*(builder: var WakuNodeBuilder, config: NetConfig) = - builder.netConfig = some(config) + builder.netConfig = Opt.some(config) proc withNetworkConfigurationDetails*( builder: var WakuNodeBuilder, bindIp: IpAddress, bindPort: Port, - extIp = none(IpAddress), - extPort = none(Port), + extIp = Opt.none(IpAddress), + extPort = Opt.none(Port), extMultiAddrs = newSeq[MultiAddress](), wsBindPort: Port = Port(8000), wsEnabled: bool = false, wssEnabled: bool = false, - wakuFlags = none(CapabilitiesBitfield), - dns4DomainName = none(string), + wakuFlags = Opt.none(CapabilitiesBitfield), + dns4DomainName = Opt.none(string), dnsNameServers = @[parseIpAddress("1.1.1.1"), parseIpAddress("1.0.0.1")], ): WakuNodeBuilderResult {. deprecated: "use 'builder.withNetworkConfiguration()' instead" @@ -93,7 +93,7 @@ proc withNetworkConfigurationDetails*( extIp = extIp, extPort = extPort, extMultiAddrs = extMultiAddrs, - wsBindPort = some(wsBindPort), + wsBindPort = Opt.some(wsBindPort), wsEnabled = wsEnabled, wssEnabled = wssEnabled, wakuFlags = wakuFlags, @@ -106,10 +106,10 @@ proc withNetworkConfigurationDetails*( ## Peer storage and peer manager proc withPeerStorage*( - builder: var WakuNodeBuilder, peerStorage: PeerStorage, capacity = none(int) + builder: var WakuNodeBuilder, peerStorage: PeerStorage, capacity = Opt.none(int) ) = if not peerStorage.isNil(): - builder.peerStorage = some(peerStorage) + builder.peerStorage = Opt.some(peerStorage) builder.peerStorageCapacity = capacity @@ -131,7 +131,7 @@ proc withColocationLimit*(builder: var WakuNodeBuilder, colocationLimit: int) = builder.colocationLimit = colocationLimit proc withRateLimit*(builder: var WakuNodeBuilder, limits: ProtocolRateLimitSettings) = - builder.rateLimitSettings = some(limits) + builder.rateLimitSettings = Opt.some(limits) proc withCircuitRelay*(builder: var WakuNodeBuilder, circuitRelay: Relay) = builder.circuitRelay = circuitRelay @@ -140,21 +140,21 @@ proc withCircuitRelay*(builder: var WakuNodeBuilder, circuitRelay: Relay) = proc withSwitchConfiguration*( builder: var WakuNodeBuilder, - maxConnections = none(int), + maxConnections = Opt.none(int), nameResolver: NameResolver = nil, sendSignedPeerRecord = false, - secureKey = none(string), - secureCert = none(string), - agentString = none(string), + secureKey = Opt.none(string), + secureCert = Opt.none(string), + agentString = Opt.none(string), ) = builder.switchMaxConnections = maxConnections - builder.switchSendSignedPeerRecord = some(sendSignedPeerRecord) + builder.switchSendSignedPeerRecord = Opt.some(sendSignedPeerRecord) builder.switchSslSecureKey = secureKey builder.switchSslSecureCert = secureCert builder.switchAgentString = agentString if not nameResolver.isNil(): - builder.switchNameResolver = some(nameResolver) + builder.switchNameResolver = Opt.some(nameResolver) ## Build @@ -209,8 +209,8 @@ proc build*(builder: WakuNodeBuilder): Result[WakuNode, string] = let peerManager = PeerManager.new( switch = switch, storage = builder.peerStorage.get(nil), - maxRelayPeers = some(builder.maxRelayPeers), - maxServicePeers = some(builder.maxServicePeers), + maxRelayPeers = Opt.some(builder.maxRelayPeers), + maxServicePeers = Opt.some(builder.maxServicePeers), colocationLimit = builder.colocationLimit, shardedPeerManagement = builder.shardAware, maxConnections = builder.switchMaxConnections.get(MaxConnections), diff --git a/logos_delivery/waku/factory/conf_builder/discv5_conf_builder.nim b/logos_delivery/waku/factory/conf_builder/discv5_conf_builder.nim index e28cb10fb..e5965101f 100644 --- a/logos_delivery/waku/factory/conf_builder/discv5_conf_builder.nim +++ b/logos_delivery/waku/factory/conf_builder/discv5_conf_builder.nim @@ -1,4 +1,4 @@ -import chronicles, std/[net, options, sequtils], results +import chronicles, std/[net, sequtils], results import ../waku_conf logScope: @@ -16,49 +16,49 @@ const ## Discv5 Config Builder ## ########################### type Discv5ConfBuilder* = object - enabled*: Option[bool] + enabled*: Opt[bool] bootstrapNodes*: seq[string] - bitsPerHop*: Option[int] - bucketIpLimit*: Option[uint] - enrAutoUpdate*: Option[bool] - tableIpLimit*: Option[uint] - udpPort*: Option[Port] + bitsPerHop*: Opt[int] + bucketIpLimit*: Opt[uint] + enrAutoUpdate*: Opt[bool] + tableIpLimit*: Opt[uint] + udpPort*: Opt[Port] proc init*(T: type Discv5ConfBuilder): Discv5ConfBuilder = Discv5ConfBuilder() proc withEnabled*(b: var Discv5ConfBuilder, enabled: bool) = - b.enabled = some(enabled) + b.enabled = Opt.some(enabled) proc withBitsPerHop*(b: var Discv5ConfBuilder, bitsPerHop: int) = - b.bitsPerHop = some(bitsPerHop) + b.bitsPerHop = Opt.some(bitsPerHop) proc withBucketIpLimit*(b: var Discv5ConfBuilder, bucketIpLimit: uint) = - b.bucketIpLimit = some(bucketIpLimit) + b.bucketIpLimit = Opt.some(bucketIpLimit) proc withEnrAutoUpdate*(b: var Discv5ConfBuilder, enrAutoUpdate: bool) = - b.enrAutoUpdate = some(enrAutoUpdate) + b.enrAutoUpdate = Opt.some(enrAutoUpdate) proc withTableIpLimit*(b: var Discv5ConfBuilder, tableIpLimit: uint) = - b.tableIpLimit = some(tableIpLimit) + b.tableIpLimit = Opt.some(tableIpLimit) proc withUdpPort*(b: var Discv5ConfBuilder, udpPort: Port) = - b.udpPort = some(udpPort) + b.udpPort = Opt.some(udpPort) proc withUdpPort*(b: var Discv5ConfBuilder, udpPort: uint16) = - b.udpPort = some(Port(udpPort)) + b.udpPort = Opt.some(Port(udpPort)) proc withBootstrapNodes*(b: var Discv5ConfBuilder, bootstrapNodes: seq[string]) = # TODO: validate ENRs? b.bootstrapNodes = concat(b.bootstrapNodes, bootstrapNodes) -proc build*(b: Discv5ConfBuilder): Result[Option[Discv5Conf], string] = +proc build*(b: Discv5ConfBuilder): Result[Opt[Discv5Conf], string] = if not b.enabled.get(DefaultDiscv5Enabled): - return ok(none(Discv5Conf)) + return ok(Opt.none(Discv5Conf)) return ok( - some( + Opt.some( Discv5Conf( bootstrapNodes: b.bootstrapNodes, bitsPerHop: b.bitsPerHop.get(DefaultDiscv5BitsPerHop), diff --git a/logos_delivery/waku/factory/conf_builder/dns_discovery_conf_builder.nim b/logos_delivery/waku/factory/conf_builder/dns_discovery_conf_builder.nim index 1c577bbf8..4ae8570a1 100644 --- a/logos_delivery/waku/factory/conf_builder/dns_discovery_conf_builder.nim +++ b/logos_delivery/waku/factory/conf_builder/dns_discovery_conf_builder.nim @@ -1,4 +1,4 @@ -import chronicles, std/[net, options, strutils], results +import chronicles, std/[net, strutils], results import ../waku_conf logScope: @@ -8,21 +8,21 @@ logScope: ## DNS Discovery Config Builder ## ################################## type DnsDiscoveryConfBuilder* = object - enrTreeUrl*: Option[string] + enrTreeUrl*: Opt[string] nameServers*: seq[IpAddress] proc init*(T: type DnsDiscoveryConfBuilder): DnsDiscoveryConfBuilder = DnsDiscoveryConfBuilder() proc withEnrTreeUrl*(b: var DnsDiscoveryConfBuilder, enrTreeUrl: string) = - b.enrTreeUrl = some(enrTreeUrl) + b.enrTreeUrl = Opt.some(enrTreeUrl) proc withNameServers*(b: var DnsDiscoveryConfBuilder, nameServers: seq[IpAddress]) = b.nameServers = nameServers -proc build*(b: DnsDiscoveryConfBuilder): Result[Option[DnsDiscoveryConf], string] = +proc build*(b: DnsDiscoveryConfBuilder): Result[Opt[DnsDiscoveryConf], string] = if b.enrTreeUrl.isNone(): - return ok(none(DnsDiscoveryConf)) + return ok(Opt.none(DnsDiscoveryConf)) if isEmptyOrWhiteSpace(b.enrTreeUrl.get()): return err("dnsDiscovery.enrTreeUrl cannot be an empty string") @@ -30,5 +30,7 @@ proc build*(b: DnsDiscoveryConfBuilder): Result[Option[DnsDiscoveryConf], string return err("dnsDiscovery.nameServers is not specified") return ok( - some(DnsDiscoveryConf(nameServers: b.nameServers, enrTreeUrl: b.enrTreeUrl.get())) + Opt.some( + DnsDiscoveryConf(nameServers: b.nameServers, enrTreeUrl: b.enrTreeUrl.get()) + ) ) diff --git a/logos_delivery/waku/factory/conf_builder/filter_service_conf_builder.nim b/logos_delivery/waku/factory/conf_builder/filter_service_conf_builder.nim index dafd6b5ab..4f063627a 100644 --- a/logos_delivery/waku/factory/conf_builder/filter_service_conf_builder.nim +++ b/logos_delivery/waku/factory/conf_builder/filter_service_conf_builder.nim @@ -1,4 +1,4 @@ -import chronicles, std/options, results +import chronicles, results import ../waku_conf logScope: @@ -14,40 +14,40 @@ const ## Filter Service Config Builder ## ################################### type FilterServiceConfBuilder* = object - enabled*: Option[bool] - maxPeersToServe*: Option[uint32] - subscriptionTimeout*: Option[uint16] - maxCriteria*: Option[uint32] + enabled*: Opt[bool] + maxPeersToServe*: Opt[uint32] + subscriptionTimeout*: Opt[uint16] + maxCriteria*: Opt[uint32] proc init*(T: type FilterServiceConfBuilder): FilterServiceConfBuilder = FilterServiceConfBuilder() proc withEnabled*(b: var FilterServiceConfBuilder, enabled: bool) = - b.enabled = some(enabled) + b.enabled = Opt.some(enabled) proc withMaxPeersToServe*(b: var FilterServiceConfBuilder, maxPeersToServe: uint32) = - b.maxPeersToServe = some(maxPeersToServe) + b.maxPeersToServe = Opt.some(maxPeersToServe) proc withMaxPeersToServeIfNotAssigned*( b: var FilterServiceConfBuilder, maxPeersToServe: uint32 ) = if b.maxPeersToServe.isNone(): - b.maxPeersToServe = some(maxPeersToServe) + b.maxPeersToServe = Opt.some(maxPeersToServe) proc withSubscriptionTimeout*( b: var FilterServiceConfBuilder, subscriptionTimeout: uint16 ) = - b.subscriptionTimeout = some(subscriptionTimeout) + b.subscriptionTimeout = Opt.some(subscriptionTimeout) proc withMaxCriteria*(b: var FilterServiceConfBuilder, maxCriteria: uint32) = - b.maxCriteria = some(maxCriteria) + b.maxCriteria = Opt.some(maxCriteria) -proc build*(b: FilterServiceConfBuilder): Result[Option[FilterServiceConf], string] = +proc build*(b: FilterServiceConfBuilder): Result[Opt[FilterServiceConf], string] = if not b.enabled.get(DefaultFilterEnabled): - return ok(none(FilterServiceConf)) + return ok(Opt.none(FilterServiceConf)) return ok( - some( + Opt.some( FilterServiceConf( maxPeersToServe: b.maxPeersToServe.get(DefaultFilterMaxPeersToServe), subscriptionTimeout: b.subscriptionTimeout.get(DefaultFilterSubscriptionTimeout), diff --git a/logos_delivery/waku/factory/conf_builder/kademlia_discovery_conf_builder.nim b/logos_delivery/waku/factory/conf_builder/kademlia_discovery_conf_builder.nim index 2810815c6..95e0c368d 100644 --- a/logos_delivery/waku/factory/conf_builder/kademlia_discovery_conf_builder.nim +++ b/logos_delivery/waku/factory/conf_builder/kademlia_discovery_conf_builder.nim @@ -1,6 +1,4 @@ -import logos_delivery/waku/compat/option_valueor -import chronicles, std/options, results -import logos_delivery/waku/discovery/waku_kademlia +import chronicles, results, logos_delivery/waku/discovery/waku_kademlia import chronos import libp2p/[peerid, multiaddress, peerinfo] import libp2p/protocols/kademlia/types @@ -15,16 +13,16 @@ const DefaultServiceLookupInterval* = chronos.seconds(60) type KademliaDiscoveryConfBuilder* = object - enabled*: Option[bool] + enabled*: Opt[bool] bootstrapNodes*: seq[string] - randomLookupInterval*: Option[Duration] - serviceLookupInterval*: Option[Duration] + randomLookupInterval*: Opt[Duration] + serviceLookupInterval*: Opt[Duration] proc init*(T: type KademliaDiscoveryConfBuilder): KademliaDiscoveryConfBuilder = KademliaDiscoveryConfBuilder() proc withEnabled*(b: var KademliaDiscoveryConfBuilder, enabled: bool) = - b.enabled = some(enabled) + b.enabled = Opt.some(enabled) proc withBootstrapNodes*( b: var KademliaDiscoveryConfBuilder, bootstrapNodes: seq[string] @@ -34,22 +32,22 @@ proc withBootstrapNodes*( proc withRandomLookupInterval*( b: var KademliaDiscoveryConfBuilder, interval: Duration ) = - b.randomLookupInterval = some(interval) + b.randomLookupInterval = Opt.some(interval) proc withServiceLookupInterval*( b: var KademliaDiscoveryConfBuilder, interval: Duration ) = - b.serviceLookupInterval = some(interval) + b.serviceLookupInterval = Opt.some(interval) proc build*( b: KademliaDiscoveryConfBuilder -): Result[Option[KademliaDiscoveryConf], string] = +): Result[Opt[KademliaDiscoveryConf], string] = # Explicit disable wins: enabled=false disables regardless of bootstrap nodes. - if b.enabled == some(false): - return ok(none(KademliaDiscoveryConf)) + if b.enabled == Opt.some(false): + return ok(Opt.none(KademliaDiscoveryConf)) # Otherwise enabled if config-enabled or any bootstrap nodes are provided. if not b.enabled.get(DefaultKadEnabled) and b.bootstrapNodes.len == 0: - return ok(none(KademliaDiscoveryConf)) + return ok(Opt.none(KademliaDiscoveryConf)) var parsedNodes: seq[(PeerId, seq[MultiAddress])] for nodeStr in b.bootstrapNodes: @@ -58,7 +56,7 @@ proc build*( parsedNodes.add((peerId, @[ma])) return ok( - some( + Opt.some( KademliaDiscoveryConf( bootstrapNodes: parsedNodes, randomLookupInterval: b.randomLookupInterval.get(DefaultRandomLookupInterval), diff --git a/logos_delivery/waku/factory/conf_builder/metrics_server_conf_builder.nim b/logos_delivery/waku/factory/conf_builder/metrics_server_conf_builder.nim index ec3245f97..b1bf150aa 100644 --- a/logos_delivery/waku/factory/conf_builder/metrics_server_conf_builder.nim +++ b/logos_delivery/waku/factory/conf_builder/metrics_server_conf_builder.nim @@ -1,4 +1,4 @@ -import chronicles, std/[net, options], results +import chronicles, std/net, results import ../waku_conf logScope: @@ -14,36 +14,36 @@ const ## Metrics Server Config Builder ## ################################### type MetricsServerConfBuilder* = object - enabled*: Option[bool] + enabled*: Opt[bool] - httpAddress*: Option[IpAddress] - httpPort*: Option[Port] - logging*: Option[bool] + httpAddress*: Opt[IpAddress] + httpPort*: Opt[Port] + logging*: Opt[bool] proc init*(T: type MetricsServerConfBuilder): MetricsServerConfBuilder = MetricsServerConfBuilder() proc withEnabled*(b: var MetricsServerConfBuilder, enabled: bool) = - b.enabled = some(enabled) + b.enabled = Opt.some(enabled) proc withHttpAddress*(b: var MetricsServerConfBuilder, httpAddress: IpAddress) = - b.httpAddress = some(httpAddress) + b.httpAddress = Opt.some(httpAddress) proc withHttpPort*(b: var MetricsServerConfBuilder, httpPort: Port) = - b.httpPort = some(httpPort) + b.httpPort = Opt.some(httpPort) proc withHttpPort*(b: var MetricsServerConfBuilder, httpPort: uint16) = - b.httpPort = some(Port(httpPort)) + b.httpPort = Opt.some(Port(httpPort)) proc withLogging*(b: var MetricsServerConfBuilder, logging: bool) = - b.logging = some(logging) + b.logging = Opt.some(logging) -proc build*(b: MetricsServerConfBuilder): Result[Option[MetricsServerConf], string] = +proc build*(b: MetricsServerConfBuilder): Result[Opt[MetricsServerConf], string] = if not b.enabled.get(DefaultMetricsEnabled): - return ok(none(MetricsServerConf)) + return ok(Opt.none(MetricsServerConf)) return ok( - some( + Opt.some( MetricsServerConf( httpAddress: b.httpAddress.get(DefaultMetricsHttpAddress), httpPort: b.httpPort.get(DefaultMetricsHttpPort), diff --git a/logos_delivery/waku/factory/conf_builder/mix_conf_builder.nim b/logos_delivery/waku/factory/conf_builder/mix_conf_builder.nim index fb2b17dde..70e3aeeef 100644 --- a/logos_delivery/waku/factory/conf_builder/mix_conf_builder.nim +++ b/logos_delivery/waku/factory/conf_builder/mix_conf_builder.nim @@ -1,6 +1,9 @@ -import logos_delivery/waku/compat/option_valueor -import chronicles, std/options, results -import libp2p/crypto/crypto, libp2p/crypto/curve25519, libp2p_mix/curve25519 +import + chronicles, + results, + libp2p/crypto/crypto, + libp2p/crypto/curve25519, + libp2p_mix/curve25519 import ../waku_conf, logos_delivery/waku/waku_mix logScope: @@ -12,35 +15,39 @@ const DefaultMixEnabled: bool = false ## Mix Config Builder ## ################################## type MixConfBuilder* = object - enabled: Option[bool] - mixKey: Option[string] + enabled: Opt[bool] + mixKey: Opt[string] mixNodes: seq[MixNodePubInfo] proc init*(T: type MixConfBuilder): MixConfBuilder = MixConfBuilder() proc withEnabled*(b: var MixConfBuilder, enabled: bool) = - b.enabled = some(enabled) + b.enabled = Opt.some(enabled) proc withMixKey*(b: var MixConfBuilder, mixKey: string) = - b.mixKey = some(mixKey) + b.mixKey = Opt.some(mixKey) proc withMixNodes*(b: var MixConfBuilder, mixNodes: seq[MixNodePubInfo]) = b.mixNodes = mixNodes -proc build*(b: MixConfBuilder): Result[Option[MixConf], string] = +proc build*(b: MixConfBuilder): Result[Opt[MixConf], string] = if not b.enabled.get(DefaultMixEnabled): - return ok(none[MixConf]()) + return ok(Opt.none(MixConf)) else: if b.mixKey.isSome(): let mixPrivKey = intoCurve25519Key(ncrutils.fromHex(b.mixKey.get())) let mixPubKey = public(mixPrivKey) return ok( - some(MixConf(mixKey: mixPrivKey, mixPubKey: mixPubKey, mixNodes: b.mixNodes)) + Opt.some( + MixConf(mixKey: mixPrivKey, mixPubKey: mixPubKey, mixNodes: b.mixNodes) + ) ) else: let (mixPrivKey, mixPubKey) = generateKeyPair().valueOr: return err("Generate key pair error: " & $error) return ok( - some(MixConf(mixKey: mixPrivKey, mixPubKey: mixPubKey, mixNodes: b.mixNodes)) + Opt.some( + MixConf(mixKey: mixPrivKey, mixPubKey: mixPubKey, mixNodes: b.mixNodes) + ) ) diff --git a/logos_delivery/waku/factory/conf_builder/quic_conf_builder.nim b/logos_delivery/waku/factory/conf_builder/quic_conf_builder.nim index 8233b1581..460b5577f 100644 --- a/logos_delivery/waku/factory/conf_builder/quic_conf_builder.nim +++ b/logos_delivery/waku/factory/conf_builder/quic_conf_builder.nim @@ -1,4 +1,4 @@ -import chronicles, std/[net, options], results +import chronicles, std/net, results import logos_delivery/waku/factory/waku_conf logScope: @@ -11,23 +11,23 @@ const DefaultQuicPort*: Port = Port(60000) ## QUIC Config Builder ## ######################### type QuicConfBuilder* = object - enabled*: Option[bool] - quicPort*: Option[Port] + enabled*: Opt[bool] + quicPort*: Opt[Port] proc init*(T: type QuicConfBuilder): QuicConfBuilder = QuicConfBuilder() proc withEnabled*(b: var QuicConfBuilder, enabled: bool) = - b.enabled = some(enabled) + b.enabled = Opt.some(enabled) proc withQuicPort*(b: var QuicConfBuilder, quicPort: Port) = - b.quicPort = some(quicPort) + b.quicPort = Opt.some(quicPort) proc withQuicPort*(b: var QuicConfBuilder, quicPort: uint16) = - b.quicPort = some(Port(quicPort)) + b.quicPort = Opt.some(Port(quicPort)) -proc build*(b: QuicConfBuilder): Result[Option[QuicConf], string] = +proc build*(b: QuicConfBuilder): Result[Opt[QuicConf], string] = if not b.enabled.get(false): - return ok(none(QuicConf)) + return ok(Opt.none(QuicConf)) - return ok(some(QuicConf(port: b.quicPort.get(DefaultQuicPort)))) + return ok(Opt.some(QuicConf(port: b.quicPort.get(DefaultQuicPort)))) diff --git a/logos_delivery/waku/factory/conf_builder/rate_limit_conf_builder.nim b/logos_delivery/waku/factory/conf_builder/rate_limit_conf_builder.nim index e4a6d260b..204974580 100644 --- a/logos_delivery/waku/factory/conf_builder/rate_limit_conf_builder.nim +++ b/logos_delivery/waku/factory/conf_builder/rate_limit_conf_builder.nim @@ -1,25 +1,23 @@ -import logos_delivery/waku/compat/option_valueor -import chronicles, std/[net, options], results -import logos_delivery/waku/common/rate_limit/setting +import chronicles, std/net, results, logos_delivery/waku/common/rate_limit/setting logScope: topics = "waku conf builder rate limit" type RateLimitConfBuilder* = object - strValue: Option[seq[string]] - objValue: Option[ProtocolRateLimitSettings] + strValue: Opt[seq[string]] + objValue: Opt[ProtocolRateLimitSettings] proc init*(T: type RateLimitConfBuilder): RateLimitConfBuilder = RateLimitConfBuilder() proc withRateLimits*(b: var RateLimitConfBuilder, rateLimits: seq[string]) = - b.strValue = some(rateLimits) + b.strValue = Opt.some(rateLimits) proc withRateLimitsIfNotAssigned*( b: var RateLimitConfBuilder, rateLimits: seq[string] ) = if b.strValue.isNone() or b.strValue.get().len == 0: - b.strValue = some(rateLimits) + b.strValue = Opt.some(rateLimits) proc build*(b: RateLimitConfBuilder): Result[ProtocolRateLimitSettings, string] = if b.strValue.isSome() and b.objValue.isSome(): diff --git a/logos_delivery/waku/factory/conf_builder/rest_server_conf_builder.nim b/logos_delivery/waku/factory/conf_builder/rest_server_conf_builder.nim index 1bf7d17ff..eed1cc532 100644 --- a/logos_delivery/waku/factory/conf_builder/rest_server_conf_builder.nim +++ b/logos_delivery/waku/factory/conf_builder/rest_server_conf_builder.nim @@ -1,4 +1,4 @@ -import chronicles, std/[net, options, sequtils], results +import chronicles, std/[net, sequtils], results import ../waku_conf logScope: @@ -13,41 +13,41 @@ const ## REST Server Config Builder ## ################################ type RestServerConfBuilder* = object - enabled*: Option[bool] + enabled*: Opt[bool] allowOrigin*: seq[string] - listenAddress*: Option[IpAddress] - port*: Option[Port] - admin*: Option[bool] - relayCacheCapacity*: Option[uint32] + listenAddress*: Opt[IpAddress] + port*: Opt[Port] + admin*: Opt[bool] + relayCacheCapacity*: Opt[uint32] proc init*(T: type RestServerConfBuilder): RestServerConfBuilder = RestServerConfBuilder() proc withEnabled*(b: var RestServerConfBuilder, enabled: bool) = - b.enabled = some(enabled) + b.enabled = Opt.some(enabled) proc withAllowOrigin*(b: var RestServerConfBuilder, allowOrigin: seq[string]) = b.allowOrigin = concat(b.allowOrigin, allowOrigin) proc withListenAddress*(b: var RestServerConfBuilder, listenAddress: IpAddress) = - b.listenAddress = some(listenAddress) + b.listenAddress = Opt.some(listenAddress) proc withPort*(b: var RestServerConfBuilder, port: Port) = - b.port = some(port) + b.port = Opt.some(port) proc withPort*(b: var RestServerConfBuilder, port: uint16) = - b.port = some(Port(port)) + b.port = Opt.some(Port(port)) proc withAdmin*(b: var RestServerConfBuilder, admin: bool) = - b.admin = some(admin) + b.admin = Opt.some(admin) proc withRelayCacheCapacity*(b: var RestServerConfBuilder, relayCacheCapacity: uint32) = - b.relayCacheCapacity = some(relayCacheCapacity) + b.relayCacheCapacity = Opt.some(relayCacheCapacity) -proc build*(b: RestServerConfBuilder): Result[Option[RestServerConf], string] = +proc build*(b: RestServerConfBuilder): Result[Opt[RestServerConf], string] = if not b.enabled.get(DefaultRestEnabled): - return ok(none(RestServerConf)) + return ok(Opt.none(RestServerConf)) if b.listenAddress.isNone(): return err("restServer.listenAddress is not specified") @@ -55,7 +55,7 @@ proc build*(b: RestServerConfBuilder): Result[Option[RestServerConf], string] = return err("restServer.relayCacheCapacity is not specified") return ok( - some( + Opt.some( RestServerConf( allowOrigin: b.allowOrigin, listenAddress: b.listenAddress.get(), diff --git a/logos_delivery/waku/factory/conf_builder/rln_relay_conf_builder.nim b/logos_delivery/waku/factory/conf_builder/rln_relay_conf_builder.nim index 8835f4c66..5aad2e7ee 100644 --- a/logos_delivery/waku/factory/conf_builder/rln_relay_conf_builder.nim +++ b/logos_delivery/waku/factory/conf_builder/rln_relay_conf_builder.nim @@ -1,4 +1,4 @@ -import chronicles, std/options, results, stint, stew/endians2 +import chronicles, results, stint, stew/endians2 import ../waku_conf logScope: @@ -13,69 +13,69 @@ const ## RLN Relay Config Builder ## ############################## type RlnConfBuilder* = object - enabled*: Option[bool] - chainId*: Option[UInt256] - ethClientUrls*: Option[seq[string]] - ethContractAddress*: Option[string] - credIndex*: Option[uint] - credPassword*: Option[string] - credPath*: Option[string] - dynamic*: Option[bool] - epochSizeSec*: Option[uint64] - userMessageLimit*: Option[uint64] + enabled*: Opt[bool] + chainId*: Opt[UInt256] + ethClientUrls*: Opt[seq[string]] + ethContractAddress*: Opt[string] + credIndex*: Opt[uint] + credPassword*: Opt[string] + credPath*: Opt[string] + dynamic*: Opt[bool] + epochSizeSec*: Opt[uint64] + userMessageLimit*: Opt[uint64] proc init*(T: type RlnConfBuilder): RlnConfBuilder = RlnConfBuilder() proc withEnabled*(b: var RlnConfBuilder, enabled: bool) = - b.enabled = some(enabled) + b.enabled = Opt.some(enabled) proc withChainId*(b: var RlnConfBuilder, chainId: uint | UInt256) = when chainId is uint: - b.chainId = some(UInt256.fromBytesBE(chainId.toBytesBE())) + b.chainId = Opt.some(UInt256.fromBytesBE(chainId.toBytesBE())) else: - b.chainId = some(chainId) + b.chainId = Opt.some(chainId) proc withCredIndex*(b: var RlnConfBuilder, credIndex: uint) = - b.credIndex = some(credIndex) + b.credIndex = Opt.some(credIndex) proc withCredPassword*(b: var RlnConfBuilder, credPassword: string) = - b.credPassword = some(credPassword) + b.credPassword = Opt.some(credPassword) proc withCredPath*(b: var RlnConfBuilder, credPath: string) = - b.credPath = some(credPath) + b.credPath = Opt.some(credPath) proc withDynamic*(b: var RlnConfBuilder, dynamic: bool) = - b.dynamic = some(dynamic) + b.dynamic = Opt.some(dynamic) proc withEthClientUrls*(b: var RlnConfBuilder, ethClientUrls: seq[string]) = - b.ethClientUrls = some(ethClientUrls) + b.ethClientUrls = Opt.some(ethClientUrls) proc withEthContractAddress*(b: var RlnConfBuilder, ethContractAddress: string) = - b.ethContractAddress = some(ethContractAddress) + b.ethContractAddress = Opt.some(ethContractAddress) proc withEpochSizeSec*(b: var RlnConfBuilder, epochSizeSec: uint64) = - b.epochSizeSec = some(epochSizeSec) + b.epochSizeSec = Opt.some(epochSizeSec) proc withUserMessageLimit*(b: var RlnConfBuilder, userMessageLimit: uint64) = - b.userMessageLimit = some(userMessageLimit) + b.userMessageLimit = Opt.some(userMessageLimit) -proc build*(b: RlnConfBuilder): Result[Option[RlnConf], string] = +proc build*(b: RlnConfBuilder): Result[Opt[RlnConf], string] = if not b.enabled.get(DefaultRlnRelayEnabled): - return ok(none(RlnConf)) + return ok(Opt.none(RlnConf)) if b.chainId.isNone(): return err("RLN Relay Chain Id is not specified") let creds = if b.credPath.isSome() and b.credPassword.isSome(): - some(RlnCreds(path: b.credPath.get(), password: b.credPassword.get())) + Opt.some(RlnCreds(path: b.credPath.get(), password: b.credPassword.get())) elif b.credPath.isSome() and b.credPassword.isNone(): return err("RLN Relay Credential Password is not specified but path is") elif b.credPath.isNone() and b.credPassword.isSome(): return err("RLN Relay Credential Path is not specified but password is") else: - none(RlnCreds) + Opt.none(RlnCreds) if b.dynamic.isNone(): return err("rlnRelay.dynamic is not specified") @@ -84,7 +84,7 @@ proc build*(b: RlnConfBuilder): Result[Option[RlnConf], string] = if b.ethContractAddress.get("") == "": return err("rlnRelay.ethContractAddress is not specified") return ok( - some( + Opt.some( RlnConf( chainId: b.chainId.get(), credIndex: b.credIndex, diff --git a/logos_delivery/waku/factory/conf_builder/store_service_conf_builder.nim b/logos_delivery/waku/factory/conf_builder/store_service_conf_builder.nim index 20507e7d0..abb37e7b8 100644 --- a/logos_delivery/waku/factory/conf_builder/store_service_conf_builder.nim +++ b/logos_delivery/waku/factory/conf_builder/store_service_conf_builder.nim @@ -1,6 +1,4 @@ -import logos_delivery/waku/compat/option_valueor -import std/[options, strutils, sequtils] -import chronicles, results, chronos +import std/[strutils, sequtils], chronicles, results, chronos import ../waku_conf, ./store_sync_conf_builder logScope: @@ -18,35 +16,35 @@ const ## Store Service Config Builder ## ################################## type StoreServiceConfBuilder* = object - enabled*: Option[bool] + enabled*: Opt[bool] - dbMigration*: Option[bool] - dbURl*: Option[string] - dbVacuum*: Option[bool] - maxNumDbConnections*: Option[int] + dbMigration*: Opt[bool] + dbURl*: Opt[string] + dbVacuum*: Opt[bool] + maxNumDbConnections*: Opt[int] retentionPolicies*: seq[string] - resume*: Option[bool] + resume*: Opt[bool] storeSyncConf*: StoreSyncConfBuilder proc init*(T: type StoreServiceConfBuilder): StoreServiceConfBuilder = StoreServiceConfBuilder(storeSyncConf: StoreSyncConfBuilder.init()) proc withEnabled*(b: var StoreServiceConfBuilder, enabled: bool) = - b.enabled = some(enabled) + b.enabled = Opt.some(enabled) proc withDbMigration*(b: var StoreServiceConfBuilder, dbMigration: bool) = - b.dbMigration = some(dbMigration) + b.dbMigration = Opt.some(dbMigration) proc withDbUrl*(b: var StoreServiceConfBuilder, dbUrl: string) = - b.dbURl = some(dbUrl) + b.dbURl = Opt.some(dbUrl) proc withDbVacuum*(b: var StoreServiceConfBuilder, dbVacuum: bool) = - b.dbVacuum = some(dbVacuum) + b.dbVacuum = Opt.some(dbVacuum) proc withMaxNumDbConnections*( b: var StoreServiceConfBuilder, maxNumDbConnections: int ) = - b.maxNumDbConnections = some(maxNumDbConnections) + b.maxNumDbConnections = Opt.some(maxNumDbConnections) proc withRetentionPolicies*(b: var StoreServiceConfBuilder, retentionPolicies: string) = b.retentionPolicies = retentionPolicies @@ -56,7 +54,7 @@ proc withRetentionPolicies*(b: var StoreServiceConfBuilder, retentionPolicies: s .filterIt(it.len > 0) proc withResume*(b: var StoreServiceConfBuilder, resume: bool) = - b.resume = some(resume) + b.resume = Opt.some(resume) const ValidRetentionPolicyTypes = ["time", "capacity", "size"] @@ -85,9 +83,9 @@ proc validateRetentionPolicies(policies: seq[string]): Result[void, string] = return ok() -proc build*(b: StoreServiceConfBuilder): Result[Option[StoreServiceConf], string] = +proc build*(b: StoreServiceConfBuilder): Result[Opt[StoreServiceConf], string] = if not b.enabled.get(DefaultStoreEnabled): - return ok(none(StoreServiceConf)) + return ok(Opt.none(StoreServiceConf)) if b.dbUrl.get("") == "": return err "store.dbUrl is not specified" @@ -104,7 +102,7 @@ proc build*(b: StoreServiceConfBuilder): Result[Option[StoreServiceConf], string b.retentionPolicies return ok( - some( + Opt.some( StoreServiceConf( dbMigration: b.dbMigration.get(DefaultStoreDbMigration), dbURl: b.dbUrl.get(), diff --git a/logos_delivery/waku/factory/conf_builder/store_sync_conf_builder.nim b/logos_delivery/waku/factory/conf_builder/store_sync_conf_builder.nim index 74cbcece0..dca53ab71 100644 --- a/logos_delivery/waku/factory/conf_builder/store_sync_conf_builder.nim +++ b/logos_delivery/waku/factory/conf_builder/store_sync_conf_builder.nim @@ -1,4 +1,4 @@ -import chronicles, std/options, results +import chronicles, results import ../waku_conf logScope: @@ -10,30 +10,30 @@ const DefaultStoreSyncEnabled: bool = false ## Store Sync Config Builder ## ################################## type StoreSyncConfBuilder* = object - enabled*: Option[bool] + enabled*: Opt[bool] - rangeSec*: Option[uint32] - intervalSec*: Option[uint32] - relayJitterSec*: Option[uint32] + rangeSec*: Opt[uint32] + intervalSec*: Opt[uint32] + relayJitterSec*: Opt[uint32] proc init*(T: type StoreSyncConfBuilder): StoreSyncConfBuilder = StoreSyncConfBuilder() proc withEnabled*(b: var StoreSyncConfBuilder, enabled: bool) = - b.enabled = some(enabled) + b.enabled = Opt.some(enabled) proc withRangeSec*(b: var StoreSyncConfBuilder, rangeSec: uint32) = - b.rangeSec = some(rangeSec) + b.rangeSec = Opt.some(rangeSec) proc withIntervalSec*(b: var StoreSyncConfBuilder, intervalSec: uint32) = - b.intervalSec = some(intervalSec) + b.intervalSec = Opt.some(intervalSec) proc withRelayJitterSec*(b: var StoreSyncConfBuilder, relayJitterSec: uint32) = - b.relayJitterSec = some(relayJitterSec) + b.relayJitterSec = Opt.some(relayJitterSec) -proc build*(b: StoreSyncConfBuilder): Result[Option[StoreSyncConf], string] = +proc build*(b: StoreSyncConfBuilder): Result[Opt[StoreSyncConf], string] = if not b.enabled.get(DefaultStoreSyncEnabled): - return ok(none(StoreSyncConf)) + return ok(Opt.none(StoreSyncConf)) if b.rangeSec.isNone(): return err "store.rangeSec is not specified" @@ -43,7 +43,7 @@ proc build*(b: StoreSyncConfBuilder): Result[Option[StoreSyncConf], string] = return err "store.relayJitterSec is not specified" return ok( - some( + Opt.some( StoreSyncConf( rangeSec: b.rangeSec.get(), intervalSec: b.intervalSec.get(), diff --git a/logos_delivery/waku/factory/conf_builder/waku_conf_builder.nim b/logos_delivery/waku/factory/conf_builder/waku_conf_builder.nim index 0eaec4934..469506e55 100644 --- a/logos_delivery/waku/factory/conf_builder/waku_conf_builder.nim +++ b/logos_delivery/waku/factory/conf_builder/waku_conf_builder.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor import libp2p/crypto/crypto, libp2p/multiaddress, - std/[net, options, sequtils], + std/[net, sequtils], stint, chronicles, chronos, @@ -101,14 +100,14 @@ type MaxMessageSize* = object # TODO: Add default to most values so that when a developer uses # the builder, it works out-of-the-box type WakuConfBuilder* = object - nodeKey: Option[crypto.PrivateKey] + nodeKey: Opt[crypto.PrivateKey] - clusterId: Option[uint16] - shardingConf: Option[ShardingConfKind] - numShardsInCluster: Option[uint16] - subscribeShards: Option[seq[uint16]] - protectedShards: Option[seq[ProtectedShard]] - contentTopics: Option[seq[string]] + clusterId: Opt[uint16] + shardingConf: Opt[ShardingConfKind] + numShardsInCluster: Opt[uint16] + subscribeShards: Opt[seq[uint16]] + protectedShards: Opt[seq[ProtectedShard]] + contentTopics: Opt[seq[string]] # Conf builders dnsDiscoveryConf*: DnsDiscoveryConfBuilder @@ -124,54 +123,54 @@ type WakuConfBuilder* = object rateLimitConf*: RateLimitConfBuilder kademliaDiscoveryConf*: KademliaDiscoveryConfBuilder # End conf builders - relay: Option[bool] - lightPush: Option[bool] - peerExchange: Option[bool] - storeSync: Option[bool] - relayPeerExchange: Option[bool] - mix: Option[bool] + relay: Opt[bool] + lightPush: Opt[bool] + peerExchange: Opt[bool] + storeSync: Opt[bool] + relayPeerExchange: Opt[bool] + mix: Opt[bool] # TODO: move within a relayConf - rendezvous: Option[bool] + rendezvous: Opt[bool] - networkPresetConf: Option[NetworkPresetConf] + networkPresetConf: Opt[NetworkPresetConf] staticNodes: seq[string] - remoteStoreNode: Option[string] - remoteLightPushNode: Option[string] - remoteFilterNode: Option[string] - remotePeerExchangeNode: Option[string] + remoteStoreNode: Opt[string] + remoteLightPushNode: Opt[string] + remoteFilterNode: Opt[string] + remotePeerExchangeNode: Opt[string] maxMessageSize: MaxMessageSize - logLevel: Option[logging.LogLevel] - logFormat: Option[logging.LogFormat] + logLevel: Opt[logging.LogLevel] + logFormat: Opt[logging.LogFormat] - natStrategy: Option[string] + natStrategy: Opt[string] - p2pTcpPort: Option[Port] - p2pListenAddress: Option[IpAddress] - portsShift: Option[uint16] - dns4DomainName: Option[string] + p2pTcpPort: Opt[Port] + p2pListenAddress: Opt[IpAddress] + portsShift: Opt[uint16] + dns4DomainName: Opt[string] extMultiAddrs: seq[string] - extMultiAddrsOnly: Option[bool] + extMultiAddrsOnly: Opt[bool] dnsAddrsNameServers: seq[IpAddress] - peerPersistence: Option[bool] - peerStoreCapacity: Option[int] - maxConnections: Option[int] - colocationLimit: Option[int] + peerPersistence: Opt[bool] + peerStoreCapacity: Opt[int] + maxConnections: Opt[int] + colocationLimit: Opt[int] - agentString: Option[string] + agentString: Opt[string] - maxRelayPeers: Option[int] - relayShardedPeerManagement: Option[bool] - relayServiceRatio: Option[string] - circuitRelayClient: Option[bool] + maxRelayPeers: Opt[int] + relayShardedPeerManagement: Opt[bool] + relayServiceRatio: Opt[string] + circuitRelayClient: Opt[bool] - localStoragePath: Option[string] + localStoragePath: Opt[string] proc init*(T: type WakuConfBuilder): WakuConfBuilder = WakuConfBuilder( @@ -191,74 +190,74 @@ proc init*(T: type WakuConfBuilder): WakuConfBuilder = proc withNetworkPresetConf*( b: var WakuConfBuilder, networkPresetConf: NetworkPresetConf ) = - b.networkPresetConf = some(networkPresetConf) + b.networkPresetConf = Opt.some(networkPresetConf) proc withNodeKey*(b: var WakuConfBuilder, nodeKey: crypto.PrivateKey) = - b.nodeKey = some(nodeKey) + b.nodeKey = Opt.some(nodeKey) proc withClusterId*(b: var WakuConfBuilder, clusterId: uint16) = - b.clusterId = some(clusterId) + b.clusterId = Opt.some(clusterId) proc withShardingConf*(b: var WakuConfBuilder, shardingConf: ShardingConfKind) = - b.shardingConf = some(shardingConf) + b.shardingConf = Opt.some(shardingConf) proc withNumShardsInCluster*(b: var WakuConfBuilder, numShardsInCluster: uint16) = - b.numShardsInCluster = some(numShardsInCluster) + b.numShardsInCluster = Opt.some(numShardsInCluster) proc withSubscribeShards*(b: var WakuConfBuilder, shards: seq[uint16]) = - b.subscribeShards = some(shards) + b.subscribeShards = Opt.some(shards) proc withProtectedShards*( b: var WakuConfBuilder, protectedShards: seq[ProtectedShard] ) = - b.protectedShards = some(protectedShards) + b.protectedShards = Opt.some(protectedShards) proc withContentTopics*(b: var WakuConfBuilder, contentTopics: seq[string]) = - b.contentTopics = some(contentTopics) + b.contentTopics = Opt.some(contentTopics) proc withRelay*(b: var WakuConfBuilder, relay: bool) = - b.relay = some(relay) + b.relay = Opt.some(relay) proc withLightPush*(b: var WakuConfBuilder, lightPush: bool) = - b.lightPush = some(lightPush) + b.lightPush = Opt.some(lightPush) proc withStoreSync*(b: var WakuConfBuilder, storeSync: bool) = - b.storeSync = some(storeSync) + b.storeSync = Opt.some(storeSync) proc withPeerExchange*(b: var WakuConfBuilder, peerExchange: bool) = - b.peerExchange = some(peerExchange) + b.peerExchange = Opt.some(peerExchange) proc withRelayPeerExchange*(b: var WakuConfBuilder, relayPeerExchange: bool) = - b.relayPeerExchange = some(relayPeerExchange) + b.relayPeerExchange = Opt.some(relayPeerExchange) proc withRendezvous*(b: var WakuConfBuilder, rendezvous: bool) = - b.rendezvous = some(rendezvous) + b.rendezvous = Opt.some(rendezvous) proc withMix*(builder: var WakuConfBuilder, mix: bool) = - builder.mix = some(mix) + builder.mix = Opt.some(mix) proc withRemoteStoreNode*(b: var WakuConfBuilder, remoteStoreNode: string) = - b.remoteStoreNode = some(remoteStoreNode) + b.remoteStoreNode = Opt.some(remoteStoreNode) proc withRemoteLightPushNode*(b: var WakuConfBuilder, remoteLightPushNode: string) = - b.remoteLightPushNode = some(remoteLightPushNode) + b.remoteLightPushNode = Opt.some(remoteLightPushNode) proc withRemoteFilterNode*(b: var WakuConfBuilder, remoteFilterNode: string) = - b.remoteFilterNode = some(remoteFilterNode) + b.remoteFilterNode = Opt.some(remoteFilterNode) proc withRemotePeerExchangeNode*( b: var WakuConfBuilder, remotePeerExchangeNode: string ) = - b.remotePeerExchangeNode = some(remotePeerExchangeNode) + b.remotePeerExchangeNode = Opt.some(remotePeerExchangeNode) proc withPeerPersistence*(b: var WakuConfBuilder, peerPersistence: bool) = - b.peerPersistence = some(peerPersistence) + b.peerPersistence = Opt.some(peerPersistence) proc withPeerStoreCapacity*(b: var WakuConfBuilder, peerStoreCapacity: int) = - b.peerStoreCapacity = some(peerStoreCapacity) + b.peerStoreCapacity = Opt.some(peerStoreCapacity) proc withMaxConnections*(b: var WakuConfBuilder, maxConnections: int) = - b.maxConnections = some(maxConnections) + b.maxConnections = Opt.some(maxConnections) proc withDnsAddrsNameServers*( b: var WakuConfBuilder, dnsAddrsNameServers: seq[IpAddress] @@ -266,51 +265,51 @@ proc withDnsAddrsNameServers*( b.dnsAddrsNameServers.insert(dnsAddrsNameServers) proc withLogLevel*(b: var WakuConfBuilder, logLevel: logging.LogLevel) = - b.logLevel = some(logLevel) + b.logLevel = Opt.some(logLevel) proc withLogFormat*(b: var WakuConfBuilder, logFormat: logging.LogFormat) = - b.logFormat = some(logFormat) + b.logFormat = Opt.some(logFormat) proc withP2pTcpPort*(b: var WakuConfBuilder, p2pTcpPort: Port) = - b.p2pTcpPort = some(p2pTcpPort) + b.p2pTcpPort = Opt.some(p2pTcpPort) proc withP2pTcpPort*(b: var WakuConfBuilder, p2pTcpPort: uint16) = - b.p2pTcpPort = some(Port(p2pTcpPort)) + b.p2pTcpPort = Opt.some(Port(p2pTcpPort)) proc withPortsShift*(b: var WakuConfBuilder, portsShift: uint16) = - b.portsShift = some(portsShift) + b.portsShift = Opt.some(portsShift) proc withP2pListenAddress*(b: var WakuConfBuilder, p2pListenAddress: IpAddress) = - b.p2pListenAddress = some(p2pListenAddress) + b.p2pListenAddress = Opt.some(p2pListenAddress) proc withExtMultiAddrsOnly*(b: var WakuConfBuilder, extMultiAddrsOnly: bool) = - b.extMultiAddrsOnly = some(extMultiAddrsOnly) + b.extMultiAddrsOnly = Opt.some(extMultiAddrsOnly) proc withDns4DomainName*(b: var WakuConfBuilder, dns4DomainName: string) = - b.dns4DomainName = some(dns4DomainName) + b.dns4DomainName = Opt.some(dns4DomainName) proc withNatStrategy*(b: var WakuConfBuilder, natStrategy: string) = - b.natStrategy = some(natStrategy) + b.natStrategy = Opt.some(natStrategy) proc withAgentString*(b: var WakuConfBuilder, agentString: string) = - b.agentString = some(agentString) + b.agentString = Opt.some(agentString) proc withColocationLimit*(b: var WakuConfBuilder, colocationLimit: int) = - b.colocationLimit = some(colocationLimit) + b.colocationLimit = Opt.some(colocationLimit) proc withRelayServiceRatio*(b: var WakuConfBuilder, relayServiceRatio: string) = - b.relayServiceRatio = some(relayServiceRatio) + b.relayServiceRatio = Opt.some(relayServiceRatio) proc withCircuitRelayClient*(b: var WakuConfBuilder, circuitRelayClient: bool) = - b.circuitRelayClient = some(circuitRelayClient) + b.circuitRelayClient = Opt.some(circuitRelayClient) proc withRelayShardedPeerManagement*( b: var WakuConfBuilder, relayShardedPeerManagement: bool ) = - b.relayShardedPeerManagement = some(relayShardedPeerManagement) + b.relayShardedPeerManagement = Opt.some(relayShardedPeerManagement) proc withLocalStoragePath*(b: var WakuConfBuilder, localStoragePath: string) = - b.localStoragePath = some(localStoragePath) + b.localStoragePath = Opt.some(localStoragePath) proc withExtMultiAddrs*(builder: var WakuConfBuilder, extMultiAddrs: seq[string]) = builder.extMultiAddrs = concat(builder.extMultiAddrs, extMultiAddrs) @@ -339,9 +338,9 @@ proc nodeKey( return ok(nodeKey) proc buildShardingConf( - bShardingConfKind: Option[ShardingConfKind], - bNumShardsInCluster: Option[uint16], - bSubscribeShards: Option[seq[uint16]], + bShardingConfKind: Opt[ShardingConfKind], + bNumShardsInCluster: Opt[uint16], + bSubscribeShards: Opt[seq[uint16]], ): (ShardingConf, seq[uint16]) = case bShardingConfKind.get(DefaultShardingConfKind) of StaticSharding: @@ -354,7 +353,7 @@ proc buildShardingConf( (shardingConf, bSubscribeShards.get(toSeq(0.uint16 .. upperShard))) template checkSetPresetValueToField[T]( - field: var Option[T], presetVal: T, msg: static string + field: var Opt[T], presetVal: T, msg: static string ) = ## Set the field to the preset's value, unless the field is already set ## (explicit wins). Warn iff the field's existing value differs from the @@ -364,7 +363,7 @@ template checkSetPresetValueToField[T]( if field.get() != presetVal: warn msg, used = field.get(), discarded = presetVal else: - field = some(presetVal) + field = Opt.some(presetVal) proc checkAddPresetValueToField[T](field: var seq[T], presetVals: seq[T]) = ## Append the preset's list values to the field's existing list. Lists @@ -481,7 +480,7 @@ proc applyNetworkPresetConf(builder: var WakuConfBuilder) = warn "Failed to process entry nodes from network conf", error = processed.error() proc rejectOverride[T]( - field: Option[T], presetValue: T, msg: string + field: Opt[T], presetValue: T, msg: string ): Result[void, string] = ## Errors with `msg` if `field` is set to anything other than the preset's value. if field.isSome() and field.get() != presetValue: @@ -702,11 +701,11 @@ proc build*( if builder.dns4DomainName.isSome(): let d = builder.dns4DomainName.get() if d.string != "": - some(d) + Opt.some(d) else: - none(string) + Opt.none(string) else: - none(string) + Opt.none(string) var extMultiAddrs: seq[MultiAddress] = @[] for s in builder.extMultiAddrs: diff --git a/logos_delivery/waku/factory/conf_builder/web_socket_conf_builder.nim b/logos_delivery/waku/factory/conf_builder/web_socket_conf_builder.nim index d71ffbc1f..84586258b 100644 --- a/logos_delivery/waku/factory/conf_builder/web_socket_conf_builder.nim +++ b/logos_delivery/waku/factory/conf_builder/web_socket_conf_builder.nim @@ -1,4 +1,4 @@ -import chronicles, std/[net, options], results +import chronicles, std/net, results import logos_delivery/waku/factory/waku_conf logScope: @@ -13,45 +13,45 @@ const ## WebSocket Config Builder ## ############################## type WebSocketConfBuilder* = object - enabled*: Option[bool] - webSocketPort*: Option[Port] - secureEnabled*: Option[bool] - keyPath*: Option[string] - certPath*: Option[string] + enabled*: Opt[bool] + webSocketPort*: Opt[Port] + secureEnabled*: Opt[bool] + keyPath*: Opt[string] + certPath*: Opt[string] proc init*(T: type WebSocketConfBuilder): WebSocketConfBuilder = WebSocketConfBuilder() proc withEnabled*(b: var WebSocketConfBuilder, enabled: bool) = - b.enabled = some(enabled) + b.enabled = Opt.some(enabled) proc withSecureEnabled*(b: var WebSocketConfBuilder, secureEnabled: bool) = - b.secureEnabled = some(secureEnabled) + b.secureEnabled = Opt.some(secureEnabled) if b.secureEnabled.get(): - b.enabled = some(true) # ws must be enabled to use wss + b.enabled = Opt.some(true) # ws must be enabled to use wss proc withWebSocketPort*(b: var WebSocketConfBuilder, webSocketPort: Port) = - b.webSocketPort = some(webSocketPort) + b.webSocketPort = Opt.some(webSocketPort) proc withWebSocketPort*(b: var WebSocketConfBuilder, webSocketPort: uint16) = - b.webSocketPort = some(Port(webSocketPort)) + b.webSocketPort = Opt.some(Port(webSocketPort)) proc withKeyPath*(b: var WebSocketConfBuilder, keyPath: string) = - b.keyPath = some(keyPath) + b.keyPath = Opt.some(keyPath) proc withCertPath*(b: var WebSocketConfBuilder, certPath: string) = - b.certPath = some(certPath) + b.certPath = Opt.some(certPath) -proc build*(b: WebSocketConfBuilder): Result[Option[WebSocketConf], string] = +proc build*(b: WebSocketConfBuilder): Result[Opt[WebSocketConf], string] = if not b.enabled.get(DefaultWebSocketEnabled): - return ok(none(WebSocketConf)) + return ok(Opt.none(WebSocketConf)) if not b.secureEnabled.get(DefaultWebSocketSecureEnabled): return ok( - some( + Opt.some( WebSocketConf( port: b.webSocketPort.get(DefaultWebSocketPort), - secureConf: none(WebSocketSecureConf), + secureConf: Opt.none(WebSocketSecureConf), ) ) ) @@ -62,10 +62,10 @@ proc build*(b: WebSocketConfBuilder): Result[Option[WebSocketConf], string] = return err("WebSocketSecure enabled but cert path is not specified") return ok( - some( + Opt.some( WebSocketConf( port: b.webSocketPort.get(DefaultWebSocketPort), - secureConf: some( + secureConf: Opt.some( WebSocketSecureConf(keyPath: b.keyPath.get(), certPath: b.certPath.get()) ), ) diff --git a/logos_delivery/waku/factory/internal_config.nim b/logos_delivery/waku/factory/internal_config.nim index 45d7f0b4c..0ea11f7c6 100644 --- a/logos_delivery/waku/factory/internal_config.nim +++ b/logos_delivery/waku/factory/internal_config.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor import chronicles, chronos, @@ -6,7 +5,7 @@ import libp2p/crypto/curve25519, libp2p/multiaddress, libp2p/nameresolving/dnsresolver, - std/[options, sequtils, net], + std/[sequtils, net], results import @@ -85,9 +84,9 @@ proc dnsResolve*( proc networkConfiguration*( clusterId: uint16, conf: EndpointConf, - discv5Conf: Option[Discv5Conf], - webSocketConf: Option[WebSocketConf], - quicConf: Option[QuicConf], + discv5Conf: Opt[Discv5Conf], + webSocketConf: Opt[WebSocketConf], + quicConf: Opt[QuicConf], wakuFlags: CapabilitiesBitfield, dnsAddrsNameServers: seq[IpAddress], clientId: string, @@ -97,9 +96,9 @@ proc networkConfiguration*( let (quicEnabled, quicBindPort) = if quicConf.isSome(): let qConf = quicConf.get() - (true, some(qConf.port)) + (true, Opt.some(qConf.port)) else: - (false, none(Port)) + (false, Opt.none(Port)) # NAT-map the QUIC UDP port (placeholder when QUIC off) var (extIp, extTcpPort, extUdpPort) = setupNat( @@ -110,9 +109,9 @@ proc networkConfiguration*( let discv5UdpPort = if discv5Conf.isSome(): - some(discv5Conf.get().udpPort) + Opt.some(discv5Conf.get().udpPort) else: - none(Port) + Opt.none(Port) ## TODO: the NAT setup assumes a manual port mapping configuration if extIp ## config is set. This probably implies adding manual config item for @@ -120,7 +119,7 @@ proc networkConfiguration*( ## manual config, the external port is the same as the bind port. extPort = if (extIp.isSome() or conf.dns4DomainName.isSome()) and extTcpPort.isNone(): - some(tcpBindPort) + Opt.some(tcpBindPort) else: extTcpPort @@ -136,7 +135,7 @@ proc networkConfiguration*( let dns = (await dnsResolve(conf.dns4DomainName.get(), dnsAddrsNameServers)).valueOr: return err($error) # Pass error down the stack - extIp = some(parseIpAddress(dns)) + extIp = Opt.some(parseIpAddress(dns)) except CatchableError: return err("Could not update extIp to resolved DNS IP: " & getCurrentExceptionMsg()) @@ -144,9 +143,9 @@ proc networkConfiguration*( let (wsEnabled, wsBindPort, wssEnabled) = if webSocketConf.isSome: let wsConf = webSocketConf.get() - (true, some(wsConf.port), wsConf.secureConf.isSome) + (true, Opt.some(wsConf.port), wsConf.secureConf.isSome) else: - (false, none(Port), false) + (false, Opt.none(Port), false) # Wrap in none because NetConfig does not have a default constructor # TODO: We could change bindIp in NetConfig to be something less restrictive @@ -167,7 +166,7 @@ proc networkConfiguration*( extQuicPort = extQuicPort, dns4DomainName = conf.dns4DomainName, discv5UdpPort = discv5UdpPort, - wakuFlags = some(wakuFlags), + wakuFlags = Opt.some(wakuFlags), dnsNameServers = dnsAddrsNameServers, ) diff --git a/logos_delivery/waku/factory/node_factory.nim b/logos_delivery/waku/factory/node_factory.nim index daa2e5fd0..5cd06b457 100644 --- a/logos_delivery/waku/factory/node_factory.nim +++ b/logos_delivery/waku/factory/node_factory.nim @@ -1,6 +1,6 @@ -import logos_delivery/waku/compat/option_valueor import - std/[options, sequtils], + results, + std/sequtils, chronicles, chronos, libp2p/peerid, @@ -44,7 +44,7 @@ import ## Peer persistence const PeerPersistenceDbUrl = "peers.db" -proc setupPeerStorage(): Result[Option[WakuPeerStorage], string] = +proc setupPeerStorage(): Result[Opt[WakuPeerStorage], string] = let db = ?SqliteDatabase.new(PeerPersistenceDbUrl) ?peer_store_sqlite_migrations.migrate(db) @@ -52,7 +52,7 @@ proc setupPeerStorage(): Result[Option[WakuPeerStorage], string] = let res = WakuPeerStorage.new(db).valueOr: return err("failed to init peer store" & error) - return ok(some(res)) + return ok(Opt.some(res)) ## Init waku node instance @@ -61,7 +61,7 @@ proc initNode( netConfig: NetConfig, rng: crypto.Rng, record: enr.Record, - peerStore: Option[WakuPeerStorage], + peerStore: Opt[WakuPeerStorage], relay: Relay, dynamicBootstrapNodes: openArray[RemotePeerInfo] = @[], ): Result[WakuNode, string] = @@ -78,9 +78,9 @@ proc initNode( let (secureKey, secureCert) = if conf.webSocketConf.isSome() and conf.webSocketConf.get().secureConf.isSome(): let wssConf = conf.webSocketConf.get().secureConf.get() - (some(wssConf.keyPath), some(wssConf.certPath)) + (Opt.some(wssConf.keyPath), Opt.some(wssConf.certPath)) else: - (none(string), none(string)) + (Opt.none(string), Opt.none(string)) let nameResolver = DnsResolver.new(conf.dnsAddrsNameServers.mapIt(initTAddress(it, Port(53)))) @@ -93,13 +93,13 @@ proc initNode( builder.withNetworkConfiguration(netConfig) builder.withPeerStorage(pStorage, capacity = conf.peerStoreCapacity) builder.withSwitchConfiguration( - maxConnections = some(conf.maxConnections.int), + maxConnections = Opt.some(conf.maxConnections.int), secureKey = secureKey, secureCert = secureCert, nameResolver = nameResolver, sendSignedPeerRecord = conf.relayPeerExchange, # We send our own signed peer record when peer exchange enabled - agentString = some(conf.agentString), + agentString = Opt.some(conf.agentString), ) builder.withColocationLimit(conf.colocationLimit) @@ -252,7 +252,7 @@ proc setupProtocols( warn("Auto sharding is disabled") # Mount relay on all nodes - var peerExchangeHandler = none(RoutingRecordsHandler) + var peerExchangeHandler = Opt.none(RoutingRecordsHandler) if conf.relayPeerExchange: proc handlePeerExchange( peer: PeerId, topic: string, peers: seq[RoutingRecordsPair] @@ -270,7 +270,7 @@ proc setupProtocols( # Peers added are filtered by the peer manager node.peerManager.addPeer(peer, PeerOrigin.PeerExchange) - peerExchangeHandler = some(handlePeerExchange) + peerExchangeHandler = Opt.some(handlePeerExchange) # TODO: when using autosharding, the user should not be expected to pass any shards, but only content topics # Hence, this joint logic should be removed in favour of an either logic: @@ -388,7 +388,7 @@ proc setupProtocols( if conf.peerExchangeService: try: await mountPeerExchange( - node, some(conf.clusterId), node.rateLimitSettings.getSetting(PEEREXCHG) + node, Opt.some(conf.clusterId), node.rateLimitSettings.getSetting(PEEREXCHG) ) except CatchableError: return @@ -479,7 +479,7 @@ proc setupNode*( info "Setting up storage" ## Peer persistence - var peerStore: Option[WakuPeerStorage] + var peerStore: Opt[WakuPeerStorage] if wakuConf.peerPersistence: peerStore = setupPeerStorage().valueOr: error "Setting up storage failed", error = "failed to setup peer store " & error diff --git a/logos_delivery/waku/factory/waku_conf.nim b/logos_delivery/waku/factory/waku_conf.nim index db1a8aa28..614b1318f 100644 --- a/logos_delivery/waku/factory/waku_conf.nim +++ b/logos_delivery/waku/factory/waku_conf.nim @@ -1,5 +1,5 @@ import - std/[net, options, strutils], + std/[net, strutils], chronicles, chronos, libp2p/crypto/crypto, @@ -36,7 +36,7 @@ type WebSocketSecureConf* {.requiresInit.} = object type WebSocketConf* = object port*: Port - secureConf*: Option[WebSocketSecureConf] + secureConf*: Opt[WebSocketSecureConf] type QuicConf* = object port*: Port @@ -61,14 +61,14 @@ type MixConf* = ref object mixPubKey*: Curve25519Key mixnodes*: seq[MixNodePubInfo] -type StoreServiceConf* {.requiresInit.} = object +type StoreServiceConf* = object dbMigration*: bool dbURl*: string dbVacuum*: bool maxNumDbConnections*: int retentionPolicies*: seq[string] resume*: bool - storeSyncConf*: Option[StoreSyncConf] + storeSyncConf*: Opt[StoreSyncConf] type FilterServiceConf* {.requiresInit.} = object maxPeersToServe*: uint32 @@ -78,7 +78,7 @@ type FilterServiceConf* {.requiresInit.} = object type EndpointConf* = object # TODO: make enum natStrategy*: string p2pTcpPort*: Port - dns4DomainName*: Option[string] + dns4DomainName*: Opt[string] p2pListenAddress*: IpAddress extMultiAddrs*: seq[MultiAddress] extMultiAddrsOnly*: bool @@ -87,7 +87,7 @@ type EndpointConf* = object # TODO: make enum ## All information needed by a waku node should be contained ## In this object. A convenient `validate` method enables doing ## sanity checks beyond type enforcement. -## If `Option` is `some` it means the related protocol is enabled. +## If `Opt` is `some` it means the related protocol is enabled. type WakuConf* {.requiresInit.} = ref object # ref because `getRunningNetConfig` modifies it nodeKey*: crypto.PrivateKey @@ -109,17 +109,17 @@ type WakuConf* {.requiresInit.} = ref object rendezvous*: bool circuitRelayClient*: bool - discv5Conf*: Option[Discv5Conf] - dnsDiscoveryConf*: Option[DnsDiscoveryConf] - filterServiceConf*: Option[FilterServiceConf] - storeServiceConf*: Option[StoreServiceConf] - rlnRelayConf*: Option[RlnConf] - restServerConf*: Option[RestServerConf] - metricsServerConf*: Option[MetricsServerConf] - webSocketConf*: Option[WebSocketConf] - quicConf*: Option[QuicConf] - mixConf*: Option[MixConf] - kademliaDiscoveryConf*: Option[KademliaDiscoveryConf] + discv5Conf*: Opt[Discv5Conf] + dnsDiscoveryConf*: Opt[DnsDiscoveryConf] + filterServiceConf*: Opt[FilterServiceConf] + storeServiceConf*: Opt[StoreServiceConf] + rlnRelayConf*: Opt[RlnConf] + restServerConf*: Opt[RestServerConf] + metricsServerConf*: Opt[MetricsServerConf] + webSocketConf*: Opt[WebSocketConf] + quicConf*: Opt[QuicConf] + mixConf*: Opt[MixConf] + kademliaDiscoveryConf*: Opt[KademliaDiscoveryConf] dnsAddrsNameServers*: seq[IpAddress] endpointConf*: EndpointConf @@ -127,10 +127,10 @@ type WakuConf* {.requiresInit.} = ref object # TODO: could probably make it a `PeerRemoteInfo` staticNodes*: seq[string] - remoteStoreNode*: Option[string] - remoteLightPushNode*: Option[string] - remoteFilterNode*: Option[string] - remotePeerExchangeNode*: Option[string] + remoteStoreNode*: Opt[string] + remoteLightPushNode*: Opt[string] + remoteFilterNode*: Opt[string] + remotePeerExchangeNode*: Opt[string] maxMessageSizeBytes*: uint64 @@ -139,7 +139,7 @@ type WakuConf* {.requiresInit.} = ref object peerPersistence*: bool # TODO: should clearly be a uint - peerStoreCapacity*: Option[int] + peerStoreCapacity*: Opt[int] # TODO: should clearly be a uint maxConnections*: int @@ -150,7 +150,7 @@ type WakuConf* {.requiresInit.} = ref object rateLimit*: ProtocolRateLimitSettings # TODO: those could be in a relay conf object - maxRelayPeers*: Option[int] + maxRelayPeers*: Opt[int] relayShardedPeerManagement*: bool # TODO: use proper type relayServiceRatio*: string diff --git a/logos_delivery/waku/incentivization/common.nim b/logos_delivery/waku/incentivization/common.nim index 1fdfb05a9..45686f3fa 100644 --- a/logos_delivery/waku/incentivization/common.nim +++ b/logos_delivery/waku/incentivization/common.nim @@ -1,9 +1,9 @@ -import std/options +import results import logos_delivery/waku/incentivization/rpc proc init*(T: type EligibilityStatus, isEligible: bool): T = if isEligible: - EligibilityStatus(statusCode: uint32(200), statusDesc: some("OK")) + EligibilityStatus(statusCode: uint32(200), statusDesc: Opt.some("OK")) else: - EligibilityStatus(statusCode: uint32(402), statusDesc: some("Payment Required")) + EligibilityStatus(statusCode: uint32(402), statusDesc: Opt.some("Payment Required")) diff --git a/logos_delivery/waku/incentivization/eligibility_manager.nim b/logos_delivery/waku/incentivization/eligibility_manager.nim index ed882f524..298d52ccf 100644 --- a/logos_delivery/waku/incentivization/eligibility_manager.nim +++ b/logos_delivery/waku/incentivization/eligibility_manager.nim @@ -1,5 +1,6 @@ -import logos_delivery/waku/compat/option_valueor -import std/[options, sets], chronos, web3, stew/byteutils, stint, results, chronicles +import std/sets, chronos, web3, stew/byteutils, stint, results + +import chronicles import logos_delivery/waku/incentivization/rpc, tests/waku_rln_relay/utils_onchain diff --git a/logos_delivery/waku/incentivization/reputation_manager.nim b/logos_delivery/waku/incentivization/reputation_manager.nim index 3177c0fdf..cd8e6963b 100644 --- a/logos_delivery/waku/incentivization/reputation_manager.nim +++ b/logos_delivery/waku/incentivization/reputation_manager.nim @@ -1,4 +1,4 @@ -import tables, std/options +import results, tables import ../waku_lightpush_legacy/rpc type @@ -8,26 +8,24 @@ type BadResponse GoodResponse - # Encode reputation indicator as Option[bool]: - # some(true) => GoodRep - # some(false) => BadRep - # none(bool) => unknown / not set + # Encode reputation indicator as Opt[bool]: + # Opt.some(true) => GoodRep + # Opt.some(false) => BadRep + # Opt.none(bool) => unknown / not set ReputationManager* = ref object - reputationOf*: Table[PeerId, Option[bool]] + reputationOf*: Table[PeerId, Opt[bool]] proc init*(T: type ReputationManager): ReputationManager = - return ReputationManager(reputationOf: initTable[PeerId, Option[bool]]()) + return ReputationManager(reputationOf: initTable[PeerId, Opt[bool]]()) -proc setReputation*( - manager: var ReputationManager, peer: PeerId, repValue: Option[bool] -) = +proc setReputation*(manager: var ReputationManager, peer: PeerId, repValue: Opt[bool]) = manager.reputationOf[peer] = repValue -proc getReputation*(manager: ReputationManager, peer: PeerId): Option[bool] = +proc getReputation*(manager: ReputationManager, peer: PeerId): Opt[bool] = if peer in manager.reputationOf: result = manager.reputationOf[peer] else: - result = none(bool) + result = Opt.none(bool) # Evaluate the quality of a PushResponse by checking its isSuccess field proc evaluateResponse*(response: PushResponse): ResponseQuality = @@ -43,6 +41,6 @@ proc updateReputationFromResponse*( let respQuality = evaluateResponse(response) case respQuality of BadResponse: - manager.setReputation(peer, some(false)) # false => BadRep + manager.setReputation(peer, Opt.some(false)) # false => BadRep of GoodResponse: - manager.setReputation(peer, some(true)) # true => GoodRep + manager.setReputation(peer, Opt.some(true)) # true => GoodRep diff --git a/logos_delivery/waku/incentivization/rpc.nim b/logos_delivery/waku/incentivization/rpc.nim index 5223f5b5b..6e54ec201 100644 --- a/logos_delivery/waku/incentivization/rpc.nim +++ b/logos_delivery/waku/incentivization/rpc.nim @@ -1,12 +1,12 @@ -import std/options +import results # Implementing the RFC: # https://github.com/vacp2p/rfc/tree/master/content/docs/rfcs/73 type EligibilityProof* = object - proofOfPayment*: Option[seq[byte]] + proofOfPayment*: Opt[seq[byte]] EligibilityStatus* = object statusCode*: uint32 - statusDesc*: Option[string] + statusDesc*: Opt[string] diff --git a/logos_delivery/waku/incentivization/rpc_codec.nim b/logos_delivery/waku/incentivization/rpc_codec.nim index 9529ddffe..1696bb8c3 100644 --- a/logos_delivery/waku/incentivization/rpc_codec.nim +++ b/logos_delivery/waku/incentivization/rpc_codec.nim @@ -1,5 +1,4 @@ -import std/options -import ../common/protobuf, ./rpc +import results, ../common/protobuf, ./rpc # Codec for EligibilityProof @@ -18,9 +17,9 @@ proc decode*(T: type EligibilityProof, buffer: seq[byte]): ProtobufResult[T] = var epRpc = EligibilityProof() var proofOfPayment = newSeq[byte]() if not ?pb.getField(1, proofOfPayment): - epRpc.proofOfPayment = none(seq[byte]) + epRpc.proofOfPayment = Opt.none(seq[byte]) else: - epRpc.proofOfPayment = some(proofOfPayment) + epRpc.proofOfPayment = Opt.some(proofOfPayment) ok(epRpc) # Codec for EligibilityStatus @@ -45,7 +44,7 @@ proc decode*(T: type EligibilityStatus, buffer: seq[byte]): ProtobufResult[T] = # status description var description = "" if not ?pb.getField(2, description): - esRpc.statusDesc = none(string) + esRpc.statusDesc = Opt.none(string) else: - esRpc.statusDesc = some(description) + esRpc.statusDesc = Opt.some(description) ok(esRpc) diff --git a/logos_delivery/waku/net/net_config.nim b/logos_delivery/waku/net/net_config.nim index 7d1fca9ff..5f1174e98 100644 --- a/logos_delivery/waku/net/net_config.nim +++ b/logos_delivery/waku/net/net_config.nim @@ -1,31 +1,28 @@ {.push raises: [].} -import - std/[options, sequtils, strutils, net], - results, - libp2p/[multiaddress, multicodec, wire] +import std/[sequtils, strutils, net], results, libp2p/[multiaddress, multicodec, wire] import ../../waku/waku_core/peers import ../waku_enr type NetConfig* = object hostAddress*: MultiAddress clusterId*: uint16 - wsHostAddress*: Option[MultiAddress] - quicHostAddress*: Option[MultiAddress] - hostExtAddress*: Option[MultiAddress] - wsExtAddress*: Option[MultiAddress] + wsHostAddress*: Opt[MultiAddress] + quicHostAddress*: Opt[MultiAddress] + hostExtAddress*: Opt[MultiAddress] + wsExtAddress*: Opt[MultiAddress] wssEnabled*: bool - extIp*: Option[IpAddress] - extPort*: Option[Port] - dns4DomainName*: Option[string] + extIp*: Opt[IpAddress] + extPort*: Opt[Port] + dns4DomainName*: Opt[string] dnsNameServers*: seq[IpAddress] announcedAddresses*: seq[MultiAddress] extMultiAddrs*: seq[MultiAddress] enrMultiAddrs*: seq[MultiAddress] - enrIp*: Option[IpAddress] - enrPort*: Option[Port] - discv5UdpPort*: Option[Port] - wakuFlags*: Option[CapabilitiesBitfield] + enrIp*: Opt[IpAddress] + enrPort*: Opt[Port] + discv5UdpPort*: Opt[Port] + wakuFlags*: Opt[CapabilitiesBitfield] bindIp*: IpAddress bindPort*: Port @@ -81,24 +78,24 @@ proc isP2pTcpAddress*(ma: MultiAddress): bool = proc getPorts*( listenAddrs: seq[MultiAddress] -): Result[tuple[tcpPort, websocketPort, quicPort: Option[Port]], string] = - var tcpPort, websocketPort, quicPort = none(Port) +): Result[tuple[tcpPort, websocketPort, quicPort: Opt[Port]], string] = + var tcpPort, websocketPort, quicPort = Opt.none(Port) for a in listenAddrs: if a.isWsAddress(): if websocketPort.isNone(): let wsAddress = initTAddress(a).valueOr: return err("getPorts wsAddr error:" & $error) - websocketPort = some(wsAddress.port) + websocketPort = Opt.some(wsAddress.port) elif a.isQuicAddress(): if quicPort.isNone(): let quicAddress = initTAddress(a).valueOr: return err("getPorts quicAddr error:" & $error) - quicPort = some(quicAddress.port) + quicPort = Opt.some(quicAddress.port) elif tcpPort.isNone(): let tcpAddress = initTAddress(a).valueOr: return err("getPorts tcpAddr error:" & $error) - tcpPort = some(tcpAddress.port) + tcpPort = Opt.some(tcpAddress.port) return ok((tcpPort: tcpPort, websocketPort: websocketPort, quicPort: quicPort)) @@ -114,20 +111,20 @@ proc init*( T: type NetConfig, bindIp: IpAddress, bindPort: Port, - extIp = none(IpAddress), - extPort = none(Port), + extIp = Opt.none(IpAddress), + extPort = Opt.none(Port), extMultiAddrs = newSeq[MultiAddress](), extMultiAddrsOnly: bool = false, - wsBindPort: Option[Port] = some(DefaultWsBindPort), + wsBindPort: Opt[Port] = Opt.some(DefaultWsBindPort), wsEnabled: bool = false, wssEnabled: bool = false, - quicBindPort = none(Port), + quicBindPort = Opt.none(Port), quicEnabled: bool = false, - extQuicPort = none(Port), - dns4DomainName = none(string), - discv5UdpPort = none(Port), + extQuicPort = Opt.none(Port), + dns4DomainName = Opt.none(string), + discv5UdpPort = Opt.none(Port), clusterId: uint16 = 0, - wakuFlags = none(CapabilitiesBitfield), + wakuFlags = Opt.none(CapabilitiesBitfield), dnsNameServers = @[parseIpAddress("1.1.1.1"), parseIpAddress("1.0.0.1")], ): NetConfigResult = ## Initialize and validate waku node network configuration @@ -135,19 +132,19 @@ proc init*( # Bind addresses let hostAddress = ip4TcpEndPoint(bindIp, bindPort) - var wsHostAddress = none(MultiAddress) + var wsHostAddress = Opt.none(MultiAddress) if wsEnabled or wssEnabled: try: - wsHostAddress = some( + wsHostAddress = Opt.some( ip4TcpEndPoint(bindIp, wsbindPort.get(DefaultWsBindPort)) & wsFlag(wssEnabled) ) except CatchableError: return err(getCurrentExceptionMsg()) - var quicHostAddress = none(MultiAddress) + var quicHostAddress = Opt.none(MultiAddress) if quicEnabled: try: - quicHostAddress = some(ipQuicEndPoint(bindIp, quicBindPort.get(bindPort))) + quicHostAddress = Opt.some(ipQuicEndPoint(bindIp, quicBindPort.get(bindPort))) except CatchableError: return err("failed to initialize quic address: " & getCurrentExceptionMsg()) @@ -155,26 +152,26 @@ proc init*( if extIp.isSome(): extIp else: - some(bindIp) + Opt.some(bindIp) let enrPort = if extPort.isSome(): extPort else: - some(bindPort) + Opt.some(bindPort) # Setup external addresses, if available - var hostExtAddress, wsExtAddress, quicExtAddress = none(MultiAddress) + var hostExtAddress, wsExtAddress, quicExtAddress = Opt.none(MultiAddress) if dns4DomainName.isSome(): # Use dns4 for externally announced addresses try: - hostExtAddress = some(dns4TcpEndPoint(dns4DomainName.get(), extPort.get())) + hostExtAddress = Opt.some(dns4TcpEndPoint(dns4DomainName.get(), extPort.get())) except CatchableError: return err(getCurrentExceptionMsg()) if wsHostAddress.isSome(): try: - wsExtAddress = some( + wsExtAddress = Opt.some( dns4TcpEndPoint(dns4DomainName.get(), wsBindPort.get(DefaultWsBindPort)) & wsFlag(wssEnabled) ) @@ -183,7 +180,7 @@ proc init*( if quicHostAddress.isSome(): try: - quicExtAddress = some( + quicExtAddress = Opt.some( dns4QuicEndPoint( dns4DomainName.get(), extQuicPort.get(quicBindPort.get(bindPort)) ) @@ -193,11 +190,11 @@ proc init*( else: # No public domain name, use ext IP if available if extIp.isSome() and extPort.isSome(): - hostExtAddress = some(ip4TcpEndPoint(extIp.get(), extPort.get())) + hostExtAddress = Opt.some(ip4TcpEndPoint(extIp.get(), extPort.get())) if wsHostAddress.isSome(): try: - wsExtAddress = some( + wsExtAddress = Opt.some( ip4TcpEndPoint(extIp.get(), wsBindPort.get(DefaultWsBindPort)) & wsFlag(wssEnabled) ) @@ -206,7 +203,7 @@ proc init*( if quicHostAddress.isSome(): try: - quicExtAddress = some( + quicExtAddress = Opt.some( ipQuicEndPoint(extIp.get(), extQuicPort.get(quicBindPort.get(bindPort))) ) except CatchableError: diff --git a/logos_delivery/waku/node/health_monitor/node_health_monitor.nim b/logos_delivery/waku/node/health_monitor/node_health_monitor.nim index 8a4aadb4b..cfd47dd6a 100644 --- a/logos_delivery/waku/node/health_monitor/node_health_monitor.nim +++ b/logos_delivery/waku/node/health_monitor/node_health_monitor.nim @@ -1,15 +1,16 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[options, sets, random, sequtils, json, strutils, tables], + results, + std/[sets, random, sequtils, json, strutils, tables], chronos, chronicles, libp2p/protocols/rendezvous, libp2p/protocols/pubsub, libp2p/protocols/pubsub/rpc/messages, logos_delivery/api/types, - logos_delivery/api/events/kernel_events, # EventConnectionStatusChange + logos_delivery/api/events/kernel_events, + # EventConnectionStatusChange logos_delivery/waku/[ waku_relay, api/events/health_events, @@ -360,7 +361,7 @@ proc getAllProtocolHealthInfo( proc calculateConnectionState*( protocols: seq[ProtocolHealth], strength: Table[WakuProtocol, int], ## latest connectivity strength (e.g. peer count) for a protocol - dLowOpt: Option[int], ## minimum relay peers for Connected status if in Core (Relay) mode + dLowOpt: Opt[int], ## minimum relay peers for Connected status if in Core (Relay) mode ): ConnectionStatus = var relayCount = 0 @@ -429,9 +430,9 @@ proc calculateConnectionState*( proc calculateConnectionState*(hm: NodeHealthMonitor): ConnectionStatus = let dLow = if isNil(hm.node.wakuRelay): - none(int) + Opt.none(int) else: - some(hm.node.wakuRelay.parameters.dLow) + Opt.some(hm.node.wakuRelay.parameters.dLow) return calculateConnectionState(hm.cachedProtocols, hm.strength, dLow) proc getNodeHealthReport*(hm: NodeHealthMonitor): Future[HealthReport] {.async.} = diff --git a/logos_delivery/waku/node/health_monitor/protocol_health.nim b/logos_delivery/waku/node/health_monitor/protocol_health.nim index 50d9c5572..080ffe1f9 100644 --- a/logos_delivery/waku/node/health_monitor/protocol_health.nim +++ b/logos_delivery/waku/node/health_monitor/protocol_health.nim @@ -1,4 +1,4 @@ -import std/[options, strformat] +import results, std/strformat import ./health_status import logos_delivery/waku/common/waku_protocol @@ -7,42 +7,43 @@ export waku_protocol type ProtocolHealth* = object protocol*: string health*: HealthStatus - desc*: Option[string] ## describes why a certain protocol is considered `NOT_READY` + desc*: Opt[string] ## describes why a certain protocol is considered `NOT_READY` proc notReady*(p: var ProtocolHealth, desc: string): ProtocolHealth = p.health = HealthStatus.NOT_READY - p.desc = some(desc) + p.desc = Opt.some(desc) return p proc ready*(p: var ProtocolHealth): ProtocolHealth = p.health = HealthStatus.READY - p.desc = none[string]() + p.desc = Opt.none(string) return p proc notMounted*(p: var ProtocolHealth): ProtocolHealth = p.health = HealthStatus.NOT_MOUNTED - p.desc = none[string]() + p.desc = Opt.none(string) return p proc synchronizing*(p: var ProtocolHealth): ProtocolHealth = p.health = HealthStatus.SYNCHRONIZING - p.desc = none[string]() + p.desc = Opt.none(string) return p proc initializing*(p: var ProtocolHealth): ProtocolHealth = p.health = HealthStatus.INITIALIZING - p.desc = none[string]() + p.desc = Opt.none(string) return p proc shuttingDown*(p: var ProtocolHealth): ProtocolHealth = p.health = HealthStatus.SHUTTING_DOWN - p.desc = none[string]() + p.desc = Opt.none(string) return p proc `$`*(p: ProtocolHealth): string = - return fmt"protocol: {p.protocol}, health: {p.health}, description: {p.desc}" + let desc = p.desc.get("") + return fmt"protocol: {p.protocol}, health: {p.health}, description: {desc}" proc init*(p: typedesc[ProtocolHealth], protocol: WakuProtocol): ProtocolHealth = return ProtocolHealth( - protocol: $protocol, health: HealthStatus.NOT_MOUNTED, desc: none[string]() + protocol: $protocol, health: HealthStatus.NOT_MOUNTED, desc: Opt.none(string) ) diff --git a/logos_delivery/waku/node/peer_manager/peer_manager.nim b/logos_delivery/waku/node/peer_manager/peer_manager.nim index 5ffc185b0..d0cb5ec14 100644 --- a/logos_delivery/waku/node/peer_manager/peer_manager.nim +++ b/logos_delivery/waku/node/peer_manager/peer_manager.nim @@ -1,10 +1,8 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[ - options, sets, sequtils, times, strformat, strutils, math, random, tables, algorithm - ], + results, + std/[sets, sequtils, times, strformat, strutils, math, random, tables, algorithm], chronos, chronicles, metrics, @@ -241,7 +239,7 @@ proc loadFromStorage(pm: PeerManager) {.gcsafe.} = trace "recovered peers from storage", amount = amount proc selectPeers*( - pm: PeerManager, proto: string, shard: Option[PubsubTopic] = none(PubsubTopic) + pm: PeerManager, proto: string, shard: Opt[PubsubTopic] = Opt.none(PubsubTopic) ): seq[RemotePeerInfo] = ## Returns all peers that support the given protocol (and optionally shard), ## shuffled randomly. Callers can further filter or pick from this list. @@ -263,8 +261,8 @@ proc selectPeers*( return peers proc selectPeer*( - pm: PeerManager, proto: string, shard: Option[PubsubTopic] = none(PubsubTopic) -): Option[RemotePeerInfo] = + pm: PeerManager, proto: string, shard: Opt[PubsubTopic] = Opt.none(PubsubTopic) +): Opt[RemotePeerInfo] = ## Selects a single peer for a given protocol, checking service slots first ## (for non-relay protocols). let peers = pm.selectPeers(proto, shard) @@ -275,23 +273,23 @@ proc selectPeer*( if peers.len > 0: trace "Got peer from peerstore", peerId = peers[0].peerId, multi = peers[0].addrs[0], protocol = proto - return some(peers[0]) + return Opt.some(peers[0]) trace "No peer found for protocol", protocol = proto - return none(RemotePeerInfo) + return Opt.none(RemotePeerInfo) # For other protocols, we select the peer that is slotted for the given protocol pm.serviceSlots.withValue(proto, serviceSlot): trace "Got peer from service slots", peerId = serviceSlot[].peerId, multi = serviceSlot[].addrs[0], protocol = proto - return some(serviceSlot[]) + return Opt.some(serviceSlot[]) # If not slotted, we select a random peer for the given protocol if peers.len > 0: trace "Got peer from peerstore", peerId = peers[0].peerId, multi = peers[0].addrs[0], protocol = proto - return some(peers[0]) + return Opt.some(peers[0]) trace "No peer found for protocol", protocol = proto - return none(RemotePeerInfo) + return Opt.none(RemotePeerInfo) # Adds a peer to the service slots, which is a list of peers that are slotted for a given protocol proc addServicePeer*(pm: PeerManager, remotePeerInfo: RemotePeerInfo, proto: string) = @@ -439,14 +437,14 @@ proc dialPeer( proto: string, dialTimeout = DefaultDialTimeout, source = "api", -): Future[Option[Connection]] {.async.} = +): Future[Opt[Connection]] {.async.} = if peerId == pm.switch.peerInfo.peerId: error "could not dial self" - return none(Connection) + return Opt.none(Connection) if proto == WakuRelayCodec: error "dial shall not be used to connect to relays" - return none(Connection) + return Opt.none(Connection) trace "Dialing peer", wireAddr = addrs, peerId = peerId, proto = proto @@ -455,7 +453,7 @@ proc dialPeer( let res = catch: if await dialFut.withTimeout(dialTimeout): - return some(dialFut.read()) + return Opt.some(dialFut.read()) else: await cancelAndWait(dialFut) @@ -463,7 +461,7 @@ proc dialPeer( trace "Dialing peer failed", peerId = peerId, reason = reasonFailed, proto = proto - return none(Connection) + return Opt.none(Connection) proc dialPeer*( pm: PeerManager, @@ -471,7 +469,7 @@ proc dialPeer*( proto: string, dialTimeout = DefaultDialTimeout, source = "api", -): Future[Option[Connection]] {.async.} = +): Future[Opt[Connection]] {.async.} = # Dial a given peer and add it to the list of known peers # TODO: check peer validity and score before continuing. Limit number of peers to be managed. @@ -492,7 +490,7 @@ proc dialPeer*( proto: string, dialTimeout = DefaultDialTimeout, source = "api", -): Future[Option[Connection]] {.async.} = +): Future[Opt[Connection]] {.async.} = # Dial an existing peer by looking up it's existing addrs in the switch's peerStore # TODO: check peer validity and score before continuing. Limit number of peers to be managed. @@ -735,20 +733,20 @@ proc getNumStreams*(pm: PeerManager, protocol: string): (int, int) = numStreamsOut += 1 return (numStreamsIn, numStreamsOut) -proc getPeerIp(pm: PeerManager, peerId: PeerId): Option[string] = +proc getPeerIp(pm: PeerManager, peerId: PeerId): Opt[string] = if not pm.switch.connManager.getConnections().hasKey(peerId): - return none(string) + return Opt.none(string) let conns = pm.switch.connManager.getConnections().getOrDefault(peerId) if conns.len == 0: - return none(string) + return Opt.none(string) let obAddr = conns[0].connection.observedAddr.valueOr: - return none(string) + return Opt.none(string) # TODO: think if circuit relay ips should be handled differently - return some(obAddr.getHostname()) + return Opt.some(obAddr.getHostname()) #~~~~~~~~~~~~~~~~~# # Event Handling # @@ -1168,8 +1166,8 @@ proc new*( T: type PeerManager, switch: Switch, wakuMetadata: WakuMetadata = nil, - maxRelayPeers: Option[int] = none(int), - maxServicePeers: Option[int] = none(int), + maxRelayPeers: Opt[int] = Opt.none(int), + maxServicePeers: Opt[int] = Opt.none(int), relayServiceRatio: string = "50:50", storage: PeerStorage = nil, initialBackoffInSec = InitialBackoffInSec, diff --git a/logos_delivery/waku/node/peer_manager/peer_store/waku_peer_storage.nim b/logos_delivery/waku/node/peer_manager/peer_store/waku_peer_storage.nim index bea265d31..f52fd6466 100644 --- a/logos_delivery/waku/node/peer_manager/peer_store/waku_peer_storage.nim +++ b/logos_delivery/waku/node/peer_manager/peer_store/waku_peer_storage.nim @@ -1,12 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[sets, options], - results, - sqlite3_abi, - eth/p2p/discoveryv5/enr, - libp2p/protobuf/minprotobuf + std/sets, results, sqlite3_abi, eth/p2p/discoveryv5/enr, libp2p/protobuf/minprotobuf import ../../../common/databases/db_sqlite, ../../../waku_core, @@ -51,7 +46,7 @@ proc decode*(T: type RemotePeerInfo, buffer: seq[byte]): ProtoResult[T] = var record: Record if record.fromBytes(rlpBytes): - storedInfo.enr = some(record) + storedInfo.enr = Opt.some(record) ok(storedInfo) diff --git a/logos_delivery/waku/node/peer_manager/waku_peer_store.nim b/logos_delivery/waku/node/peer_manager/waku_peer_store.nim index e4e48f20e..922ce61f4 100644 --- a/logos_delivery/waku/node/peer_manager/waku_peer_store.nim +++ b/logos_delivery/waku/node/peer_manager/waku_peer_store.nim @@ -1,8 +1,8 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[tables, sequtils, sets, options, strutils], + results, + std/[tables, sequtils, sets, strutils], chronos, chronicles, eth/p2p/discoveryv5/enr, @@ -57,9 +57,9 @@ proc getPeer*(peerStore: PeerStore, peerId: PeerId): RemotePeerInfo = addrs: addresses, enr: if peerStore[ENRBook][peerId] != default(enr.Record): - some(peerStore[ENRBook][peerId]) + Opt.some(peerStore[ENRBook][peerId]) else: - none(enr.Record), + Opt.none(enr.Record), protocols: peerStore[ProtoBook][peerId], shards: peerStore[ShardBook][peerId], agent: peerStore[AgentBook][peerId], @@ -73,9 +73,9 @@ proc getPeer*(peerStore: PeerStore, peerId: PeerId): RemotePeerInfo = numberFailedConn: peerStore[NumberFailedConnBook][peerId], mixPubKey: if peerStore[MixPubKeyBook][peerId] != default(Curve25519Key): - some(peerStore[MixPubKeyBook][peerId]) + Opt.some(peerStore[MixPubKeyBook][peerId]) else: - none(Curve25519Key), + Opt.none(Curve25519Key), ) proc delete*(peerStore: PeerStore, peerId: PeerId) = diff --git a/logos_delivery/waku/node/subscription_manager.nim b/logos_delivery/waku/node/subscription_manager.nim index 2c18a7b5e..2a0d5cbac 100644 --- a/logos_delivery/waku/node/subscription_manager.nim +++ b/logos_delivery/waku/node/subscription_manager.nim @@ -1,5 +1,5 @@ -import logos_delivery/waku/compat/option_valueor -import std/[sequtils, sets, tables, options], chronos, chronicles, metrics, results +import std/[sequtils, sets, tables], chronos, chronicles, metrics, results + import libp2p/[peerid, peerinfo] import brokers/broker_context @@ -479,7 +479,7 @@ proc selectFilterCandidates( # Start with every filter server peer that can serve the shard var allCandidates = self.node.peerManager.selectPeers( - filter_common.WakuFilterSubscribeCodec, some(shard) + filter_common.WakuFilterSubscribeCodec, Opt.some(shard) ) # Remove all already used in this shard or being filter-subscribed for it diff --git a/logos_delivery/waku/node/waku_metrics.nim b/logos_delivery/waku/node/waku_metrics.nim index 30e5e6a2a..6d3eef5a0 100644 --- a/logos_delivery/waku/node/waku_metrics.nim +++ b/logos_delivery/waku/node/waku_metrics.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import chronicles, chronos, metrics, metrics/chronos_httpserver diff --git a/logos_delivery/waku/node/waku_node.nim b/logos_delivery/waku/node/waku_node.nim index db90ab47c..b1448eb2a 100644 --- a/logos_delivery/waku/node/waku_node.nim +++ b/logos_delivery/waku/node/waku_node.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[options, tables, strutils, sequtils, os, net, random, sets], + std/[tables, strutils, sequtils, os, net, random, sets], chronos, chronicles, metrics, @@ -95,7 +94,7 @@ type WakuInfo* = object # NOTE One for simplicity, can extend later as needed listenAddresses*: seq[string] enrUri*: string #multiaddrStrings*: seq[string] - mixPubKey*: Option[string] + mixPubKey*: Opt[string] # NOTE based on Eth2Node in NBC eth2_network.nim WakuNode* = ref object @@ -118,7 +117,7 @@ type wakuPeerExchange*: WakuPeerExchange wakuPeerExchangeClient*: WakuPeerExchangeClient wakuMetadata*: WakuMetadata - wakuAutoSharding*: Option[Sharding] + wakuAutoSharding*: Opt[Sharding] enr*: enr.Record libp2pPing*: Ping rng*: crypto.Rng @@ -154,7 +153,7 @@ import ./subscription_manager proc deduceRelayShard( node: WakuNode, contentTopic: ContentTopic, - pubsubTopicOp: Option[PubsubTopic] = none[PubsubTopic](), + pubsubTopicOp: Opt[PubsubTopic] = Opt.none(PubsubTopic), ): Result[RelayShard, string] = let pubsubTopic = pubsubTopicOp.valueOr: if node.wakuAutoSharding.isNone(): @@ -264,7 +263,7 @@ proc info*(node: WakuNode): WakuInfo = var wakuInfo = WakuInfo(listenAddresses: listenStr, enrUri: enrUri) if not node.wakuMix.isNil(): let keyStr = node.wakuMix.pubKey.to0xHex() - wakuInfo.mixPubKey = some(keyStr) + wakuInfo.mixPubKey = Opt.some(keyStr) info "node info", wakuInfo return wakuInfo @@ -302,7 +301,7 @@ proc mountAutoSharding*( ): Result[void, string] = info "mounting auto sharding", clusterId = clusterId, shardCount = shardCount node.wakuAutoSharding = - some(Sharding(clusterId: clusterId, shardCountGenZero: shardCount)) + Opt.some(Sharding(clusterId: clusterId, shardCountGenZero: shardCount)) return ok() @@ -519,7 +518,7 @@ proc startProvidersAndListeners*(node: WakuNode) = RequestRelayShard.setProvider( node.brokerCtx, proc( - pubsubTopic: Option[PubsubTopic], contentTopic: ContentTopic + pubsubTopic: Opt[PubsubTopic], contentTopic: ContentTopic ): Result[RequestRelayShard, string] = let shard = node.deduceRelayShard(contentTopic, pubsubTopic).valueOr: return err($error) @@ -565,7 +564,7 @@ proc startProvidersAndListeners*(node: WakuNode) = for contentTopic in topics: var topicHealth = TopicHealth.NOT_SUBSCRIBED - let shardResult = node.deduceRelayShard(contentTopic, none[PubsubTopic]()) + let shardResult = node.deduceRelayShard(contentTopic, Opt.none(PubsubTopic)) if shardResult.isOk(): let shardObj = shardResult.get() diff --git a/logos_delivery/waku/node/waku_node/filter.nim b/logos_delivery/waku/node/waku_node/filter.nim index 4b2ea8494..80557a328 100644 --- a/logos_delivery/waku/node/waku_node/filter.nim +++ b/logos_delivery/waku/node/waku_node/filter.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[options, sugar, tables, sequtils, os, net], + std/[sugar, tables, sequtils, os, net], chronos, chronicles, metrics, @@ -54,7 +53,7 @@ proc mountFilter*( maxFilterPeers, maxFilterCriteriaPerPeer, messageCacheTTL, - some(rateLimitSetting), + Opt.some(rateLimitSetting), ) try: @@ -100,7 +99,7 @@ proc mountFilterClient*(node: WakuNode) {.async: (raises: []).} = proc filterSubscribe*( node: WakuNode, - pubsubTopic: Option[PubsubTopic], + pubsubTopic: Opt[PubsubTopic], contentTopics: ContentTopic | seq[ContentTopic], peer: RemotePeerInfo | string, ): Future[FilterSubscribeResult] {.async: (raises: []).} = @@ -184,7 +183,7 @@ proc filterSubscribe*( proc filterUnsubscribe*( node: WakuNode, - pubsubTopic: Option[PubsubTopic], + pubsubTopic: Opt[PubsubTopic], contentTopics: ContentTopic | seq[ContentTopic], peer: RemotePeerInfo | string, ): Future[FilterSubscribeResult] {.async: (raises: []).} = diff --git a/logos_delivery/waku/node/waku_node/lightpush.nim b/logos_delivery/waku/node/waku_node/lightpush.nim index 56d39aae3..ff47796fc 100644 --- a/logos_delivery/waku/node/waku_node/lightpush.nim +++ b/logos_delivery/waku/node/waku_node/lightpush.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[hashes, options, strutils, tables, net], + std/[hashes, strutils, tables, net], chronos, chronicles, metrics, @@ -49,8 +48,9 @@ proc mountLegacyLightPush*( info "mounting legacy lightpush with relay" let pushHandler = legacy_lightpush_protocol.getRelayPushHandler(node.wakuRelay) - node.wakuLegacyLightPush = - WakuLegacyLightPush.new(node.peerManager, node.rng, pushHandler, some(rateLimit)) + node.wakuLegacyLightPush = WakuLegacyLightPush.new( + node.peerManager, node.rng, pushHandler, Opt.some(rateLimit) + ) if node.started: # Node has started already. Let's start lightpush too. @@ -90,7 +90,7 @@ proc internalLegacyLightpushPublish( return await node.wakuLegacyLightPush.handleSelfLightPushRequest(pubsubTopic, message) proc resolveLegacyPubsubTopic( - node: WakuNode, pubsubTopic: Option[PubsubTopic], contentTopic: ContentTopic + node: WakuNode, pubsubTopic: Opt[PubsubTopic], contentTopic: ContentTopic ): Result[PubsubTopic, string] = ## Returns the explicit pubsub topic, else derives it from `contentTopic` ## via autosharding. The legacy wire format requires a pubsub topic and the @@ -107,7 +107,7 @@ proc resolveLegacyPubsubTopic( proc runRlnRefreshRetry( node: WakuNode, - rln: Option[Rln], + rln: Opt[Rln], msgWithProof: WakuMessage, pubsubForPublish: PubsubTopic, peer: RemotePeerInfo, @@ -131,7 +131,7 @@ proc runRlnRefreshRetry( proc legacyLightpushPublish*( node: WakuNode, - pubsubTopic: Option[PubsubTopic], + pubsubTopic: Opt[PubsubTopic], message: WakuMessage, peer: RemotePeerInfo, ): Future[legacy_lightpush_protocol.WakuLightPushResult[string]] {.async, gcsafe.} = @@ -149,9 +149,9 @@ proc legacyLightpushPublish*( let rln = if node.rln.isNil(): - none(Rln) + Opt.none(Rln) else: - some(node.rln) + Opt.some(node.rln) let msgWithProof = (await checkAndGenerateRLNProof(rln, message)).valueOr: return err("failed call checkAndGenerateRLNProof from lightpush: " & error) @@ -178,7 +178,7 @@ proc legacyLightpushPublish*( # TODO: Move to application module (e.g., wakunode2.nim) proc legacyLightpushPublish*( - node: WakuNode, pubsubTopic: Option[PubsubTopic], message: WakuMessage + node: WakuNode, pubsubTopic: Opt[PubsubTopic], message: WakuMessage ): Future[legacy_lightpush_protocol.WakuLightPushResult[string]] {. async, gcsafe, deprecated: "Use 'node.legacyLightpushPublish()' instead" .} = @@ -186,7 +186,7 @@ proc legacyLightpushPublish*( error "failed to publish message as legacy lightpush not available" return err("waku legacy lightpush not available") - var peerOpt: Option[RemotePeerInfo] = none(RemotePeerInfo) + var peerOpt: Opt[RemotePeerInfo] = Opt.none(RemotePeerInfo) if not node.wakuLegacyLightpushClient.isNil(): peerOpt = node.peerManager.selectPeer(WakuLegacyLightPushCodec) if peerOpt.isNone(): @@ -194,7 +194,7 @@ proc legacyLightpushPublish*( error "failed to publish message", err = msg return err(msg) elif not node.wakuLegacyLightPush.isNil(): - peerOpt = some(RemotePeerInfo.init($node.switch.peerInfo.peerId)) + peerOpt = Opt.some(RemotePeerInfo.init($node.switch.peerInfo.peerId)) return await node.legacyLightpushPublish(pubsubTopic, message, peer = peerOpt.get()) @@ -210,7 +210,7 @@ proc mountLightPush*( let pushHandler = lightpush_protocol.getRelayPushHandler(node.wakuRelay) node.wakuLightPush = WakuLightPush.new( - node.peerManager, node.rng, pushHandler, node.wakuAutoSharding, some(rateLimit) + node.peerManager, node.rng, pushHandler, node.wakuAutoSharding, Opt.some(rateLimit) ) if node.started: @@ -259,9 +259,11 @@ proc lightpushPublishHandler( "Waku lightpush with mix not available", ) - return await node.wakuLightpushClient.publish(some(pubsubTopic), message, conn) + return + await node.wakuLightpushClient.publish(Opt.some(pubsubTopic), message, conn) else: - return await node.wakuLightpushClient.publish(some(pubsubTopic), message, peer) + return + await node.wakuLightpushClient.publish(Opt.some(pubsubTopic), message, peer) if not node.wakuLightPush.isNil(): if mixify: @@ -275,14 +277,15 @@ proc lightpushPublishHandler( contentTopic = message.contentTopic, target_peer_id = peer.peerId, msg_hash = msgHash - return - await node.wakuLightPush.handleSelfLightPushRequest(some(pubsubTopic), message) + return await node.wakuLightPush.handleSelfLightPushRequest( + Opt.some(pubsubTopic), message + ) proc lightpushPublish*( node: WakuNode, - pubsubTopic: Option[PubsubTopic], + pubsubTopic: Opt[PubsubTopic], message: WakuMessage, - peerOpt: Option[RemotePeerInfo] = none(RemotePeerInfo), + peerOpt: Opt[RemotePeerInfo] = Opt.none(RemotePeerInfo), mixify: bool = false, ): Future[lightpush_protocol.WakuLightPushResult] {.async.} = if node.wakuLightpushClient.isNil() and node.wakuLightPush.isNil(): @@ -330,9 +333,9 @@ proc lightpushPublish*( let rln = if node.rln.isNil(): - none(Rln) + Opt.none(Rln) else: - some(node.rln) + Opt.some(node.rln) let msgWithProof = (await checkAndGenerateRLNProof(rln, message)).valueOr: return lighpushErrorResult(LightPushErrorCode.OUT_OF_RLN_PROOF, error) diff --git a/logos_delivery/waku/node/waku_node/peer_exchange.nim b/logos_delivery/waku/node/waku_node/peer_exchange.nim index cd6e6146c..b77ef3cac 100644 --- a/logos_delivery/waku/node/waku_node/peer_exchange.nim +++ b/logos_delivery/waku/node/waku_node/peer_exchange.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[options, tables, net], + std/[tables, net], chronos, chronicles, metrics, @@ -33,13 +32,13 @@ logScope: proc mountPeerExchange*( node: WakuNode, - cluster: Option[uint16] = none(uint16), + cluster: Opt[uint16] = Opt.none(uint16), rateLimit: RateLimitSetting = DefaultGlobalNonRelayRateLimit, ) {.async: (raises: []).} = info "mounting waku peer exchange" node.wakuPeerExchange = - WakuPeerExchange.new(node.peerManager, cluster, some(rateLimit)) + WakuPeerExchange.new(node.peerManager, cluster, Opt.some(rateLimit)) if node.started: try: @@ -65,7 +64,7 @@ proc fetchPeerExchangePeers*( return err( ( status_code: PeerExchangeResponseStatusCode.SERVICE_UNAVAILABLE, - status_desc: some("PeerExchangeClient is not mounted"), + status_desc: Opt.some("PeerExchangeClient is not mounted"), ) ) diff --git a/logos_delivery/waku/node/waku_node/ping.nim b/logos_delivery/waku/node/waku_node/ping.nim index e7e011477..20562b8a9 100644 --- a/logos_delivery/waku/node/waku_node/ping.nim +++ b/logos_delivery/waku/node/waku_node/ping.nim @@ -1,8 +1,6 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[options], chronos, chronicles, metrics, diff --git a/logos_delivery/waku/node/waku_node/relay.nim b/logos_delivery/waku/node/waku_node/relay.nim index 77143fabb..715c6e2a9 100644 --- a/logos_delivery/waku/node/waku_node/relay.nim +++ b/logos_delivery/waku/node/waku_node/relay.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[options, net], + std/net, chronos, chronicles, metrics, @@ -45,18 +44,18 @@ logScope: proc getTopicOfSubscriptionEvent( node: WakuNode, subscription: SubscriptionEvent -): Result[(PubsubTopic, Option[ContentTopic]), string] = +): Result[(PubsubTopic, Opt[ContentTopic]), string] = case subscription.kind of ContentSub, ContentUnsub: if node.wakuAutoSharding.isSome(): let shard = node.wakuAutoSharding.get().getShard((subscription.topic)).valueOr: return err("Autosharding error: " & error) - return ok(($shard, some(subscription.topic))) + return ok(($shard, Opt.some(subscription.topic))) else: return err("Static sharding is used, relay subscriptions must specify a pubsub topic") of PubsubSub, PubsubUnsub: - return ok((subscription.topic, none[ContentTopic]())) + return ok((subscription.topic, Opt.none(ContentTopic))) else: return err("Unsupported subscription type in relay getTopicOfSubscriptionEvent") @@ -117,7 +116,7 @@ proc isSubscribed*( return ok(node.wakuRelay.isSubscribed(pubsubTopic)) proc publish*( - node: WakuNode, pubsubTopicOp: Option[PubsubTopic], message: WakuMessage + node: WakuNode, pubsubTopicOp: Opt[PubsubTopic], message: WakuMessage ): Future[Result[int, string]] {.async, gcsafe.} = ## Publish a `WakuMessage`. Pubsub topic contains; none, a named or static shard. ## `WakuMessage` should contain a `contentTopic` field for light node functionality. @@ -154,7 +153,7 @@ proc publish*( proc mountRelay*( node: WakuNode, - peerExchangeHandler = none(RoutingRecordsHandler), + peerExchangeHandler = Opt.none(RoutingRecordsHandler), maxMessageSize = int(DefaultMaxWakuMessageSize), ): Future[Result[void, string]] {.async.} = if not node.wakuRelay.isNil(): @@ -188,8 +187,8 @@ proc mountRelay*( proc setRlnValidator*( node: WakuNode, rlnConf: WakuRlnConfig, - spamHandler = none(SpamHandler), - registrationHandler = none(RegistrationHandler), + spamHandler = Opt.none(SpamHandler), + registrationHandler = Opt.none(RegistrationHandler), ) {.async.} = info "setting rln validator" diff --git a/logos_delivery/waku/node/waku_node/store.nim b/logos_delivery/waku/node/waku_node/store.nim index 189ef9052..92d236a37 100644 --- a/logos_delivery/waku/node/waku_node/store.nim +++ b/logos_delivery/waku/node/waku_node/store.nim @@ -1,8 +1,6 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[options], chronos, chronicles, metrics, @@ -84,8 +82,8 @@ proc toStoreResult(res: waku_archive.ArchiveResult): StoreQueryResult = res.messages.add(kv) for i in 0 ..< response.messages.len: - res.messages[i].message = some(response.messages[i]) - res.messages[i].pubsubTopic = some(response.topics[i]) + res.messages[i].message = Opt.some(response.messages[i]) + res.messages[i].pubsubTopic = Opt.some(response.topics[i]) res.paginationCursor = response.cursor @@ -109,7 +107,7 @@ proc mountStore*( return response.toStoreResult() node.wakuStore = - store.WakuStore.new(node.peerManager, node.rng, requestHandler, some(rateLimit)) + store.WakuStore.new(node.peerManager, node.rng, requestHandler, Opt.some(rateLimit)) if node.started: await node.wakuStore.start() diff --git a/logos_delivery/waku/node/waku_switch.nim b/logos_delivery/waku/node/waku_switch.nim index 0cba923e4..e0983cbee 100644 --- a/logos_delivery/waku/node/waku_switch.nim +++ b/logos_delivery/waku/node/waku_switch.nim @@ -2,7 +2,7 @@ {.push raises: [].} import - std/options, + results, chronos, chronicles, eth/keys, @@ -56,10 +56,10 @@ proc withWssTransport*( ) proc newWakuSwitch*( - privKey = none(crypto.PrivateKey), + privKey = Opt.none(crypto.PrivateKey), address = MultiAddress.init("/ip4/127.0.0.1/tcp/0").tryGet(), - wsAddress = none(MultiAddress), - quicAddress = none(MultiAddress), + wsAddress = Opt.none(MultiAddress), + quicAddress = Opt.none(MultiAddress), secureManagers: openarray[SecureProtocol] = [SecureProtocol.Noise], transportFlags: set[ServerFlags] = {}, rng: crypto.Rng, @@ -74,8 +74,8 @@ proc newWakuSwitch*( wssEnabled: bool = false, secureKeyPath: string = "", secureCertPath: string = "", - agentString = none(string), # defaults to nim-libp2p version - peerStoreCapacity = none(int), # defaults to 1.25 maxConnections + agentString = Opt.none(string), # defaults to nim-libp2p version + peerStoreCapacity = Opt.none(int), # defaults to 1.25 maxConnections rendezvous: RendezVous = nil, circuitRelay: Relay, ): Switch {.raises: [Defect, IOError, LPError].} = diff --git a/logos_delivery/waku/persistency/backend_comm.nim b/logos_delivery/waku/persistency/backend_comm.nim index 193e52825..d680cc282 100644 --- a/logos_delivery/waku/persistency/backend_comm.nim +++ b/logos_delivery/waku/persistency/backend_comm.nim @@ -21,7 +21,7 @@ {.push raises: [].} -import std/[options, strutils] +import std/strutils import chronos, results import brokers/[event_broker, request_broker, broker_context] import brokers/internal/mt_codec @@ -52,6 +52,40 @@ proc mtUnmarshalValue*( value = Key(s) return true +proc mtMarshalValue*[T]( + buf: ptr UncheckedArray[byte], cap: int, value: Opt[T], pos: var int +): bool {.gcsafe.} = + let present = uint8(if value.isSome(): 1 else: 0) + if not mtMarshalValue(buf, cap, present, pos): + return false + if value.isSome(): + return mtMarshalValue(buf, cap, value.get(), pos) + return true + +proc mtUnmarshalValue*[T]( + buf: ptr UncheckedArray[byte], len: int, value: var Opt[T], pos: var int +): bool {.gcsafe.} = + var present: uint8 + if not mtUnmarshalValue(buf, len, present, pos): + return false + if present == 0: + value = Opt.none(T) + return true + var payload: T + if not mtUnmarshalValue(buf, len, payload, pos): + return false + value = Opt.some(payload) + return true + +proc mtMarshalSizeValue*[T](value: Opt[T]): int {.gcsafe.} = + # Opt[T] is generic: for a copyMem-able T the generic size pass takes the + # sizeof() branch (padding included) while our marshal writes flag+payload. + mixin mtMarshalSizeValue + var size = sizeof(uint8) + if value.isSome(): + size += mtMarshalSizeValue(value.get()) + return size + proc mtMarshalValue*( buf: ptr UncheckedArray[byte], cap: int, value: TxOp, pos: var int ): bool {.gcsafe.} = @@ -103,7 +137,7 @@ EventBroker(mt): RequestBroker(mt): type KvGet* = object - value*: Option[seq[byte]] + value*: Opt[seq[byte]] proc signature*(category: string, key: Key): Future[Result[KvGet, string]] {.async.} diff --git a/logos_delivery/waku/persistency/backend_sqlite.nim b/logos_delivery/waku/persistency/backend_sqlite.nim index 95757bc2c..80920b8df 100644 --- a/logos_delivery/waku/persistency/backend_sqlite.nim +++ b/logos_delivery/waku/persistency/backend_sqlite.nim @@ -4,7 +4,6 @@ ## per-job storage threads driven by brokers; phase 2 verifies the SQL ## itself against an in-memory database. -import std/options import results, sqlite3_abi import ../common/databases/[common, db_sqlite] import ./[types, keys, schema] @@ -192,10 +191,10 @@ proc applyOps*(b: KvBackend, ops: openArray[TxOp]): Result[void, PersistencyErro proc getOne*( b: KvBackend, category: string, key: Key -): Result[Option[seq[byte]], PersistencyError] = - var found: Option[seq[byte]] = none(seq[byte]) +): Result[Opt[seq[byte]], PersistencyError] = + var found: Opt[seq[byte]] = Opt.none(seq[byte]) proc onRow(rs: ptr sqlite3_stmt) {.gcsafe, raises: [].} = - found = some(readBlob(rs, 0.cint)) + found = Opt.some(readBlob(rs, 0.cint)) ?b.db.runRead( "SELECT payload FROM kv WHERE category = ? AND key = ? LIMIT 1;", diff --git a/logos_delivery/waku/persistency/backend_thread.nim b/logos_delivery/waku/persistency/backend_thread.nim index 28f328729..0dbee93e6 100644 --- a/logos_delivery/waku/persistency/backend_thread.nim +++ b/logos_delivery/waku/persistency/backend_thread.nim @@ -18,7 +18,7 @@ ## refc ref-count traffic across threads. The arg is freed by ## ``stopStorageThread`` after ``joinThread`` returns. -import std/[options, os] +import std/os import std/atomics # std/concurrency/atomics is the same module in Nim 2.2 import chronos, chronicles, results import brokers/[event_broker, request_broker, broker_context] diff --git a/logos_delivery/waku/persistency/persistency.nim b/logos_delivery/waku/persistency/persistency.nim index d6ac28a1e..46ce7622e 100644 --- a/logos_delivery/waku/persistency/persistency.nim +++ b/logos_delivery/waku/persistency/persistency.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor ## Public facade and main driver types for the persistency library. ## ## ``Persistency`` is the per-root coordinator; one instance owns one @@ -41,7 +40,7 @@ import logos_delivery/waku/compat/option_valueor {.push raises: [].} -import std/[locks, options, os, sequtils, tables] +import std/[locks, os, sequtils, tables] import chronos, chronicles, results import brokers/[event_broker, request_broker, broker_context] import ./[types, keys, payload, backend_comm, backend_thread] @@ -362,7 +361,7 @@ template liftErr(s: string): PersistencyError = proc get*( t: Job, category: string, key: Key -): Future[Result[Option[seq[byte]], PersistencyError]] {.async.} = +): Future[Result[Opt[seq[byte]], PersistencyError]] {.async.} = let r = (await KvGet.request(t.context, category, key)).valueOr: return err(liftErr(error)) return ok(r.value) @@ -409,7 +408,7 @@ proc deleteAcked*( proc get*( p: Persistency, jobId: string, category: string, key: Key -): Future[Result[Option[seq[byte]], PersistencyError]] {.async.} = +): Future[Result[Opt[seq[byte]], PersistencyError]] {.async.} = let j = ?p.job(jobId) return await j.get(category, key) diff --git a/logos_delivery/waku/persistency/sds_persistency.nim b/logos_delivery/waku/persistency/sds_persistency.nim index 3c44f7802..f9d834ff3 100644 --- a/logos_delivery/waku/persistency/sds_persistency.nim +++ b/logos_delivery/waku/persistency/sds_persistency.nim @@ -53,7 +53,7 @@ {.push raises: [].} -import std/[algorithm, options] +import std/algorithm import chronos, chronicles, results import libp2p/protobuf/minprotobuf import ./persistency diff --git a/logos_delivery/waku/requests/node_requests.nim b/logos_delivery/waku/requests/node_requests.nim index a5ca263cd..5d6cebbce 100644 --- a/logos_delivery/waku/requests/node_requests.nim +++ b/logos_delivery/waku/requests/node_requests.nim @@ -1,5 +1,4 @@ -import std/options -import brokers/[request_broker, multi_request_broker] +import results, brokers/[request_broker, multi_request_broker] import logos_delivery/waku/waku_core/[topics] RequestBroker(sync): @@ -7,5 +6,5 @@ RequestBroker(sync): relayShard*: RelayShard proc signature( - pubsubTopic: Option[PubsubTopic], contentTopic: ContentTopic + pubsubTopic: Opt[PubsubTopic], contentTopic: ContentTopic ): Result[RequestRelayShard, string] diff --git a/logos_delivery/waku/rest_api/endpoint/admin/handlers.nim b/logos_delivery/waku/rest_api/endpoint/admin/handlers.nim index f49b75652..a0ba93f5c 100644 --- a/logos_delivery/waku/rest_api/endpoint/admin/handlers.nim +++ b/logos_delivery/waku/rest_api/endpoint/admin/handlers.nim @@ -1,8 +1,9 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import std/[sets, strformat, sequtils, tables], + std/options, + results, chronicles, chronicles/topics_registry, json_serialization, @@ -70,7 +71,7 @@ proc tuplesToWakuPeers(peers: var WakuPeers, peersTup: seq[PeerProtocolTuple]) = ) proc populateAdminPeerInfo( - peers: var WakuPeers, node: WakuNode, codec: Option[string] = none[string]() + peers: var WakuPeers, node: WakuNode, codec: Opt[string] = Opt.none(string) ) = if codec.isNone(): peers = node.peerManager.switch.peerStore.peers().mapIt(WakuPeer.init(it)) @@ -96,7 +97,7 @@ proc populateAdminPeerInfoForCodecs(node: WakuNode, codecs: seq[string]): WakuPe var peers: WakuPeers = @[] for codec in codecs: - populateAdminPeerInfo(peers, node, some(codec)) + populateAdminPeerInfo(peers, node, Opt.some(codec)) return peers diff --git a/logos_delivery/waku/rest_api/endpoint/admin/types.nim b/logos_delivery/waku/rest_api/endpoint/admin/types.nim index 846f5a2fa..4af1bdf7b 100644 --- a/logos_delivery/waku/rest_api/endpoint/admin/types.nim +++ b/logos_delivery/waku/rest_api/endpoint/admin/types.nim @@ -3,7 +3,7 @@ import chronicles, json_serialization, - json_serialization/std/options, + json_serialization/pkg/results, json_serialization/lexer, results, libp2p/protocols/pubsub/pubsubpeer @@ -17,7 +17,7 @@ type WakuPeer* = object connected*: Connectedness agent*: string origin*: PeerOrigin - score*: Option[float64] + score*: Opt[float64] type WakuPeers* = seq[WakuPeer] @@ -97,44 +97,44 @@ proc readValue*( reader: var JsonReader[RestJson], value: var WakuPeer ) {.gcsafe, raises: [SerializationError, IOError].} = var - multiaddr: Option[string] - protocols: Option[seq[string]] - shards: Option[seq[uint16]] - connected: Option[Connectedness] - agent: Option[string] - origin: Option[PeerOrigin] - score: Option[float64] + multiaddr: Opt[string] + protocols: Opt[seq[string]] + shards: Opt[seq[uint16]] + connected: Opt[Connectedness] + agent: Opt[string] + origin: Opt[PeerOrigin] + score: Opt[float64] for fieldName in readObjectFields(reader): case fieldName of "multiaddr": if multiaddr.isSome(): reader.raiseUnexpectedField("Multiple `multiaddr` fields found", "WakuPeer") - multiaddr = some(reader.readValue(string)) + multiaddr = Opt.some(reader.readValue(string)) of "protocols": if protocols.isSome(): reader.raiseUnexpectedField("Multiple `protocols` fields found", "WakuPeer") - protocols = some(reader.readValue(seq[string])) + protocols = Opt.some(reader.readValue(seq[string])) of "shards": if shards.isSome(): reader.raiseUnexpectedField("Multiple `shards` fields found", "WakuPeer") - shards = some(reader.readValue(seq[uint16])) + shards = Opt.some(reader.readValue(seq[uint16])) of "connected": if connected.isSome(): reader.raiseUnexpectedField("Multiple `connected` fields found", "WakuPeer") - connected = some(reader.readValue(Connectedness)) + connected = Opt.some(reader.readValue(Connectedness)) of "agent": if agent.isSome(): reader.raiseUnexpectedField("Multiple `agent` fields found", "WakuPeer") - agent = some(reader.readValue(string)) + agent = Opt.some(reader.readValue(string)) of "origin": if origin.isSome(): reader.raiseUnexpectedField("Multiple `origin` fields found", "WakuPeer") - origin = some(reader.readValue(PeerOrigin)) + origin = Opt.some(reader.readValue(PeerOrigin)) of "score": if score.isSome(): reader.raiseUnexpectedField("Multiple `score` fields found", "WakuPeer") - score = some(reader.readValue(float64)) + score = Opt.some(reader.readValue(float64)) else: unrecognizedFieldWarning(value) @@ -170,19 +170,19 @@ proc readValue*( reader: var JsonReader[RestJson], value: var PeersOfShard ) {.gcsafe, raises: [SerializationError, IOError].} = var - shard: Option[uint16] - peers: Option[WakuPeers] + shard: Opt[uint16] + peers: Opt[WakuPeers] for fieldName in readObjectFields(reader): case fieldName of "shard": if shard.isSome(): reader.raiseUnexpectedField("Multiple `shard` fields found", "PeersOfShard") - shard = some(reader.readValue(uint16)) + shard = Opt.some(reader.readValue(uint16)) of "peers": if peers.isSome(): reader.raiseUnexpectedField("Multiple `peers` fields found", "PeersOfShard") - peers = some(reader.readValue(WakuPeers)) + peers = Opt.some(reader.readValue(WakuPeers)) else: unrecognizedFieldWarning(value) @@ -198,8 +198,8 @@ proc readValue*( reader: var JsonReader[RestJson], value: var FilterTopic ) {.gcsafe, raises: [SerializationError, IOError].} = var - pubsubTopic: Option[string] - contentTopic: Option[string] + pubsubTopic: Opt[string] + contentTopic: Opt[string] for fieldName in readObjectFields(reader): case fieldName @@ -208,13 +208,13 @@ proc readValue*( reader.raiseUnexpectedField( "Multiple `pubsubTopic` fields found", "FilterTopic" ) - pubsubTopic = some(reader.readValue(string)) + pubsubTopic = Opt.some(reader.readValue(string)) of "contentTopic": if contentTopic.isSome(): reader.raiseUnexpectedField( "Multiple `contentTopic` fields found", "FilterTopic" ) - contentTopic = some(reader.readValue(string)) + contentTopic = Opt.some(reader.readValue(string)) else: unrecognizedFieldWarning(value) @@ -230,8 +230,8 @@ proc readValue*( reader: var JsonReader[RestJson], value: var FilterSubscription ) {.gcsafe, raises: [SerializationError, IOError].} = var - peerId: Option[string] - filterCriteria: Option[seq[FilterTopic]] + peerId: Opt[string] + filterCriteria: Opt[seq[FilterTopic]] for fieldName in readObjectFields(reader): case fieldName @@ -240,13 +240,13 @@ proc readValue*( reader.raiseUnexpectedField( "Multiple `peerId` fields found", "FilterSubscription" ) - peerId = some(reader.readValue(string)) + peerId = Opt.some(reader.readValue(string)) of "filterCriteria": if filterCriteria.isSome(): reader.raiseUnexpectedField( "Multiple `filterCriteria` fields found", "FilterSubscription" ) - filterCriteria = some(reader.readValue(seq[FilterTopic])) + filterCriteria = Opt.some(reader.readValue(seq[FilterTopic])) else: unrecognizedFieldWarning(value) @@ -284,7 +284,7 @@ proc init*(T: type WakuPeer, peerInfo: RemotePeerInfo): WakuPeer = connected: peerInfo.connectedness, agent: peerInfo.agent, origin: peerInfo.origin, - score: none(float64), + score: Opt.none(float64), ) proc init*(T: type WakuPeer, pubsubPeer: PubSubPeer, pm: PeerManager): WakuPeer = @@ -296,7 +296,7 @@ proc init*(T: type WakuPeer, pubsubPeer: PubSubPeer, pm: PeerManager): WakuPeer connected: peerInfo.connectedness, agent: peerInfo.agent, origin: peerInfo.origin, - score: some(pubsubPeer.score), + score: Opt.some(pubsubPeer.score), ) proc add*( diff --git a/logos_delivery/waku/rest_api/endpoint/builder.nim b/logos_delivery/waku/rest_api/endpoint/builder.nim index f9bc1da89..2914833d9 100644 --- a/logos_delivery/waku/rest_api/endpoint/builder.nim +++ b/logos_delivery/waku/rest_api/endpoint/builder.nim @@ -1,7 +1,6 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} -import net, tables +import results, net, tables import presto import logos_delivery/waku/waku_node, @@ -82,9 +81,9 @@ proc startRestServerEssentials*( let allowedOrigin = if len(conf.allowOrigin) > 0: - some(conf.allowOrigin.join(",")) + Opt.some(conf.allowOrigin.join(",")) else: - none(string) + Opt.none(string) let address = conf.listenAddress let port = conf.port @@ -179,9 +178,9 @@ proc startRestServerProtocolSupport*( let filterDiscoHandler = if not wakuDiscv5.isNil(): - some(defaultDiscoveryHandler(wakuDiscv5, Filter)) + Opt.some(defaultDiscoveryHandler(wakuDiscv5, Filter)) else: - none(DiscoveryHandler) + Opt.none(DiscoveryHandler) rest_filter_endpoint.installFilterRestApiHandlers( router, node, filterCache, filterDiscoHandler @@ -192,9 +191,9 @@ proc startRestServerProtocolSupport*( ## Store REST API let storeDiscoHandler = if not wakuDiscv5.isNil(): - some(defaultDiscoveryHandler(wakuDiscv5, Store)) + Opt.some(defaultDiscoveryHandler(wakuDiscv5, Store)) else: - none(DiscoveryHandler) + Opt.none(DiscoveryHandler) rest_store_endpoint.installStoreApiHandlers(router, node, storeDiscoHandler) @@ -206,9 +205,9 @@ proc startRestServerProtocolSupport*( (lightPushEnabled and node.wakuLegacyLightPush != nil and node.wakuRelay != nil): let lightDiscoHandler = if not wakuDiscv5.isNil(): - some(defaultDiscoveryHandler(wakuDiscv5, Lightpush)) + Opt.some(defaultDiscoveryHandler(wakuDiscv5, Lightpush)) else: - none(DiscoveryHandler) + Opt.none(DiscoveryHandler) rest_legacy_lightpush_endpoint.installLightPushRequestHandler( router, node, lightDiscoHandler diff --git a/logos_delivery/waku/rest_api/endpoint/debug/client.nim b/logos_delivery/waku/rest_api/endpoint/debug/client.nim index c2d588197..7249c767d 100644 --- a/logos_delivery/waku/rest_api/endpoint/debug/client.nim +++ b/logos_delivery/waku/rest_api/endpoint/debug/client.nim @@ -1,7 +1,7 @@ {.push raises: [].} import - chronicles, json_serialization, json_serialization/std/options, presto/[route, client] + chronicles, json_serialization, json_serialization/pkg/results, presto/[route, client] import ../serdes, ../rest_serdes, ./types export types diff --git a/logos_delivery/waku/rest_api/endpoint/debug/handlers.nim b/logos_delivery/waku/rest_api/endpoint/debug/handlers.nim index ee63511f5..43b6fbbf1 100644 --- a/logos_delivery/waku/rest_api/endpoint/debug/handlers.nim +++ b/logos_delivery/waku/rest_api/endpoint/debug/handlers.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import chronicles, json_serialization, presto/route diff --git a/logos_delivery/waku/rest_api/endpoint/debug/types.nim b/logos_delivery/waku/rest_api/endpoint/debug/types.nim index c03af0675..d8d0f375d 100644 --- a/logos_delivery/waku/rest_api/endpoint/debug/types.nim +++ b/logos_delivery/waku/rest_api/endpoint/debug/types.nim @@ -1,6 +1,6 @@ {.push raises: [].} -import chronicles, json_serialization, json_serialization/std/options +import results, chronicles, json_serialization, json_serialization/pkg/results import ../../../waku_node, ../serdes import std/typetraits @@ -8,15 +8,15 @@ import std/typetraits type DebugWakuInfo* = object listenAddresses*: seq[string] - enrUri*: Option[string] - mixPubKey*: Option[string] + enrUri*: Opt[string] + mixPubKey*: Opt[string] #### Type conversion proc toDebugWakuInfo*(nodeInfo: WakuInfo): DebugWakuInfo = DebugWakuInfo( listenAddresses: nodeInfo.listenAddresses, - enrUri: some(nodeInfo.enrUri), + enrUri: Opt.some(nodeInfo.enrUri), mixPubKey: nodeInfo.mixPubKey, ) @@ -37,8 +37,8 @@ proc readValue*( reader: var JsonReader[RestJson], value: var DebugWakuInfo ) {.raises: [SerializationError, IOError].} = var - listenAddresses: Option[seq[string]] - enrUri: Option[string] + listenAddresses: Opt[seq[string]] + enrUri: Opt[string] for fieldName in readObjectFields(reader): case fieldName @@ -47,17 +47,17 @@ proc readValue*( reader.raiseUnexpectedField( "Multiple `listenAddresses` fields found", "DebugWakuInfo" ) - listenAddresses = some(reader.readValue(seq[string])) + listenAddresses = Opt.some(reader.readValue(seq[string])) of "enrUri": if enrUri.isSome(): reader.raiseUnexpectedField("Multiple `enrUri` fields found", "DebugWakuInfo") - enrUri = some(reader.readValue(string)) + enrUri = Opt.some(reader.readValue(string)) of "mixPubKey": if value.mixPubKey.isSome(): reader.raiseUnexpectedField( "Multiple `mixPubKey` fields found", "DebugWakuInfo" ) - value.mixPubKey = some(reader.readValue(string)) + value.mixPubKey = Opt.some(reader.readValue(string)) else: unrecognizedFieldWarning(value) diff --git a/logos_delivery/waku/rest_api/endpoint/filter/client.nim b/logos_delivery/waku/rest_api/endpoint/filter/client.nim index db1a6895e..de2b1bebe 100644 --- a/logos_delivery/waku/rest_api/endpoint/filter/client.nim +++ b/logos_delivery/waku/rest_api/endpoint/filter/client.nim @@ -5,7 +5,7 @@ import stew/byteutils, chronicles, json_serialization, - json_serialization/std/options, + json_serialization/pkg/results, presto/[route, client, common] import ../../../common/base64, ../serdes, ../rest_serdes, ./types diff --git a/logos_delivery/waku/rest_api/endpoint/filter/handlers.nim b/logos_delivery/waku/rest_api/endpoint/filter/handlers.nim index 60a16dfb3..fc8149999 100644 --- a/logos_delivery/waku/rest_api/endpoint/filter/handlers.nim +++ b/logos_delivery/waku/rest_api/endpoint/filter/handlers.nim @@ -1,13 +1,14 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import std/strformat, std/sequtils, + std/options, + results, stew/byteutils, chronicles, json_serialization, - json_serialization/std/options, + json_serialization/pkg/results, presto/route, presto/common import @@ -167,7 +168,7 @@ proc filterPostPutSubscriptionRequestHandler( node: WakuNode, contentBody: Option[ContentBody], cache: MessageCache, - discHandler: Option[DiscoveryHandler] = none(DiscoveryHandler), + discHandler: Opt[DiscoveryHandler] = Opt.none(DiscoveryHandler), ): Future[RestApiResponse] {.async.} = ## handles any filter subscription requests, adds or modifies. @@ -208,7 +209,7 @@ proc installFilterPostSubscriptionsHandler( router: var RestRouter, node: WakuNode, cache: MessageCache, - discHandler: Option[DiscoveryHandler] = none(DiscoveryHandler), + discHandler: Opt[DiscoveryHandler] = Opt.none(DiscoveryHandler), ) = router.api(MethodPost, ROUTE_FILTER_SUBSCRIPTIONS) do( contentBody: Option[ContentBody] @@ -224,7 +225,7 @@ proc installFilterPutSubscriptionsHandler( router: var RestRouter, node: WakuNode, cache: MessageCache, - discHandler: Option[DiscoveryHandler] = none(DiscoveryHandler), + discHandler: Opt[DiscoveryHandler] = Opt.none(DiscoveryHandler), ) = router.api(MethodPut, ROUTE_FILTER_SUBSCRIPTIONS) do( contentBody: Option[ContentBody] @@ -240,7 +241,7 @@ proc installFilterDeleteSubscriptionsHandler( router: var RestRouter, node: WakuNode, cache: MessageCache, - discHandler: Option[DiscoveryHandler] = none(DiscoveryHandler), + discHandler: Opt[DiscoveryHandler] = Opt.none(DiscoveryHandler), ) = router.api(MethodDelete, ROUTE_FILTER_SUBSCRIPTIONS) do( contentBody: Option[ContentBody] @@ -288,7 +289,7 @@ proc installFilterDeleteAllSubscriptionsHandler( router: var RestRouter, node: WakuNode, cache: MessageCache, - discHandler: Option[DiscoveryHandler] = none(DiscoveryHandler), + discHandler: Opt[DiscoveryHandler] = Opt.none(DiscoveryHandler), ) = router.api(MethodDelete, ROUTE_FILTER_ALL_SUBSCRIPTIONS) do( contentBody: Option[ContentBody] @@ -335,7 +336,7 @@ const ROUTE_FILTER_SUBSCRIBER_PING* = "/filter/v2/subscriptions/{requestId}" proc installFilterPingSubscriberHandler( router: var RestRouter, node: WakuNode, - discHandler: Option[DiscoveryHandler] = none(DiscoveryHandler), + discHandler: Opt[DiscoveryHandler] = Opt.none(DiscoveryHandler), ) = router.api(MethodGet, ROUTE_FILTER_SUBSCRIBER_PING) do( requestId: string @@ -402,7 +403,7 @@ proc installFilterRestApiHandlers*( router: var RestRouter, node: WakuNode, cache: MessageCache, - discHandler: Option[DiscoveryHandler] = none(DiscoveryHandler), + discHandler: Opt[DiscoveryHandler] = Opt.none(DiscoveryHandler), ) = installFilterPingSubscriberHandler(router, node, discHandler) installFilterPostSubscriptionsHandler(router, node, cache, discHandler) diff --git a/logos_delivery/waku/rest_api/endpoint/filter/types.nim b/logos_delivery/waku/rest_api/endpoint/filter/types.nim index 6d18e7f6e..675423daf 100644 --- a/logos_delivery/waku/rest_api/endpoint/filter/types.nim +++ b/logos_delivery/waku/rest_api/endpoint/filter/types.nim @@ -1,10 +1,11 @@ {.push raises: [].} import + results, std/[sets, strformat], chronicles, json_serialization, - json_serialization/std/options, + json_serialization/pkg/results, presto/[route, client, common], libp2p/peerid import ../../../common/base64, ../../../waku_core, ../serdes @@ -13,17 +14,17 @@ import ../../../common/base64, ../../../waku_core, ../serdes type FilterWakuMessage* = object payload*: Base64String - contentTopic*: Option[ContentTopic] - version*: Option[Natural] - timestamp*: Option[int64] - meta*: Option[Base64String] - ephemeral*: Option[bool] + contentTopic*: Opt[ContentTopic] + version*: Opt[Natural] + timestamp*: Opt[int64] + meta*: Opt[Base64String] + ephemeral*: Opt[bool] type FilterGetMessagesResponse* = seq[FilterWakuMessage] type FilterLegacySubscribeRequest* = object # Subscription request for legacy filter support - pubsubTopic*: Option[PubSubTopic] + pubsubTopic*: Opt[PubSubTopic] contentFilters*: seq[ContentTopic] type FilterSubscriberPing* = object @@ -31,12 +32,12 @@ type FilterSubscriberPing* = object type FilterSubscribeRequest* = object requestId*: string - pubsubTopic*: Option[PubSubTopic] + pubsubTopic*: Opt[PubSubTopic] contentFilters*: seq[ContentTopic] type FilterUnsubscribeRequest* = object requestId*: string - pubsubTopic*: Option[PubSubTopic] + pubsubTopic*: Opt[PubSubTopic] contentFilters*: seq[ContentTopic] type FilterUnsubscribeAllRequest* = object @@ -51,15 +52,15 @@ type FilterSubscriptionResponse* = object proc toFilterWakuMessage*(msg: WakuMessage): FilterWakuMessage = FilterWakuMessage( payload: base64.encode(msg.payload), - contentTopic: some(msg.contentTopic), - version: some(Natural(msg.version)), - timestamp: some(msg.timestamp), + contentTopic: Opt.some(msg.contentTopic), + version: Opt.some(Natural(msg.version)), + timestamp: Opt.some(msg.timestamp), meta: if msg.meta.len > 0: - some(base64.encode(msg.meta)) + Opt.some(base64.encode(msg.meta)) else: - none(Base64String), - ephemeral: some(msg.ephemeral), + Opt.none(Base64String), + ephemeral: Opt.some(msg.ephemeral), ) proc toWakuMessage*(msg: FilterWakuMessage, version = 0): Result[WakuMessage, string] = @@ -155,12 +156,12 @@ proc readValue*( reader: var JsonReader[RestJson], value: var FilterWakuMessage ) {.raises: [SerializationError, IOError].} = var - payload = none(Base64String) - contentTopic = none(ContentTopic) - version = none(Natural) - timestamp = none(int64) - meta = none(Base64String) - ephemeral = none(bool) + payload = Opt.none(Base64String) + contentTopic = Opt.none(ContentTopic) + version = Opt.none(Natural) + timestamp = Opt.none(int64) + meta = Opt.none(Base64String) + ephemeral = Opt.none(bool) var keys = initHashSet[string]() for fieldName in readObjectFields(reader): @@ -175,17 +176,17 @@ proc readValue*( case fieldName of "payload": - payload = some(reader.readValue(Base64String)) + payload = Opt.some(reader.readValue(Base64String)) of "contentTopic": - contentTopic = some(reader.readValue(ContentTopic)) + contentTopic = Opt.some(reader.readValue(ContentTopic)) of "version": - version = some(reader.readValue(Natural)) + version = Opt.some(reader.readValue(Natural)) of "timestamp": - timestamp = some(reader.readValue(int64)) + timestamp = Opt.some(reader.readValue(int64)) of "meta": - meta = some(reader.readValue(Base64String)) + meta = Opt.some(reader.readValue(Base64String)) of "ephemeral": - ephemeral = some(reader.readValue(bool)) + ephemeral = Opt.some(reader.readValue(bool)) else: unrecognizedFieldWarning(value) @@ -205,8 +206,8 @@ proc readValue*( reader: var JsonReader[RestJson], value: var FilterLegacySubscribeRequest ) {.raises: [SerializationError, IOError].} = var - pubsubTopic = none(PubsubTopic) - contentFilters = none(seq[ContentTopic]) + pubsubTopic = Opt.none(PubsubTopic) + contentFilters = Opt.none(seq[ContentTopic]) var keys = initHashSet[string]() for fieldName in readObjectFields(reader): @@ -221,9 +222,9 @@ proc readValue*( case fieldName of "pubsubTopic": - pubsubTopic = some(reader.readValue(PubsubTopic)) + pubsubTopic = Opt.some(reader.readValue(PubsubTopic)) of "contentFilters": - contentFilters = some(reader.readValue(seq[ContentTopic])) + contentFilters = Opt.some(reader.readValue(seq[ContentTopic])) else: unrecognizedFieldWarning(value) @@ -236,16 +237,16 @@ proc readValue*( value = FilterLegacySubscribeRequest( pubsubTopic: if pubsubTopic.isNone() or pubsubTopic.get() == "": - none(string) + Opt.none(string) else: - some(pubsubTopic.get()), + Opt.some(pubsubTopic.get()), contentFilters: contentFilters.get(), ) proc readValue*( reader: var JsonReader[RestJson], value: var FilterSubscriberPing ) {.raises: [SerializationError, IOError].} = - var requestId = none(string) + var requestId = Opt.none(string) var keys = initHashSet[string]() for fieldName in readObjectFields(reader): @@ -260,7 +261,7 @@ proc readValue*( case fieldName of "requestId": - requestId = some(reader.readValue(string)) + requestId = Opt.some(reader.readValue(string)) else: unrecognizedFieldWarning(value) @@ -273,9 +274,9 @@ proc readValue*( reader: var JsonReader[RestJson], value: var FilterSubscribeRequest ) {.raises: [SerializationError, IOError].} = var - requestId = none(string) - pubsubTopic = none(PubsubTopic) - contentFilters = none(seq[ContentTopic]) + requestId = Opt.none(string) + pubsubTopic = Opt.none(PubsubTopic) + contentFilters = Opt.none(seq[ContentTopic]) var keys = initHashSet[string]() for fieldName in readObjectFields(reader): @@ -290,11 +291,11 @@ proc readValue*( case fieldName of "requestId": - requestId = some(reader.readValue(string)) + requestId = Opt.some(reader.readValue(string)) of "pubsubTopic": - pubsubTopic = some(reader.readValue(PubsubTopic)) + pubsubTopic = Opt.some(reader.readValue(PubsubTopic)) of "contentFilters": - contentFilters = some(reader.readValue(seq[ContentTopic])) + contentFilters = Opt.some(reader.readValue(seq[ContentTopic])) else: unrecognizedFieldWarning(value) @@ -311,9 +312,9 @@ proc readValue*( requestId: requestId.get(), pubsubTopic: if pubsubTopic.isNone() or pubsubTopic.get() == "": - none(string) + Opt.none(string) else: - some(pubsubTopic.get()), + Opt.some(pubsubTopic.get()), contentFilters: contentFilters.get(), ) @@ -321,9 +322,9 @@ proc readValue*( reader: var JsonReader[RestJson], value: var FilterUnsubscribeRequest ) {.raises: [SerializationError, IOError].} = var - requestId = none(string) - pubsubTopic = none(PubsubTopic) - contentFilters = none(seq[ContentTopic]) + requestId = Opt.none(string) + pubsubTopic = Opt.none(PubsubTopic) + contentFilters = Opt.none(seq[ContentTopic]) var keys = initHashSet[string]() for fieldName in readObjectFields(reader): @@ -338,11 +339,11 @@ proc readValue*( case fieldName of "requestId": - requestId = some(reader.readValue(string)) + requestId = Opt.some(reader.readValue(string)) of "pubsubTopic": - pubsubTopic = some(reader.readValue(PubsubTopic)) + pubsubTopic = Opt.some(reader.readValue(PubsubTopic)) of "contentFilters": - contentFilters = some(reader.readValue(seq[ContentTopic])) + contentFilters = Opt.some(reader.readValue(seq[ContentTopic])) else: unrecognizedFieldWarning(value) @@ -359,16 +360,16 @@ proc readValue*( requestId: requestId.get(), pubsubTopic: if pubsubTopic.isNone() or pubsubTopic.get() == "": - none(string) + Opt.none(string) else: - some(pubsubTopic.get()), + Opt.some(pubsubTopic.get()), contentFilters: contentFilters.get(), ) proc readValue*( reader: var JsonReader[RestJson], value: var FilterUnsubscribeAllRequest ) {.raises: [SerializationError, IOError].} = - var requestId = none(string) + var requestId = Opt.none(string) var keys = initHashSet[string]() for fieldName in readObjectFields(reader): @@ -383,7 +384,7 @@ proc readValue*( case fieldName of "requestId": - requestId = some(reader.readValue(string)) + requestId = Opt.some(reader.readValue(string)) else: unrecognizedFieldWarning(value) @@ -396,8 +397,8 @@ proc readValue*( reader: var JsonReader[RestJson], value: var FilterSubscriptionResponse ) {.raises: [SerializationError, IOError].} = var - requestId = none(string) - statusDesc = none(string) + requestId = Opt.none(string) + statusDesc = Opt.none(string) var keys = initHashSet[string]() for fieldName in readObjectFields(reader): @@ -412,9 +413,9 @@ proc readValue*( case fieldName of "requestId": - requestId = some(reader.readValue(string)) + requestId = Opt.some(reader.readValue(string)) of "statusDesc": - statusDesc = some(reader.readValue(string)) + statusDesc = Opt.some(reader.readValue(string)) else: unrecognizedFieldWarning(value) diff --git a/logos_delivery/waku/rest_api/endpoint/health/handlers.nim b/logos_delivery/waku/rest_api/endpoint/health/handlers.nim index 955e599d9..dc7588d16 100644 --- a/logos_delivery/waku/rest_api/endpoint/health/handlers.nim +++ b/logos_delivery/waku/rest_api/endpoint/health/handlers.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import chronicles, json_serialization, presto/route diff --git a/logos_delivery/waku/rest_api/endpoint/health/types.nim b/logos_delivery/waku/rest_api/endpoint/health/types.nim index c32a0c778..23feef93f 100644 --- a/logos_delivery/waku/rest_api/endpoint/health/types.nim +++ b/logos_delivery/waku/rest_api/endpoint/health/types.nim @@ -1,8 +1,6 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} -import results -import chronicles, json_serialization, json_serialization/std/options +import results, chronicles, json_serialization, json_serialization/pkg/results import ../serdes import logos_delivery/api/types import logos_delivery/waku/[waku_node, node/health_monitor] @@ -20,14 +18,14 @@ proc writeValue*( proc readValue*( reader: var JsonReader[RestJson], value: var ProtocolHealth ) {.gcsafe, raises: [SerializationError, IOError].} = - var protocol = none[string]() - var health = none[HealthStatus]() - var desc = none[string]() + var protocol = Opt.none(string) + var health = Opt.none(HealthStatus) + var desc = Opt.none(string) for fieldName in readObjectFields(reader): if fieldName == "desc": if desc.isSome(): reader.raiseUnexpectedField("Multiple `desc` fields found", "ProtocolHealth") - desc = some(reader.readValue(string)) + desc = Opt.some(reader.readValue(string)) else: if protocol.isSome(): reader.raiseUnexpectedField( @@ -37,8 +35,8 @@ proc readValue*( let fieldValue = reader.readValue(string) let h = HealthStatus.init(fieldValue).valueOr: reader.raiseUnexpectedValue("Invalid `health` value: " & $error) - health = some(h) - protocol = some(fieldName) + health = Opt.some(h) + protocol = Opt.some(fieldName) value = ProtocolHealth(protocol: protocol.get(), health: health.get(), desc: desc) @@ -55,9 +53,9 @@ proc readValue*( reader: var JsonReader[RestJson], value: var HealthReport ) {.raises: [SerializationError, IOError].} = var - nodeHealth: Option[HealthStatus] - connectionStatus: Option[ConnectionStatus] - protocolsHealth: Option[seq[ProtocolHealth]] + nodeHealth: Opt[HealthStatus] + connectionStatus: Opt[ConnectionStatus] + protocolsHealth: Opt[seq[ProtocolHealth]] for fieldName in readObjectFields(reader): case fieldName @@ -70,7 +68,7 @@ proc readValue*( let health = HealthStatus.init(reader.readValue(string)).valueOr: reader.raiseUnexpectedValue("Invalid `health` value: " & $error) - nodeHealth = some(health) + nodeHealth = Opt.some(health) of "connectionStatus": if connectionStatus.isSome(): reader.raiseUnexpectedField( @@ -80,14 +78,14 @@ proc readValue*( let state = ConnectionStatus.init(reader.readValue(string)).valueOr: reader.raiseUnexpectedValue("Invalid `connectionStatus` value: " & $error) - connectionStatus = some(state) + connectionStatus = Opt.some(state) of "protocolsHealth": if protocolsHealth.isSome(): reader.raiseUnexpectedField( "Multiple `protocolsHealth` fields found", "HealthReport" ) - protocolsHealth = some(reader.readValue(seq[ProtocolHealth])) + protocolsHealth = Opt.some(reader.readValue(seq[ProtocolHealth])) else: unrecognizedFieldWarning(value) diff --git a/logos_delivery/waku/rest_api/endpoint/legacy_lightpush/handlers.nim b/logos_delivery/waku/rest_api/endpoint/legacy_lightpush/handlers.nim index 058b84b8e..a2748de45 100644 --- a/logos_delivery/waku/rest_api/endpoint/legacy_lightpush/handlers.nim +++ b/logos_delivery/waku/rest_api/endpoint/legacy_lightpush/handlers.nim @@ -1,12 +1,13 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import std/strformat, + std/options, + results, stew/byteutils, chronicles, json_serialization, - json_serialization/std/options, + json_serialization/pkg/results, presto/route, presto/common @@ -43,7 +44,7 @@ const ROUTE_LIGHTPUSH = "/lightpush/v1/message" proc installLightPushRequestHandler*( router: var RestRouter, node: WakuNode, - discHandler: Option[DiscoveryHandler] = none(DiscoveryHandler), + discHandler: Opt[DiscoveryHandler] = Opt.none(DiscoveryHandler), ) = router.api(MethodPost, ROUTE_LIGHTPUSH) do( contentBody: Option[ContentBody] diff --git a/logos_delivery/waku/rest_api/endpoint/legacy_lightpush/types.nim b/logos_delivery/waku/rest_api/endpoint/legacy_lightpush/types.nim index 60368403f..63ccac701 100644 --- a/logos_delivery/waku/rest_api/endpoint/legacy_lightpush/types.nim +++ b/logos_delivery/waku/rest_api/endpoint/legacy_lightpush/types.nim @@ -1,10 +1,11 @@ {.push raises: [].} import + results, std/[sets, strformat], chronicles, json_serialization, - json_serialization/std/options, + json_serialization/pkg/results, presto/[route, client] import ../../../waku_core, ../relay/types as relay_types, ../serdes @@ -14,7 +15,7 @@ export relay_types #### Types type PushRequest* = object - pubsubTopic*: Option[PubSubTopic] + pubsubTopic*: Opt[PubSubTopic] message*: RelayWakuMessage #### Serialization and deserialization @@ -32,8 +33,8 @@ proc readValue*( reader: var JsonReader[RestJson], value: var PushRequest ) {.raises: [SerializationError, IOError].} = var - pubsubTopic = none(PubsubTopic) - message = none(RelayWakuMessage) + pubsubTopic = Opt.none(PubsubTopic) + message = Opt.none(RelayWakuMessage) var keys = initHashSet[string]() for fieldName in readObjectFields(reader): @@ -48,9 +49,9 @@ proc readValue*( case fieldName of "pubsubTopic": - pubsubTopic = some(reader.readValue(PubsubTopic)) + pubsubTopic = Opt.some(reader.readValue(PubsubTopic)) of "message": - message = some(reader.readValue(RelayWakuMessage)) + message = Opt.some(reader.readValue(RelayWakuMessage)) else: unrecognizedFieldWarning(value) @@ -60,8 +61,8 @@ proc readValue*( value = PushRequest( pubsubTopic: if pubsubTopic.isNone() or pubsubTopic.get() == "": - none(string) + Opt.none(string) else: - some(pubsubTopic.get()), + Opt.some(pubsubTopic.get()), message: message.get(), ) diff --git a/logos_delivery/waku/rest_api/endpoint/lightpush/client.nim b/logos_delivery/waku/rest_api/endpoint/lightpush/client.nim index abf832a3c..a80d437f5 100644 --- a/logos_delivery/waku/rest_api/endpoint/lightpush/client.nim +++ b/logos_delivery/waku/rest_api/endpoint/lightpush/client.nim @@ -7,7 +7,7 @@ import strformat, chronicles, json_serialization, - json_serialization/std/options, + json_serialization/pkg/results, presto/[route, client, common] import ../../../waku_core, ../serdes, ../responses, ../rest_serdes, ./types diff --git a/logos_delivery/waku/rest_api/endpoint/lightpush/handlers.nim b/logos_delivery/waku/rest_api/endpoint/lightpush/handlers.nim index 5980c028c..18e1eb10a 100644 --- a/logos_delivery/waku/rest_api/endpoint/lightpush/handlers.nim +++ b/logos_delivery/waku/rest_api/endpoint/lightpush/handlers.nim @@ -1,12 +1,13 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import std/strformat, + std/options, + results, stew/byteutils, chronicles, json_serialization, - json_serialization/std/options, + json_serialization/pkg/results, presto/route, presto/common @@ -42,7 +43,7 @@ proc makeRestResponse(response: WakuLightPushResult): RestApiResponse = var apiResponse: PushResponse if response.isOk(): - apiResponse.relayPeerCount = some(response.get()) + apiResponse.relayPeerCount = Opt.some(response.get()) else: httpStatus = convertErrorKindToHttpStatus(response.error().code) apiResponse.statusDesc = response.error().desc @@ -61,7 +62,7 @@ const ROUTE_LIGHTPUSH = "/lightpush/v3/message" proc installLightPushRequestHandler*( router: var RestRouter, node: WakuNode, - discHandler: Option[DiscoveryHandler] = none(DiscoveryHandler), + discHandler: Opt[DiscoveryHandler] = Opt.none(DiscoveryHandler), ) = router.api(MethodPost, ROUTE_LIGHTPUSH) do( contentBody: Option[ContentBody] @@ -77,7 +78,7 @@ proc installLightPushRequestHandler*( let msg = req.message.toWakuMessage().valueOr: return makeRestResponse(lightpushResultBadRequest("Invalid message! " & $error)) - var toPeer = none(RemotePeerInfo) + var toPeer = Opt.none(RemotePeerInfo) if useSelfHostedLightPush(node): discard else: @@ -93,7 +94,7 @@ proc installLightPushRequestHandler*( peerOp.valueOr: return makeRestResponse(lightpushResultServiceUnavailable(NoPeerNoneFoundError)) - toPeer = some(aPeer) + toPeer = Opt.some(aPeer) let subFut = node.lightpushPublish(req.pubsubTopic, msg, toPeer) diff --git a/logos_delivery/waku/rest_api/endpoint/lightpush/types.nim b/logos_delivery/waku/rest_api/endpoint/lightpush/types.nim index 1fb87ab45..bd2e578f0 100644 --- a/logos_delivery/waku/rest_api/endpoint/lightpush/types.nim +++ b/logos_delivery/waku/rest_api/endpoint/lightpush/types.nim @@ -1,10 +1,11 @@ {.push raises: [].} import + results, std/[sets, strformat], chronicles, json_serialization, - json_serialization/std/options, + json_serialization/pkg/results, presto/[route, client] import ../../../waku_core, ../relay/types as relay_types, ../serdes @@ -15,12 +16,12 @@ export relay_types type PushRequest* = object - pubsubTopic*: Option[PubSubTopic] + pubsubTopic*: Opt[PubSubTopic] message*: RelayWakuMessage PushResponse* = object - statusDesc*: Option[string] - relayPeerCount*: Option[uint32] + statusDesc*: Opt[string] + relayPeerCount*: Opt[uint32] #### Serialization and deserialization proc writeValue*( @@ -36,8 +37,8 @@ proc readValue*( reader: var JsonReader[RestJson], value: var PushRequest ) {.raises: [SerializationError, IOError].} = var - pubsubTopic = none(PubsubTopic) - message = none(RelayWakuMessage) + pubsubTopic = Opt.none(PubsubTopic) + message = Opt.none(RelayWakuMessage) var keys = initHashSet[string]() for fieldName in readObjectFields(reader): @@ -52,9 +53,9 @@ proc readValue*( case fieldName of "pubsubTopic": - pubsubTopic = some(reader.readValue(PubsubTopic)) + pubsubTopic = Opt.some(reader.readValue(PubsubTopic)) of "message": - message = some(reader.readValue(RelayWakuMessage)) + message = Opt.some(reader.readValue(RelayWakuMessage)) else: unrecognizedFieldWarning(value) @@ -64,9 +65,9 @@ proc readValue*( value = PushRequest( pubsubTopic: if pubsubTopic.isNone() or pubsubTopic.get() == "": - none(string) + Opt.none(string) else: - some(pubsubTopic.get()), + Opt.some(pubsubTopic.get()), message: message.get(), ) @@ -84,8 +85,8 @@ proc readValue*( reader: var JsonReader[RestJson], value: var PushResponse ) {.raises: [SerializationError, IOError].} = var - statusDesc = none(string) - relayPeerCount = none(uint32) + statusDesc = Opt.none(string) + relayPeerCount = Opt.none(uint32) var keys = initHashSet[string]() for fieldName in readObjectFields(reader): @@ -100,9 +101,9 @@ proc readValue*( case fieldName of "statusDesc": - statusDesc = some(reader.readValue(string)) + statusDesc = Opt.some(reader.readValue(string)) of "relayPeerCount": - relayPeerCount = some(reader.readValue(uint32)) + relayPeerCount = Opt.some(reader.readValue(uint32)) else: unrecognizedFieldWarning(value) diff --git a/logos_delivery/waku/rest_api/endpoint/origin_handler.nim b/logos_delivery/waku/rest_api/endpoint/origin_handler.nim index 148dd3962..0a8fa9ec2 100644 --- a/logos_delivery/waku/rest_api/endpoint/origin_handler.nim +++ b/logos_delivery/waku/rest_api/endpoint/origin_handler.nim @@ -1,36 +1,30 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} -import - std/[options, strutils, net], - regex, - results, - chronicles, - chronos, - chronos/apps/http/httpserver +import std/[strutils, net], regex, results +import chronicles, chronos, chronos/apps/http/httpserver type OriginHandlerMiddlewareRef* = ref object of HttpServerMiddlewareRef - allowedOriginMatcher: Option[Regex2] + allowedOriginMatcher: Opt[Regex2] everyOriginAllowed: bool -proc isEveryOriginAllowed(maybeAllowedOrigin: Option[string]): bool = +proc isEveryOriginAllowed(maybeAllowedOrigin: Opt[string]): bool = return maybeAllowedOrigin.isSome() and maybeAllowedOrigin.get() == "*" -proc compileOriginMatcher(maybeAllowedOrigin: Option[string]): Option[Regex2] = +proc compileOriginMatcher(maybeAllowedOrigin: Opt[string]): Opt[Regex2] = if maybeAllowedOrigin.isNone(): - return none(Regex2) + return Opt.none(Regex2) let allowedOrigin = maybeAllowedOrigin.get() if (len(allowedOrigin) == 0): - return none(Regex2) + return Opt.none(Regex2) try: var matchOrigin: string if allowedOrigin == "*": matchOrigin = r".*" - return some(re2(matchOrigin, {regexCaseless, regexExtended})) + return Opt.some(re2(matchOrigin, {regexCaseless, regexExtended})) let allowedOrigins = allowedOrigin.split(",") @@ -56,11 +50,11 @@ proc compileOriginMatcher(maybeAllowedOrigin: Option[string]): Option[Regex2] = let finalExpression = matchExpressions.join("|") - return some(re2(finalExpression, {regexCaseless, regexExtended})) + return Opt.some(re2(finalExpression, {regexCaseless, regexExtended})) except RegexError: var msg = getCurrentExceptionMsg() error "Failed to compile regex", source = allowedOrigin, err = msg - return none(Regex2) + return Opt.none(Regex2) proc originsMatch( originHandler: OriginHandlerMiddlewareRef, requestOrigin: string @@ -115,7 +109,7 @@ proc originMiddlewareProc( proc new*( t: typedesc[OriginHandlerMiddlewareRef], - allowedOrigin: Option[string] = none(string), + allowedOrigin: Opt[string] = Opt.none(string), ): HttpServerMiddlewareRef = let middleware = OriginHandlerMiddlewareRef( allowedOriginMatcher: compileOriginMatcher(allowedOrigin), diff --git a/logos_delivery/waku/rest_api/endpoint/relay/handlers.nim b/logos_delivery/waku/rest_api/endpoint/relay/handlers.nim index 0976877f4..e88408215 100644 --- a/logos_delivery/waku/rest_api/endpoint/relay/handlers.nim +++ b/logos_delivery/waku/rest_api/endpoint/relay/handlers.nim @@ -1,13 +1,13 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import std/sequtils, + std/options, stew/byteutils, results, chronicles, json_serialization, - json_serialization/std/options, + json_serialization/pkg/results, presto/route, presto/common import @@ -229,7 +229,9 @@ proc installRelayApiHandlers*( # if we reach here its either a non-RLN message or a RLN message with a valid proof info "Publishing message", pubSubTopic = pubSubTopic, rln = not node.rln.isNil() - if not (waitFor node.publish(some(pubSubTopic), message).withTimeout(futTimeout)): + if not ( + waitFor node.publish(Opt.some(pubSubTopic), message).withTimeout(futTimeout) + ): error "Failed to publish message to topic", pubSubTopic = pubSubTopic return RestApiResponse.internalServerError("Failed to publish: timedout") @@ -361,7 +363,7 @@ proc installRelayApiHandlers*( info "Publishing message", contentTopic = message.contentTopic, rln = not node.rln.isNil() - var publishFut = node.publish(some($pubsubTopic), message) + var publishFut = node.publish(Opt.some($pubsubTopic), message) if not await publishFut.withTimeout(futTimeout): return RestApiResponse.internalServerError("Failed to publish: timedout") diff --git a/logos_delivery/waku/rest_api/endpoint/relay/types.nim b/logos_delivery/waku/rest_api/endpoint/relay/types.nim index ca7d1ff05..c874847b8 100644 --- a/logos_delivery/waku/rest_api/endpoint/relay/types.nim +++ b/logos_delivery/waku/rest_api/endpoint/relay/types.nim @@ -1,10 +1,11 @@ {.push raises: [].} import + results, std/[sets, strformat, times], chronicles, json_serialization, - json_serialization/std/options, + json_serialization/pkg/results, presto/[route, client, common] import ../../../common/base64, ../../../waku_core, ../serdes @@ -12,12 +13,12 @@ import ../../../common/base64, ../../../waku_core, ../serdes type RelayWakuMessage* = object payload*: Base64String - contentTopic*: Option[ContentTopic] - version*: Option[Natural] - timestamp*: Option[int64] - meta*: Option[Base64String] - ephemeral*: Option[bool] - proof*: Option[Base64String] + contentTopic*: Opt[ContentTopic] + version*: Opt[Natural] + timestamp*: Opt[int64] + meta*: Opt[Base64String] + ephemeral*: Opt[bool] + proof*: Opt[Base64String] type RelayGetMessagesResponse* = seq[RelayWakuMessage] @@ -28,16 +29,16 @@ type proc toRelayWakuMessage*(msg: WakuMessage): RelayWakuMessage = RelayWakuMessage( payload: base64.encode(msg.payload), - contentTopic: some(msg.contentTopic), - version: some(Natural(msg.version)), - timestamp: some(msg.timestamp), + contentTopic: Opt.some(msg.contentTopic), + version: Opt.some(Natural(msg.version)), + timestamp: Opt.some(msg.timestamp), meta: if msg.meta.len > 0: - some(base64.encode(msg.meta)) + Opt.some(base64.encode(msg.meta)) else: - none(Base64String), - ephemeral: some(msg.ephemeral), - proof: some(base64.encode(msg.proof)), + Opt.none(Base64String), + ephemeral: Opt.some(msg.ephemeral), + proof: Opt.some(base64.encode(msg.proof)), ) proc toWakuMessage*(msg: RelayWakuMessage, version = 0): Result[WakuMessage, string] = @@ -91,13 +92,13 @@ proc readValue*( reader: var JsonReader[RestJson], value: var RelayWakuMessage ) {.raises: [SerializationError, IOError].} = var - payload = none(Base64String) - contentTopic = none(ContentTopic) - version = none(Natural) - timestamp = none(int64) - meta = none(Base64String) - ephemeral = none(bool) - proof = none(Base64String) + payload = Opt.none(Base64String) + contentTopic = Opt.none(ContentTopic) + version = Opt.none(Natural) + timestamp = Opt.none(int64) + meta = Opt.none(Base64String) + ephemeral = Opt.none(bool) + proof = Opt.none(Base64String) var keys = initHashSet[string]() for fieldName in readObjectFields(reader): @@ -112,19 +113,19 @@ proc readValue*( case fieldName of "payload": - payload = some(reader.readValue(Base64String)) + payload = Opt.some(reader.readValue(Base64String)) of "contentTopic": - contentTopic = some(reader.readValue(ContentTopic)) + contentTopic = Opt.some(reader.readValue(ContentTopic)) of "version": - version = some(reader.readValue(Natural)) + version = Opt.some(reader.readValue(Natural)) of "timestamp": - timestamp = some(reader.readValue(int64)) + timestamp = Opt.some(reader.readValue(int64)) of "meta": - meta = some(reader.readValue(Base64String)) + meta = Opt.some(reader.readValue(Base64String)) of "ephemeral": - ephemeral = some(reader.readValue(bool)) + ephemeral = Opt.some(reader.readValue(bool)) of "proof": - proof = some(reader.readValue(Base64String)) + proof = Opt.some(reader.readValue(Base64String)) else: unrecognizedFieldWarning(value) diff --git a/logos_delivery/waku/rest_api/endpoint/rest_serdes.nim b/logos_delivery/waku/rest_api/endpoint/rest_serdes.nim index 3441b6b26..45642a086 100644 --- a/logos_delivery/waku/rest_api/endpoint/rest_serdes.nim +++ b/logos_delivery/waku/rest_api/endpoint/rest_serdes.nim @@ -1,14 +1,14 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import std/typetraits, std/os, + std/options, results, chronicles, serialization, json_serialization, - json_serialization/std/options, + json_serialization/pkg/results, json_serialization/std/net, json_serialization/std/sets, presto/common diff --git a/logos_delivery/waku/rest_api/endpoint/serdes.nim b/logos_delivery/waku/rest_api/endpoint/serdes.nim index ab7ed8d25..98f42f9fa 100644 --- a/logos_delivery/waku/rest_api/endpoint/serdes.nim +++ b/logos_delivery/waku/rest_api/endpoint/serdes.nim @@ -7,7 +7,7 @@ import chronicles, serialization, json_serialization, - json_serialization/std/options, + json_serialization/pkg/results, json_serialization/std/net, json_serialization/std/sets, presto/common diff --git a/logos_delivery/waku/rest_api/endpoint/server.nim b/logos_delivery/waku/rest_api/endpoint/server.nim index 44a02ccb2..b7e6b1012 100644 --- a/logos_delivery/waku/rest_api/endpoint/server.nim +++ b/logos_delivery/waku/rest_api/endpoint/server.nim @@ -73,7 +73,7 @@ proc new*( maxRequestBodySize: int = 1_048_576, requestErrorHandler: RestRequestErrorHandler = nil, dualstack = DualStackType.Auto, - allowedOrigin: Option[string] = none(string), + allowedOrigin: Opt[string] = Opt.none(string), ): RestServerResult[WakuRestServerRef] = var server = WakuRestServerRef(router: router) @@ -116,14 +116,13 @@ proc getRouter(): RestRouter = ## because it will be used for query routing. if pattern.startsWith("{") and pattern.endsWith("}"): 0 else: 1 - # disable allowed origin handling by presto, we add our own handling as middleware - RestRouter.init(validate, allowedOrigin = none(string)) + RestRouter.init(validate) proc init*( T: type WakuRestServerRef, ip: IpAddress, port: Port, - allowedOrigin = none(string), + allowedOrigin = Opt.none(string), conf = RestServerConf.default(), requestErrorHandler: RestRequestErrorHandler = nil, ): RestServerResult[T] = @@ -159,7 +158,7 @@ proc init*( proc newRestHttpServer*( ip: IpAddress, port: Port, - allowedOrigin = none(string), + allowedOrigin = Opt.none(string), conf = RestServerConf.default(), requestErrorHandler: RestRequestErrorHandler = nil, ): RestServerResult[WakuRestServerRef] = diff --git a/logos_delivery/waku/rest_api/endpoint/store/client.nim b/logos_delivery/waku/rest_api/endpoint/store/client.nim index 71ba7610d..d53883fc9 100644 --- a/logos_delivery/waku/rest_api/endpoint/store/client.nim +++ b/logos_delivery/waku/rest_api/endpoint/store/client.nim @@ -1,7 +1,11 @@ {.push raises: [].} import - chronicles, json_serialization, json_serialization/std/options, presto/[route, client] + results, + chronicles, + json_serialization, + json_serialization/pkg/results, + presto/[route, client] import ../../../waku_store/common, ../../../waku_core/message/digest, @@ -34,7 +38,7 @@ proc decodeBytes*( statusCode: uint32(ErrorCode.BAD_RESPONSE), statusDesc: res, messages: newSeq[WakuMessageKeyValueHex](0), - paginationCursor: none(string), + paginationCursor: Opt.none(string), ) ) diff --git a/logos_delivery/waku/rest_api/endpoint/store/handlers.nim b/logos_delivery/waku/rest_api/endpoint/store/handlers.nim index 072041f29..aa0136922 100644 --- a/logos_delivery/waku/rest_api/endpoint/store/handlers.nim +++ b/logos_delivery/waku/rest_api/endpoint/store/handlers.nim @@ -1,19 +1,21 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} +import std/options, std/[strformat, sugar], results + +import chronicles, uri, json_serialization, presto/route import - std/[strformat, sugar], results, chronicles, uri, json_serialization, presto/route -import - ../../../waku_core, - ../../../waku_store/common, - ../../../waku_store/self_req_handler, - ../../../waku_node, - ../../../node/peer_manager, - ../../../common/paging, - ../../handlers, - ../responses, - ../serdes, - ./types + logos_delivery/waku/[ + waku_core, + waku_store/common, + waku_store/self_req_handler, + waku_node, + node/peer_manager, + common/paging, + rest_api/handlers, + rest_api/endpoint/responses, + rest_api/endpoint/serdes, + rest_api/endpoint/store/types, + ] export types @@ -54,20 +56,20 @@ proc performStoreQuery( return resp -# Converts a string time representation into an Option[Timestamp]. +# Converts a string time representation into an Opt[Timestamp]. # Only positive time is considered a valid Timestamp in the request -proc parseTime(input: Option[string]): Result[Option[Timestamp], string] = +proc parseTime(input: Opt[string]): Result[Opt[Timestamp], string] = if input.isSome() and input.get() != "": try: let time = parseInt(input.get()) if time > 0: - return ok(some(Timestamp(time))) + return ok(Opt.some(Timestamp(time))) except ValueError: return err("time parsing error: " & getCurrentExceptionMsg()) - return ok(none(Timestamp)) + return ok(Opt.none(Timestamp)) -proc parseIncludeData(input: Option[string]): Result[bool, string] = +proc parseIncludeData(input: Opt[string]): Result[bool, string] = var includeData = false if input.isSome() and input.get() != "": try: @@ -79,24 +81,24 @@ proc parseIncludeData(input: Option[string]): Result[bool, string] = # Creates a HistoryQuery from the given params proc createStoreQuery( - includeData: Option[string], - pubsubTopic: Option[string], - contentTopics: Option[string], - startTime: Option[string], - endTime: Option[string], - hashes: Option[string], - cursor: Option[string], - direction: Option[string], - pageSize: Option[string], + includeData: Opt[string], + pubsubTopic: Opt[string], + contentTopics: Opt[string], + startTime: Opt[string], + endTime: Opt[string], + hashes: Opt[string], + cursor: Opt[string], + direction: Opt[string], + pageSize: Opt[string], ): Result[StoreQueryRequest, string] = var parsedIncludeData = ?parseIncludeData(includeData) # Parse pubsubTopic parameter - var parsedPubsubTopic = none(string) + var parsedPubsubTopic = Opt.none(string) if pubsubTopic.isSome(): let decodedPubsubTopic = decodeUrl(pubsubTopic.get()) if decodedPubsubTopic != "": - parsedPubsubTopic = some(decodedPubsubTopic) + parsedPubsubTopic = Opt.some(decodedPubsubTopic) # Parse the content topics var parsedContentTopics = newSeq[ContentTopic](0) @@ -123,20 +125,20 @@ proc createStoreQuery( parsedDirection = direction.get().into() # Parse page size field - var parsedPagedSize = none(uint64) + var parsedPagedSize = Opt.none(uint64) if pageSize.isSome() and pageSize.get() != "": try: - parsedPagedSize = some(uint64(parseInt(pageSize.get()))) + parsedPagedSize = Opt.some(uint64(parseInt(pageSize.get()))) except CatchableError: return err("page size parsing error: " & getCurrentExceptionMsg()) # Enforce default value of page_size to 20 if parsedPagedSize.isNone(): - parsedPagedSize = some(20.uint64) + parsedPagedSize = Opt.some(20.uint64) # Enforce max value of page_size to 100 if parsedPagedSize.get() > 100: - parsedPagedSize = some(100.uint64) + parsedPagedSize = Opt.some(100.uint64) return ok( StoreQueryRequest( @@ -152,13 +154,11 @@ proc createStoreQuery( ) ) -# Simple type conversion. The "Option[Result[string, cstring]]" -# type is used by the nim-presto library. -proc toOpt(self: Option[Result[string, cstring]]): Option[string] = +proc toOpt(self: Option[Result[string, cstring]]): Opt[string] = if not self.isSome() or self.get().value == "": - return none(string) + return Opt.none(string) if self.isSome() and self.get().value != "": - return some(self.get().value) + return Opt.some(self.get().value) proc retrieveMsgsFromSelfNode( self: WakuNode, storeQuery: StoreQueryRequest @@ -183,7 +183,7 @@ proc retrieveMsgsFromSelfNode( proc installStoreApiHandlers*( router: var RestRouter, node: WakuNode, - discHandler: Option[DiscoveryHandler] = none(DiscoveryHandler), + discHandler: Opt[DiscoveryHandler] = Opt.none(DiscoveryHandler), ) = # Handles the store-query request according to the passed parameters router.api(MethodGet, "/store/v3/messages") do( diff --git a/logos_delivery/waku/rest_api/endpoint/store/types.nim b/logos_delivery/waku/rest_api/endpoint/store/types.nim index c53797233..b4c9128c9 100644 --- a/logos_delivery/waku/rest_api/endpoint/store/types.nim +++ b/logos_delivery/waku/rest_api/endpoint/store/types.nim @@ -1,12 +1,12 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[sets, strformat, uri, options, sequtils], + results, + std/[sets, strformat, uri, sequtils], stew/byteutils, chronicles, json_serialization, - json_serialization/std/options, + json_serialization/pkg/results, presto/[route, client, common] import ../../../waku_store/common, ../../../common/base64, ../../../waku_core, ../serdes @@ -18,15 +18,15 @@ Json.setWriter JsonWriter, PreferredOutput = string #### Type conversion -proc parseHash*(input: Option[string]): Result[Option[WakuMessageHash], string] = +proc parseHash*(input: Opt[string]): Result[Opt[WakuMessageHash], string] = let hexUrlEncoded = if input.isSome(): input.get() else: - return ok(none(WakuMessageHash)) + return ok(Opt.none(WakuMessageHash)) if hexUrlEncoded == "": - return ok(none(WakuMessageHash)) + return ok(Opt.none(WakuMessageHash)) let hexDecoded = decodeUrl(hexUrlEncoded, false) @@ -42,9 +42,9 @@ proc parseHash*(input: Option[string]): Result[Option[WakuMessageHash], string] let hash: WakuMessageHash = fromBytes(decodedBytes) - return ok(some(hash)) + return ok(Opt.some(hash)) -proc parseHashes*(input: Option[string]): Result[seq[WakuMessageHash], string] = +proc parseHashes*(input: Opt[string]): Result[seq[WakuMessageHash], string] = var hashes: seq[WakuMessageHash] = @[] if not input.isSome() or input.get() == "": @@ -54,7 +54,7 @@ proc parseHashes*(input: Option[string]): Result[seq[WakuMessageHash], string] = if decodedUrl != "": for subString in decodedUrl.split(','): - let hash = ?parseHash(some(subString)) + let hash = ?parseHash(Opt.some(subString)) if hash.isSome(): hashes.add(hash.get()) @@ -172,9 +172,9 @@ proc readValue*( reader: var JsonReader, value: var WakuMessageKeyValueHex ) {.gcsafe, raises: [SerializationError, IOError].} = var - messageHash = none(string) - message = none(WakuMessage) - pubsubTopic = none(PubsubTopic) + messageHash = Opt.none(string) + message = Opt.none(WakuMessage) + pubsubTopic = Opt.none(PubsubTopic) for fieldName in readObjectFields(reader): case fieldName @@ -183,19 +183,19 @@ proc readValue*( reader.raiseUnexpectedField( "Multiple `messageHash` fields found", "WakuMessageKeyValueHex" ) - messageHash = some(reader.readValue(string)) + messageHash = Opt.some(reader.readValue(string)) of "message": if message.isSome(): reader.raiseUnexpectedField( "Multiple `message` fields found", "WakuMessageKeyValueHex" ) - message = some(reader.readValue(WakuMessage)) + message = Opt.some(reader.readValue(WakuMessage)) of "pubsubTopic": if pubsubTopic.isSome(): reader.raiseUnexpectedField( "Multiple `pubsubTopic` fields found", "WakuMessageKeyValueHex" ) - pubsubTopic = some(reader.readValue(string)) + pubsubTopic = Opt.some(reader.readValue(string)) else: reader.raiseUnexpectedField("Unrecognided field", cstring(fieldName)) @@ -227,11 +227,11 @@ proc readValue*( reader: var JsonReader, value: var StoreQueryResponseHex ) {.gcsafe, raises: [SerializationError, IOError].} = var - requestId = none(string) - code = none(uint32) - desc = none(string) - messages = none(seq[WakuMessageKeyValueHex]) - cursor = none(string) + requestId = Opt.none(string) + code = Opt.none(uint32) + desc = Opt.none(string) + messages = Opt.none(seq[WakuMessageKeyValueHex]) + cursor = Opt.none(string) for fieldName in readObjectFields(reader): case fieldName @@ -240,31 +240,31 @@ proc readValue*( reader.raiseUnexpectedField( "Multiple `requestId` fields found", "StoreQueryResponseHex" ) - requestId = some(reader.readValue(string)) + requestId = Opt.some(reader.readValue(string)) of "statusCode": if code.isSome(): reader.raiseUnexpectedField( "Multiple `statusCode` fields found", "StoreQueryResponseHex" ) - code = some(reader.readValue(uint32)) + code = Opt.some(reader.readValue(uint32)) of "statusDesc": if desc.isSome(): reader.raiseUnexpectedField( "Multiple `statusDesc` fields found", "StoreQueryResponseHex" ) - desc = some(reader.readValue(string)) + desc = Opt.some(reader.readValue(string)) of "messages": if messages.isSome(): reader.raiseUnexpectedField( "Multiple `messages` fields found", "StoreQueryResponseHex" ) - messages = some(reader.readValue(seq[WakuMessageKeyValueHex])) + messages = Opt.some(reader.readValue(seq[WakuMessageKeyValueHex])) of "paginationCursor": if cursor.isSome(): reader.raiseUnexpectedField( "Multiple `paginationCursor` fields found", "StoreQueryResponseHex" ) - cursor = some(reader.readValue(string)) + cursor = Opt.some(reader.readValue(string)) else: reader.raiseUnexpectedField("Unrecognided field", cstring(fieldName)) diff --git a/logos_delivery/waku/rest_api/handlers.nim b/logos_delivery/waku/rest_api/handlers.nim index 520c0518a..affd67ca8 100644 --- a/logos_delivery/waku/rest_api/handlers.nim +++ b/logos_delivery/waku/rest_api/handlers.nim @@ -1,18 +1,17 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} -import chronos, std/[options, sequtils], results +import chronos, std/sequtils, results import ../discovery/waku_discv5, ../waku_relay, ../waku_core, ./message_cache ### Discovery type DiscoveryHandler* = - proc(): Future[Result[Option[RemotePeerInfo], string]] {.async, closure.} + proc(): Future[Result[Opt[RemotePeerInfo], string]] {.async, closure.} proc defaultDiscoveryHandler*( discv5: WakuDiscoveryV5, cap: Capabilities ): DiscoveryHandler = - proc(): Future[Result[Option[RemotePeerInfo], string]] {.async, closure.} = + proc(): Future[Result[Opt[RemotePeerInfo], string]] {.async, closure.} = #Discv5 is already filtering peers by shards no need to pass a predicate. let findPeers = discv5.findRandomPeers() @@ -24,12 +23,12 @@ proc defaultDiscoveryHandler*( peers.keepItIf(it.supportsCapability(cap)) if peers.len == 0: - return ok(none(RemotePeerInfo)) + return ok(Opt.none(RemotePeerInfo)) let remotePeerInfo = peers[0].toRemotePeerInfo().valueOr: return err($error) - return ok(some(remotePeerInfo)) + return ok(Opt.some(remotePeerInfo)) ### Message Cache diff --git a/logos_delivery/waku/rest_api/message_cache.nim b/logos_delivery/waku/rest_api/message_cache.nim index acef5a729..8a6ce6d54 100644 --- a/logos_delivery/waku/rest_api/message_cache.nim +++ b/logos_delivery/waku/rest_api/message_cache.nim @@ -1,7 +1,7 @@ {.push raises: [].} import - std/[sequtils, sugar, algorithm, options], + std/[sequtils, sugar, algorithm], results, chronicles, chronos, @@ -41,23 +41,23 @@ proc pubsubTopicCount*(self: MessageCache): int = proc contentTopicCount*(self: MessageCache): int = self.contentTopics.len -proc pubsubSearch(self: MessageCache, pubsubTopic: PubsubTopic): Option[int] = +proc pubsubSearch(self: MessageCache, pubsubTopic: PubsubTopic): Opt[int] = # Return some with the index if found none otherwise. for i, topic in self.pubsubTopics: if topic == pubsubTopic: - return some(i) + return Opt.some(i) - return none(int) + return Opt.none(int) -proc contentSearch(self: MessageCache, contentTopic: ContentTopic): Option[int] = +proc contentSearch(self: MessageCache, contentTopic: ContentTopic): Opt[int] = # Return some with the index if found none otherwise. for i, topic in self.contentTopics: if topic == contentTopic: - return some(i) + return Opt.some(i) - return none(int) + return Opt.none(int) proc isPubsubSubscribed*(self: MessageCache, pubsubTopic: PubsubTopic): bool = self.pubsubSearch(pubsubTopic).isSome() diff --git a/logos_delivery/waku/rln/config.nim b/logos_delivery/waku/rln/config.nim index 4d449f392..d2f4e6e29 100644 --- a/logos_delivery/waku/rln/config.nim +++ b/logos_delivery/waku/rln/config.nim @@ -1,6 +1,6 @@ {.push raises: [].} -import std/options, stint +import results, stint import logos_delivery/waku/common/error_handling @@ -13,14 +13,14 @@ type RlnConf* = object of RootObj # change the config to either nest or use enum/type variant so it's obvious # and then it can be set to `requiresInit` dynamic*: bool - credIndex*: Option[uint] + credIndex*: Opt[uint] ethContractAddress*: string ethClientUrls*: seq[string] chainId*: UInt256 - creds*: Option[RlnCreds] + creds*: Opt[RlnCreds] epochSizeSec*: uint64 userMessageLimit*: uint64 - ethPrivateKey*: Option[string] + ethPrivateKey*: Opt[string] type WakuRlnConfig* = object of RlnConf onFatalErrorAction*: OnFatalErrorHandler diff --git a/logos_delivery/waku/rln/group_manager/group_manager_base.nim b/logos_delivery/waku/rln/group_manager/group_manager_base.nim index 5f91cf19f..deaa6533e 100644 --- a/logos_delivery/waku/rln/group_manager/group_manager_base.nim +++ b/logos_delivery/waku/rln/group_manager/group_manager_base.nim @@ -1,8 +1,8 @@ import ../../common/error_handling, ../protocol_types, ../protocol_metrics, ../constants -import options, chronos, results, std/[deques] +import chronos, results, std/[deques] -export options, chronos, results, protocol_types, protocol_metrics, deques +export chronos, results, protocol_types, protocol_metrics, deques # This module contains the GroupManager interface # The GroupManager is responsible for managing the group state @@ -19,16 +19,16 @@ type OnWithdrawCallback* = proc(withdrawals: seq[Membership]): Future[void] {.gc type GroupManagerResult*[T] = Result[T, string] type GroupManager* = ref object of RootObj - idCredentials*: Option[IdentityCredential] - membershipIndex*: Option[MembershipIndex] - registerCb*: Option[OnRegisterCallback] - withdrawCb*: Option[OnWithdrawCallback] + idCredentials*: Opt[IdentityCredential] + membershipIndex*: Opt[MembershipIndex] + registerCb*: Opt[OnRegisterCallback] + withdrawCb*: Opt[OnWithdrawCallback] rlnInstance*: ptr RlnRaw initialized*: bool latestIndex*: MembershipIndex validRoots*: Deque[MerkleNode] onFatalErrorAction*: OnFatalErrorHandler - userMessageLimit*: Option[UserMessageLimit] + userMessageLimit*: Opt[UserMessageLimit] rlnRelayMaxMessageLimit*: uint64 # This proc is used to initialize the group manager @@ -76,7 +76,7 @@ method registerBatch*( # This proc is used to set a callback that will be called when a new identity commitment is registered # The callback may be called multiple times, and should be used to for any post processing method onRegister*(g: GroupManager, cb: OnRegisterCallback) {.base, gcsafe.} = - g.registerCb = some(cb) + g.registerCb = Opt.some(cb) # This proc is used to withdraw/remove an identity commitment from the merkle tree # The user should have the identity secret hash to this commitment, by either deriving it, or owning it @@ -113,7 +113,7 @@ method stop*(g: GroupManager): Future[void] {.base, async.} = # This proc is used to set a callback that will be called when an identity commitment is withdrawn # The callback may be called multiple times, and should be used to for any post processing method onWithdraw*(g: GroupManager, cb: OnWithdrawCallback) {.base, gcsafe.} = - g.withdrawCb = some(cb) + g.withdrawCb = Opt.some(cb) method indexOfRoot*( g: GroupManager, root: MerkleNode diff --git a/logos_delivery/waku/rln/group_manager/on_chain/group_manager.nim b/logos_delivery/waku/rln/group_manager/on_chain/group_manager.nim index a912306a5..4b591edfa 100644 --- a/logos_delivery/waku/rln/group_manager/on_chain/group_manager.nim +++ b/logos_delivery/waku/rln/group_manager/on_chain/group_manager.nim @@ -1,7 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import + results, os, web3, web3/eth_api_types, @@ -33,15 +33,15 @@ type WakuRlnContractWithSender = Sender[WakuRlnContract] OnchainGroupManager* = ref object of GroupManager ethClientUrls*: seq[string] - ethPrivateKey*: Option[string] + ethPrivateKey*: Opt[string] ethContractAddress*: string - ethRpc*: Option[Web3] - wakuRlnContract*: Option[WakuRlnContractWithSender] - registrationTxHash*: Option[TxHash] + ethRpc*: Opt[Web3] + wakuRlnContract*: Opt[WakuRlnContractWithSender] + registrationTxHash*: Opt[TxHash] chainId*: UInt256 - keystorePath*: Option[string] - keystorePassword*: Option[string] - registrationHandler*: Option[RegistrationHandler] + keystorePath*: Opt[string] + keystorePassword*: Opt[string] + registrationHandler*: Opt[RegistrationHandler] latestProcessedBlock*: BlockNumber merkleProofCache*: seq[byte] merkleProofCacheGeneration: uint64 @@ -406,7 +406,7 @@ method register*( ) ).valueOr: return err("Failed to get transaction receipt: " & error) - g.registrationTxHash = some(txHash) + g.registrationTxHash = Opt.some(txHash) # the receipt topic holds the hash of signature of the raised events trace "registration receipt", receipt = tsReceipt[] @@ -420,10 +420,10 @@ method register*( "MembershipRegistered(uint256,uint256,uint32)" ).data) - var membershipRegisteredLog: Option[LogObject] + var membershipRegisteredLog: Opt[LogObject] for log in tsReceipt.logs: if log.topics.len > 0 and log.topics[0] == expectedEventSignature: - membershipRegisteredLog = some(log) + membershipRegisteredLog = Opt.some(log) break if membershipRegisteredLog.isNone(): @@ -438,9 +438,9 @@ method register*( ## Extract membership index from transaction log data (big endian) membershipIndex = UInt256.fromBytesBE(arguments[64 .. 95]) - g.userMessageLimit = some(userMessageLimit) - g.membershipIndex = some(membershipIndex.toMembershipIndex()) - g.idCredentials = some(identityCredential) + g.userMessageLimit = Opt.some(userMessageLimit) + g.membershipIndex = Opt.some(membershipIndex.toMembershipIndex()) + g.idCredentials = Opt.some(identityCredential) let rateCommitment = RateCommitment( idCommitment: identityCredential.idCommitment, userMessageLimit: userMessageLimit @@ -573,10 +573,10 @@ method verifyProof*( return ok(validProof) method onRegister*(g: OnchainGroupManager, cb: OnRegisterCallback) {.gcsafe.} = - g.registerCb = some(cb) + g.registerCb = Opt.some(cb) method onWithdraw*(g: OnchainGroupManager, cb: OnWithdrawCallback) {.gcsafe.} = - g.withdrawCb = some(cb) + g.withdrawCb = Opt.some(cb) proc establishConnection( g: OnchainGroupManager @@ -648,8 +648,8 @@ method init*(g: OnchainGroupManager): Future[GroupManagerResult[void]] {.async.} let contractAddress = web3.fromHex(web3.Address, g.ethContractAddress) let wakuRlnContract = ethRpc.contractSender(WakuRlnContract, contractAddress) - g.ethRpc = some(ethRpc) - g.wakuRlnContract = some(wakuRlnContract) + g.ethRpc = Opt.some(ethRpc) + g.wakuRlnContract = Opt.some(wakuRlnContract) if g.keystorePath.isSome() and g.keystorePassword.isSome(): if not fileExists(g.keystorePath.get()): @@ -671,14 +671,14 @@ method init*(g: OnchainGroupManager): Future[GroupManagerResult[void]] {.async.} ).valueOr: return err("failed to get the keystore credentials: " & $error) - g.membershipIndex = some(keystoreCred.treeIndex) - g.userMessageLimit = some(keystoreCred.userMessageLimit) + g.membershipIndex = Opt.some(keystoreCred.treeIndex) + g.userMessageLimit = Opt.some(keystoreCred.userMessageLimit) let idCommitment = keystoreCred.identityCredential.idCommitment let membershipExists = (await g.fetchMembershipStatus(idCommitment)).valueOr: return err("the commitment does not have a membership: " & error) - g.idCredentials = some(keystoreCred.identityCredential) + g.idCredentials = Opt.some(keystoreCred.identityCredential) let maxMembershipRateLimitRes = await g.fetchMaxMembershipRateLimit() let maxMembershipRateLimit = maxMembershipRateLimitRes.valueOr: @@ -696,7 +696,7 @@ method init*(g: OnchainGroupManager): Future[GroupManagerResult[void]] {.async.} return newEthRpc.ondisconnect = ethRpc.ondisconnect - g.ethRpc = some(newEthRpc) + g.ethRpc = Opt.some(newEthRpc) ethRpc.ondisconnect = proc() = asyncSpawn onDisconnect() diff --git a/logos_delivery/waku/rln/group_manager/on_chain/rpc_wrapper.nim b/logos_delivery/waku/rln/group_manager/on_chain/rpc_wrapper.nim index c5fbc4a01..7b8e1d091 100644 --- a/logos_delivery/waku/rln/group_manager/on_chain/rpc_wrapper.nim +++ b/logos_delivery/waku/rln/group_manager/on_chain/rpc_wrapper.nim @@ -1,4 +1,5 @@ import + results, web3, web3/eth_api_types, web3/primitives, diff --git a/logos_delivery/waku/rln/proof.nim b/logos_delivery/waku/rln/proof.nim index 8a29eb67b..ba4b0361a 100644 --- a/logos_delivery/waku/rln/proof.nim +++ b/logos_delivery/waku/rln/proof.nim @@ -1,11 +1,17 @@ {.push raises: [].} -import std/[options, times, sequtils] +import std/[times, sequtils] import chronos, chronicles, results, stew/byteutils -import ./types, ./protocol_types, ./conversion_utils, ./group_manager, ./nonce_manager - -import logos_delivery/waku/waku_core +import + logos_delivery/waku/[ + rln/types, + rln/protocol_types, + rln/conversion_utils, + rln/group_manager, + rln/nonce_manager, + waku_core, + ] proc calcEpoch*(rln: Rln, t: float64): Epoch = ## gets time `t` as `flaot64` with subseconds resolution in the fractional part @@ -56,13 +62,16 @@ proc toRLNSignal*(wakumessage: WakuMessage): seq[byte] = proc generateRLNProof*( rln: Rln, input: seq[byte], senderEpochTime: float64 -): Future[Result[seq[byte], string]] {.async.} = +): Future[Result[seq[byte], string]] {.async: (raises: []).} = let epoch = rln.calcEpoch(senderEpochTime) let nonce = rln.nonceManager.getNonce().valueOr: return err("could not get new message id to generate an rln proof: " & $error) - let proof = (await rln.groupManager.generateProof(input, epoch, nonce)).valueOr: - return err("could not generate rln-v2 proof: " & $error) - return ok(proof.encode().buffer) + try: + let proof = (await rln.groupManager.generateProof(input, epoch, nonce)).valueOr: + return err("could not generate rln-v2 proof: " & $error) + return ok(proof.encode().buffer) + except CatchableError as e: + return err("exception generating rln proof: " & e.msg) proc generateRLNProofWithRootRefresh*( rln: Rln, input: seq[byte], senderEpochTime: float64 @@ -97,7 +106,7 @@ proc attachRLNProof*( return ok(msgWithProof) proc checkAndGenerateRLNProof*( - rln: Option[Rln], message: WakuMessage + rln: Opt[Rln], message: WakuMessage ): Future[Result[WakuMessage, string]] {.async.} = ## Returns the message with an attached RLN proof, or unchanged when it ## already carries a proof or RLN is not configured. diff --git a/logos_delivery/waku/rln/protocol_types.nim b/logos_delivery/waku/rln/protocol_types.nim index 66aa72f53..4a34d57ed 100644 --- a/logos_delivery/waku/rln/protocol_types.nim +++ b/logos_delivery/waku/rln/protocol_types.nim @@ -1,6 +1,6 @@ {.push raises: [].} -import std/[options, tables, deques], stew/arrayops, stint, chronos, web3, eth/keys +import std/[tables, deques], stew/arrayops, stint, chronos, web3, eth/keys import ../waku_core, ../waku_keystore, ../common/protobuf export waku_keystore, waku_core diff --git a/logos_delivery/waku/rln/rln.nim b/logos_delivery/waku/rln/rln.nim index fa952822b..633d433dd 100644 --- a/logos_delivery/waku/rln/rln.nim +++ b/logos_delivery/waku/rln/rln.nim @@ -1,10 +1,8 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import std/[sequtils, tables, times, deques], chronicles, - options, chronos, stint, web3, @@ -182,7 +180,7 @@ proc monitorEpochs(rln: Rln) {.async.} = await sleepAsync(sleepDuration) proc mount( - conf: WakuRlnConfig, registrationHandler = none(RegistrationHandler) + conf: WakuRlnConfig, registrationHandler = Opt.none(RegistrationHandler) ): Future[Result[Rln, string]] {.async.} = var groupManager: GroupManager @@ -193,12 +191,12 @@ proc mount( let (rlnRelayCredPath, rlnRelayCredPassword) = if conf.creds.isSome: - (some(conf.creds.get().path), some(conf.creds.get().password)) + (Opt.some(conf.creds.get().path), Opt.some(conf.creds.get().password)) else: - (none(string), none(string)) + (Opt.none(string), Opt.none(string)) groupManager = OnchainGroupManager( - userMessageLimit: some(conf.userMessageLimit), + userMessageLimit: Opt.some(conf.userMessageLimit), ethClientUrls: conf.ethClientUrls, ethContractAddress: $conf.ethContractAddress, chainId: conf.chainId, @@ -258,7 +256,9 @@ proc isReady*(rlnPeer: Rln): Future[bool] {.async.} = return false proc new*( - T: type Rln, conf: WakuRlnConfig, registrationHandler = none(RegistrationHandler) + T: type Rln, + conf: WakuRlnConfig, + registrationHandler = Opt.none(RegistrationHandler), ): Future[Result[Rln, string]] {.async.} = ## Mounts the rln-relay protocol on the node. ## The rln-relay protocol can be mounted in two modes: on-chain and off-chain. diff --git a/logos_delivery/waku/rln/rln/rln_interface.nim b/logos_delivery/waku/rln/rln/rln_interface.nim index d9b2fc903..23ac6c654 100644 --- a/logos_delivery/waku/rln/rln/rln_interface.nim +++ b/logos_delivery/waku/rln/rln/rln_interface.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor ## Nim wrappers for librln (zerokit v2.0.2, safer-ffi typed handles). ## ## Built against the `stateless` zerokit feature: tree-mutation FFI is not @@ -17,8 +16,7 @@ import logos_delivery/waku/compat/option_valueor ## x<32> | y<32> | nullifier<32> ] ## Total RLNProof byte size: 1 + 128 + 1 + 5*32 = 290 bytes. -import results -import ../protocol_types +import results, ../protocol_types {.push raises: [], gcsafe.} diff --git a/logos_delivery/waku/rln/rln/wrappers.nim b/logos_delivery/waku/rln/rln/wrappers.nim index 4f46fc164..d2d115484 100644 --- a/logos_delivery/waku/rln/rln/wrappers.nim +++ b/logos_delivery/waku/rln/rln/wrappers.nim @@ -1,8 +1,15 @@ -import logos_delivery/waku/compat/option_valueor -import chronicles, eth/keys, stew/[arrayops, endians2], stint, results +import stew/[arrayops, endians2], stint, results -import ./rln_interface, ../conversion_utils, ../protocol_types, ../protocol_metrics -import ../../waku_core, ../../waku_keystore +import chronicles, eth/keys + +import + logos_delivery/waku/[ + rln/rln/rln_interface, + rln/conversion_utils, + rln/protocol_types, + rln/protocol_metrics, + ] +import logos_delivery/waku/[waku_core, waku_keystore] {.push raises: [], gcsafe.} diff --git a/logos_delivery/waku/waku.nim b/logos_delivery/waku/waku.nim index 29290483f..29b42a7ef 100644 --- a/logos_delivery/waku/waku.nim +++ b/logos_delivery/waku/waku.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[options, sequtils, strformat], + std/[sequtils, strformat], results, chronicles, chronos, diff --git a/logos_delivery/waku/waku_archive/archive.nim b/logos_delivery/waku/waku_archive/archive.nim index ea5e2bf02..165d87277 100644 --- a/logos_delivery/waku/waku_archive/archive.nim +++ b/logos_delivery/waku/waku_archive/archive.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[times, options, sequtils, algorithm], + std/[times, sequtils, algorithm], stew/[byteutils], chronicles, chronos, @@ -233,7 +232,7 @@ proc findMessages*( var hashes = newSeq[WakuMessageHash]() var messages = newSeq[WakuMessage]() var topics = newSeq[PubsubTopic]() - var cursor = none(ArchiveCursor) + var cursor = Opt.none(ArchiveCursor) if rows.len == 0: return ok(ArchiveResponse(hashes: hashes, messages: messages, cursor: cursor)) @@ -253,7 +252,7 @@ proc findMessages*( let (hash, _, _) = rows[^2] - cursor = some(hash) + cursor = Opt.some(hash) # Messages MUST be returned in chronological order if not isAscendingOrder: diff --git a/logos_delivery/waku/waku_archive/common.nim b/logos_delivery/waku/waku_archive/common.nim index f26c73da9..4ef5e370b 100644 --- a/logos_delivery/waku/waku_archive/common.nim +++ b/logos_delivery/waku/waku_archive/common.nim @@ -1,7 +1,6 @@ {.push raises: [].} -import std/options, results -import ../waku_core, ../common/paging +import results, ../waku_core, ../common/paging ## Public API types @@ -10,11 +9,11 @@ type ArchiveQuery* = object includeData*: bool - pubsubTopic*: Option[PubsubTopic] + pubsubTopic*: Opt[PubsubTopic] contentTopics*: seq[ContentTopic] - cursor*: Option[ArchiveCursor] - startTime*: Option[Timestamp] - endTime*: Option[Timestamp] + cursor*: Opt[ArchiveCursor] + startTime*: Opt[Timestamp] + endTime*: Opt[Timestamp] hashes*: seq[WakuMessageHash] pageSize*: uint direction*: PagingDirection @@ -24,7 +23,7 @@ type hashes*: seq[WakuMessageHash] messages*: seq[WakuMessage] topics*: seq[PubsubTopic] - cursor*: Option[ArchiveCursor] + cursor*: Opt[ArchiveCursor] ArchiveErrorKind* {.pure.} = enum UNKNOWN = uint32(0) diff --git a/logos_delivery/waku/waku_archive/driver.nim b/logos_delivery/waku/waku_archive/driver.nim index 4d5cedd66..bb9dd532f 100644 --- a/logos_delivery/waku/waku_archive/driver.nim +++ b/logos_delivery/waku/waku_archive/driver.nim @@ -1,6 +1,6 @@ {.push raises: [].} -import std/options, results, chronos +import results, chronos import ../waku_core, ./common const DefaultPageSize*: uint = 25 @@ -30,10 +30,10 @@ method getMessages*( driver: ArchiveDriver, includeData = true, contentTopics = newSeq[ContentTopic](0), - pubsubTopic = none(PubsubTopic), - cursor = none(ArchiveCursor), - startTime = none(Timestamp), - endTime = none(Timestamp), + pubsubTopic = Opt.none(PubsubTopic), + cursor = Opt.none(ArchiveCursor), + startTime = Opt.none(Timestamp), + endTime = Opt.none(Timestamp), hashes = newSeq[WakuMessageHash](0), maxPageSize = DefaultPageSize, ascendingOrder = true, diff --git a/logos_delivery/waku/waku_archive/driver/builder.nim b/logos_delivery/waku/waku_archive/driver/builder.nim index 632468a00..811b16999 100644 --- a/logos_delivery/waku/waku_archive/driver/builder.nim +++ b/logos_delivery/waku/waku_archive/driver/builder.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import results, chronicles, chronos diff --git a/logos_delivery/waku/waku_archive/driver/postgres_driver/migrations.nim b/logos_delivery/waku/waku_archive/driver/postgres_driver/migrations.nim index f216e75b8..a1a3e93fe 100644 --- a/logos_delivery/waku/waku_archive/driver/postgres_driver/migrations.nim +++ b/logos_delivery/waku/waku_archive/driver/postgres_driver/migrations.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import std/strutils, results, chronicles, chronos diff --git a/logos_delivery/waku/waku_archive/driver/postgres_driver/postgres_driver.nim b/logos_delivery/waku/waku_archive/driver/postgres_driver/postgres_driver.nim index e909f953f..43a36821a 100644 --- a/logos_delivery/waku/waku_archive/driver/postgres_driver/postgres_driver.nim +++ b/logos_delivery/waku/waku_archive/driver/postgres_driver/postgres_driver.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[options, sequtils, strutils, strformat, times, sugar], + std/[sequtils, strutils, strformat, times, sugar], stew/[byteutils, arrayops], results, chronos, @@ -169,7 +168,7 @@ proc reset*(s: PostgresDriver): Future[ArchiveDriverResult[void]] {.async.} = let ret = await s.decreaseDatabaseSize(targetSize, forceRemoval) return ret -proc timeCursorCallbackImpl(pqResult: ptr PGresult, timeCursor: var Option[Timestamp]) = +proc timeCursorCallbackImpl(pqResult: ptr PGresult, timeCursor: var Opt[Timestamp]) = ## Callback to get a timestamp out of the DB. ## Used to get the cursor timestamp. @@ -192,7 +191,7 @@ proc timeCursorCallbackImpl(pqResult: ptr PGresult, timeCursor: var Option[Times error "could not parse correctly", error = error.msg return - timeCursor = some(time) + timeCursor = Opt.some(time) proc hashCallbackImpl( pqResult: ptr PGresult, rows: var seq[(WakuMessageHash, PubsubTopic, WakuMessage)] @@ -445,8 +444,8 @@ proc dropOrphanPartitions( proc getTimeCursor( s: PostgresDriver, hashHex: string -): Future[ArchiveDriverResult[Option[Timestamp]]] {.async.} = - var timeCursor: Option[Timestamp] +): Future[ArchiveDriverResult[Opt[Timestamp]]] {.async.} = + var timeCursor: Opt[Timestamp] proc cursorCallback(pqResult: ptr PGresult) = timeCursorCallbackImpl(pqResult, timeCursor) @@ -465,10 +464,10 @@ proc getTimeCursor( proc getMessagesArbitraryQuery( s: PostgresDriver, contentTopics: seq[ContentTopic] = @[], - pubsubTopic = none(PubsubTopic), - cursor = none(ArchiveCursor), - startTime = none(Timestamp), - endTime = none(Timestamp), + pubsubTopic = Opt.none(PubsubTopic), + cursor = Opt.none(ArchiveCursor), + startTime = Opt.none(Timestamp), + endTime = Opt.none(Timestamp), hexHashes: seq[string] = @[], maxPageSize = DefaultPageSize, ascendingOrder = true, @@ -544,10 +543,10 @@ proc getMessagesArbitraryQuery( proc getMessageHashesArbitraryQuery( s: PostgresDriver, contentTopics: seq[ContentTopic] = @[], - pubsubTopic = none(PubsubTopic), - cursor = none(ArchiveCursor), - startTime = none(Timestamp), - endTime = none(Timestamp), + pubsubTopic = Opt.none(PubsubTopic), + cursor = Opt.none(ArchiveCursor), + startTime = Opt.none(Timestamp), + endTime = Opt.none(Timestamp), hexHashes: seq[string] = @[], maxPageSize = DefaultPageSize, ascendingOrder = true, @@ -626,7 +625,7 @@ proc getMessagesPreparedStmt( s: PostgresDriver, contentTopic: string, pubsubTopic: PubsubTopic, - cursor = none(ArchiveCursor), + cursor = Opt.none(ArchiveCursor), startTime: Timestamp, endTime: Timestamp, hashes: string, @@ -717,7 +716,7 @@ proc getMessageHashesPreparedStmt( s: PostgresDriver, contentTopic: string, pubsubTopic: PubsubTopic, - cursor = none(ArchiveCursor), + cursor = Opt.none(ArchiveCursor), startTime: Timestamp, endTime: Timestamp, hashes: string, @@ -859,10 +858,10 @@ proc getMessagesWithinLimits( self: PostgresDriver, includeData: bool, contentTopics: seq[ContentTopic], - pubsubTopic: Option[PubsubTopic], - cursor: Option[ArchiveCursor], - startTime: Option[Timestamp], - endTime: Option[Timestamp], + pubsubTopic: Opt[PubsubTopic], + cursor: Opt[ArchiveCursor], + startTime: Opt[Timestamp], + endTime: Opt[Timestamp], hashes: seq[WakuMessageHash], maxPageSize: uint, ascendingOrder: bool, @@ -923,10 +922,10 @@ method getMessages*( s: PostgresDriver, includeData = true, contentTopics = newSeq[ContentTopic](0), - pubsubTopic = none(PubsubTopic), - cursor = none(ArchiveCursor), - startTime = none(Timestamp), - endTime = none(Timestamp), + pubsubTopic = Opt.none(PubsubTopic), + cursor = Opt.none(ArchiveCursor), + startTime = Opt.none(Timestamp), + endTime = Opt.none(Timestamp), hashes = newSeq[WakuMessageHash](0), maxPageSize = DefaultPageSize, ascendingOrder = true, diff --git a/logos_delivery/waku/waku_archive/driver/queue_driver/queue_driver.nim b/logos_delivery/waku/waku_archive/driver/queue_driver/queue_driver.nim index a810d231a..96a72d7f9 100644 --- a/logos_delivery/waku/waku_archive/driver/queue_driver/queue_driver.nim +++ b/logos_delivery/waku/waku_archive/driver/queue_driver/queue_driver.nim @@ -1,7 +1,6 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} -import std/options, results, stew/sorted_set, chronicles, chronos +import results, stew/sorted_set, chronicles, chronos import ../../../waku_core, ../../common, ../../driver, ./index logScope: @@ -81,7 +80,7 @@ proc getPage( driver: QueueDriver, pageSize: uint = 0, forward: bool = true, - cursor: Option[Index] = none(Index), + cursor: Opt[Index] = Opt.none(Index), predicate: QueryFilterMatcher = nil, ): QueueDriverGetPageResult {.raises: [].} = ## Populate a single page in forward direction @@ -249,19 +248,19 @@ method getMessages*( driver: QueueDriver, includeData = true, contentTopics: seq[ContentTopic] = @[], - pubsubTopic = none(PubsubTopic), - cursor = none(ArchiveCursor), - startTime = none(Timestamp), - endTime = none(Timestamp), + pubsubTopic = Opt.none(PubsubTopic), + cursor = Opt.none(ArchiveCursor), + startTime = Opt.none(Timestamp), + endTime = Opt.none(Timestamp), hashes: seq[WakuMessageHash] = @[], maxPageSize = DefaultPageSize, ascendingOrder = true, requestId = "", ): Future[ArchiveDriverResult[seq[ArchiveRow]]] {.async.} = - var index = none(Index) + var index = Opt.none(Index) if cursor.isSome(): - index = some(Index(hash: cursor.get())) + index = Opt.some(Index(hash: cursor.get())) let matchesQuery: QueryFilterMatcher = func (index: Index, msg: WakuMessage): bool = diff --git a/logos_delivery/waku/waku_archive/driver/sqlite_driver/queries.nim b/logos_delivery/waku/waku_archive/driver/sqlite_driver/queries.nim index 9ef6591c2..c7e0037cc 100644 --- a/logos_delivery/waku/waku_archive/driver/sqlite_driver/queries.nim +++ b/logos_delivery/waku/waku_archive/driver/sqlite_driver/queries.nim @@ -1,6 +1,6 @@ {.push raises: [].} -import std/[options, sequtils], stew/byteutils, sqlite3_abi, results +import std/sequtils, stew/byteutils, sqlite3_abi, results import chronicles import ../../../common/databases/db_sqlite, @@ -253,15 +253,15 @@ proc selectAllMessageHashes*(db: SqliteDatabase): DatabaseResult[seq[WakuMessage ## Select messages by history query with limit -proc combineClauses(clauses: varargs[Option[string]]): Option[string] = +proc combineClauses(clauses: varargs[Opt[string]]): Opt[string] = let whereSeq = @clauses.filterIt(it.isSome()).mapIt(it.get()) if whereSeq.len <= 0: - return none(string) + return Opt.none(string) var where: string = whereSeq[0] for clause in whereSeq[1 ..^ 1]: where &= " AND " & clause - return some(where) + return Opt.some(where) proc prepareStmt( db: SqliteDatabase, stmt: string @@ -299,11 +299,11 @@ proc selectTimestampByHashQuery(table: string): SqlQueryStr = proc getCursorTimestamp( db: SqliteDatabase, hash: WakuMessageHash -): DatabaseResult[Option[Timestamp]] = - var timestamp = none(Timestamp) +): DatabaseResult[Opt[Timestamp]] = + var timestamp = Opt.none(Timestamp) proc queryRowCallback(s: ptr sqlite3_stmt) = - timestamp = some(queryRowTimestampCallback(s, 0)) + timestamp = Opt.some(queryRowTimestampCallback(s, 0)) let query = selectTimestampByHashQuery(DbTable) let dbStmt = ?db.prepareStmt(query) @@ -314,60 +314,60 @@ proc getCursorTimestamp( proc whereClause( cursor: bool, - pubsubTopic: Option[PubsubTopic], + pubsubTopic: Opt[PubsubTopic], contentTopic: seq[ContentTopic], - startTime: Option[Timestamp], - endTime: Option[Timestamp], + startTime: Opt[Timestamp], + endTime: Opt[Timestamp], hashes: seq[WakuMessageHash], ascending: bool, -): Option[string] = +): Opt[string] = let cursorClause = if cursor: let comp = if ascending: ">" else: "<" - some("(timestamp, messageHash) " & comp & " (?, ?)") + Opt.some("(timestamp, messageHash) " & comp & " (?, ?)") else: - none(string) + Opt.none(string) let pubsubTopicClause = if pubsubTopic.isNone(): - none(string) + Opt.none(string) else: - some("pubsubTopic = (?)") + Opt.some("pubsubTopic = (?)") let contentTopicClause = if contentTopic.len <= 0: - none(string) + Opt.none(string) else: var where = "contentTopic IN (" where &= "?" for _ in 1 ..< contentTopic.len: where &= ", ?" where &= ")" - some(where) + Opt.some(where) let startTimeClause = if startTime.isNone(): - none(string) + Opt.none(string) else: - some("timestamp >= (?)") + Opt.some("timestamp >= (?)") let endTimeClause = if endTime.isNone(): - none(string) + Opt.none(string) else: - some("timestamp <= (?)") + Opt.some("timestamp <= (?)") let hashesClause = if hashes.len <= 0: - none(string) + Opt.none(string) else: var where = "messageHash IN (" where &= "?" for _ in 1 ..< hashes.len: where &= ", ?" where &= ")" - some(where) + Opt.some(where) return combineClauses( cursorClause, pubsubTopicClause, contentTopicClause, startTimeClause, endTimeClause, @@ -376,11 +376,11 @@ proc whereClause( proc execSelectMessagesWithLimitStmt( s: SqliteStmt, - cursor: Option[(Timestamp, WakuMessageHash)], - pubsubTopic: Option[PubsubTopic], + cursor: Opt[(Timestamp, WakuMessageHash)], + pubsubTopic: Opt[PubsubTopic], contentTopic: seq[ContentTopic], - startTime: Option[Timestamp], - endTime: Option[Timestamp], + startTime: Opt[Timestamp], + endTime: Opt[Timestamp], hashes: seq[WakuMessageHash], onRowCallback: DataProc, ): DatabaseResult[void] = @@ -438,7 +438,7 @@ proc execSelectMessagesWithLimitStmt( discard sqlite3_clear_bindings(s) # no errors possible proc selectMessagesWithLimitQuery( - table: string, where: Option[string], limit: uint, ascending = true + table: string, where: Opt[string], limit: uint, ascending = true ): SqlQueryStr = let order = if ascending: "ASC" else: "DESC" @@ -458,7 +458,7 @@ proc selectMessagesWithLimitQuery( return query proc selectMessageHashesWithLimitQuery( - table: string, where: Option[string], limit: uint, ascending = true + table: string, where: Opt[string], limit: uint, ascending = true ): SqlQueryStr = let order = if ascending: "ASC" else: "DESC" @@ -476,15 +476,15 @@ proc selectMessageHashesWithLimitQuery( proc selectMessagesByStoreQueryWithLimit*( db: SqliteDatabase, contentTopic: seq[ContentTopic], - pubsubTopic: Option[PubsubTopic], - cursor: Option[WakuMessageHash], - startTime: Option[Timestamp], - endTime: Option[Timestamp], + pubsubTopic: Opt[PubsubTopic], + cursor: Opt[WakuMessageHash], + startTime: Opt[Timestamp], + endTime: Opt[Timestamp], hashes: seq[WakuMessageHash], limit: uint, ascending: bool, ): DatabaseResult[seq[(WakuMessageHash, PubsubTopic, WakuMessage)]] = - var timeCursor = none((Timestamp, WakuMessageHash)) + var timeCursor = Opt.none((Timestamp, WakuMessageHash)) if cursor.isSome(): let hash: WakuMessageHash = cursor.get() @@ -494,7 +494,7 @@ proc selectMessagesByStoreQueryWithLimit*( if timeOpt.isNone(): return err("cursor not found") - timeCursor = some((timeOpt.get(), hash)) + timeCursor = Opt.some((timeOpt.get(), hash)) var rows: seq[(WakuMessageHash, PubsubTopic, WakuMessage)] = @[] @@ -536,15 +536,15 @@ proc selectMessagesByStoreQueryWithLimit*( proc selectMessageHashesByStoreQueryWithLimit*( db: SqliteDatabase, contentTopic: seq[ContentTopic], - pubsubTopic: Option[PubsubTopic], - cursor: Option[WakuMessageHash], - startTime: Option[Timestamp], - endTime: Option[Timestamp], + pubsubTopic: Opt[PubsubTopic], + cursor: Opt[WakuMessageHash], + startTime: Opt[Timestamp], + endTime: Opt[Timestamp], hashes: seq[WakuMessageHash], limit: uint, ascending: bool, ): DatabaseResult[seq[(WakuMessageHash, PubsubTopic, WakuMessage)]] = - var timeCursor = none((Timestamp, WakuMessageHash)) + var timeCursor = Opt.none((Timestamp, WakuMessageHash)) if cursor.isSome(): let hash: WakuMessageHash = cursor.get() @@ -554,7 +554,7 @@ proc selectMessageHashesByStoreQueryWithLimit*( if timeOpt.isNone(): return err("cursor not found") - timeCursor = some((timeOpt.get(), hash)) + timeCursor = Opt.some((timeOpt.get(), hash)) var rows: seq[(WakuMessageHash, PubsubTopic, WakuMessage)] = @[] diff --git a/logos_delivery/waku/waku_archive/driver/sqlite_driver/sqlite_driver.nim b/logos_delivery/waku/waku_archive/driver/sqlite_driver/sqlite_driver.nim index 913f3d307..e12fb12bc 100644 --- a/logos_delivery/waku/waku_archive/driver/sqlite_driver/sqlite_driver.nim +++ b/logos_delivery/waku/waku_archive/driver/sqlite_driver/sqlite_driver.nim @@ -1,9 +1,8 @@ -import logos_delivery/waku/compat/option_valueor # The code in this file is an adaptation of the Sqlite KV Store found in nim-eth. # https://github.com/status-im/nim-eth/blob/master/eth/db/kvstore_sqlite3.nim {.push raises: [].} -import std/options, stew/byteutils, chronicles, chronos, results +import stew/byteutils, chronicles, chronos, results import ../../../common/databases/db_sqlite, ../../../waku_core, @@ -73,10 +72,10 @@ method getMessages*( s: SqliteDriver, includeData = true, contentTopics = newSeq[ContentTopic](0), - pubsubTopic = none(PubsubTopic), - cursor = none(ArchiveCursor), - startTime = none(Timestamp), - endTime = none(Timestamp), + pubsubTopic = Opt.none(PubsubTopic), + cursor = Opt.none(ArchiveCursor), + startTime = Opt.none(Timestamp), + endTime = Opt.none(Timestamp), hashes = newSeq[WakuMessageHash](0), maxPageSize = DefaultPageSize, ascendingOrder = true, diff --git a/logos_delivery/waku/waku_archive/retention_policy/builder.nim b/logos_delivery/waku/waku_archive/retention_policy/builder.nim index ad49ed45e..62323dce2 100644 --- a/logos_delivery/waku/waku_archive/retention_policy/builder.nim +++ b/logos_delivery/waku/waku_archive/retention_policy/builder.nim @@ -1,7 +1,6 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} -import std/[strutils, options], regex, results +import std/strutils, regex, results import ../retention_policy, ./retention_policy_time, @@ -10,12 +9,12 @@ import proc new( T: type RetentionPolicy, retPolicy: string -): RetentionPolicyResult[Option[RetentionPolicy]] = +): RetentionPolicyResult[Opt[RetentionPolicy]] = let retPolicy = retPolicy.toLower # Validate the retention policy format if retPolicy == "" or retPolicy == "none": - return ok(none(RetentionPolicy)) + return ok(Opt.none(RetentionPolicy)) const StoreMessageRetentionPolicyRegex = re2"^\w+:\d*\.?\d+((g|m)b)?$" if not retPolicy.match(StoreMessageRetentionPolicyRegex): @@ -35,7 +34,7 @@ proc new( return err("invalid time retention policy argument") let retPolicy: RetentionPolicy = TimeRetentionPolicy.new(retentionTimeSeconds) - return ok(some(retPolicy)) + return ok(Opt.some(retPolicy)) elif policy == "capacity": var retentionCapacity: int try: @@ -44,7 +43,7 @@ proc new( return err("invalid capacity retention policy argument") let retPolicy: RetentionPolicy = CapacityRetentionPolicy.new(retentionCapacity) - return ok(some(retPolicy)) + return ok(Opt.some(retPolicy)) elif policy == "size": var retentionSize: string retentionSize = policyArgs @@ -81,7 +80,7 @@ proc new( return err("invalid size retention policy argument: a non-zero value is required") let retPolicy: RetentionPolicy = SizeRetentionPolicy.new(sizeQuantity) - return ok(some(retPolicy)) + return ok(Opt.some(retPolicy)) else: return err("unknown retention policy") diff --git a/logos_delivery/waku/waku_archive/retention_policy/retention_policy_capacity.nim b/logos_delivery/waku/waku_archive/retention_policy/retention_policy_capacity.nim index 088508b9b..ff4da6861 100644 --- a/logos_delivery/waku/waku_archive/retention_policy/retention_policy_capacity.nim +++ b/logos_delivery/waku/waku_archive/retention_policy/retention_policy_capacity.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import results, chronicles, chronos diff --git a/logos_delivery/waku/waku_core/peers.nim b/logos_delivery/waku/waku_core/peers.nim index c28ae5427..5fca2a649 100644 --- a/logos_delivery/waku/waku_core/peers.nim +++ b/logos_delivery/waku/waku_core/peers.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[options, sequtils, strutils, uri, net], + std/[sequtils, strutils, uri, net], results, chronos, chronicles, @@ -50,10 +49,10 @@ type type RemotePeerInfo* = ref object peerId*: PeerID addrs*: seq[MultiAddress] - enr*: Option[enr.Record] + enr*: Opt[enr.Record] protocols*: seq[string] shards*: seq[uint16] - mixPubKey*: Option[Curve25519Key] + mixPubKey*: Opt[Curve25519Key] agent*: string protoVersion*: string @@ -77,7 +76,7 @@ proc init*( T: typedesc[RemotePeerInfo], peerId: PeerID, addrs: seq[MultiAddress] = @[], - enr: Option[enr.Record] = none(enr.Record), + enr: Opt[enr.Record] = Opt.none(enr.Record), protocols: seq[string] = @[], shards: seq[uint16] = @[], publicKey: crypto.PublicKey = crypto.PublicKey(), @@ -89,7 +88,7 @@ proc init*( direction: PeerDirection = UnknownDirection, lastFailedConn: Moment = Moment.init(0, Second), numberFailedConn: int = 0, - mixPubKey: Option[Curve25519Key] = none(Curve25519Key), + mixPubKey: Opt[Curve25519Key] = Opt.none(Curve25519Key), ): T = RemotePeerInfo( peerId: peerId, @@ -113,7 +112,7 @@ proc init*( T: typedesc[RemotePeerInfo], peerId: string, addrs: seq[MultiAddress] = @[], - enr: Option[enr.Record] = none(enr.Record), + enr: Opt[enr.Record] = Opt.none(enr.Record), protocols: seq[string] = @[], shards: seq[uint16] = @[], ): T {.raises: [Defect, ResultError[cstring], LPError].} = @@ -240,19 +239,17 @@ proc parsePeerInfo*(maddrs: varargs[string]): Result[RemotePeerInfo, string] = parsePeerInfo(multiAddresses) -proc parseUrlPeerAddr*( - peerAddr: Option[string] -): Result[Option[RemotePeerInfo], string] = +proc parseUrlPeerAddr*(peerAddr: Opt[string]): Result[Opt[RemotePeerInfo], string] = # Checks whether the peerAddr parameter represents a valid p2p multiaddress. # The param must be in the format `(ip4|ip6)/tcp/p2p/$peerId` but URL-encoded if not peerAddr.isSome() or peerAddr.get() == "": - return ok(none(RemotePeerInfo)) + return ok(Opt.none(RemotePeerInfo)) let parsedAddr = decodeUrl(peerAddr.get()) let parsedPeerInfo = parsePeerInfo(parsedAddr).valueOr: return err("Failed parsing remote peer info: " & error) - return ok(some(parsedPeerInfo)) + return ok(Opt.some(parsedPeerInfo)) proc sortQuicFirst(addrs: seq[MultiAddress]): seq[MultiAddress] = ## QUIC addresses first, so they are dialed ahead of TCP. @@ -311,7 +308,7 @@ proc toRemotePeerInfo*(enrRec: enr.Record): Result[RemotePeerInfo, cstring] = error "Could not retrieve supported protocols from enr", peerId = peerId, msg = protocolsRes.error.msg - return ok(RemotePeerInfo.init(peerId, addrs, some(enrRec), protocols)) + return ok(RemotePeerInfo.init(peerId, addrs, Opt.some(enrRec), protocols)) converter toRemotePeerInfo*(peerRecord: PeerRecord): RemotePeerInfo = ## Converts peer records to dialable RemotePeerInfo @@ -324,7 +321,7 @@ converter toRemotePeerInfo*(peerInfo: PeerInfo): RemotePeerInfo = RemotePeerInfo( peerId: peerInfo.peerId, addrs: sortQuicFirst(peerInfo.listenAddrs), - enr: none(enr.Record), + enr: Opt.none(enr.Record), protocols: peerInfo.protocols, shards: @[], agent: peerInfo.agentVersion, diff --git a/logos_delivery/waku/waku_core/topics/content_topic.nim b/logos_delivery/waku/waku_core/topics/content_topic.nim index 23da9a24a..c8ba467fb 100644 --- a/logos_delivery/waku/waku_core/topics/content_topic.nim +++ b/logos_delivery/waku/waku_core/topics/content_topic.nim @@ -1,11 +1,10 @@ -import logos_delivery/waku/compat/option_valueor ## Waku content topics definition and namespacing utils ## ## See 23/WAKU2-TOPICS RFC: https://rfc.vac.dev/spec/23/ {.push raises: [].} -import std/options, std/strutils, results +import std/strutils, results import ./parsing export parsing @@ -19,7 +18,7 @@ const DefaultContentTopic* = ContentTopic("/waku/2/default-content/proto") ## Namespaced content topic type NsContentTopic* = object - generation*: Option[int] + generation*: Opt[int] application*: string version*: string name*: string @@ -27,7 +26,7 @@ type NsContentTopic* = object proc init*( T: type NsContentTopic, - generation: Option[int], + generation: Opt[int], application: string, version: string, name: string, @@ -90,7 +89,7 @@ proc parse*( if enc.len == 0: return err(ParsingError.missingPart("encoding")) - return ok(NsContentTopic.init(none(int), app, ver, name, enc)) + return ok(NsContentTopic.init(Opt.none(int), app, ver, name, enc)) of 5: if parts[0].len == 0: return err(ParsingError.missingPart("generation")) @@ -117,7 +116,7 @@ proc parse*( if enc.len == 0: return err(ParsingError.missingPart("encoding")) - return ok(NsContentTopic.init(some(gen), app, ver, name, enc)) + return ok(NsContentTopic.init(Opt.some(gen), app, ver, name, enc)) else: let errMsg = "Invalid content topic structure. Expected either //// or /////" diff --git a/logos_delivery/waku/waku_core/topics/sharding.nim b/logos_delivery/waku/waku_core/topics/sharding.nim index 704180554..e04e68e8e 100644 --- a/logos_delivery/waku/waku_core/topics/sharding.nim +++ b/logos_delivery/waku/waku_core/topics/sharding.nim @@ -1,11 +1,10 @@ -import logos_delivery/waku/compat/option_valueor ## Waku autosharding utils ## ## See 51/WAKU2-RELAY-SHARDING RFC: https://rfc.vac.dev/spec/51/#automatic-sharding {.push raises: [].} -import nimcrypto, std/options, std/tables, stew/endians2, results, stew/byteutils +import nimcrypto, std/tables, stew/endians2, results, stew/byteutils import ./content_topic, ./pubsub_topic diff --git a/logos_delivery/waku/waku_enr/capabilities.nim b/logos_delivery/waku/waku_enr/capabilities.nim index 42008e9c7..6a8ec4406 100644 --- a/logos_delivery/waku/waku_enr/capabilities.nim +++ b/logos_delivery/waku/waku_enr/capabilities.nim @@ -1,8 +1,6 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} -import - std/[options, bitops, sequtils, net, tables], results, eth/keys, libp2p/crypto/crypto +import std/[bitops, sequtils, net, tables], results, eth/keys, libp2p/crypto/crypto import ../common/enr, ../waku_core/codecs import libp2p_mix @@ -84,15 +82,15 @@ proc withWakuCapabilities*(builder: var EnrBuilder, caps: openArray[Capabilities # ENR record accessors (e.g., Record, TypedRecord, etc.) -func waku2*(record: TypedRecord): Option[CapabilitiesBitfield] = +func waku2*(record: TypedRecord): Opt[CapabilitiesBitfield] = let field = record.tryGet(CapabilitiesEnrField, seq[uint8]) if field.isNone(): - return none(CapabilitiesBitfield) + return Opt.none(CapabilitiesBitfield) if field.get().len != 1: - return none(CapabilitiesBitfield) + return Opt.none(CapabilitiesBitfield) - some(CapabilitiesBitfield(field.get()[0])) + Opt.some(CapabilitiesBitfield(field.get()[0])) proc supportsCapability*(r: Record, cap: Capabilities): bool = let recordRes = r.toTyped().valueOr: diff --git a/logos_delivery/waku/waku_enr/multiaddr.nim b/logos_delivery/waku/waku_enr/multiaddr.nim index a275b2599..db2e86ca1 100644 --- a/logos_delivery/waku/waku_enr/multiaddr.nim +++ b/logos_delivery/waku/waku_enr/multiaddr.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[options, sequtils, net], + std/[sequtils, net], stew/endians2, results, eth/keys, @@ -84,12 +83,12 @@ func withMultiaddrs*(builder: var EnrBuilder, multiaddrs: varargs[MultiAddress]) # ENR record accessors (e.g., Record, TypedRecord, etc.) -func multiaddrs*(record: TypedRecord): Option[seq[MultiAddress]] = +func multiaddrs*(record: TypedRecord): Opt[seq[MultiAddress]] = let field = record.tryGet(MultiaddrEnrField, seq[byte]) if field.isNone(): - return none(seq[MultiAddress]) + return Opt.none(seq[MultiAddress]) let decodeRes = decodeMultiaddrs(field.get()).valueOr: - return none(seq[MultiAddress]) + return Opt.none(seq[MultiAddress]) - some(decodeRes) + Opt.some(decodeRes) diff --git a/logos_delivery/waku/waku_enr/sharding.nim b/logos_delivery/waku/waku_enr/sharding.nim index 682772539..3d52fbfe8 100644 --- a/logos_delivery/waku/waku_enr/sharding.nim +++ b/logos_delivery/waku/waku_enr/sharding.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[options, bitops, sequtils, net], + std/[bitops, sequtils, net], stew/endians2, results, chronicles, @@ -58,9 +57,9 @@ func init*( ok(RelayShards(clusterId: clusterId, shardIds: indicesSeq)) -func topicsToRelayShards*(topics: seq[string]): Result[Option[RelayShards], string] = +func topicsToRelayShards*(topics: seq[string]): Result[Opt[RelayShards], string] = if topics.len < 1: - return ok(none(RelayShards)) + return ok(Opt.none(RelayShards)) let parsedTopicsRes = topics.mapIt(RelayShard.parse(it)) @@ -75,7 +74,7 @@ func topicsToRelayShards*(topics: seq[string]): Result[Option[RelayShards], stri parsedTopicsRes[0].get().clusterId, parsedTopicsRes.mapIt(it.get().shardId) ) - return ok(some(relayShard)) + return ok(Opt.some(relayShard)) func contains*(rs: RelayShards, clusterId, shardId: uint16): bool = return rs.clusterId == clusterId and rs.shardIds.contains(shardId) @@ -193,31 +192,31 @@ func withShardedTopics*( # ENR record accessors (e.g., Record, TypedRecord, etc.) -proc relayShardingIndicesList*(record: TypedRecord): Option[RelayShards] = +proc relayShardingIndicesList*(record: TypedRecord): Opt[RelayShards] = let field = record.tryGet(ShardingIndicesListEnrField, seq[byte]).valueOr: - return none(RelayShards) + return Opt.none(RelayShards) let indexList = fromIndicesList(field).valueOr: info "invalid shards list", error = error - return none(RelayShards) + return Opt.none(RelayShards) - some(indexList) + Opt.some(indexList) -proc relayShardingBitVector*(record: TypedRecord): Option[RelayShards] = +proc relayShardingBitVector*(record: TypedRecord): Opt[RelayShards] = let field = record.tryGet(ShardingBitVectorEnrField, seq[byte]).valueOr: - return none(RelayShards) + return Opt.none(RelayShards) let bitVector = fromBitVector(field).valueOr: info "invalid shards bit vector", error = error - return none(RelayShards) + return Opt.none(RelayShards) - some(bitVector) + Opt.some(bitVector) -proc relaySharding*(record: TypedRecord): Option[RelayShards] = +proc relaySharding*(record: TypedRecord): Opt[RelayShards] = let indexList = record.relayShardingIndicesList().valueOr: return record.relayShardingBitVector() - return some(indexList) + return Opt.some(indexList) ## Utils diff --git a/logos_delivery/waku/waku_filter_v2/client.nim b/logos_delivery/waku/waku_filter_v2/client.nim index 51ed18af3..ae12372ba 100644 --- a/logos_delivery/waku/waku_filter_v2/client.nim +++ b/logos_delivery/waku/waku_filter_v2/client.nim @@ -1,11 +1,9 @@ -import logos_delivery/waku/compat/option_valueor -import libp2p/crypto/crypto +import results, libp2p/crypto/crypto ## Waku Filter client for subscribing and receiving filtered messages {.push raises: [].} import - std/options, chronicles, chronos, libp2p/protocols/protocol, @@ -42,7 +40,7 @@ proc sendSubscribeRequest( trace "Sending filter subscribe request", peerId = servicePeer.peerId, filterSubscribeRequest - var connOpt: Option[Connection] + var connOpt: Opt[Connection] try: connOpt = await wfc.peerManager.dialPeer(servicePeer, WakuFilterSubscribeCodec) if connOpt.isNone(): diff --git a/logos_delivery/waku/waku_filter_v2/protocol.nim b/logos_delivery/waku/waku_filter_v2/protocol.nim index ab77ce2dc..768f303fe 100644 --- a/logos_delivery/waku/waku_filter_v2/protocol.nim +++ b/logos_delivery/waku/waku_filter_v2/protocol.nim @@ -1,10 +1,10 @@ -import logos_delivery/waku/compat/option_valueor ## Waku Filter protocol for subscribing and filtering messages {.push raises: [].} import - std/[options, sequtils, sets, tables], + results, + std/[sequtils, sets, tables], stew/byteutils, chronicles, chronos, @@ -48,7 +48,7 @@ proc setSubscriptionTimeout*(wf: WakuFilter, newTimeout: Duration) = proc subscribe( wf: WakuFilter, peerId: PeerID, - pubsubTopic: Option[PubsubTopic], + pubsubTopic: Opt[PubsubTopic], contentTopics: seq[ContentTopic], ): Future[FilterSubscribeResult] {.async.} = # TODO: check if this condition is valid??? @@ -81,7 +81,7 @@ proc subscribe( proc unsubscribe( wf: WakuFilter, peerId: PeerID, - pubsubTopic: Option[PubsubTopic], + pubsubTopic: Opt[PubsubTopic], contentTopics: seq[ContentTopic], ): FilterSubscribeResult = if pubsubTopic.isNone() or contentTopics.len == 0: @@ -163,7 +163,7 @@ proc handleSubscribeRequest*( return FilterSubscribeResponse( requestId: request.requestId, statusCode: error.kind.uint32, - statusDesc: some($error), + statusDesc: Opt.some($error), ) return FilterSubscribeResponse.ok(request.requestId) @@ -331,7 +331,7 @@ proc initProtocolHandler(wf: WakuFilter) = response = FilterSubscribeResponse( requestId: "N/A", statusCode: FilterSubscribeErrorKind.TOO_MANY_REQUESTS.uint32, - statusDesc: some("filter request rejected due rate limit exceeded"), + statusDesc: Opt.some("filter request rejected due rate limit exceeded"), ) try: @@ -360,7 +360,7 @@ proc new*( maxFilterPeers: uint32 = MaxFilterPeers, maxFilterCriteriaPerPeer: uint32 = MaxFilterCriteriaPerPeer, messageCacheTTL: Duration = MessageCacheTTL, - rateLimitSetting: Option[RateLimitSetting] = none[RateLimitSetting](), + rateLimitSetting: Opt[RateLimitSetting] = Opt.none(RateLimitSetting), ): T = let wf = WakuFilter( subscriptions: FilterSubscriptions.new( diff --git a/logos_delivery/waku/waku_filter_v2/rpc.nim b/logos_delivery/waku/waku_filter_v2/rpc.nim index a81a7bd9a..30c0742c0 100644 --- a/logos_delivery/waku/waku_filter_v2/rpc.nim +++ b/logos_delivery/waku/waku_filter_v2/rpc.nim @@ -1,6 +1,6 @@ {.push raises: [].} -import json_serialization, std/options +import results, json_serialization import ../waku_core type @@ -14,13 +14,13 @@ type FilterSubscribeRequest* = object # Request from client to service node requestId*: string filterSubscribeType*: FilterSubscribeType - pubsubTopic*: Option[PubsubTopic] + pubsubTopic*: Opt[PubsubTopic] contentTopics*: seq[ContentTopic] FilterSubscribeResponse* = object # Response from service node to client requestId*: string statusCode*: uint32 - statusDesc*: Option[string] + statusDesc*: Opt[string] MessagePush* = object # Message pushed from service node to client wakuMessage*: WakuMessage @@ -40,7 +40,7 @@ proc subscribe*( FilterSubscribeRequest( requestId: requestId, filterSubscribeType: SUBSCRIBE, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopics, ) @@ -53,7 +53,7 @@ proc unsubscribe*( FilterSubscribeRequest( requestId: requestId, filterSubscribeType: UNSUBSCRIBE, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopics, ) @@ -61,11 +61,13 @@ proc unsubscribeAll*(T: type FilterSubscribeRequest, requestId: string): T = FilterSubscribeRequest(requestId: requestId, filterSubscribeType: UNSUBSCRIBE_ALL) proc ok*(T: type FilterSubscribeResponse, requestId: string, desc = "OK"): T = - FilterSubscribeResponse(requestId: requestId, statusCode: 200, statusDesc: some(desc)) + FilterSubscribeResponse( + requestId: requestId, statusCode: 200, statusDesc: Opt.some(desc) + ) proc `$`*(err: FilterSubscribeResponse): string = "FilterSubscribeResponse of req:" & err.requestId & " [" & $err.statusCode & "] " & - $err.statusDesc + err.statusDesc.get("") proc `$`*(req: FilterSubscribeRequest): string = "FilterSubscribeRequest of req:" & req.requestId & " [" & $req.filterSubscribeType & diff --git a/logos_delivery/waku/waku_filter_v2/rpc_codec.nim b/logos_delivery/waku/waku_filter_v2/rpc_codec.nim index 94bdb367c..98c7111e2 100644 --- a/logos_delivery/waku/waku_filter_v2/rpc_codec.nim +++ b/logos_delivery/waku/waku_filter_v2/rpc_codec.nim @@ -1,7 +1,6 @@ {.push raises: [].} -import std/options -import ../common/protobuf, ../waku_core, ./rpc +import results, ../common/protobuf, ../waku_core, ./rpc const DefaultMaxSubscribeSize* = 10 * DefaultMaxWakuMessageSize + 64 * 1024 @@ -39,9 +38,9 @@ proc decode*(T: type FilterSubscribeRequest, buffer: seq[byte]): ProtobufResult[ var pubsubTopic: PubsubTopic if not ?pb.getField(10, pubsubTopic): - rpc.pubsubTopic = none(PubsubTopic) + rpc.pubsubTopic = Opt.none(PubsubTopic) else: - rpc.pubsubTopic = some(pubsubTopic) + rpc.pubsubTopic = Opt.some(pubsubTopic) discard ?pb.getRepeatedField(11, rpc.contentTopics) @@ -68,9 +67,9 @@ proc decode*(T: type FilterSubscribeResponse, buffer: seq[byte]): ProtobufResult var statusDesc: string if not ?pb.getField(11, statusDesc): - rpc.statusDesc = none(string) + rpc.statusDesc = Opt.none(string) else: - rpc.statusDesc = some(statusDesc) + rpc.statusDesc = Opt.some(statusDesc) ok(rpc) diff --git a/logos_delivery/waku/waku_filter_v2/subscriptions.nim b/logos_delivery/waku/waku_filter_v2/subscriptions.nim index 5c942cbf5..e1ec1664d 100644 --- a/logos_delivery/waku/waku_filter_v2/subscriptions.nim +++ b/logos_delivery/waku/waku_filter_v2/subscriptions.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[options, sets, tables, sequtils], + std/[sets, tables, sequtils], chronicles, chronos, libp2p/peerid, diff --git a/logos_delivery/waku/waku_keystore/keystore.nim b/logos_delivery/waku/waku_keystore/keystore.nim index 757024591..109972451 100644 --- a/logos_delivery/waku/waku_keystore/keystore.nim +++ b/logos_delivery/waku/waku_keystore/keystore.nim @@ -1,7 +1,6 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} -import options, json, strutils, sequtils, std/[tables, os] +import json, strutils, sequtils, std/[tables, os] import ./keyfile, ./conversion_utils, ./protocol_types, ./utils diff --git a/logos_delivery/waku/waku_lightpush/callbacks.nim b/logos_delivery/waku/waku_lightpush/callbacks.nim index 80d9c2439..16cdef9a5 100644 --- a/logos_delivery/waku/waku_lightpush/callbacks.nim +++ b/logos_delivery/waku/waku_lightpush/callbacks.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import results diff --git a/logos_delivery/waku/waku_lightpush/client.nim b/logos_delivery/waku/waku_lightpush/client.nim index 9572b9323..b282c2fa3 100644 --- a/logos_delivery/waku/waku_lightpush/client.nim +++ b/logos_delivery/waku/waku_lightpush/client.nim @@ -1,8 +1,7 @@ import libp2p/crypto/crypto -import logos_delivery/waku/compat/option_valueor {.push raises: [].} -import std/options, results, chronicles, chronos, metrics, bearssl/rand, stew/byteutils +import results, chronicles, chronos, metrics, bearssl/rand, stew/byteutils import libp2p/peerid, libp2p/stream/connection import ../waku_core/peers, @@ -35,7 +34,7 @@ proc sendPushRequest( wl: WakuLightPushClient, req: LightPushRequest, peer: PeerId | RemotePeerInfo, - conn: Option[Connection] = none(Connection), + conn: Opt[Connection] = Opt.none(Connection), ): Future[WakuLightPushResult] {.async.} = let connection = conn.valueOr: (await wl.peerManager.dialPeer(peer, WakuLightPushCodec)).valueOr: @@ -74,7 +73,7 @@ proc sendPushRequest( proc publish*( wl: WakuLightPushClient, - pubSubTopic: Option[PubsubTopic] = none(PubsubTopic), + pubSubTopic: Opt[PubsubTopic] = Opt.none(PubsubTopic), wakuMessage: WakuMessage, dest: Connection | PeerId | RemotePeerInfo, ): Future[WakuLightPushResult] {.async, gcsafe.} = @@ -100,7 +99,7 @@ proc publish*( let relayPeerCount = when dest is Connection: - ?await wl.sendPushRequest(request, dest.peerId, some(dest)) + ?await wl.sendPushRequest(request, dest.peerId, Opt.some(dest)) else: ?await wl.sendPushRequest(request, dest) @@ -115,7 +114,7 @@ proc publishToAny*( return lighpushErrorResult( LightPushErrorCode.NO_PEERS_TO_RELAY, "no suitable remote peers" ) - return await wl.publish(some(pubsubTopic), wakuMessage, peer) + return await wl.publish(Opt.some(pubsubTopic), wakuMessage, peer) proc publishWithConn*( wl: WakuLightPushClient, @@ -124,4 +123,4 @@ proc publishWithConn*( conn: Connection, destPeer: PeerId, ): Future[WakuLightPushResult] {.async, gcsafe.} = - return await wl.publish(some(pubSubTopic), message, conn) + return await wl.publish(Opt.some(pubSubTopic), message, conn) diff --git a/logos_delivery/waku/waku_lightpush/common.nim b/logos_delivery/waku/waku_lightpush/common.nim index f0762e2d2..00b26bafc 100644 --- a/logos_delivery/waku/waku_lightpush/common.nim +++ b/logos_delivery/waku/waku_lightpush/common.nim @@ -1,6 +1,6 @@ {.push raises: [].} -import std/options, results, chronos, libp2p/peerid +import results, chronos, libp2p/peerid import ../waku_core, ./rpc, ../waku_relay/protocol from ../waku_core/codecs import WakuLightPushCodec @@ -21,7 +21,7 @@ const LightPushErrorCode* = ( NO_PEERS_TO_RELAY: LightPushStatusCode(505), ) -type ErrorStatus* = tuple[code: LightpushStatusCode, desc: Option[string]] +type ErrorStatus* = tuple[code: LightpushStatusCode, desc: Opt[string]] type WakuLightPushResult* = Result[uint32, ErrorStatus] type PushMessageHandler* = proc( @@ -51,40 +51,42 @@ func lightpushSuccessResult*(relayPeerCount: uint32): WakuLightPushResult = return ok(relayPeerCount) func lightpushResultInternalError*(msg: string): WakuLightPushResult = - return err((LightPushErrorCode.INTERNAL_SERVER_ERROR, some(msg))) + return err((LightPushErrorCode.INTERNAL_SERVER_ERROR, Opt.some(msg))) func lightpushResultBadRequest*(msg: string): WakuLightPushResult = - return err((LightPushErrorCode.BAD_REQUEST, some(msg))) + return err((LightPushErrorCode.BAD_REQUEST, Opt.some(msg))) func lightpushResultServiceUnavailable*(msg: string): WakuLightPushResult = - return err((LightPushErrorCode.SERVICE_NOT_AVAILABLE, some(msg))) + return err((LightPushErrorCode.SERVICE_NOT_AVAILABLE, Opt.some(msg))) func lighpushErrorResult*( statusCode: LightpushStatusCode, desc: string ): WakuLightPushResult = - return err((statusCode, some(desc))) + return err((statusCode, Opt.some(desc))) func mapPubishingErrorToPushResult*( publishOutcome: PublishOutcome ): WakuLightPushResult = case publishOutcome of NoTopicSpecified: - return - err((LightPushErrorCode.INVALID_MESSAGE, some("Empty topic, skipping publish"))) + return err( + (LightPushErrorCode.INVALID_MESSAGE, Opt.some("Empty topic, skipping publish")) + ) of DuplicateMessage: - return - err((LightPushErrorCode.INVALID_MESSAGE, some("Dropping already-seen message"))) + return err( + (LightPushErrorCode.INVALID_MESSAGE, Opt.some("Dropping already-seen message")) + ) of NoPeersToPublish: return err( ( LightPushErrorCode.NO_PEERS_TO_RELAY, - some("No peers for topic, skipping publish"), + Opt.some("No peers for topic, skipping publish"), ) ) of CannotGenerateMessageId: return err( ( LightPushErrorCode.INTERNAL_SERVER_ERROR, - some("Error generating message id, skipping publish"), + Opt.some("Error generating message id, skipping publish"), ) ) diff --git a/logos_delivery/waku/waku_lightpush/protocol.nim b/logos_delivery/waku/waku_lightpush/protocol.nim index 7c6c55928..a698dd344 100644 --- a/logos_delivery/waku/waku_lightpush/protocol.nim +++ b/logos_delivery/waku/waku_lightpush/protocol.nim @@ -1,15 +1,7 @@ import libp2p/crypto/crypto -import logos_delivery/waku/compat/option_valueor {.push raises: [].} -import - std/[options, strutils], - results, - stew/byteutils, - chronicles, - chronos, - metrics, - bearssl/rand +import std/strutils, results, stew/byteutils, chronicles, chronos, metrics, bearssl/rand import ../node/peer_manager/peer_manager, ../waku_core, @@ -28,7 +20,7 @@ type WakuLightPush* = ref object of LPProtocol peerManager*: PeerManager pushHandler*: PushMessageHandler requestRateLimiter*: RequestRateLimiter - autoSharding: Option[Sharding] + autoSharding: Opt[Sharding] proc handleRequest( wl: WakuLightPush, peerId: PeerId, pushRequest: LightpushRequest @@ -38,29 +30,30 @@ proc handleRequest( let msg = "Pubsub topic must be specified when static sharding is enabled" error "lightpush request handling error", error = msg return WakuLightPushResult.err( - (code: LightPushErrorCode.INVALID_MESSAGE, desc: some(msg)) + (code: LightPushErrorCode.INVALID_MESSAGE, desc: Opt.some(msg)) ) let parsedTopic = NsContentTopic.parse(pushRequest.message.contentTopic).valueOr: let msg = "Invalid content-topic:" & $error error "lightpush request handling error", error = msg return WakuLightPushResult.err( - (code: LightPushErrorCode.INVALID_MESSAGE, desc: some(msg)) + (code: LightPushErrorCode.INVALID_MESSAGE, desc: Opt.some(msg)) ) wl.autoSharding.get().getShard(parsedTopic).valueOr: let msg = "Auto-sharding error: " & error error "lightpush request handling error", error = msg return WakuLightPushResult.err( - (code: LightPushErrorCode.INTERNAL_SERVER_ERROR, desc: some(msg)) + (code: LightPushErrorCode.INTERNAL_SERVER_ERROR, desc: Opt.some(msg)) ) # ensure checking topic will not cause error at gossipsub level if pubsubTopic.isEmptyOrWhitespace(): let msg = "topic must not be empty" error "lightpush request handling error", error = msg - return - WakuLightPushResult.err((code: LightPushErrorCode.BAD_REQUEST, desc: some(msg))) + return WakuLightPushResult.err( + (code: LightPushErrorCode.BAD_REQUEST, desc: Opt.some(msg)) + ) waku_lightpush_v3_messages.inc(labelValues = ["PushRequest"]) @@ -89,13 +82,13 @@ proc handleRequest*( return LightPushResponse( requestId: "N/A", # due to decode failure we don't know requestId statusCode: errorCode, - statusDesc: some(desc), + statusDesc: Opt.some(desc), ) let relayPeerCount = (await wl.handleRequest(peerId, request)).valueOr: let desc = error.desc waku_lightpush_v3_errors.inc(labelValues = [$error.code]) - error "failed to push message", error = desc + error "failed to push message", error = desc.get("") return LightPushResponse( requestId: request.requestId, statusCode: error.code, statusDesc: desc ) @@ -103,8 +96,8 @@ proc handleRequest*( return LightPushResponse( requestId: request.requestId, statusCode: LightPushSuccessCode.SUCCESS, - statusDesc: none[string](), - relayPeerCount: some(relayPeerCount), + statusDesc: Opt.none(string), + relayPeerCount: Opt.some(relayPeerCount), ) proc initProtocolHandler(wl: WakuLightPush) = @@ -140,7 +133,7 @@ proc initProtocolHandler(wl: WakuLightPush) = ## attack surface requestId: "N/A", statusCode: LightPushErrorCode.TOO_MANY_REQUESTS, - statusDesc: some(TooManyRequestsMessage), + statusDesc: Opt.some(TooManyRequestsMessage), ) ) @@ -160,8 +153,8 @@ proc new*( peerManager: PeerManager, rng: crypto.Rng, pushHandler: PushMessageHandler, - autoSharding: Option[Sharding], - rateLimitSetting: Option[RateLimitSetting] = none[RateLimitSetting](), + autoSharding: Opt[Sharding], + rateLimitSetting: Opt[RateLimitSetting] = Opt.none(RateLimitSetting), ): T = let wl = WakuLightPush( rng: rng, diff --git a/logos_delivery/waku/waku_lightpush/rpc.nim b/logos_delivery/waku/waku_lightpush/rpc.nim index f19563b99..228d9f836 100644 --- a/logos_delivery/waku/waku_lightpush/rpc.nim +++ b/logos_delivery/waku/waku_lightpush/rpc.nim @@ -1,7 +1,6 @@ {.push raises: [].} -import std/options -import ../waku_core +import results, ../waku_core type LightPushStatusCode* = distinct uint32 proc `==`*(a, b: LightPushStatusCode): bool {.borrow.} @@ -10,11 +9,11 @@ proc `$`*(code: LightPushStatusCode): string {.borrow.} type LightpushRequest* = object requestId*: string - pubSubTopic*: Option[PubsubTopic] + pubSubTopic*: Opt[PubsubTopic] message*: WakuMessage LightPushResponse* = object requestId*: string statusCode*: LightPushStatusCode - statusDesc*: Option[string] - relayPeerCount*: Option[uint32] + statusDesc*: Opt[string] + relayPeerCount*: Opt[uint32] diff --git a/logos_delivery/waku/waku_lightpush/rpc_codec.nim b/logos_delivery/waku/waku_lightpush/rpc_codec.nim index 0a4f934d6..cec295f24 100644 --- a/logos_delivery/waku/waku_lightpush/rpc_codec.nim +++ b/logos_delivery/waku/waku_lightpush/rpc_codec.nim @@ -1,7 +1,6 @@ {.push raises: [].} -import std/options -import ../common/protobuf, ../waku_core, ./rpc +import results, ../common/protobuf, ../waku_core, ./rpc const DefaultMaxRpcSize* = -1 @@ -27,9 +26,9 @@ proc decode*(T: type LightpushRequest, buffer: seq[byte]): ProtobufResult[T] = var pubSubTopic: PubsubTopic if not ?pb.getField(20, pubSubTopic): - rpc.pubSubTopic = none(PubsubTopic) + rpc.pubSubTopic = Opt.none(PubsubTopic) else: - rpc.pubSubTopic = some(pubSubTopic) + rpc.pubSubTopic = Opt.some(pubSubTopic) var messageBuf: seq[byte] if not ?pb.getField(21, messageBuf): @@ -68,14 +67,14 @@ proc decode*(T: type LightPushResponse, buffer: seq[byte]): ProtobufResult[T] = var statusDesc: string if not ?pb.getField(11, statusDesc): - rpc.statusDesc = none(string) + rpc.statusDesc = Opt.none(string) else: - rpc.statusDesc = some(statusDesc) + rpc.statusDesc = Opt.some(statusDesc) var relayPeerCount: uint32 if not ?pb.getField(12, relayPeerCount): - rpc.relayPeerCount = none(uint32) + rpc.relayPeerCount = Opt.none(uint32) else: - rpc.relayPeerCount = some(relayPeerCount) + rpc.relayPeerCount = Opt.some(relayPeerCount) return ok(rpc) diff --git a/logos_delivery/waku/waku_lightpush/self_req_handler.nim b/logos_delivery/waku/waku_lightpush/self_req_handler.nim index 06a0d3715..141af9ad9 100644 --- a/logos_delivery/waku/waku_lightpush/self_req_handler.nim +++ b/logos_delivery/waku/waku_lightpush/self_req_handler.nim @@ -9,11 +9,11 @@ ## which spawn a full service Waku node ## that could be used also as a lightpush client, helping testing and development. -import results, chronos, std/options, metrics +import results, chronos, metrics import ../waku_core, ./protocol, ./common, ./rpc, ./rpc_codec, ../utils/requests proc handleSelfLightPushRequest*( - self: WakuLightPush, pubSubTopic: Option[PubsubTopic], message: WakuMessage + self: WakuLightPush, pubSubTopic: Opt[PubsubTopic], message: WakuMessage ): Future[WakuLightPushResult] {.async.} = ## Handles the lightpush requests made by the node to itself. ## Normally used in REST-lightpush requests diff --git a/logos_delivery/waku/waku_lightpush_legacy/client.nim b/logos_delivery/waku/waku_lightpush_legacy/client.nim index 0ed5ca823..1cd3a4302 100644 --- a/logos_delivery/waku/waku_lightpush_legacy/client.nim +++ b/logos_delivery/waku/waku_lightpush_legacy/client.nim @@ -1,8 +1,7 @@ import libp2p/crypto/crypto -import logos_delivery/waku/compat/option_valueor {.push raises: [].} -import std/options, results, chronicles, chronos, metrics, bearssl/rand, stew/byteutils +import results, chronicles, chronos, metrics, bearssl/rand, stew/byteutils import libp2p/peerid import ../waku_core/peers, @@ -38,7 +37,7 @@ proc sendPushRequest( defer: await connection.closeWithEOF() - let rpc = PushRPC(requestId: generateRequestId(wl.rng), request: some(req)) + let rpc = PushRPC(requestId: generateRequestId(wl.rng), request: Opt.some(req)) await connection.writeLP(rpc.encode().buffer) var buffer: seq[byte] diff --git a/logos_delivery/waku/waku_lightpush_legacy/protocol.nim b/logos_delivery/waku/waku_lightpush_legacy/protocol.nim index b3d728f9c..ba982f8f1 100644 --- a/logos_delivery/waku/waku_lightpush_legacy/protocol.nim +++ b/logos_delivery/waku/waku_lightpush_legacy/protocol.nim @@ -1,7 +1,7 @@ import libp2p/crypto/crypto {.push raises: [].} -import std/options, results, stew/byteutils, chronicles, chronos, metrics, bearssl/rand +import results, stew/byteutils, chronicles, chronos, metrics, bearssl/rand import ../node/peer_manager/peer_manager, ../waku_core, @@ -62,8 +62,8 @@ proc handleRequest*( if not isSuccess: waku_lightpush_errors.inc(labelValues = [pushResponseInfo]) error "failed to push message", error = pushResponseInfo - let response = PushResponse(isSuccess: isSuccess, info: some(pushResponseInfo)) - let rpc = PushRPC(requestId: requestId, response: some(response)) + let response = PushResponse(isSuccess: isSuccess, info: Opt.some(pushResponseInfo)) + let rpc = PushRPC(requestId: requestId, response: Opt.some(response)) return rpc proc initProtocolHandler(wl: WakuLegacyLightPush) = @@ -98,8 +98,9 @@ proc initProtocolHandler(wl: WakuLegacyLightPush) = ## in reject case as it is comparably too expensive and opens possible ## attack surface requestId: "N/A", - response: - some(PushResponse(isSuccess: false, info: some(TooManyRequestsMessage))), + response: Opt.some( + PushResponse(isSuccess: false, info: Opt.some(TooManyRequestsMessage)) + ), ) ) @@ -119,7 +120,7 @@ proc new*( peerManager: PeerManager, rng: crypto.Rng, pushHandler: PushMessageHandler, - rateLimitSetting: Option[RateLimitSetting] = none[RateLimitSetting](), + rateLimitSetting: Opt[RateLimitSetting] = Opt.none(RateLimitSetting), ): T = let wl = WakuLegacyLightPush( rng: rng, diff --git a/logos_delivery/waku/waku_lightpush_legacy/rpc.nim b/logos_delivery/waku/waku_lightpush_legacy/rpc.nim index 33ba3f5e3..ba92bd55f 100644 --- a/logos_delivery/waku/waku_lightpush_legacy/rpc.nim +++ b/logos_delivery/waku/waku_lightpush_legacy/rpc.nim @@ -1,7 +1,6 @@ {.push raises: [].} -import std/options -import ../waku_core +import results, ../waku_core type PushRequest* = object @@ -10,9 +9,9 @@ type PushResponse* = object isSuccess*: bool - info*: Option[string] + info*: Opt[string] PushRPC* = object requestId*: string - request*: Option[PushRequest] - response*: Option[PushResponse] + request*: Opt[PushRequest] + response*: Opt[PushResponse] diff --git a/logos_delivery/waku/waku_lightpush_legacy/rpc_codec.nim b/logos_delivery/waku/waku_lightpush_legacy/rpc_codec.nim index 25d2bd210..a31c71f03 100644 --- a/logos_delivery/waku/waku_lightpush_legacy/rpc_codec.nim +++ b/logos_delivery/waku/waku_lightpush_legacy/rpc_codec.nim @@ -1,7 +1,6 @@ {.push raises: [].} -import std/options -import ../common/protobuf, ../waku_core, ./rpc +import results, ../common/protobuf, ../waku_core, ./rpc const DefaultMaxRpcSize* = -1 @@ -53,9 +52,9 @@ proc decode*(T: type PushResponse, buffer: seq[byte]): ProtobufResult[T] = var info: string if not ?pb.getField(2, info): - rpc.info = none(string) + rpc.info = Opt.none(string) else: - rpc.info = some(info) + rpc.info = Opt.some(info) ok(rpc) @@ -81,16 +80,16 @@ proc decode*(T: type PushRPC, buffer: seq[byte]): ProtobufResult[T] = var requestBuffer: seq[byte] if not ?pb.getField(2, requestBuffer): - rpc.request = none(PushRequest) + rpc.request = Opt.none(PushRequest) else: let request = ?PushRequest.decode(requestBuffer) - rpc.request = some(request) + rpc.request = Opt.some(request) var responseBuffer: seq[byte] if not ?pb.getField(3, responseBuffer): - rpc.response = none(PushResponse) + rpc.response = Opt.none(PushResponse) else: let response = ?PushResponse.decode(responseBuffer) - rpc.response = some(response) + rpc.response = Opt.some(response) ok(rpc) diff --git a/logos_delivery/waku/waku_lightpush_legacy/self_req_handler.nim b/logos_delivery/waku/waku_lightpush_legacy/self_req_handler.nim index 3c5d09a9c..c1c04ad44 100644 --- a/logos_delivery/waku/waku_lightpush_legacy/self_req_handler.nim +++ b/logos_delivery/waku/waku_lightpush_legacy/self_req_handler.nim @@ -9,7 +9,7 @@ ## which spawn a full service Waku node ## that could be used also as a lightpush client, helping testing and development. -import results, chronos, chronicles, std/options, metrics, stew/byteutils +import results, chronos, chronicles, metrics, stew/byteutils import ../waku_core, ./protocol, @@ -31,7 +31,7 @@ proc handleSelfLightPushRequest*( let selfPeerId = self.peerManager.switch.peerInfo.peerId let req = PushRequest(pubSubTopic: pubSubTopic, message: message) - let rpc = PushRPC(requestId: generateRequestId(self.rng), request: some(req)) + let rpc = PushRPC(requestId: generateRequestId(self.rng), request: Opt.some(req)) let respRpc = await self.handleRequest(selfPeerId, rpc.encode().buffer) diff --git a/logos_delivery/waku/waku_metadata/protocol.nim b/logos_delivery/waku/waku_metadata/protocol.nim index d080ff2b7..2a59fd487 100644 --- a/logos_delivery/waku/waku_metadata/protocol.nim +++ b/logos_delivery/waku/waku_metadata/protocol.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[options, sequtils], + std/sequtils, results, chronicles, chronos, @@ -29,7 +28,7 @@ proc respond( m: WakuMetadata, conn: Connection ): Future[Result[void, string]] {.async, gcsafe.} = let response = WakuMetadataResponse( - clusterId: some(m.clusterId.uint32), shards: m.getShards().mapIt(it.uint32) + clusterId: Opt.some(m.clusterId.uint32), shards: m.getShards().mapIt(it.uint32) ) let res = catch: @@ -43,7 +42,7 @@ proc request*( m: WakuMetadata, conn: Connection ): Future[Result[WakuMetadataResponse, string]] {.async, gcsafe.} = let request = WakuMetadataRequest( - clusterId: some(m.clusterId), shards: m.getShards().mapIt(it.uint32) + clusterId: Opt.some(m.clusterId), shards: m.getShards().mapIt(it.uint32) ) let writeRes = catch: diff --git a/logos_delivery/waku/waku_metadata/rpc.nim b/logos_delivery/waku/waku_metadata/rpc.nim index fcb11e57d..37a9e77d0 100644 --- a/logos_delivery/waku/waku_metadata/rpc.nim +++ b/logos_delivery/waku/waku_metadata/rpc.nim @@ -1,15 +1,15 @@ {.push raises: [].} -import std/options +import results import ../common/protobuf type WakuMetadataRequest* = object - clusterId*: Option[uint32] + clusterId*: Opt[uint32] shards*: seq[uint32] type WakuMetadataResponse* = object - clusterId*: Option[uint32] + clusterId*: Opt[uint32] shards*: seq[uint32] proc encode*(rpc: WakuMetadataRequest): ProtoBuffer = @@ -29,9 +29,9 @@ proc decode*(T: type WakuMetadataRequest, buffer: seq[byte]): ProtoResult[T] = var clusterId: uint64 if not ?pb.getField(1, clusterId): - rpc.clusterId = none(uint32) + rpc.clusterId = Opt.none(uint32) else: - rpc.clusterId = some(clusterId.uint32) + rpc.clusterId = Opt.some(clusterId.uint32) var shards: seq[uint64] if ?pb.getPackedRepeatedField(3, shards): @@ -63,9 +63,9 @@ proc decode*(T: type WakuMetadataResponse, buffer: seq[byte]): ProtoResult[T] = var clusterId: uint64 if not ?pb.getField(1, clusterId): - rpc.clusterId = none(uint32) + rpc.clusterId = Opt.none(uint32) else: - rpc.clusterId = some(clusterId.uint32) + rpc.clusterId = Opt.some(clusterId.uint32) var shards: seq[uint64] diff --git a/logos_delivery/waku/waku_mix/protocol.nim b/logos_delivery/waku/waku_mix/protocol.nim index 613b6e3c7..3ab5bfd66 100644 --- a/logos_delivery/waku/waku_mix/protocol.nim +++ b/logos_delivery/waku/waku_mix/protocol.nim @@ -1,7 +1,6 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} -import chronicles, std/options, chronos, results, metrics +import chronicles, chronos, results, metrics import libp2p/crypto/curve25519, @@ -66,7 +65,7 @@ proc processBootNodes( count.inc() peermgr.addPeer( - RemotePeerInfo.init(peerId, @[multiAddr], mixPubKey = some(node.pubKey)) + RemotePeerInfo.init(peerId, @[multiAddr], mixPubKey = Opt.some(node.pubKey)) ) mix_pool_size.set(count) info "using mix bootstrap nodes ", count = count diff --git a/logos_delivery/waku/waku_peer_exchange/client.nim b/logos_delivery/waku/waku_peer_exchange/client.nim index 1f15d76fc..f2ceb67c4 100644 --- a/logos_delivery/waku/waku_peer_exchange/client.nim +++ b/logos_delivery/waku/waku_peer_exchange/client.nim @@ -1,9 +1,14 @@ -import logos_delivery/waku/compat/option_valueor -import std/options, results, chronicles, chronos, metrics +import results +import chronicles, chronos, metrics +import + logos_delivery/waku/[ + waku_peer_exchange/common, + waku_peer_exchange/rpc, + waku_peer_exchange/rpc_codec, + node/peer_manager, + ] -import ./common, ./rpc, ./rpc_codec, ../node/peer_manager - -from ../waku_core/codecs import WakuPeerExchangeCodec +from logos_delivery/waku/waku_core/codecs import WakuPeerExchangeCodec declarePublicGauge waku_px_peers_received_total, "number of ENRs received via peer exchange" @@ -26,7 +31,7 @@ proc request*( var buffer: seq[byte] var callResult = - (status_code: PeerExchangeResponseStatusCode.SUCCESS, status_desc: none(string)) + (status_code: PeerExchangeResponseStatusCode.SUCCESS, status_desc: Opt.none(string)) try: await conn.writeLP(rpc.encode().buffer) buffer = await conn.readLp(DefaultMaxRpcSize.int) @@ -35,7 +40,7 @@ proc request*( waku_px_client_errors.inc(labelValues = ["error_sending_or_receiving_px_req"]) callResult = ( status_code: PeerExchangeResponseStatusCode.SERVICE_UNAVAILABLE, - status_desc: some($exc.msg), + status_desc: Opt.some($exc.msg), ) finally: # close, no more data is expected @@ -50,7 +55,7 @@ proc request*( return err( ( status_code: PeerExchangeResponseStatusCode.BAD_RESPONSE, - status_desc: some($error), + status_desc: Opt.some($error), ) ) if decoded.response.status_code != PeerExchangeResponseStatusCode.SUCCESS: @@ -74,7 +79,7 @@ proc request*( return err( ( status_code: PeerExchangeResponseStatusCode.DIAL_FAILURE, - status_desc: some(dialFailure), + status_desc: Opt.some(dialFailure), ) ) return await wpx.request(numPeers, connOpt.get()) @@ -83,7 +88,7 @@ proc request*( return err( ( status_code: PeerExchangeResponseStatusCode.BAD_RESPONSE, - status_desc: some("exception dialing peer: " & getCurrentExceptionMsg()), + status_desc: Opt.some("exception dialing peer: " & getCurrentExceptionMsg()), ) ) @@ -97,7 +102,7 @@ proc request*( return err( ( status_code: PeerExchangeResponseStatusCode.SERVICE_UNAVAILABLE, - status_desc: some(peerNotFoundFailure), + status_desc: Opt.some(peerNotFoundFailure), ) ) return await wpx.request(numPeers, peerOpt.get()) diff --git a/logos_delivery/waku/waku_peer_exchange/protocol.nim b/logos_delivery/waku/waku_peer_exchange/protocol.nim index ce1f0cd04..1e76be230 100644 --- a/logos_delivery/waku/waku_peer_exchange/protocol.nim +++ b/logos_delivery/waku/waku_peer_exchange/protocol.nim @@ -1,6 +1,5 @@ -import logos_delivery/waku/compat/option_valueor import - std/[options, sequtils, random], + std/[sequtils, random], results, chronicles, chronos, @@ -33,7 +32,7 @@ logScope: type WakuPeerExchange* = ref object of LPProtocol peerManager*: PeerManager - cluster*: Option[uint16] + cluster*: Opt[uint16] # todo: next step: ring buffer; future: implement cache satisfying https://rfc.vac.dev/spec/34/ requestRateLimiter*: RequestRateLimiter @@ -52,7 +51,7 @@ proc respond( return err( ( status_code: PeerExchangeResponseStatusCode.DIAL_FAILURE, - status_desc: some("stream closed before response: " & exc.msg), + status_desc: Opt.some("stream closed before response: " & exc.msg), ) ) @@ -61,7 +60,7 @@ proc respond( proc respondError( wpx: WakuPeerExchange, status_code: PeerExchangeResponseStatusCode, - status_desc: Option[string], + status_desc: Opt[string], conn: Connection, ): Future[WakuPeerExchangeResult[void]] {.async: (raises: [CancelledError]), gcsafe.} = let rpc = PeerExchangeRpc.makeErrorResponse(status_code, status_desc) @@ -76,14 +75,14 @@ proc respondError( return err( ( status_code: PeerExchangeResponseStatusCode.SERVICE_UNAVAILABLE, - status_desc: some("stream closed before response: " & exc.msg), + status_desc: Opt.some("stream closed before response: " & exc.msg), ) ) return ok() proc poolFilter*( - cluster: Option[uint16], origin: PeerOrigin, enr: enr.Record + cluster: Opt[uint16], origin: PeerOrigin, enr: enr.Record ): Result[void, string] = if origin != Discv5: trace "peer not from discv5", origin = $origin @@ -93,7 +92,7 @@ proc poolFilter*( return err("peer has mismatching cluster") return ok() -proc poolFilter*(cluster: Option[uint16], peer: RemotePeerInfo): Result[void, string] = +proc poolFilter*(cluster: Opt[uint16], peer: RemotePeerInfo): Result[void, string] = if peer.enr.isNone(): info "peer has no ENR", peer = $peer return err("peer has no ENR: " & $peer) @@ -147,7 +146,7 @@ proc initProtocolHandler(wpx: WakuPeerExchange) = ( await wpx.respondError( - PeerExchangeResponseStatusCode.BAD_REQUEST, some($error), conn + PeerExchangeResponseStatusCode.BAD_REQUEST, Opt.some($error), conn ) ).isOkOr: error "Failed to respond with BAD_REQUEST", error = $error @@ -166,7 +165,7 @@ proc initProtocolHandler(wpx: WakuPeerExchange) = ( await wpx.respondError( - PeerExchangeResponseStatusCode.TOO_MANY_REQUESTS, none(string), conn + PeerExchangeResponseStatusCode.TOO_MANY_REQUESTS, Opt.none(string), conn ) ).isOkOr: error "Failed to respond with TOO_MANY_REQUESTS", error = $error @@ -177,8 +176,8 @@ proc initProtocolHandler(wpx: WakuPeerExchange) = proc new*( T: type WakuPeerExchange, peerManager: PeerManager, - cluster: Option[uint16] = none(uint16), - rateLimitSetting: Option[RateLimitSetting] = none[RateLimitSetting](), + cluster: Opt[uint16] = Opt.none(uint16), + rateLimitSetting: Opt[RateLimitSetting] = Opt.none(RateLimitSetting), ): T = let wpx = WakuPeerExchange( peerManager: peerManager, diff --git a/logos_delivery/waku/waku_peer_exchange/rpc.nim b/logos_delivery/waku/waku_peer_exchange/rpc.nim index 4a91e8db1..b2cd41000 100644 --- a/logos_delivery/waku/waku_peer_exchange/rpc.nim +++ b/logos_delivery/waku/waku_peer_exchange/rpc.nim @@ -1,4 +1,4 @@ -import std/options +import results type PeerExchangeResponseStatusCode* {.pure.} = enum @@ -19,10 +19,10 @@ type PeerExchangeResponse* = object peerInfos*: seq[PeerExchangePeerInfo] status_code*: PeerExchangeResponseStatusCode - status_desc*: Option[string] + status_desc*: Opt[string] PeerExchangeResponseStatus* = - tuple[status_code: PeerExchangeResponseStatusCode, status_desc: Option[string]] + tuple[status_code: PeerExchangeResponseStatusCode, status_desc: Opt[string]] PeerExchangeRpc* = object request*: PeerExchangeRequest @@ -41,7 +41,7 @@ proc makeResponse*(T: type PeerExchangeRpc, peerInfos: seq[PeerExchangePeerInfo] proc makeErrorResponse*( T: type PeerExchangeRpc, status_code: PeerExchangeResponseStatusCode, - status_desc: Option[string] = none(string), + status_desc: Opt[string] = Opt.none(string), ): T = return T( response: PeerExchangeResponse(status_code: status_code, status_desc: status_desc) diff --git a/logos_delivery/waku/waku_peer_exchange/rpc_codec.nim b/logos_delivery/waku/waku_peer_exchange/rpc_codec.nim index e6eaa0ca2..00aefd275 100644 --- a/logos_delivery/waku/waku_peer_exchange/rpc_codec.nim +++ b/logos_delivery/waku/waku_peer_exchange/rpc_codec.nim @@ -1,7 +1,6 @@ {.push raises: [].} -import std/options -import ../common/protobuf, ./rpc +import results, ../common/protobuf, ./rpc proc encode*(rpc: PeerExchangeRequest): ProtoBuffer = var pb = initProtoBuffer() @@ -79,9 +78,9 @@ proc decode*(T: type PeerExchangeResponse, buffer: seq[byte]): ProtobufResult[T] var status_desc: string if ?pb.getField(11, status_desc): - rpc.status_desc = some(status_desc) + rpc.status_desc = Opt.some(status_desc) else: - rpc.status_desc = none(string) + rpc.status_desc = Opt.none(string) ok(rpc) diff --git a/logos_delivery/waku/waku_relay/protocol.nim b/logos_delivery/waku/waku_relay/protocol.nim index 409b02929..0997a1fd8 100644 --- a/logos_delivery/waku/waku_relay/protocol.nim +++ b/logos_delivery/waku/waku_relay/protocol.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor ## Waku Relay module. Thin layer on top of GossipSub. ## ## See https://github.com/vacp2p/specs/blob/master/specs/waku/v2/waku-relay.md diff --git a/logos_delivery/waku/waku_rendezvous/client.nim b/logos_delivery/waku/waku_rendezvous/client.nim index c4aada9e6..c23c0ae9a 100644 --- a/logos_delivery/waku/waku_rendezvous/client.nim +++ b/logos_delivery/waku/waku_rendezvous/client.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[options, sequtils, tables], + std/[sequtils, tables], results, chronos, chronicles, @@ -68,7 +67,7 @@ proc requestAll*( let rInfo = RemotePeerInfo.init( record.peerId, record.addresses, - mixPubKey = some(intoCurve25519Key(fromHex(record.mixKey))), + mixPubKey = Opt.some(intoCurve25519Key(fromHex(record.mixKey))), ) self.peerManager.addPeer(rInfo) diff --git a/logos_delivery/waku/waku_rendezvous/common.nim b/logos_delivery/waku/waku_rendezvous/common.nim index 9776fd3a7..bca45dece 100644 --- a/logos_delivery/waku/waku_rendezvous/common.nim +++ b/logos_delivery/waku/waku_rendezvous/common.nim @@ -1,7 +1,6 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} -import std/options, chronos +import results, chronos import ../common/enr, ../waku_enr/capabilities, ../waku_enr/sharding @@ -40,8 +39,8 @@ proc computeNamespace*(clusterId: uint16, shard: uint16, cap: Capabilities): str return namespace -proc getRelayShards*(enr: enr.Record): Option[RelayShards] = +proc getRelayShards*(enr: enr.Record): Opt[RelayShards] = let typedRecord = enr.toTyped().valueOr: - return none(RelayShards) + return Opt.none(RelayShards) return typedRecord.relaySharding() diff --git a/logos_delivery/waku/waku_rendezvous/protocol.nim b/logos_delivery/waku/waku_rendezvous/protocol.nim index 253fa5a12..1fe72c803 100644 --- a/logos_delivery/waku/waku_rendezvous/protocol.nim +++ b/logos_delivery/waku/waku_rendezvous/protocol.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[sugar, options, sequtils, tables], + std/[sugar, sequtils, tables], results, chronos, chronicles, diff --git a/logos_delivery/waku/waku_store/client.nim b/logos_delivery/waku/waku_store/client.nim index 21e2699e3..82b7f4c43 100644 --- a/logos_delivery/waku/waku_store/client.nim +++ b/logos_delivery/waku/waku_store/client.nim @@ -1,9 +1,8 @@ import libp2p/crypto/crypto -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[options, tables, sequtils, algorithm, random], + std/[tables, sequtils, algorithm, random], results, chronicles, chronos, @@ -89,7 +88,7 @@ proc query*( return await self.sendStoreRequest(request, connection) proc queryToAny*( - self: WakuStoreClient, request: StoreQueryRequest, peerId = none(PeerId) + self: WakuStoreClient, request: StoreQueryRequest, peerId = Opt.none(PeerId) ): Future[StoreQueryResult] {.async.} = ## we don't specify a particular peer and instead we get it from peer manager. ## It will retry with different store peers if the dial fails. diff --git a/logos_delivery/waku/waku_store/common.nim b/logos_delivery/waku/waku_store/common.nim index 70446be4b..482550e14 100644 --- a/logos_delivery/waku/waku_store/common.nim +++ b/logos_delivery/waku/waku_store/common.nim @@ -1,6 +1,6 @@ {.push raises: [].} -import std/[options, sequtils], results, stew/byteutils +import std/sequtils, results, stew/byteutils import ../waku_core, ../common/paging from ../waku_core/codecs import WakuStoreCodec @@ -22,21 +22,21 @@ type requestId*: string includeData*: bool - pubsubTopic*: Option[PubsubTopic] + pubsubTopic*: Opt[PubsubTopic] contentTopics*: seq[ContentTopic] - startTime*: Option[Timestamp] - endTime*: Option[Timestamp] + startTime*: Opt[Timestamp] + endTime*: Opt[Timestamp] messageHashes*: seq[WakuMessageHash] - paginationCursor*: Option[WakuMessageHash] + paginationCursor*: Opt[WakuMessageHash] paginationForward*: PagingDirection - paginationLimit*: Option[uint64] + paginationLimit*: Opt[uint64] WakuMessageKeyValue* = object messageHash*: WakuMessageHash - message*: Option[WakuMessage] - pubsubTopic*: Option[PubsubTopic] + message*: Opt[WakuMessage] + pubsubTopic*: Opt[PubsubTopic] StoreQueryResponse* = object requestId*: string @@ -46,13 +46,13 @@ type messages*: seq[WakuMessageKeyValue] - paginationCursor*: Option[WakuMessageHash] + paginationCursor*: Opt[WakuMessageHash] # Types to be used by clients that use the hash in hex WakuMessageKeyValueHex* = object messageHash*: string - message*: Option[WakuMessage] - pubsubTopic*: Option[PubsubTopic] + message*: Opt[WakuMessage] + pubsubTopic*: Opt[PubsubTopic] StoreQueryResponseHex* = object requestId*: string @@ -62,7 +62,7 @@ type messages*: seq[WakuMessageKeyValueHex] - paginationCursor*: Option[string] + paginationCursor*: Opt[string] StatusCode* {.pure.} = enum UNKNOWN = uint32(000) @@ -150,7 +150,7 @@ proc toHex*(response: StoreQueryResponse): StoreQueryResponseHex = messages: response.messages.mapIt(it.toHex()), # Convert each message to hex paginationCursor: if response.paginationCursor.isSome: - some(response.paginationCursor.get().to0xHex()) + Opt.some(response.paginationCursor.get().to0xHex()) else: - none[string](), + Opt.none(string), ) diff --git a/logos_delivery/waku/waku_store/protocol.nim b/logos_delivery/waku/waku_store/protocol.nim index d09532d43..bf34bb615 100644 --- a/logos_delivery/waku/waku_store/protocol.nim +++ b/logos_delivery/waku/waku_store/protocol.nim @@ -1,11 +1,10 @@ -import logos_delivery/waku/compat/option_valueor ## Waku Store protocol for historical messaging support. ## See spec for more details: ## https://github.com/vacp2p/specs/blob/master/specs/waku/v2/waku-store.md {.push raises: [].} import - std/[options, times], + std/times, results, chronicles, chronos, @@ -159,9 +158,9 @@ proc new*( peerManager: PeerManager, rng: crypto.Rng, requestHandler: StoreQueryRequestHandler, - rateLimitSetting: Option[RateLimitSetting] = none[RateLimitSetting](), + rateLimitSetting: Opt[RateLimitSetting] = Opt.none(RateLimitSetting), ): T = - if requestHandler.isNil(): # TODO use an Option instead ??? + if requestHandler.isNil(): # TODO use an Opt instead ??? raise newException(NilAccessDefect, "history query handler is nil") let store = WakuStore( diff --git a/logos_delivery/waku/waku_store/resume.nim b/logos_delivery/waku/waku_store/resume.nim index 9350bf6b7..0f45b8a6b 100644 --- a/logos_delivery/waku/waku_store/resume.nim +++ b/logos_delivery/waku/waku_store/resume.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/options, + results, sqlite3_abi, chronicles, chronos, @@ -39,7 +38,7 @@ type db: SqliteDatabase replaceStmt: SqliteStmt[(Timestamp), void] - transferCallBack: Option[TransferCallback] + transferCallBack: Opt[TransferCallback] peerManager: PeerManager @@ -79,15 +78,15 @@ proc initTransferHandler( return # tying archive, store client and resume into one callback and saving it for later - self.transferCallBack = some( + self.transferCallBack = Opt.some( proc( timestamp: Timestamp, peer: RemotePeerInfo ): Future[Result[void, string]] {.async: (raises: []), closure.} = var req = StoreQueryRequest() req.includeData = true - req.startTime = some(timestamp) - req.endTime = some(getNowInNanosecondTime()) - req.paginationLimit = some(uint64(100)) + req.startTime = Opt.some(timestamp) + req.endTime = Opt.some(getNowInNanosecondTime()) + req.paginationLimit = Opt.some(uint64(100)) while true: let catchable = catch: diff --git a/logos_delivery/waku/waku_store/rpc_codec.nim b/logos_delivery/waku/waku_store/rpc_codec.nim index a5e5e2d0b..2dbb890cd 100644 --- a/logos_delivery/waku/waku_store/rpc_codec.nim +++ b/logos_delivery/waku/waku_store/rpc_codec.nim @@ -1,6 +1,6 @@ {.push raises: [].} -import std/options, stew/arrayops +import results, stew/arrayops import ../common/[protobuf, paging], ../waku_core, ./common const DefaultMaxRpcSize* = -1 @@ -61,9 +61,9 @@ proc decode*( var pubsubTopic: string if not ?pb.getField(10, pubsubTopic): - req.pubsubTopic = none(string) + req.pubsubTopic = Opt.none(string) else: - req.pubsubTopic = some(pubsubTopic) + req.pubsubTopic = Opt.some(pubsubTopic) var topics: seq[string] if not ?pb.getRepeatedField(11, topics): @@ -73,15 +73,15 @@ proc decode*( var start: zint64 if not ?pb.getField(12, start): - req.startTime = none(Timestamp) + req.startTime = Opt.none(Timestamp) else: - req.startTime = some(Timestamp(int64(start))) + req.startTime = Opt.some(Timestamp(int64(start))) var endTime: zint64 if not ?pb.getField(13, endTime): - req.endTime = none(Timestamp) + req.endTime = Opt.none(Timestamp) else: - req.endTime = some(Timestamp(int64(endTime))) + req.endTime = Opt.some(Timestamp(int64(endTime))) var buffer: seq[seq[byte]] if not ?pb.getRepeatedField(20, buffer): @@ -95,11 +95,11 @@ proc decode*( var cursor: seq[byte] if not ?pb.getField(51, cursor): - req.paginationCursor = none(WakuMessageHash) + req.paginationCursor = Opt.none(WakuMessageHash) else: var hash: WakuMessageHash discard copyFrom[byte](hash, cursor) - req.paginationCursor = some(hash) + req.paginationCursor = Opt.some(hash) var paging: uint32 if not ?pb.getField(52, paging): @@ -109,9 +109,9 @@ proc decode*( var limit: uint64 if not ?pb.getField(53, limit): - req.paginationLimit = none(uint64) + req.paginationLimit = Opt.none(uint64) else: - req.paginationLimit = some(limit) + req.paginationLimit = Opt.some(limit) return ok(req) @@ -164,11 +164,11 @@ proc decode*( var proto: ProtoBuffer var topic: string if ?pb.getField(2, proto) and ?pb.getField(3, topic): - keyValue.message = some(?WakuMessage.decode(proto.buffer)) - keyValue.pubsubTopic = some(topic) + keyValue.message = Opt.some(?WakuMessage.decode(proto.buffer)) + keyValue.pubsubTopic = Opt.some(topic) else: - keyValue.message = none(WakuMessage) - keyValue.pubsubTopic = none(string) + keyValue.message = Opt.none(WakuMessage) + keyValue.pubsubTopic = Opt.none(string) return ok(keyValue) @@ -204,10 +204,10 @@ proc decode*( var cursor: seq[byte] if not ?pb.getField(51, cursor): - res.paginationCursor = none(WakuMessageHash) + res.paginationCursor = Opt.none(WakuMessageHash) else: var hash: WakuMessageHash discard copyFrom[byte](hash, cursor) - res.paginationCursor = some(hash) + res.paginationCursor = Opt.some(hash) return ok(res) diff --git a/logos_delivery/waku/waku_store/self_req_handler.nim b/logos_delivery/waku/waku_store/self_req_handler.nim index acd933724..315961307 100644 --- a/logos_delivery/waku/waku_store/self_req_handler.nim +++ b/logos_delivery/waku/waku_store/self_req_handler.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor ## ## This file is aimed to attend the requests that come directly ## from the 'self' node. It is expected to attend the store requests that diff --git a/logos_delivery/waku/waku_store_sync/common.nim b/logos_delivery/waku/waku_store_sync/common.nim index da8a5df95..1c718d726 100644 --- a/logos_delivery/waku/waku_store_sync/common.nim +++ b/logos_delivery/waku/waku_store_sync/common.nim @@ -1,6 +1,6 @@ {.push raises: [].} -import std/[options], chronos, stew/[byteutils] +import chronos, stew/[byteutils] import ../waku_core diff --git a/logos_delivery/waku/waku_store_sync/reconciliation.nim b/logos_delivery/waku/waku_store_sync/reconciliation.nim index 6f301d633..db3574a5e 100644 --- a/logos_delivery/waku/waku_store_sync/reconciliation.nim +++ b/logos_delivery/waku/waku_store_sync/reconciliation.nim @@ -1,8 +1,7 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import - std/[sequtils, options, sets], + std/[sequtils, sets], stew/byteutils, results, chronicles, @@ -110,9 +109,7 @@ proc messageIngress*( error "failed to insert new message", msg_hash = byteutils.toHex(id.hash), error = $error -proc preProcessPayload( - self: SyncReconciliation, payload: RangesData -): Option[RangesData] = +proc preProcessPayload(self: SyncReconciliation, payload: RangesData): Opt[RangesData] = ## Check the received payload for topics and/or time mismatch. var payload = payload @@ -122,7 +119,7 @@ proc preProcessPayload( let pubsubIntersection = self.pubsubTopics * payload.pubsubTopics.toHashSet() if pubsubIntersection.len < 1: - return none(RangesData) + return Opt.none(RangesData) payload.pubsubTopics = pubsubIntersection.toSeq() elif self.pubsubTopics.len > 0: @@ -133,7 +130,7 @@ proc preProcessPayload( let contentIntersection = self.contentTopics * payload.contentTopics.toHashSet() if contentIntersection.len < 1: - return none(RangesData) + return Opt.none(RangesData) payload.contentTopics = contentIntersection.toSeq() elif self.contentTopics.len > 0: @@ -160,7 +157,7 @@ proc preProcessPayload( else: break - return some(payload) + return Opt.some(payload) proc processRequest( self: SyncReconciliation, conn: Connection @@ -304,7 +301,7 @@ proc initiate( proc storeSynchronization*( self: SyncReconciliation, - peerInfo: Option[RemotePeerInfo] = none(RemotePeerInfo), + peerInfo: Opt[RemotePeerInfo] = Opt.none(RemotePeerInfo), offset: Duration = self.relayJitter, syncRange: Duration = self.syncRange, pubsubTopics: HashSet[PubsubTopic] = self.pubsubTopics, @@ -348,9 +345,9 @@ proc initFillStorage( var query = ArchiveQuery( includeData: true, - cursor: none(ArchiveCursor), - startTime: some(starTime), - endTime: some(endTime), + cursor: Opt.none(ArchiveCursor), + startTime: Opt.some(starTime), + endTime: Opt.some(endTime), pageSize: 100, direction: PagingDirection.FORWARD, ) diff --git a/logos_delivery/waku/waku_store_sync/storage/seq_storage.nim b/logos_delivery/waku/waku_store_sync/storage/seq_storage.nim index 272b3a78a..7f9d3b46d 100644 --- a/logos_delivery/waku/waku_store_sync/storage/seq_storage.nim +++ b/logos_delivery/waku/waku_store_sync/storage/seq_storage.nim @@ -1,5 +1,5 @@ import - std/[algorithm, sequtils, math, options, tables, packedsets, sugar], + std/[algorithm, sequtils, math, tables, packedsets, sugar], results, chronos, stew/arrayops @@ -167,7 +167,7 @@ method prune*(self: SeqStorage, timestamp: Timestamp): int {.raises: [].} = proc computefingerprintFromSlice( self: SeqStorage, - sliceOpt: Option[Slice[int]], + sliceOpt: Opt[Slice[int]], pubsubTopicSet: PackedSet[int], contentTopicSet: PackedSet[int], ): Fingerprint = @@ -199,7 +199,7 @@ proc computefingerprintFromSlice( return fingerprint -proc findIdxBounds(self: SeqStorage, slice: Slice[SyncID]): Option[Slice[int]] = +proc findIdxBounds(self: SeqStorage, slice: Slice[SyncID]): Opt[Slice[int]] = ## Given bounds find the corresponding indices in this storage let lower = self.elements.lowerBound(slice.a, common.cmp) @@ -207,13 +207,13 @@ proc findIdxBounds(self: SeqStorage, slice: Slice[SyncID]): Option[Slice[int]] = if upper < 1: # entire range is before any of our elements - return none(Slice[int]) + return Opt.none(Slice[int]) if lower >= self.elements.len: # entire range is after any of our elements - return none(Slice[int]) + return Opt.none(Slice[int]) - return some(lower ..< upper) + return Opt.some(lower ..< upper) method computeFingerprint*( self: SeqStorage, @@ -308,7 +308,7 @@ proc processFingerprintRange*( continue let fingerprint = - self.computeFingerprintFromSlice(some(slice), pubsubTopicSet, contentTopicSet) + self.computeFingerprintFromSlice(Opt.some(slice), pubsubTopicSet, contentTopicSet) output.ranges.add((partitionBounds, RangeType.Fingerprint)) output.fingerprints.add(fingerprint) continue diff --git a/logos_delivery/waku/waku_store_sync/transfer.nim b/logos_delivery/waku/waku_store_sync/transfer.nim index aa02adfdc..5d20afb18 100644 --- a/logos_delivery/waku/waku_store_sync/transfer.nim +++ b/logos_delivery/waku/waku_store_sync/transfer.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor {.push raises: [].} import diff --git a/tests/api/test_api_health.nim b/tests/api/test_api_health.nim index 7b493964a..9b4c3d067 100644 --- a/tests/api/test_api_health.nim +++ b/tests/api/test_api_health.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, sequtils, times] +import results, std/[sequtils, times] import chronos, testutils/unittests, stew/byteutils, libp2p/[switch, peerinfo] import brokers/broker_context import ../testlib/[common, wakucore, wakunode, testasync] @@ -96,7 +96,7 @@ suite "LM API health checking": conf.listenAddress = parseIpAddress("0.0.0.0") conf.tcpPort = Port(0) conf.discv5UdpPort = Port(0) - conf.clusterId = some(3'u16) + conf.clusterId = Opt.some(3'u16) conf.numShardsInNetwork = 1 conf.rest = false @@ -241,7 +241,7 @@ suite "LM API health checking": let cTopic = ContentTopic("/waku/2/my-content-topic/proto") let shardReq = - RequestRelayShard.request(client.waku.brokerCtx, none(PubsubTopic), cTopic) + RequestRelayShard.request(client.waku.brokerCtx, Opt.none(PubsubTopic), cTopic) check shardReq.isOk() let targetShard = $shardReq.get().relayShard @@ -276,7 +276,7 @@ suite "LM API health checking": edgeConf.listenAddress = parseIpAddress("0.0.0.0") edgeConf.tcpPort = Port(0) edgeConf.discv5UdpPort = Port(0) - edgeConf.clusterId = some(3'u16) + edgeConf.clusterId = Opt.some(3'u16) edgeConf.maxMessageSize = "150 KiB" edgeConf.rest = false diff --git a/tests/api/test_api_receive.nim b/tests/api/test_api_receive.nim index 870f85860..556ec6431 100644 --- a/tests/api/test_api_receive.nim +++ b/tests/api/test_api_receive.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, sequtils, net, sets] +import results, std/[sequtils, net, sets] import chronos, testutils/unittests, stew/byteutils import libp2p/[peerid, peerinfo, crypto/crypto] import brokers/broker_context @@ -89,7 +89,7 @@ proc createApiNodeConf(numShards: uint16 = 1): WakuNodeConf = conf.listenAddress = parseIpAddress("0.0.0.0") conf.tcpPort = Port(0) conf.discv5UdpPort = Port(0) - conf.clusterId = some(3'u16) + conf.clusterId = Opt.some(3'u16) conf.numShardsInNetwork = numShards conf.rest = false result = conf @@ -168,14 +168,14 @@ proc setupNetwork(testTopic: ContentTopic): Future[TestNetwork] {.async.} = let missedMsg = WakuMessage( payload: missedPayload, contentTopic: testTopic, version: 0, timestamp: now() ) - discard (await publisher.publish(some(shard), missedMsg)).expect( + discard (await publisher.publish(Opt.some(shard), missedMsg)).expect( "Publish missed msg failed" ) block waitArchive: for _ in 0 ..< 50: let query = archive_common.ArchiveQuery( - includeData: false, contentTopics: @[testTopic], pubsubTopic: some(shard) + includeData: false, contentTopics: @[testTopic], pubsubTopic: Opt.some(shard) ) let res = await storeNode.wakuArchive.findMessages(query) if res.isOk() and res.get().hashes.len > 0: diff --git a/tests/api/test_api_send.nim b/tests/api/test_api_send.nim index 8df564b0d..6470b0168 100644 --- a/tests/api/test_api_send.nim +++ b/tests/api/test_api_send.nim @@ -1,6 +1,6 @@ {.used.} -import std/strutils +import results, std/strutils import chronos, testutils/unittests, stew/byteutils, libp2p/[switch, peerinfo] import brokers/broker_context import ../testlib/[common, wakucore, wakunode, testasync] @@ -128,7 +128,7 @@ proc createApiNodeConf( conf.listenAddress = parseIpAddress("0.0.0.0") conf.tcpPort = Port(0) conf.discv5UdpPort = Port(0) - conf.clusterId = some(3'u16) + conf.clusterId = Opt.some(3'u16) conf.numShardsInNetwork = 1 conf.rest = false result = conf diff --git a/tests/api/test_api_subscription.nim b/tests/api/test_api_subscription.nim index 90d160bc3..7558cd73e 100644 --- a/tests/api/test_api_subscription.nim +++ b/tests/api/test_api_subscription.nim @@ -1,6 +1,6 @@ {.used.} -import std/[strutils, sequtils, net, options, sets, tables] +import results, std/[strutils, sequtils, net, sets, tables] import chronos, testutils/unittests, stew/byteutils import libp2p/[peerid, peerinfo, multiaddress, crypto/crypto] import brokers/broker_context @@ -77,7 +77,7 @@ proc createApiNodeConf( conf.listenAddress = parseIpAddress("0.0.0.0") conf.tcpPort = Port(0) conf.discv5UdpPort = Port(0) - conf.clusterId = some(3'u16) + conf.clusterId = Opt.some(3'u16) conf.numShardsInNetwork = numShards conf.rest = false result = conf @@ -205,7 +205,7 @@ proc publishToMesh( let msg = WakuMessage( payload: payload, contentTopic: contentTopic, version: 0, timestamp: now() ) - return await net.publisher.publish(some(shard), msg) + return await net.publisher.publish(Opt.some(shard), msg) proc publishToMeshAfterEdgeReady( net: TestNetwork, contentTopic: ContentTopic, payload: seq[byte] @@ -688,7 +688,7 @@ suite "Messaging API, SubscriptionManager": version: 0, timestamp: now(), ) - discard (await publisher.publish(some(shard), msg1)).expect("Publish 1 failed") + discard (await publisher.publish(Opt.some(shard), msg1)).expect("Publish 1 failed") require await eventManager.waitForEvents(TestTimeout) check eventManager.receivedMessages[0].payload == "Before failover".toBytes() @@ -709,7 +709,7 @@ suite "Messaging API, SubscriptionManager": version: 0, timestamp: now(), ) - discard (await publisher.publish(some(shard), msg2)).expect("Publish 2 failed") + discard (await publisher.publish(Opt.some(shard), msg2)).expect("Publish 2 failed") require await eventManager.waitForEvents(TestTimeout) check eventManager.receivedMessages[0].payload == "After failover".toBytes() @@ -822,7 +822,7 @@ suite "Messaging API, SubscriptionManager": version: 0, timestamp: now(), ) - discard (await publisher.publish(some(shard), msg)).expect("Publish failed") + discard (await publisher.publish(Opt.some(shard), msg)).expect("Publish failed") require await eventManager.waitForEvents(TestTimeout) check eventManager.receivedMessages[0].payload == "After replacement".toBytes() diff --git a/tests/api/test_conf.nim b/tests/api/test_conf.nim index 705c00825..06a115897 100644 --- a/tests/api/test_conf.nim +++ b/tests/api/test_conf.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, net], results, chronos, testutils/unittests +import std/net, results, chronos, testutils/unittests import brokers/broker_context import logos_delivery import logos_delivery/api/conf/logos_delivery_conf_json @@ -15,7 +15,7 @@ suite "MessagingClientConf - mode expansion (toWakuNodeConf)": kc.relay == true kc.filter == true kc.lightpush == true - kc.discv5Discovery == some(true) + kc.discv5Discovery == Opt.some(true) kc.peerExchange == true kc.rendezvous == true @@ -28,19 +28,20 @@ suite "MessagingClientConf - mode expansion (toWakuNodeConf)": kc.lightpush == false kc.store == false kc.peerExchange == true - kc.discv5Discovery == some(true) # discovery stays on; mode does not force it off + kc.discv5Discovery == Opt.some(true) + # discovery stays on; mode does not force it off suite "MessagingClientConf - field mapping + transport policy": test "set fields are written to their kernel counterparts": let mc = MessagingClientConf( - clusterId: some(3'u16), - numShardsInCluster: some(4'u16), - maxMessageSize: some("150KiB"), + clusterId: Opt.some(3'u16), + numShardsInCluster: Opt.some(4'u16), + maxMessageSize: Opt.some("150KiB"), ) let kc = mc.toWakuNodeConf(LogosDeliveryMode.Core).valueOr: raiseAssert error check: - kc.clusterId == some(3'u16) + kc.clusterId == Opt.some(3'u16) kc.numShardsInNetwork == 4 kc.maxMessageSize == "150KiB" @@ -55,9 +56,9 @@ suite "MessagingClientConf - field mapping + transport policy": test "explicit transport overrides win": let mc = MessagingClientConf( - p2pTcpPort: some(Port(1234)), - websocketSupport: some(true), - quicSupport: some(false), + p2pTcpPort: Opt.some(Port(1234)), + websocketSupport: Opt.some(true), + quicSupport: Opt.some(false), ) let kc = mc.toWakuNodeConf(LogosDeliveryMode.Core).valueOr: raiseAssert error @@ -90,7 +91,8 @@ suite "MessagingClientConf - preset resolution": test "a messaging override of a kernel-mirrored field wins over the preset": let presetConf = resolvePreset("logos.dev").valueOr: raiseAssert error - let merged = merge(presetConf, MessagingClientConf(numShardsInCluster: some(1'u16))) + let merged = + merge(presetConf, MessagingClientConf(numShardsInCluster: Opt.some(1'u16))) var kernelConf = toWakuNodeConf(merged, LogosDeliveryMode.Core).valueOr: raiseAssert error kernelConf.preset = "logos.dev" @@ -102,12 +104,13 @@ suite "MessagingClientConf - preset resolution": suite "MessagingClientConf - merge (override wins)": test "a set override field wins; unset keeps the base": - let base = MessagingClientConf(clusterId: some(1'u16), maxMessageSize: some("1MB")) - let overrides = MessagingClientConf(clusterId: some(2'u16)) + let base = + MessagingClientConf(clusterId: Opt.some(1'u16), maxMessageSize: Opt.some("1MB")) + let overrides = MessagingClientConf(clusterId: Opt.some(2'u16)) let mc = merge(base, overrides) check: - mc.clusterId == some(2'u16) # override wins - mc.maxMessageSize == some("1MB") # base preserved + mc.clusterId == Opt.some(2'u16) # override wins + mc.maxMessageSize == Opt.some("1MB") # base preserved suite "parseLogosDeliveryConf - JSON parsing": test "empty object resolves to a full Core node conf": @@ -134,8 +137,8 @@ suite "parseLogosDeliveryConf - JSON parsing": raiseAssert error require lc.messagingConf.isSome() check: - WakuNodeConf(lc.kernelConf).clusterId == some(7'u16) # kernel field - lc.messagingConf.get().reliabilityEnabled == some(true) # messaging-only + WakuNodeConf(lc.kernelConf).clusterId == Opt.some(7'u16) # kernel field + lc.messagingConf.get().reliabilityEnabled == Opt.some(true) # messaging-only test "messaging overrides are recorded verbatim, unset fields left none": let lc = parseLogosDeliveryConf("""{"messagingOverrides": {"clusterId": 7}}""").valueOr: @@ -143,7 +146,7 @@ suite "parseLogosDeliveryConf - JSON parsing": require lc.messagingConf.isSome() let overrides = lc.messagingConf.get() check: - overrides.clusterId == some(7'u16) # the user's override, kept as given + overrides.clusterId == Opt.some(7'u16) # the user's override, kept as given overrides.reliabilityEnabled.isNone() # user didn't set it, so it stays none test "a preset resolves reliability into the messaging record": @@ -161,8 +164,8 @@ suite "parseLogosDeliveryConf - JSON parsing": require lc.channelsConf.isSome() let channels = lc.channelsConf.get() check: - channels.rateLimitEnabled == some(true) - channels.sdsMaxRetransmissions == some(9) + channels.rateLimitEnabled == Opt.some(true) + channels.sdsMaxRetransmissions == Opt.some(9) test "invalid mode is rejected (Core or Edge only)": check parseLogosDeliveryConf("""{"mode": "bogus"}""").isErr() @@ -185,8 +188,8 @@ suite "parseLogosDeliveryConf - JSON parsing": let kc = WakuNodeConf(lc.kernelConf) require lc.messagingConf.isSome() check: - kc.clusterId == some(7'u16) - lc.messagingConf.get().reliabilityEnabled == some(true) # messaging-only + kc.clusterId == Opt.some(7'u16) + lc.messagingConf.get().reliabilityEnabled == Opt.some(true) # messaging-only kc.tcpPort == Port(1234) test "unknown keys inside an overrides body are rejected": @@ -217,7 +220,7 @@ suite "parseLogosDeliveryConf - JSON parsing": raiseAssert error let kc = WakuNodeConf(lc.kernelConf) check: - kc.clusterId == some(7'u16) + kc.clusterId == Opt.some(7'u16) kc.store == false # null left store unset; Core does not enable it test "an invalid Ethereum RPC URL is rejected at parse time": @@ -285,10 +288,10 @@ suite "LogosDelivery.new - construction (the app-dev entry)": LogosDeliveryMode.Core, "", MessagingClientConf( - clusterId: some(3'u16), - numShardsInCluster: some(1'u16), - listenIpv4: some(parseIpAddress("0.0.0.0")), - reliabilityEnabled: some(true), + clusterId: Opt.some(3'u16), + numShardsInCluster: Opt.some(1'u16), + listenIpv4: Opt.some(parseIpAddress("0.0.0.0")), + reliabilityEnabled: Opt.some(true), ), ) ).valueOr: @@ -306,7 +309,7 @@ suite "LogosDelivery.new - construction (the app-dev entry)": await LogosDelivery.new( LogosDeliveryMode.Core, "logostest", - MessagingClientConf(listenIpv4: some(parseIpAddress("0.0.0.0"))), + MessagingClientConf(listenIpv4: Opt.some(parseIpAddress("0.0.0.0"))), ) ).valueOr: raiseAssert error @@ -315,7 +318,7 @@ suite "LogosDelivery.new - construction (the app-dev entry)": suite "MessagingClientConf - store override": test "store opt-in overrides the mode default; protocol flags follow the mode": - let kc = MessagingClientConf(store: some(true)).toWakuNodeConf( + let kc = MessagingClientConf(store: Opt.some(true)).toWakuNodeConf( LogosDeliveryMode.Edge ).valueOr: raiseAssert error @@ -325,7 +328,7 @@ suite "MessagingClientConf - store override": suite "LogosDelivery.new - raw kernel construction": asyncTest "a fleet node mounts the kernel only; start/stop tolerate the nil layers": - let kernel = MessagingClientConf(listenIpv4: some(parseIpAddress("0.0.0.0"))).toWakuNodeConf( + let kernel = MessagingClientConf(listenIpv4: Opt.some(parseIpAddress("0.0.0.0"))).toWakuNodeConf( LogosDeliveryMode.Core ).valueOr: raiseAssert error @@ -351,7 +354,7 @@ suite "parseLogosDeliveryConf - flat WakuNodeConf shape (interop compatibility)" raiseAssert error check: WakuNodeConf(lc.kernelConf).relay == true - WakuNodeConf(lc.kernelConf).clusterId == some(7'u16) + WakuNodeConf(lc.kernelConf).clusterId == Opt.some(7'u16) lc.messagingConf.isSome() # full stack lc.channelsConf.isSome() @@ -364,13 +367,13 @@ suite "parseLogosDeliveryConf - flat WakuNodeConf shape (interop compatibility)" WakuNodeConf(lc.kernelConf).relay == true # explicit flat field overrides the Edge default WakuNodeConf(lc.kernelConf).filter == false # Edge default, not set explicitly - WakuNodeConf(lc.kernelConf).clusterId == some(7'u16) + WakuNodeConf(lc.kernelConf).clusterId == Opt.some(7'u16) test "flat blob's reliabilityEnabled routes to the messaging conf, not the kernel": let lc = parseLogosDeliveryConf("""{"relay": true, "reliabilityEnabled": true}""").valueOr: raiseAssert error check: - lc.messagingConf.get().reliabilityEnabled == some(true) + lc.messagingConf.get().reliabilityEnabled == Opt.some(true) test "an unknown key in a flat blob is rejected": check parseLogosDeliveryConf("""{"relay": true, "bogusKey": 1}""").isErr() @@ -396,7 +399,7 @@ suite "parseLogosDeliveryConf - flat WakuNodeConf shape (interop compatibility)" test "port 0 is accepted in structured messagingOverrides": let lc = parseLogosDeliveryConf("""{"messagingOverrides": {"tcp-port": 0}}""").valueOr: raiseAssert error - check lc.messagingConf.get().p2pTcpPort == some(Port(0)) + check lc.messagingConf.get().p2pTcpPort == Opt.some(Port(0)) test "mode/preset with no bare field stays structured; a bare field flips it to flat": # No bare kernel field -> structured: mode owns relay, no per-flag override. diff --git a/tests/api/test_entry_nodes.nim b/tests/api/test_entry_nodes.nim index a6faf58c8..2435d5f48 100644 --- a/tests/api/test_entry_nodes.nim +++ b/tests/api/test_entry_nodes.nim @@ -1,6 +1,6 @@ {.used.} -import std/options, results, testutils/unittests +import results, testutils/unittests import tools/confutils/entry_nodes diff --git a/tests/api/test_node_conf.nim b/tests/api/test_node_conf.nim index 6048a5951..cf2b36cc5 100644 --- a/tests/api/test_node_conf.nim +++ b/tests/api/test_node_conf.nim @@ -1,6 +1,6 @@ {.used.} -import std/options, results, testutils/unittests +import results, testutils/unittests import tools/confutils/cli_args, logos_delivery/waku/factory/waku_conf, diff --git a/tests/channels/test_reliable_channel_send_receive.nim b/tests/channels/test_reliable_channel_send_receive.nim index b76851006..53a88f27a 100644 --- a/tests/channels/test_reliable_channel_send_receive.nim +++ b/tests/channels/test_reliable_channel_send_receive.nim @@ -1,6 +1,6 @@ {.used.} -import std/[net, options, os] +import results, std/[net, os] from std/times import epochTime import chronos, testutils/unittests, stew/byteutils import brokers/broker_context @@ -34,7 +34,7 @@ proc createApiNodeConf(): WakuNodeConf = conf.listenAddress = parseIpAddress("0.0.0.0") conf.tcpPort = Port(0) conf.discv5UdpPort = Port(0) - conf.clusterId = some(3'u16) + conf.clusterId = Opt.some(3'u16) conf.numShardsInNetwork = 1 conf.rest = false return conf diff --git a/tests/common/test_enr_builder.nim b/tests/common/test_enr_builder.nim index 0c87cf744..83867673e 100644 --- a/tests/common/test_enr_builder.nim +++ b/tests/common/test_enr_builder.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, net], results, testutils/unittests +import std/net, results, testutils/unittests import logos_delivery/waku/common/enr, ../testlib/wakucore suite "nim-eth ENR - builder and typed record": @@ -30,7 +30,7 @@ suite "nim-eth ENR - builder and typed record": let id = record.id check: - id == some(RecordId.V4) + id == Opt.some(RecordId.V4) let publicKey = record.secp256k1 check: @@ -58,7 +58,9 @@ suite "nim-eth ENR - Ext: IP address and TCP/UDP ports": ## When var builder = EnrBuilder.init(privateKey, seqNum) - builder.withIpAddressAndPorts(ipAddr = some(enrIpAddr), udpPort = some(enrUdpPort)) + builder.withIpAddressAndPorts( + ipAddr = Opt.some(enrIpAddr), udpPort = Opt.some(enrUdpPort) + ) let enrRes = builder.build() @@ -81,7 +83,9 @@ suite "nim-eth ENR - Ext: IP address and TCP/UDP ports": ## When var builder = EnrBuilder.init(privateKey, seqNum) - builder.withIpAddressAndPorts(ipAddr = some(enrIpAddr), tcpPort = some(enrTcpPort)) + builder.withIpAddressAndPorts( + ipAddr = Opt.some(enrIpAddr), tcpPort = Opt.some(enrTcpPort) + ) let enrRes = builder.build() @@ -91,10 +95,10 @@ suite "nim-eth ENR - Ext: IP address and TCP/UDP ports": let record = enrRes.tryGet().toTyped().get() check: @(record.secp256k1.get()) == expectedPubKey - record.ip == some(enrIpAddr.address_v4) - record.tcp == some(enrTcpPort.uint16) - record.udp == none(uint16) - record.ip6 == none(array[16, byte]) + record.ip == Opt.some(enrIpAddr.address_v4) + record.tcp == Opt.some(enrTcpPort.uint16) + record.udp == Opt.none(uint16) + record.ip6 == Opt.none(array[16, byte]) test "IPv6 and UDP port": let @@ -108,7 +112,9 @@ suite "nim-eth ENR - Ext: IP address and TCP/UDP ports": ## When var builder = EnrBuilder.init(privateKey, seqNum) - builder.withIpAddressAndPorts(ipAddr = some(enrIpAddr), udpPort = some(enrUdpPort)) + builder.withIpAddressAndPorts( + ipAddr = Opt.some(enrIpAddr), udpPort = Opt.some(enrUdpPort) + ) let enrRes = builder.build() @@ -118,9 +124,9 @@ suite "nim-eth ENR - Ext: IP address and TCP/UDP ports": let record = enrRes.tryGet().toTyped().get() check: @(record.secp256k1.get()) == expectedPubKey - record.ip == none(array[4, byte]) - record.tcp == none(uint16) - record.ip6 == some(enrIpAddr.address_v6) - record.tcp6 == none(uint16) - record.udp6 == some(enrUdpPort.uint16) - record.udp == some(enrUdpPort.uint16) + record.ip == Opt.none(array[4, byte]) + record.tcp == Opt.none(uint16) + record.ip6 == Opt.some(enrIpAddr.address_v6) + record.tcp6 == Opt.none(uint16) + record.udp6 == Opt.some(enrUdpPort.uint16) + record.udp == Opt.some(enrUdpPort.uint16) diff --git a/tests/common/test_ratelimit_setting.nim b/tests/common/test_ratelimit_setting.nim index d8140381e..0add4b76f 100644 --- a/tests/common/test_ratelimit_setting.nim +++ b/tests/common/test_ratelimit_setting.nim @@ -11,7 +11,7 @@ import libp2p/crypto/crypto import testutils/unittests import chronos, libp2p/stream/connection -import std/[options, tables] +import std/tables import ../../logos_delivery/waku/common/rate_limit/request_limiter import ../../logos_delivery/waku/common/rate_limit/timed_map diff --git a/tests/common/test_requestratelimiter.nim b/tests/common/test_requestratelimiter.nim index bd055c0f6..42b4df445 100644 --- a/tests/common/test_requestratelimiter.nim +++ b/tests/common/test_requestratelimiter.nim @@ -11,7 +11,7 @@ import libp2p/crypto/crypto import testutils/unittests import chronos, libp2p/stream/connection -import std/options +import results import ../../logos_delivery/waku/common/rate_limit/request_limiter import ../../logos_delivery/waku/common/rate_limit/timed_map @@ -27,7 +27,7 @@ suite "RequestRateLimiter": test "RequestRateLimiter Allow up to main bucket": # keep limits low for easier calculation of ratios let rateLimit: RateLimitSetting = (4, 2.minutes) - var limiter = newRequestRateLimiter(some(rateLimit)) + var limiter = newRequestRateLimiter(Opt.some(rateLimit)) # per peer tokens will be 6 / 4min # as ratio is 2 in this case but max tokens are main tokens*ratio . 0.75 # notice meanwhile we have 8 global tokens over 2 period (4 mins) in sum @@ -52,7 +52,7 @@ suite "RequestRateLimiter": test "RequestRateLimiter Restrict overusing peer": # keep limits low for easier calculation of ratios let rateLimit: RateLimitSetting = (10, 2.minutes) - var limiter = newRequestRateLimiter(some(rateLimit)) + var limiter = newRequestRateLimiter(Opt.some(rateLimit)) # per peer tokens will be 15 / 4min # as ratio is 2 in this case but max tokens are main tokens*ratio . 0.75 # notice meanwhile we have 20 tokens over 2 period (4 mins) in sum @@ -88,7 +88,7 @@ suite "RequestRateLimiter": test "RequestRateLimiter lowest possible volume": # keep limits low for easier calculation of ratios let rateLimit: RateLimitSetting = (1, 1.seconds) - var limiter = newRequestRateLimiter(some(rateLimit)) + var limiter = newRequestRateLimiter(Opt.some(rateLimit)) let now = Moment.now() # with first use we register the peer also and start its timer diff --git a/tests/factory/test_node_factory.nim b/tests/factory/test_node_factory.nim index b4e8429a3..9b95cdaea 100644 --- a/tests/factory/test_node_factory.nim +++ b/tests/factory/test_node_factory.nim @@ -1,7 +1,8 @@ {.used.} import - std/[net, options, sequtils, strutils], + results, + std/[net, sequtils, strutils], testutils/unittests, chronos, chronos/transports/[stream, datagram, common], @@ -75,7 +76,7 @@ suite "Node Factory": bindPort = bindPort, extMultiAddrs = oversizedMultiaddrs, extMultiAddrsOnly = true, - wakuFlags = some(conf.wakuFlags), + wakuFlags = Opt.some(conf.wakuFlags), ).valueOr: raiseAssert error diff --git a/tests/factory/test_waku_conf.nim b/tests/factory/test_waku_conf.nim index 117f23250..d386b0088 100644 --- a/tests/factory/test_waku_conf.nim +++ b/tests/factory/test_waku_conf.nim @@ -4,7 +4,7 @@ import libp2p/crypto/[crypto, secp], libp2p/multiaddress, nimcrypto/utils, - std/[net, options, random, sequtils], + std/[net, random, sequtils], results, testutils/unittests import @@ -288,7 +288,7 @@ suite "Waku Conf - build with cluster conf": ## Passing an AutoSharding preset and trying to override with ## --num-shards-in-network=0 (which is StaticSharding) doesn't work. ## Note that --num-shards-in-network=0 and omitting the switch are - ## internally the same. Promoting the config to an Option[uint16] is + ## internally the same. Promoting the config to an Opt[uint16] is ## probably not worth it since overriding an AutoSharding preset with ## StaticSharding shouldn't make any sense (that is, no use case). diff --git a/tests/incentivization/test_poc_eligibility.nim b/tests/incentivization/test_poc_eligibility.nim index f9f1c53fa..44baae783 100644 --- a/tests/incentivization/test_poc_eligibility.nim +++ b/tests/incentivization/test_poc_eligibility.nim @@ -1,6 +1,6 @@ {.used.} -import std/options, testutils/unittests, chronos, web3, stint, tests/testlib/testasync +import results, testutils/unittests, chronos, web3, stint, tests/testlib/testasync import logos_delivery/waku/node/peer_manager, @@ -145,7 +145,7 @@ suite "Waku Incentivization PoC Eligibility Proofs": ## Test that an unconfirmed tx is not eligible. let eligibilityProof = - EligibilityProof(proofOfPayment: some(@(TxHashNonExisting.bytes()))) + EligibilityProof(proofOfPayment: Opt.some(@(TxHashNonExisting.bytes()))) let isEligible = await manager.isEligibleTxId( eligibilityProof, receiverExpected, TxValueExpectedWei ) @@ -156,7 +156,7 @@ suite "Waku Incentivization PoC Eligibility Proofs": ## Test that a contract creation tx is not eligible. let eligibilityProof = - EligibilityProof(proofOfPayment: some(@(txHashContractCreation.bytes()))) + EligibilityProof(proofOfPayment: Opt.some(@(txHashContractCreation.bytes()))) let isEligible = await manager.isEligibleTxId( eligibilityProof, receiverExpected, TxValueExpectedWei ) @@ -168,7 +168,7 @@ suite "Waku Incentivization PoC Eligibility Proofs": ## This assumes a payment in native currency (ETH), not a token. let eligibilityProof = - EligibilityProof(proofOfPayment: some(@(txHashContractCall.bytes()))) + EligibilityProof(proofOfPayment: Opt.some(@(txHashContractCall.bytes()))) let isEligible = await manager.isEligibleTxId( eligibilityProof, receiverExpected, TxValueExpectedWei ) @@ -178,8 +178,9 @@ suite "Waku Incentivization PoC Eligibility Proofs": asyncTest "incentivization PoC: simple transfer tx is eligible": ## Test that a simple transfer tx is eligible (if necessary conditions hold). - let eligibilityProof = - EligibilityProof(proofOfPayment: some(@(txHashRightReceiverRightAmount.bytes()))) + let eligibilityProof = EligibilityProof( + proofOfPayment: Opt.some(@(txHashRightReceiverRightAmount.bytes())) + ) let isEligible = await manager.isEligibleTxId( eligibilityProof, receiverExpected, TxValueExpectedWei ) @@ -189,8 +190,9 @@ suite "Waku Incentivization PoC Eligibility Proofs": asyncTest "incentivization PoC: double-spend tx is not eligible": ## Test that the same tx submitted twice is not eligible the second time - let eligibilityProof = - EligibilityProof(proofOfPayment: some(@(txHashRightReceiverRightAmount.bytes()))) + let eligibilityProof = EligibilityProof( + proofOfPayment: Opt.some(@(txHashRightReceiverRightAmount.bytes())) + ) let isEligibleOnce = await manager.isEligibleTxId( eligibilityProof, receiverExpected, TxValueExpectedWei diff --git a/tests/incentivization/test_poc_reputation.nim b/tests/incentivization/test_poc_reputation.nim index f64947614..4d1506608 100644 --- a/tests/incentivization/test_poc_reputation.nim +++ b/tests/incentivization/test_poc_reputation.nim @@ -1,4 +1,4 @@ -import std/options, testutils/unittests, chronos, web3 +import results, testutils/unittests, chronos, web3 import logos_delivery/waku/incentivization/reputation_manager, @@ -14,32 +14,33 @@ suite "Waku Incentivization PoC Reputation": check manager.reputationOf.len == 0 test "incentivization PoC: reputation: set and get reputation": - manager.setReputation("peer1", some(true)) # Encodes GoodRep - check manager.getReputation("peer1") == some(true) + manager.setReputation("peer1", Opt.some(true)) # Encodes GoodRep + check manager.getReputation("peer1") == Opt.some(true) test "incentivization PoC: reputation: evaluate PushResponse valid": let validLightpushResponse = - PushResponse(isSuccess: true, info: some("Everything is OK")) + PushResponse(isSuccess: true, info: Opt.some("Everything is OK")) # We expect evaluateResponse to return GoodResponse if isSuccess is true check evaluateResponse(validLightpushResponse) == GoodResponse test "incentivization PoC: reputation: evaluate PushResponse invalid": - let invalidLightpushResponse = PushResponse(isSuccess: false, info: none(string)) + let invalidLightpushResponse = + PushResponse(isSuccess: false, info: Opt.none(string)) check evaluateResponse(invalidLightpushResponse) == BadResponse test "incentivization PoC: reputation: updateReputationFromResponse valid": let peerId = "peerWithValidResponse" - let validResp = PushResponse(isSuccess: true, info: some("All good")) + let validResp = PushResponse(isSuccess: true, info: Opt.some("All good")) manager.updateReputationFromResponse(peerId, validResp) - check manager.getReputation(peerId) == some(true) + check manager.getReputation(peerId) == Opt.some(true) test "incentivization PoC: reputation: updateReputationFromResponse invalid": let peerId = "peerWithInvalidResponse" - let invalidResp = PushResponse(isSuccess: false, info: none(string)) + let invalidResp = PushResponse(isSuccess: false, info: Opt.none(string)) manager.updateReputationFromResponse(peerId, invalidResp) - check manager.getReputation(peerId) == some(false) + check manager.getReputation(peerId) == Opt.some(false) test "incentivization PoC: reputation: default is None": let unknownPeerId = "unknown_peer" # The peer is not in the table yet - check manager.getReputation(unknownPeerId) == none(bool) + check manager.getReputation(unknownPeerId) == Opt.none(bool) diff --git a/tests/incentivization/test_rpc_codec.nim b/tests/incentivization/test_rpc_codec.nim index 672633113..0067f37ee 100644 --- a/tests/incentivization/test_rpc_codec.nim +++ b/tests/incentivization/test_rpc_codec.nim @@ -1,4 +1,4 @@ -import std/options, testutils/unittests, chronos, libp2p/crypto/crypto, web3 +import results, testutils/unittests, chronos, libp2p/crypto/crypto, web3 import logos_delivery/waku/incentivization/[rpc, rpc_codec, common] @@ -8,7 +8,7 @@ suite "Waku Incentivization Eligibility Codec": "0x0000000000000000000000000000000000000000000000000000000000000000" ) let txHashAsBytes = @(txHash.bytes()) - let eligibilityProof = EligibilityProof(proofOfPayment: some(txHashAsBytes)) + let eligibilityProof = EligibilityProof(proofOfPayment: Opt.some(txHashAsBytes)) let encoded = encode(eligibilityProof) let decoded = EligibilityProof.decode(encoded.buffer).get() check: diff --git a/tests/node/peer_manager/peer_store/test_migrations.nim b/tests/node/peer_manager/peer_store/test_migrations.nim index 7925af92d..7c4a67e7b 100644 --- a/tests/node/peer_manager/peer_store/test_migrations.nim +++ b/tests/node/peer_manager/peer_store/test_migrations.nim @@ -1,4 +1,4 @@ -import std/[options], results, testutils/unittests +import results, testutils/unittests import logos_delivery/waku/node/peer_manager/peer_store/migrations, diff --git a/tests/node/peer_manager/peer_store/test_waku_peer_storage.nim b/tests/node/peer_manager/peer_store/test_waku_peer_storage.nim index e7dd2a151..2f1a536c6 100644 --- a/tests/node/peer_manager/peer_store/test_waku_peer_storage.nim +++ b/tests/node/peer_manager/peer_store/test_waku_peer_storage.nim @@ -1,5 +1,5 @@ import - std/[nativesockets, options, sequtils], + std/[nativesockets, sequtils], testutils/unittests, libp2p/[multiaddress, peerid], libp2p/crypto/crypto, diff --git a/tests/node/peer_manager/peer_store/utils.nim b/tests/node/peer_manager/peer_store/utils.nim index c7c380b43..0ab940417 100644 --- a/tests/node/peer_manager/peer_store/utils.nim +++ b/tests/node/peer_manager/peer_store/utils.nim @@ -1,9 +1,9 @@ -import std/options, results +import results import logos_delivery/waku/node/peer_manager/[waku_peer_store, peer_store/waku_peer_storage], ../../../waku_archive/archive_utils -proc newTestWakuPeerStorage*(path: Option[string] = string.none()): WakuPeerStorage = +proc newTestWakuPeerStorage*(path: Opt[string] = Opt.none(string)): WakuPeerStorage = let db = newSqliteDatabase(path) WakuPeerStorage.new(db).value() diff --git a/tests/node/peer_manager/test_peer_manager.nim b/tests/node/peer_manager/test_peer_manager.nim index 25e6f4916..9ec37b9fc 100644 --- a/tests/node/peer_manager/test_peer_manager.nim +++ b/tests/node/peer_manager/test_peer_manager.nim @@ -1,4 +1,4 @@ -import chronicles, std/[options, tables, strutils], chronos, testutils/unittests +import results, chronicles, std/[tables, strutils], chronos, testutils/unittests import logos_delivery/waku/node/waku_node, @@ -52,7 +52,7 @@ suite "Peer Manager": # When making an operation that triggers onPeerMetadata discard await client.filterSubscribe( - some("/waku/2/rs/0/0"), "waku/lightpush/1", serverRemotePeerInfo + Opt.some("/waku/2/rs/0/0"), "waku/lightpush/1", serverRemotePeerInfo ) await sleepAsync(FUTURE_TIMEOUT) diff --git a/tests/node/test_wakunode_filter.nim b/tests/node/test_wakunode_filter.nim index dd92c0c37..0f2996081 100644 --- a/tests/node/test_wakunode_filter.nim +++ b/tests/node/test_wakunode_filter.nim @@ -2,7 +2,8 @@ import libp2p/crypto/crypto {.used.} import - std/[options, tables, sequtils, strutils, sets], + results, + std/[tables, sequtils, strutils, sets], testutils/unittests, chronos, chronicles, @@ -28,7 +29,7 @@ proc generateRequestId(rng: crypto.Rng): string = proc createRequest( filterSubscribeType: FilterSubscribeType, - pubsubTopic = none(PubsubTopic), + pubsubTopic = Opt.none(PubsubTopic), contentTopics = newSeq[ContentTopic](), ): FilterSubscribeRequest = let requestId = generateRequestId(common.rng()) @@ -91,7 +92,7 @@ suite "Waku Filter - End to End": asyncTest "Client Node receives Push from Server Node, via Filter": # When a client node subscribes to a filter node let subscribeResponse = await client.filterSubscribe( - some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo + Opt.some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo ) # Then the subscription is successful @@ -113,7 +114,7 @@ suite "Waku Filter - End to End": # When unsubscribing from the subscription let unsubscribeResponse = await client.filterUnsubscribe( - some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo + Opt.some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo ) # Then the unsubscription is successful @@ -137,7 +138,7 @@ suite "Waku Filter - End to End": # And valid filter subscription let subscribeResponse = await client.filterSubscribe( - some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo + Opt.some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo ) require: subscribeResponse.isOk() @@ -145,7 +146,7 @@ suite "Waku Filter - End to End": # When a server node gets a Relay message let msg1 = fakeWakuMessage(contentTopic = contentTopic) - discard await server.publish(some(pubsubTopic), msg1) + discard await server.publish(Opt.some(pubsubTopic), msg1) # Then the message is not sent to the client's filter push handler check (not await pushHandlerFuture.withTimeout(FUTURE_TIMEOUT)) @@ -164,7 +165,7 @@ suite "Waku Filter - End to End": # When a client node subscribes to the server node let subscribeResponse = await client.filterSubscribe( - some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo + Opt.some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo ) # Then the subscription is successful @@ -178,7 +179,7 @@ suite "Waku Filter - End to End": # Given a valid filter subscription var subscribeResponse = await client.filterSubscribe( - some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo + Opt.some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo ) require: subscribeResponse.isOk() @@ -203,7 +204,7 @@ suite "Waku Filter - End to End": # Given a valid filter subscription subscribeResponse = await client.filterSubscribe( - some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo + Opt.some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo ) require: subscribeResponse.isOk() @@ -226,7 +227,7 @@ suite "Waku Filter - End to End": # Given a valid filter subscription let subscribeResponse = await client.filterSubscribe( - some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo + Opt.some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo ) require: subscribeResponse.isOk() @@ -238,14 +239,14 @@ suite "Waku Filter - End to End": # When a message is sent to the subscribed content topic, via Relay let msg = fakeWakuMessage(contentTopic = contentTopic) - discard await server.publish(some(pubsubTopic), msg) + discard await server.publish(Opt.some(pubsubTopic), msg) # Then the message is not sent to the client's filter push handler check (not await pushHandlerFuture.withTimeout(FUTURE_TIMEOUT)) # Given the client refreshes the subscription let subscribeResponse2 = await clientClone.filterSubscribe( - some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo + Opt.some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo ) check: subscribeResponse2.isOk() @@ -254,7 +255,7 @@ suite "Waku Filter - End to End": # When a message is sent to the subscribed content topic, via Relay pushHandlerFuture = newPushHandlerFuture() let msg2 = fakeWakuMessage(contentTopic = contentTopic) - discard await server.publish(some(pubsubTopic), msg2) + discard await server.publish(Opt.some(pubsubTopic), msg2) # Then the message is not sent to the client's filter push handler check (not await pushHandlerFuture.withTimeout(FUTURE_TIMEOUT)) @@ -269,7 +270,7 @@ suite "Waku Filter - End to End": createRequest(filterSubscribeType = FilterSubscribeType.SUBSCRIBER_PING) filterSubscribeRequest = createRequest( filterSubscribeType = FilterSubscribeType.SUBSCRIBE, - pubsubTopic = some(DefaultPubsubTopic), + pubsubTopic = Opt.some(DefaultPubsubTopic), contentTopics = @[DefaultContentTopic], ) @@ -308,7 +309,7 @@ suite "Waku Filter - End to End": serverPeerId = server.switch.peerInfo.peerId filterSubscribeRequest = createRequest( filterSubscribeType = FilterSubscribeType.SUBSCRIBE, - pubsubTopic = some(DefaultPubsubTopic), + pubsubTopic = Opt.some(DefaultPubsubTopic), contentTopics = @[DefaultContentTopic], ) filterUnsubscribeRequest = createRequest( @@ -353,7 +354,7 @@ suite "Waku Filter - End to End": nonDefaultContentTopic = ContentTopic("/waku/2/non-default-waku/proto") filterSubscribeRequest = createRequest( filterSubscribeType = FilterSubscribeType.SUBSCRIBE, - pubsubTopic = some(DefaultPubsubTopic), + pubsubTopic = Opt.some(DefaultPubsubTopic), contentTopics = @[DefaultContentTopic, nonDefaultContentTopic], ) filterUnsubscribeAllRequest = @@ -399,7 +400,7 @@ suite "Waku Filter - End to End": nonDefaultContentTopic = ContentTopic("/waku/2/non-default-waku/proto") filterSubscribeRequest1 = createRequest( filterSubscribeType = FilterSubscribeType.SUBSCRIBE, - pubsubTopic = some(DefaultPubsubTopic), + pubsubTopic = Opt.some(DefaultPubsubTopic), contentTopics = @[DefaultContentTopic], ) filterSubscribeRequest2 = createRequest( @@ -500,12 +501,12 @@ suite "Waku Filter - End to End": let reqNoPubsubTopic = createRequest( filterSubscribeType = FilterSubscribeType.SUBSCRIBE, - pubsubTopic = none(PubsubTopic), + pubsubTopic = Opt.none(PubsubTopic), contentTopics = @[DefaultContentTopic], ) reqNoContentTopics = createRequest( filterSubscribeType = FilterSubscribeType.SUBSCRIBE, - pubsubTopic = some(DefaultPubsubTopic), + pubsubTopic = Opt.some(DefaultPubsubTopic), contentTopics = @[], ) response1 = @@ -535,7 +536,7 @@ suite "Waku Filter - End to End": ) reqTooManyContentTopics = createRequest( filterSubscribeType = FilterSubscribeType.SUBSCRIBE, - pubsubTopic = some(DefaultPubsubTopic), + pubsubTopic = Opt.some(DefaultPubsubTopic), contentTopics = contentTopics, ) response3 = @@ -561,7 +562,7 @@ suite "Waku Filter - End to End": let reqTooManyFilterCriteria = createRequest( filterSubscribeType = FilterSubscribeType.SUBSCRIBE, - pubsubTopic = some(DefaultPubsubTopic), + pubsubTopic = Opt.some(DefaultPubsubTopic), contentTopics = @[DefaultContentTopic], ) response4 = @@ -609,7 +610,7 @@ suite "Waku Filter - End to End": let reqTooManySubscriptions = createRequest( filterSubscribeType = FilterSubscribeType.SUBSCRIBE, - pubsubTopic = some(DefaultPubsubTopic), + pubsubTopic = Opt.some(DefaultPubsubTopic), contentTopics = @[DefaultContentTopic], ) response5 = @@ -645,12 +646,12 @@ suite "Waku Filter - End to End": let reqNoPubsubTopic = createRequest( filterSubscribeType = FilterSubscribeType.UNSUBSCRIBE, - pubsubTopic = none(PubsubTopic), + pubsubTopic = Opt.none(PubsubTopic), contentTopics = @[DefaultContentTopic], ) reqNoContentTopics = createRequest( filterSubscribeType = FilterSubscribeType.UNSUBSCRIBE, - pubsubTopic = some(DefaultPubsubTopic), + pubsubTopic = Opt.some(DefaultPubsubTopic), contentTopics = @[], ) response1 = @@ -680,7 +681,7 @@ suite "Waku Filter - End to End": ) reqTooManyContentTopics = createRequest( filterSubscribeType = FilterSubscribeType.UNSUBSCRIBE, - pubsubTopic = some(DefaultPubsubTopic), + pubsubTopic = Opt.some(DefaultPubsubTopic), contentTopics = contentTopics, ) response3 = @@ -698,7 +699,7 @@ suite "Waku Filter - End to End": let reqSubscriptionNotFound = createRequest( filterSubscribeType = FilterSubscribeType.UNSUBSCRIBE, - pubsubTopic = some(DefaultPubsubTopic), + pubsubTopic = Opt.some(DefaultPubsubTopic), contentTopics = @[DefaultContentTopic], ) response4 = @@ -740,7 +741,7 @@ suite "Waku Filter - End to End": client3 = newTestWakuNode(generateSecp256k1Key()) filterSubscribeRequest = createRequest( filterSubscribeType = FilterSubscribeType.SUBSCRIBE, - pubsubTopic = some(DefaultPubsubTopic), + pubsubTopic = Opt.some(DefaultPubsubTopic), contentTopics = @[DefaultContentTopic], ) diff --git a/tests/node/test_wakunode_health_monitor.nim b/tests/node/test_wakunode_health_monitor.nim index af90a9be0..71203010f 100644 --- a/tests/node/test_wakunode_health_monitor.nim +++ b/tests/node/test_wakunode_health_monitor.nim @@ -1,7 +1,6 @@ {.used.} -import - std/[json, options, sequtils, strutils, tables], testutils/unittests, chronos, results +import std/[json, sequtils, strutils, tables], testutils/unittests, chronos, results import brokers/broker_context import @@ -51,7 +50,7 @@ suite "Health Monitor - health state calculation": protoHealthMock(LightpushClientProtocol, HealthStatus.NOT_READY), ] let strength = initTable[WakuProtocol, int]() - let state = calculateConnectionState(protocols, strength, some(MockDLow)) + let state = calculateConnectionState(protocols, strength, Opt.some(MockDLow)) check state == ConnectionStatus.Disconnected test "PartiallyConnected, weak relay": @@ -59,7 +58,7 @@ suite "Health Monitor - health state calculation": let protocols = @[protoHealthMock(RelayProtocol, HealthStatus.READY)] var strength = initTable[WakuProtocol, int]() strength[RelayProtocol] = weakCount - let state = calculateConnectionState(protocols, strength, some(MockDLow)) + let state = calculateConnectionState(protocols, strength, Opt.some(MockDLow)) # Partially connected since relay connectivity is weak (> 0, but < dLow) check state == ConnectionStatus.PartiallyConnected @@ -67,7 +66,7 @@ suite "Health Monitor - health state calculation": let protocols = @[protoHealthMock(RelayProtocol, HealthStatus.READY)] var strength = initTable[WakuProtocol, int]() strength[RelayProtocol] = MockDLow - let state = calculateConnectionState(protocols, strength, some(MockDLow)) + let state = calculateConnectionState(protocols, strength, Opt.some(MockDLow)) # Fully connected since relay connectivity is ideal (>= dLow) check state == ConnectionStatus.Connected @@ -82,7 +81,7 @@ suite "Health Monitor - health state calculation": strength[LightpushClientProtocol] = HealthyThreshold strength[FilterClientProtocol] = HealthyThreshold strength[StoreClientProtocol] = HealthyThreshold - let state = calculateConnectionState(protocols, strength, some(MockDLow)) + let state = calculateConnectionState(protocols, strength, Opt.some(MockDLow)) check state == ConnectionStatus.Connected test "Disconnected, edge missing store": @@ -95,7 +94,7 @@ suite "Health Monitor - health state calculation": strength[LightpushClientProtocol] = HealthyThreshold strength[FilterClientProtocol] = HealthyThreshold strength[StoreClientProtocol] = 0 - let state = calculateConnectionState(protocols, strength, some(MockDLow)) + let state = calculateConnectionState(protocols, strength, Opt.some(MockDLow)) check state == ConnectionStatus.Disconnected test "PartiallyConnected, edge meets minimum failover requirement": @@ -109,7 +108,7 @@ suite "Health Monitor - health state calculation": strength[LightpushClientProtocol] = weakCount strength[FilterClientProtocol] = weakCount strength[StoreClientProtocol] = weakCount - let state = calculateConnectionState(protocols, strength, some(MockDLow)) + let state = calculateConnectionState(protocols, strength, Opt.some(MockDLow)) check state == ConnectionStatus.PartiallyConnected test "Connected, robust relay ignores store server": @@ -120,7 +119,7 @@ suite "Health Monitor - health state calculation": var strength = initTable[WakuProtocol, int]() strength[RelayProtocol] = MockDLow strength[StoreProtocol] = 0 - let state = calculateConnectionState(protocols, strength, some(MockDLow)) + let state = calculateConnectionState(protocols, strength, Opt.some(MockDLow)) check state == ConnectionStatus.Connected test "Connected, robust relay ignores store client": @@ -133,7 +132,7 @@ suite "Health Monitor - health state calculation": strength[RelayProtocol] = MockDLow strength[StoreProtocol] = 0 strength[StoreClientProtocol] = 0 - let state = calculateConnectionState(protocols, strength, some(MockDLow)) + let state = calculateConnectionState(protocols, strength, Opt.some(MockDLow)) check state == ConnectionStatus.Connected suite "Health Monitor - events": @@ -238,7 +237,7 @@ suite "Health Monitor - events": node: nodeA, conf: defaultTestWakuConf(), stateInfo: WakuStateInfo.init(nodeA) ) let ds = MessagingClient - .new(MessagingClientConf(reliabilityEnabled: some(false)), waku) + .new(MessagingClientConf(reliabilityEnabled: Opt.some(false)), waku) .expect("Failed to create MessagingClient") ds.start().expect("Failed to start MessagingClient") @@ -349,7 +348,7 @@ suite "Health Monitor - events": node: nodeA, conf: defaultTestWakuConf(), stateInfo: WakuStateInfo.init(nodeA) ) let ds = MessagingClient - .new(MessagingClientConf(reliabilityEnabled: some(false)), waku) + .new(MessagingClientConf(reliabilityEnabled: Opt.some(false)), waku) .expect("Failed to create MessagingClient") ds.start().expect("Failed to start MessagingClient") let subMgr = nodeA.subscriptionManager diff --git a/tests/node/test_wakunode_legacy_lightpush.nim b/tests/node/test_wakunode_legacy_lightpush.nim index aec37e18c..bbd37fb6e 100644 --- a/tests/node/test_wakunode_legacy_lightpush.nim +++ b/tests/node/test_wakunode_legacy_lightpush.nim @@ -1,7 +1,8 @@ {.used.} import - std/[options, tempfiles, net, osproc, strutils], + results, + std/[tempfiles, net, osproc, strutils], testutils/unittests, chronos, std/strformat, @@ -65,7 +66,7 @@ suite "Waku Legacy Lightpush - End To End": # When the client publishes a message let publishResponse = await lightpushClient.legacyLightpushPublish( - some(pubsubTopic), message, serverRemotePeerInfo + Opt.some(pubsubTopic), message, serverRemotePeerInfo ) if not publishResponse.isOk(): @@ -86,7 +87,7 @@ suite "Waku Legacy Lightpush - End To End": # When the client publishes an over-limit message let publishResponse = await client.legacyLightpushPublish( - some(pubsubTopic), msgOverLimit, serverRemotePeerInfo + Opt.some(pubsubTopic), msgOverLimit, serverRemotePeerInfo ) check: @@ -115,7 +116,7 @@ suite "RLN Proofs as a Lightpush Service": server = newTestWakuNode(serverKey) client = newTestWakuNode(clientKey) - anvilProc = runAnvil(stateFile = some(DEFAULT_ANVIL_STATE_PATH)) + anvilProc = runAnvil(stateFile = Opt.some(DEFAULT_ANVIL_STATE_PATH)) manager = waitFor setupOnchainGroupManager(deployContracts = false) # mount rln-relay @@ -170,11 +171,11 @@ suite "RLN Proofs as a Lightpush Service": # proof in legacyLightpushPublish; here we generate it using the server's RLN # instance since both ends share group state via the in-memory manager. let msgWithProof = - (await checkAndGenerateRLNProof(some(server.rln), message)).get() + (await checkAndGenerateRLNProof(Opt.some(server.rln), message)).get() # When the client publishes a message let publishResponse = await lightpushClient.legacyLightpushPublish( - some(pubsubTopic), msgWithProof, serverRemotePeerInfo + Opt.some(pubsubTopic), msgWithProof, serverRemotePeerInfo ) if not publishResponse.isOk(): @@ -204,7 +205,7 @@ suite "RLN Proofs as a Lightpush Service": server.wakuLegacyLightPush.pushHandler = stub let response = await server.legacyLightpushPublish( - some(pubsubTopic), message, server.peerInfo.toRemotePeerInfo() + Opt.some(pubsubTopic), message, server.peerInfo.toRemotePeerInfo() ) check: @@ -221,7 +222,7 @@ suite "RLN Proofs as a Lightpush Service": server.wakuLegacyLightPush.pushHandler = stub let response = await server.legacyLightpushPublish( - some(pubsubTopic), message, server.peerInfo.toRemotePeerInfo() + Opt.some(pubsubTopic), message, server.peerInfo.toRemotePeerInfo() ) check: @@ -239,7 +240,7 @@ suite "RLN Proofs as a Lightpush Service": server.wakuLegacyLightPush.pushHandler = stub let response = await server.legacyLightpushPublish( - some(pubsubTopic), message, server.peerInfo.toRemotePeerInfo() + Opt.some(pubsubTopic), message, server.peerInfo.toRemotePeerInfo() ) check: @@ -264,7 +265,7 @@ suite "RLN Proofs as a Lightpush Service": server.wakuLegacyLightPush.pushHandler = stub let response = await server.legacyLightpushPublish( - some(pubsubTopic), message, server.peerInfo.toRemotePeerInfo() + Opt.some(pubsubTopic), message, server.peerInfo.toRemotePeerInfo() ) server.rln = savedRln @@ -318,7 +319,8 @@ suite "Waku Legacy Lightpush message delivery": await sleepAsync(100.millis) ## When - let res = await lightNode.legacyLightpushPublish(some(CustomPubsubTopic), message) + let res = + await lightNode.legacyLightpushPublish(Opt.some(CustomPubsubTopic), message) assert res.isOk(), $res.error ## Then diff --git a/tests/node/test_wakunode_lightpush.nim b/tests/node/test_wakunode_lightpush.nim index f13cbcaab..eaedb2c97 100644 --- a/tests/node/test_wakunode_lightpush.nim +++ b/tests/node/test_wakunode_lightpush.nim @@ -1,7 +1,8 @@ {.used.} import - std/[options, tempfiles, osproc, strutils], + results, + std/[tempfiles, osproc, strutils], testutils/unittests, chronos, std/strformat, @@ -60,7 +61,7 @@ suite "Waku Lightpush - End To End": # When the client publishes a message let publishResponse = await lightpushClient.lightpushPublish( - some(pubsubTopic), message, some(serverRemotePeerInfo) + Opt.some(pubsubTopic), message, Opt.some(serverRemotePeerInfo) ) if not publishResponse.isOk(): @@ -81,14 +82,16 @@ suite "Waku Lightpush - End To End": # When the client publishes an over-limit message let publishResponse = await client.lightpushPublish( - some(pubsubTopic), msgOverLimit, some(serverRemotePeerInfo) + Opt.some(pubsubTopic), msgOverLimit, Opt.some(serverRemotePeerInfo) ) check: publishResponse.isErr() publishResponse.error.code == LightPushErrorCode.INVALID_MESSAGE publishResponse.error.desc == - some(fmt"Message size exceeded maximum of {DefaultMaxWakuMessageSize} bytes") + Opt.some( + fmt"Message size exceeded maximum of {DefaultMaxWakuMessageSize} bytes" + ) suite "RLN Proofs as a Lightpush Service": var @@ -111,7 +114,7 @@ suite "RLN Proofs as a Lightpush Service": server = newTestWakuNode(serverKey) client = newTestWakuNode(clientKey) - anvilProc = runAnvil(stateFile = some(DEFAULT_ANVIL_STATE_PATH)) + anvilProc = runAnvil(stateFile = Opt.some(DEFAULT_ANVIL_STATE_PATH)) manager = waitFor setupOnchainGroupManager(deployContracts = false) # mount rln-relay @@ -166,11 +169,11 @@ suite "RLN Proofs as a Lightpush Service": # proof in lightpushPublish; here we generate it using the server's RLN instance # since both ends share group state via the in-memory manager. let msgWithProof = - (await checkAndGenerateRLNProof(some(server.rln), message)).get() + (await checkAndGenerateRLNProof(Opt.some(server.rln), message)).get() # When the client publishes a message let publishResponse = await lightpushClient.lightpushPublish( - some(pubsubTopic), msgWithProof, some(serverRemotePeerInfo) + Opt.some(pubsubTopic), msgWithProof, Opt.some(serverRemotePeerInfo) ) if not publishResponse.isOk(): @@ -186,7 +189,8 @@ suite "RLN Proofs as a Lightpush Service": # invalidateMerkleProofCache empties the cached path so the next # proof-gen refetches from chain, and attachRLNProof rebuilds the proof # even though the message already carries one. - let firstMsg = (await checkAndGenerateRLNProof(some(server.rln), message)).get() + let firstMsg = + (await checkAndGenerateRLNProof(Opt.some(server.rln), message)).get() check firstMsg.proof.len > 0 # Corrupt the cache to model a stale/invalid witness — the same state a @@ -231,7 +235,7 @@ suite "RLN Proofs as a Lightpush Service": let goodCache = manager.merkleProofCache check goodCache.len > 0 - let response = await server.lightpushPublish(some(pubsubTopic), message) + let response = await server.lightpushPublish(Opt.some(pubsubTopic), message) check: # The rejection is surfaced immediately — no internal republish — and @@ -260,7 +264,7 @@ suite "RLN Proofs as a Lightpush Service": ) server.wakuLightPush.pushHandler = stub - let response = await server.lightpushPublish(some(pubsubTopic), message) + let response = await server.lightpushPublish(Opt.some(pubsubTopic), message) check: callCount == 1 @@ -280,7 +284,7 @@ suite "RLN Proofs as a Lightpush Service": return lightpushSuccessResult(1) server.wakuLightPush.pushHandler = stub - let firstResponse = await server.lightpushPublish(some(pubsubTopic), message) + let firstResponse = await server.lightpushPublish(Opt.some(pubsubTopic), message) check: firstResponse.isErr() @@ -288,7 +292,7 @@ suite "RLN Proofs as a Lightpush Service": # Model the caller-level retry (send service next round, REST handler): # a second publish regenerates the proof against the refreshed cache. - let secondResponse = await server.lightpushPublish(some(pubsubTopic), message) + let secondResponse = await server.lightpushPublish(Opt.some(pubsubTopic), message) check: callCount == 2 @@ -305,7 +309,7 @@ suite "RLN Proofs as a Lightpush Service": lighpushErrorResult(LightPushErrorCode.INVALID_MESSAGE, "unrelated rejection") server.wakuLightPush.pushHandler = stub - let response = await server.lightpushPublish(some(pubsubTopic), message) + let response = await server.lightpushPublish(Opt.some(pubsubTopic), message) check: callCount == 1 @@ -323,7 +327,7 @@ suite "RLN Proofs as a Lightpush Service": ) server.wakuLightPush.pushHandler = stub - let response = await server.lightpushPublish(some(pubsubTopic), message) + let response = await server.lightpushPublish(Opt.some(pubsubTopic), message) check: callCount == 1 @@ -347,7 +351,7 @@ suite "RLN Proofs as a Lightpush Service": ) server.wakuLightPush.pushHandler = stub - let response = await server.lightpushPublish(some(pubsubTopic), message) + let response = await server.lightpushPublish(Opt.some(pubsubTopic), message) server.rln = savedRln @@ -402,7 +406,7 @@ suite "Waku Lightpush message delivery": await sleepAsync(100.millis) ## When - let res = await lightNode.lightpushPublish(some(CustomPubsubTopic), message) + let res = await lightNode.lightpushPublish(Opt.some(CustomPubsubTopic), message) assert res.isOk(), $res.error assert res.get() == 1, "Expected to relay the message to 1 node" diff --git a/tests/node/test_wakunode_peer_exchange.nim b/tests/node/test_wakunode_peer_exchange.nim index e70abadc9..d9857346a 100644 --- a/tests/node/test_wakunode_peer_exchange.nim +++ b/tests/node/test_wakunode_peer_exchange.nim @@ -1,7 +1,8 @@ {.used.} import - std/[options, sequtils], + results, + std/sequtils, testutils/unittests, chronos, chronicles, @@ -81,7 +82,7 @@ suite "Waku Peer Exchange": check: node.peerManager.switch.peerStore.peers.len == 0 res.error.status_code == SERVICE_UNAVAILABLE - res.error.status_desc == some("PeerExchangeClient is not mounted") + res.error.status_desc == Opt.some("PeerExchangeClient is not mounted") asyncTest "Node fetches with mounted peer exchange, but no peers": # Given a node with peer exchange mounted @@ -91,7 +92,7 @@ suite "Waku Peer Exchange": let res = await node.fetchPeerExchangePeers(1) check: res.error.status_code == SERVICE_UNAVAILABLE - res.error.status_desc == some("peer_not_found_failure") + res.error.status_desc == Opt.some("peer_not_found_failure") # Then no peers are fetched check node.peerManager.switch.peerStore.peers.len == 0 @@ -103,7 +104,7 @@ suite "Waku Peer Exchange": # Simulate node2 discovering node3 via Discv5 var rpInfo = node3.peerInfo.toRemotePeerInfo() - rpInfo.enr = some(node3.enr) + rpInfo.enr = Opt.some(node3.enr) node2.peerManager.addPeer(rpInfo, PeerOrigin.Discv5) # Set node2 as service peer (default one) for px protocol @@ -189,13 +190,13 @@ suite "Waku Peer Exchange with discv5": bindIp = parseIpAddress("0.0.0.0") nodeKey1 = generateSecp256k1Key() - node1 = newTestWakuNode(nodeKey1, bindIp, Port(0), wakuFlags = some(flags)) + node1 = newTestWakuNode(nodeKey1, bindIp, Port(0), wakuFlags = Opt.some(flags)) nodeKey2 = generateSecp256k1Key() - node2 = newTestWakuNode(nodeKey2, bindIp, Port(0), wakuFlags = some(flags)) + node2 = newTestWakuNode(nodeKey2, bindIp, Port(0), wakuFlags = Opt.some(flags)) nodeKey3 = generateSecp256k1Key() - node3 = newTestWakuNode(nodeKey3, bindIp, Port(0), wakuFlags = some(flags)) + node3 = newTestWakuNode(nodeKey3, bindIp, Port(0), wakuFlags = Opt.some(flags)) await allFutures(node1.start(), node2.start(), node3.start()) diff --git a/tests/node/test_wakunode_peer_manager.nim b/tests/node/test_wakunode_peer_manager.nim index 73ccfe2b9..92032cd41 100644 --- a/tests/node/test_wakunode_peer_manager.nim +++ b/tests/node/test_wakunode_peer_manager.nim @@ -1,8 +1,9 @@ {.used.} import + results, os, - std/[options, tables], + std/tables, testutils/unittests, chronos, # chronos/timer, @@ -211,7 +212,7 @@ suite "Peer Manager": clientPeerStore.setCapacity(0) # And the server's remote peer info contains the node's ENR - serverRemotePeerInfo.enr = some(server.enr) + serverRemotePeerInfo.enr = Opt.some(server.enr) # And the client connects to the server await client.connectToNodes(@[serverRemotePeerInfo]) @@ -360,7 +361,7 @@ suite "Peer Manager": suite "Tracked Peer Metadata": asyncTest "Metadata Recording": # When adding a peer other than self to the peer store - serverRemotePeerInfo.enr = some(server.enr) + serverRemotePeerInfo.enr = Opt.some(server.enr) client.peerManager.addPeer(serverRemotePeerInfo) # Then the peer store should contain the peer @@ -661,7 +662,7 @@ suite "Handling Connections on Different Networks": bindIp: string = "0.0.0.0", extIp: string = "127.0.0.1", indices: seq[uint64] = @[], - recordFlags: Option[CapabilitiesBitfield] = none(CapabilitiesBitfield), + recordFlags: Opt[CapabilitiesBitfield] = Opt.none(CapabilitiesBitfield), bootstrapRecords: seq[waku_enr.Record] = @[], ): (WakuDiscoveryV5, Record) = let @@ -718,7 +719,7 @@ suite "Persistence Check": # Given an on-disk peer db exists, with a peer in it; and two connected nodes let - clientPeerStorage = newTestWakuPeerStorage(some(baseDbPath)) + clientPeerStorage = newTestWakuPeerStorage(Opt.some(baseDbPath)) serverKey = generateSecp256k1Key() clientKey = generateSecp256k1Key() server = newTestWakuNode(serverKey, listenIp, listenPort) @@ -738,7 +739,7 @@ suite "Persistence Check": # When initializing a new client using the prepopulated on-disk storage let - newClientPeerStorage = newTestWakuPeerStorage(some(baseDbPath)) + newClientPeerStorage = newTestWakuPeerStorage(Opt.some(baseDbPath)) newClient = newTestWakuNode( clientKey, listenIp, listenPort, peerStorage = newClientPeerStorage ) @@ -760,7 +761,7 @@ suite "Persistence Check": # When creating a new server with memory storage, and a client with on-disk peer storage let - clientPeerStorage = newTestWakuPeerStorage(some(baseDbPath)) + clientPeerStorage = newTestWakuPeerStorage(Opt.some(baseDbPath)) serverKey = generateSecp256k1Key() clientKey = generateSecp256k1Key() server = newTestWakuNode(serverKey, listenIp, listenPort) diff --git a/tests/node/test_wakunode_relay_rln.nim b/tests/node/test_wakunode_relay_rln.nim index 76074bb6d..93b8e7429 100644 --- a/tests/node/test_wakunode_relay_rln.nim +++ b/tests/node/test_wakunode_relay_rln.nim @@ -1,7 +1,7 @@ {.used.} import - std/[tempfiles, strutils, options], + std/[tempfiles, strutils], results, testutils/unittests, chronos, @@ -75,18 +75,18 @@ proc getWakuRlnConfigOnChain*( rlnRelayEthContractAddress: string, password: string, credIndex: uint, - fatalErrorHandler: Option[OnFatalErrorHandler] = none(OnFatalErrorHandler), - ethClientAddress: Option[string] = none(string), + fatalErrorHandler: Opt[OnFatalErrorHandler] = Opt.none(OnFatalErrorHandler), + ethClientAddress: Opt[string] = Opt.none(string), ): WakuRlnConfig = return WakuRlnConfig( dynamic: true, - credIndex: some(credIndex), + credIndex: Opt.some(credIndex), ethContractAddress: rlnRelayEthContractAddress, ethClientAddress: ethClientAddress.get(EthClient), epochSizeSec: 1, onFatalErrorAction: fatalErrorHandler.get(fatalErrorVoidHandler), # If these are used, initialisation fails with "failed to mount Rln: could not initialize the group manager: the commitment does not have a membership" - creds: some(RlnCreds(path: keystorePath, password: password)), + creds: Opt.some(RlnCreds(path: keystorePath, password: password)), ) proc setupRelayWithOnChainRln*( @@ -205,7 +205,7 @@ suite "Waku RlnRelay - End to End - Static": let contractAddress = await uploadRLNContract(EthClient) let wakuRlnConfig = WakuRlnConfig( dynamic: true, - credIndex: some(0.uint), + credIndex: Opt.some(0.uint), userMessageLimit: 111, ethClientAddress: EthClient, ethContractAddress: $contractAddress, @@ -239,7 +239,7 @@ suite "Waku RlnRelay - End to End - Static": completionFut.complete((topic, msg)) let subscriptionEvent = (kind: PubsubSub, topic: pubsubTopic) - server.subscribe(subscriptionEvent, some(relayHandler)).isOkOr: + server.subscribe(subscriptionEvent, Opt.some(relayHandler)).isOkOr: assert false, "Failed to subscribe to pubsub topic" await sleepAsync(FUTURE_TIMEOUT) @@ -287,14 +287,14 @@ suite "Waku RlnRelay - End to End - Static": raiseAssert "generateRLNProof failed: " & error # When sending the 1B message - discard await client.publish(some(pubsubTopic), message1b) + discard await client.publish(Opt.some(pubsubTopic), message1b) discard await completionFut.withTimeout(FUTURE_TIMEOUT_LONG) # Then the message is relayed check completionFut.read() == (pubsubTopic, message1b) # When sending the 1KiB message completionFut = newPushHandlerFuture() # Reset Future - discard await client.publish(some(pubsubTopic), message1kib) + discard await client.publish(Opt.some(pubsubTopic), message1kib) discard await completionFut.withTimeout(FUTURE_TIMEOUT_LONG) # Then the message is relayed @@ -302,7 +302,7 @@ suite "Waku RlnRelay - End to End - Static": # When sending the 150KiB message completionFut = newPushHandlerFuture() # Reset Future - discard await client.publish(some(pubsubTopic), message150kib) + discard await client.publish(Opt.some(pubsubTopic), message150kib) discard await completionFut.withTimeout(FUTURE_TIMEOUT_LONG) # Then the message is relayed @@ -310,7 +310,7 @@ suite "Waku RlnRelay - End to End - Static": # When sending the 150KiB plus message completionFut = newPushHandlerFuture() # Reset Future - discard await client.publish(some(pubsubTopic), message151kibPlus) + discard await client.publish(Opt.some(pubsubTopic), message151kibPlus) # Then the message is not relayed check not await completionFut.withTimeout(FUTURE_TIMEOUT_LONG) @@ -332,7 +332,7 @@ suite "Waku RlnRelay - End to End - Static": completionFut.complete((topic, msg)) let subscriptionEvent = (kind: PubsubSub, topic: pubsubTopic) - server.subscribe(subscriptionEvent, some(relayHandler)).isOkOr: + server.subscribe(subscriptionEvent, Opt.some(relayHandler)).isOkOr: assert false, "Failed to subscribe to pubsub topic" await sleepAsync(FUTURE_TIMEOUT) @@ -356,7 +356,7 @@ suite "Waku RlnRelay - End to End - Static": # When sending the 150KiB plus message completionFut = newPushHandlerFuture() # Reset Future - discard await client.publish(some(pubsubTopic), message151kibPlus) + discard await client.publish(Opt.some(pubsubTopic), message151kibPlus) # Then the message is not relayed check not await completionFut.withTimeout(FUTURE_TIMEOUT_LONG) @@ -456,7 +456,7 @@ suite "Waku RlnRelay - End to End - OnChain": invalidContractAddress, password, 0, - some(serverFatalErrorHandler), + Opt.some(serverFatalErrorHandler), ) wakuRlnConfig2 = getWakuRlnConfigOnChain( keystorePath, @@ -464,7 +464,7 @@ suite "Waku RlnRelay - End to End - OnChain": invalidContractAddress, password, 1, - some(clientFatalErrorHandler), + Opt.some(clientFatalErrorHandler), ) # Given the node enable Relay and Rln while subscribing to a pubsub topic. @@ -562,8 +562,8 @@ suite "Waku RlnRelay - End to End - OnChain": raiseAssert $error # Test Hack: Monkeypatch the idCredentials into the groupManager - server.rln.groupManager.idCredentials = some(idCredential1) - client.rln.groupManager.idCredentials = some(idCredential2) + server.rln.groupManager.idCredentials = Opt.some(idCredential1) + client.rln.groupManager.idCredentials = Opt.some(idCredential2) except Exception, CatchableError: assert false, "exception raised: " & getCurrentExceptionMsg() diff --git a/tests/node/test_wakunode_restart.nim b/tests/node/test_wakunode_restart.nim index 8d05ce131..f1ed60306 100644 --- a/tests/node/test_wakunode_restart.nim +++ b/tests/node/test_wakunode_restart.nim @@ -1,6 +1,5 @@ {.used.} -import std/options import testutils/unittests, chronos, chronicles import libp2p/switch diff --git a/tests/node/test_wakunode_sharding.nim b/tests/node/test_wakunode_sharding.nim index d1b19c361..25227efa0 100644 --- a/tests/node/test_wakunode_sharding.nim +++ b/tests/node/test_wakunode_sharding.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, sequtils, tempfiles], testutils/unittests, chronos, chronicles +import results, std/[sequtils, tempfiles], testutils/unittests, chronos, chronicles import std/[sequtils, tempfiles], @@ -62,7 +62,7 @@ suite "Sharding": # When the client publishes a message in the subscribed topic discard await client.publish( - some(topic), + Opt.some(topic), WakuMessage(payload: "message1".toBytes(), contentTopic: "contentTopic"), ) @@ -78,7 +78,7 @@ suite "Sharding": serverHandler.reset() clientHandler.reset() discard await server.publish( - some(topic), + Opt.some(topic), WakuMessage(payload: "message2".toBytes(), contentTopic: "contentTopic"), ) @@ -107,7 +107,7 @@ suite "Sharding": # When a message is published in the server's subscribed topic discard await client.publish( - some(topic1), + Opt.some(topic1), WakuMessage(payload: "message1".toBytes(), contentTopic: contentTopic), ) let @@ -123,7 +123,7 @@ suite "Sharding": clientHandler.reset() let wakuMessage2 = WakuMessage(payload: "message2".toBytes(), contentTopic: contentTopic) - discard await server.publish(some(topic2), wakuMessage2) + discard await server.publish(Opt.some(topic2), wakuMessage2) let serverResult2 = await serverHandler.waitForResult(FUTURE_TIMEOUT) clientResult2 = await clientHandler.waitForResult(FUTURE_TIMEOUT) @@ -149,7 +149,7 @@ suite "Sharding": # When the client publishes a message discard await client.publish( - some(pubsubTopic), + Opt.some(pubsubTopic), WakuMessage(payload: "message1".toBytes(), contentTopic: contentTopicShort), ) let @@ -164,7 +164,7 @@ suite "Sharding": serverHandler.reset() clientHandler.reset() discard await server.publish( - some(pubsubTopic), + Opt.some(pubsubTopic), WakuMessage(payload: "message2".toBytes(), contentTopic: contentTopicFull), ) let @@ -194,7 +194,7 @@ suite "Sharding": # When the server publishes a message in the server's subscribed topic discard await server.publish( - some(shard1), + Opt.some(shard1), WakuMessage(payload: "message1".toBytes(), contentTopic: contentTopic1), ) let @@ -209,7 +209,7 @@ suite "Sharding": serverHandler.reset() clientHandler.reset() discard await client.publish( - some(shard2), + Opt.some(shard2), WakuMessage(payload: "message2".toBytes(), contentTopic: contentTopic2), ) let @@ -234,7 +234,7 @@ suite "Sharding": # When the client publishes a message discard await client.publish( - some(pubsubTopic), + Opt.some(pubsubTopic), WakuMessage(payload: "message1".toBytes(), contentTopic: "myContentTopic"), ) let @@ -261,7 +261,7 @@ suite "Sharding": pubsubTopic = "/waku/2/rs/0/1" contentTopic = "myContentTopic" subscribeResponse = await client.filterSubscribe( - some(pubsubTopic), + Opt.some(pubsubTopic), @[contentTopic], server.switch.peerInfo.toRemotePeerInfo(), ) @@ -293,7 +293,7 @@ suite "Sharding": msg = WakuMessage(payload: "message".toBytes(), contentTopic: "myContentTopic") lightpublishRespnse = await client.legacyLightpushPublish( - some(topic), msg, server.switch.peerInfo.toRemotePeerInfo() + Opt.some(topic), msg, server.switch.peerInfo.toRemotePeerInfo() ) # Then the client receives the message @@ -315,7 +315,7 @@ suite "Sharding": # When the client publishes a message discard await client.publish( - some(pubsubTopic), + Opt.some(pubsubTopic), WakuMessage(payload: "message1".toBytes(), contentTopic: contentTopicShort), ) let @@ -330,7 +330,7 @@ suite "Sharding": serverHandler.reset() clientHandler.reset() discard await server.publish( - some(pubsubTopic), + Opt.some(pubsubTopic), WakuMessage(payload: "message2".toBytes(), contentTopic: contentTopicFull), ) let @@ -358,7 +358,7 @@ suite "Sharding": contentTopicFull = "/0/toychat/2/huilong/proto" pubsubTopic = "/waku/2/rs/0/58355" subscribeResponse1 = await client.filterSubscribe( - some(pubsubTopic), + Opt.some(pubsubTopic), @[contentTopicShort], server.switch.peerInfo.toRemotePeerInfo(), ) @@ -381,7 +381,7 @@ suite "Sharding": unsubscribeResponse = await client.filterUnsubscribeAll(server.switch.peerInfo.toRemotePeerInfo()) subscribeResponse2 = await client.filterSubscribe( - some(pubsubTopic), + Opt.some(pubsubTopic), @[contentTopicFull], server.switch.peerInfo.toRemotePeerInfo(), ) @@ -418,7 +418,7 @@ suite "Sharding": msg = WakuMessage(payload: "message".toBytes(), contentTopic: contentTopicFull) lightpublishRespnse = await client.legacyLightpushPublish( - some(pubsubTopic), msg, server.switch.peerInfo.toRemotePeerInfo() + Opt.some(pubsubTopic), msg, server.switch.peerInfo.toRemotePeerInfo() ) # Then the client receives the message @@ -455,13 +455,13 @@ suite "Sharding": storeQuery1 = StoreQueryRequest( contentTopics: @[contentTopicShort], paginationForward: PagingDirection.Forward, - paginationLimit: some(3'u64), + paginationLimit: Opt.some(3'u64), includeData: true, ) storeQuery2 = StoreQueryRequest( contentTopics: @[contentTopicFull], paginationForward: PagingDirection.Forward, - paginationLimit: some(3'u64), + paginationLimit: Opt.some(3'u64), includeData: true, ) @@ -497,7 +497,7 @@ suite "Sharding": # When the client publishes a message in the client's subscribed topic discard await client.publish( - some(pubsubTopic2), + Opt.some(pubsubTopic2), WakuMessage(payload: "message1".toBytes(), contentTopic: contentTopic2), ) let @@ -512,7 +512,7 @@ suite "Sharding": serverHandler.reset() clientHandler.reset() discard await server.publish( - some(pubsubTopic1), + Opt.some(pubsubTopic1), WakuMessage(payload: "message2".toBytes(), contentTopic: contentTopic1), ) let @@ -543,7 +543,7 @@ suite "Sharding": pubsubTopic2 = "/waku/2/rs/0/23286" # Automatically generated from the contentTopic above subscribeResponse1 = await client.filterSubscribe( - some(pubsubTopic1), + Opt.some(pubsubTopic1), @[contentTopic1], server.switch.peerInfo.toRemotePeerInfo(), ) @@ -580,7 +580,7 @@ suite "Sharding": let msg = WakuMessage(payload: "message".toBytes(), contentTopic: contentTopic2) lightpublishRespnse = await client.legacyLightpushPublish( - some(pubsubTopic2), msg, server.switch.peerInfo.toRemotePeerInfo() + Opt.some(pubsubTopic2), msg, server.switch.peerInfo.toRemotePeerInfo() ) # Then the client does not receive the message @@ -620,13 +620,13 @@ suite "Sharding": storeQuery1 = StoreQueryRequest( contentTopics: @[contentTopic1], paginationForward: PagingDirection.Forward, - paginationLimit: some(2'u64), + paginationLimit: Opt.some(2'u64), includeData: true, ) storeQuery2 = StoreQueryRequest( contentTopics: @[contentTopic2], paginationForward: PagingDirection.Forward, - paginationLimit: some(2'u64), + paginationLimit: Opt.some(2'u64), includeData: true, ) @@ -659,7 +659,7 @@ suite "Sharding": # When the client publishes a message in the topic1 discard await client.publish( - some(topic1), + Opt.some(topic1), WakuMessage(payload: "message1".toBytes(), contentTopic: contentTopic), ) @@ -676,7 +676,7 @@ suite "Sharding": clientHandler1.reset() clientHandler2.reset() discard await client.publish( - some(topic2), + Opt.some(topic2), WakuMessage(payload: "message2".toBytes(), contentTopic: contentTopic), ) @@ -705,7 +705,7 @@ suite "Sharding": # When the client publishes a message in contentTopic1 discard await client.publish( - some(pubsubTopic1), + Opt.some(pubsubTopic1), WakuMessage(payload: "message1".toBytes(), contentTopic: contentTopic1), ) @@ -722,7 +722,7 @@ suite "Sharding": clientHandler1.reset() clientHandler2.reset() discard await client.publish( - some(pubsubTopic2), + Opt.some(pubsubTopic2), WakuMessage(payload: "message2".toBytes(), contentTopic: contentTopic2), ) @@ -758,7 +758,7 @@ suite "Sharding": # When the client publishes a message in the topic1 discard await client.publish( - some(pubsubTopic1), + Opt.some(pubsubTopic1), WakuMessage(payload: "message1".toBytes(), contentTopic: contentTopic), ) @@ -783,7 +783,7 @@ suite "Sharding": serverHandler4.reset() clientHandler4.reset() discard await client.publish( - some(pubsubTopic2), + Opt.some(pubsubTopic2), WakuMessage(payload: "message2".toBytes(), contentTopic: contentTopic), ) @@ -808,7 +808,7 @@ suite "Sharding": serverHandler4.reset() clientHandler4.reset() discard await client.publish( - some(pubsubTopic3), + Opt.some(pubsubTopic3), WakuMessage(payload: "message1".toBytes(), contentTopic: contentTopic3), ) @@ -833,7 +833,7 @@ suite "Sharding": serverHandler4.reset() clientHandler4.reset() discard await client.publish( - some(pubsubTopic4), + Opt.some(pubsubTopic4), WakuMessage(payload: "message2".toBytes(), contentTopic: contentTopic4), ) @@ -862,7 +862,7 @@ suite "Sharding": # When the client publishes a message in the topic discard await client.publish( - some(topic), + Opt.some(topic), WakuMessage(payload: "message1".toBytes(), contentTopic: contentTopic), ) @@ -894,7 +894,7 @@ suite "Sharding": let msg1 = WakuMessage(payload: "message1".toBytes(), contentTopic: contentTopic) lightpublishRespnse = await client.legacyLightpushPublish( - some(topic1), msg1, server.switch.peerInfo.toRemotePeerInfo() + Opt.some(topic1), msg1, server.switch.peerInfo.toRemotePeerInfo() ) # Then the server and client receive the message in topic1's handlers, but not in topic2's @@ -912,7 +912,7 @@ suite "Sharding": let msg2 = WakuMessage(payload: "message2".toBytes(), contentTopic: contentTopic) lightpublishResponse2 = await client.legacyLightpushPublish( - some(topic2), msg2, server.switch.peerInfo.toRemotePeerInfo() + Opt.some(topic2), msg2, server.switch.peerInfo.toRemotePeerInfo() ) # Then the server and client receive the message in topic2's handlers, but not in topic1's @@ -953,10 +953,10 @@ suite "Sharding": let subscribeResponse1 = await client.filterSubscribe( - some(topic1), @[contentTopic], server.switch.peerInfo.toRemotePeerInfo() + Opt.some(topic1), @[contentTopic], server.switch.peerInfo.toRemotePeerInfo() ) subscribeResponse2 = await client.filterSubscribe( - some(topic2), @[contentTopic], server.switch.peerInfo.toRemotePeerInfo() + Opt.some(topic2), @[contentTopic], server.switch.peerInfo.toRemotePeerInfo() ) assertResultOk(subscribeResponse1) @@ -1008,15 +1008,15 @@ suite "Sharding": # Given one query for each pubsub topic let storeQuery1 = StoreQueryRequest( - pubsubTopic: some(topic1), + pubsubTopic: Opt.some(topic1), paginationForward: PagingDirection.Forward, - paginationLimit: some(2'u64), + paginationLimit: Opt.some(2'u64), includeData: true, ) storeQuery2 = StoreQueryRequest( - pubsubTopic: some(topic2), + pubsubTopic: Opt.some(topic2), paginationForward: PagingDirection.Forward, - paginationLimit: some(2'u64), + paginationLimit: Opt.some(2'u64), includeData: true, ) diff --git a/tests/node/test_wakunode_store.nim b/tests/node/test_wakunode_store.nim index b0dc3fc28..f16a36e9d 100644 --- a/tests/node/test_wakunode_store.nim +++ b/tests/node/test_wakunode_store.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, sequtils, sets], testutils/unittests, chronos, libp2p/crypto/crypto +import results, std/[sequtils, sets], testutils/unittests, chronos, libp2p/crypto/crypto import logos_delivery/waku/[ @@ -52,17 +52,17 @@ suite "Waku Store - End to End - Sorted Archive": archiveMessages = messages.mapIt( WakuMessageKeyValue( messageHash: computeMessageHash(pubsubTopic, it), - message: some(it), - pubsubTopic: some(pubsubTopic), + message: Opt.some(it), + pubsubTopic: Opt.some(pubsubTopic), ) ) storeQuery = StoreQueryRequest( includeData: true, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.Forward, - paginationLimit: some(uint64(5)), + paginationLimit: Opt.some(uint64(5)), ) let @@ -99,11 +99,11 @@ suite "Waku Store - End to End - Sorted Archive": # Given the next query var otherHistoryQuery = StoreQueryRequest( includeData: true, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationCursor: queryResponse.get().paginationCursor, paginationForward: PagingDirection.FORWARD, - paginationLimit: some(uint64(5)), + paginationLimit: Opt.some(uint64(5)), ) # When making the next history query @@ -129,10 +129,10 @@ suite "Waku Store - End to End - Sorted Archive": var nextHistoryQuery = StoreQueryRequest( includeData: true, paginationCursor: queryResponse.get().paginationCursor, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.BACKWARD, - paginationLimit: some(uint64(5)), + paginationLimit: Opt.some(uint64(5)), ) # When making the next history query @@ -146,7 +146,7 @@ suite "Waku Store - End to End - Sorted Archive": suite "Pagination with Differente Page Sizes": asyncTest "Pagination with Small Page Size": # Given the first query (1/5) - storeQuery.paginationLimit = some(uint64(2)) + storeQuery.paginationLimit = Opt.some(uint64(2)) # When making a history query let queryResponse1 = await client.query(storeQuery, serverRemotePeerInfo) @@ -159,10 +159,10 @@ suite "Waku Store - End to End - Sorted Archive": let historyQuery2 = StoreQueryRequest( includeData: true, paginationCursor: queryResponse1.get().paginationCursor, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.FORWARD, - paginationLimit: some(uint64(2)), + paginationLimit: Opt.some(uint64(2)), ) # When making the next history query @@ -176,10 +176,10 @@ suite "Waku Store - End to End - Sorted Archive": let historyQuery3 = StoreQueryRequest( includeData: true, paginationCursor: queryResponse2.get().paginationCursor, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.FORWARD, - paginationLimit: some(uint64(2)), + paginationLimit: Opt.some(uint64(2)), ) # When making the next history query @@ -193,10 +193,10 @@ suite "Waku Store - End to End - Sorted Archive": let historyQuery4 = StoreQueryRequest( includeData: true, paginationCursor: queryResponse3.get().paginationCursor, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.FORWARD, - paginationLimit: some(uint64(2)), + paginationLimit: Opt.some(uint64(2)), ) # When making the next history query @@ -210,10 +210,10 @@ suite "Waku Store - End to End - Sorted Archive": let historyQuery5 = StoreQueryRequest( includeData: true, paginationCursor: queryResponse4.get().paginationCursor, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.FORWARD, - paginationLimit: some(uint64(2)), + paginationLimit: Opt.some(uint64(2)), ) # When making the next history query @@ -225,7 +225,7 @@ suite "Waku Store - End to End - Sorted Archive": asyncTest "Pagination with Large Page Size": # Given the first query (1/2) - storeQuery.paginationLimit = some(uint64(8)) + storeQuery.paginationLimit = Opt.some(uint64(8)) # When making a history query let queryResponse1 = await client.query(storeQuery, serverRemotePeerInfo) @@ -238,10 +238,10 @@ suite "Waku Store - End to End - Sorted Archive": let historyQuery2 = StoreQueryRequest( includeData: true, paginationCursor: queryResponse1.get().paginationCursor, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.FORWARD, - paginationLimit: some(uint64(8)), + paginationLimit: Opt.some(uint64(8)), ) # When making the next history query @@ -253,7 +253,7 @@ suite "Waku Store - End to End - Sorted Archive": asyncTest "Pagination with Excessive Page Size": # Given the first query (1/1) - storeQuery.paginationLimit = some(uint64(100)) + storeQuery.paginationLimit = Opt.some(uint64(100)) # When making a history query let queryResponse1 = await client.query(storeQuery, serverRemotePeerInfo) @@ -264,7 +264,7 @@ suite "Waku Store - End to End - Sorted Archive": asyncTest "Pagination with Mixed Page Size": # Given the first query (1/3) - storeQuery.paginationLimit = some(uint64(2)) + storeQuery.paginationLimit = Opt.some(uint64(2)) # When making a history query let queryResponse1 = await client.query(storeQuery, serverRemotePeerInfo) @@ -277,10 +277,10 @@ suite "Waku Store - End to End - Sorted Archive": let historyQuery2 = StoreQueryRequest( includeData: true, paginationCursor: queryResponse1.get().paginationCursor, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.FORWARD, - paginationLimit: some(uint64(4)), + paginationLimit: Opt.some(uint64(4)), ) # When making the next history query @@ -294,10 +294,10 @@ suite "Waku Store - End to End - Sorted Archive": let historyQuery3 = StoreQueryRequest( includeData: true, paginationCursor: queryResponse2.get().paginationCursor, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.FORWARD, - paginationLimit: some(uint64(6)), + paginationLimit: Opt.some(uint64(6)), ) # When making the next history query @@ -331,13 +331,13 @@ suite "Waku Store - End to End - Sorted Archive": extraMessages.mapIt( WakuMessageKeyValue( messageHash: computeMessageHash(pubsubTopic, it), - message: some(it), - pubsubTopic: some(pubsubTopic), + message: Opt.some(it), + pubsubTopic: Opt.some(pubsubTopic), ) ) # Given the a query with zero page size (1/2) - storeQuery.paginationLimit = none(uint64) + storeQuery.paginationLimit = Opt.none(uint64) # When making a history query let queryResponse1 = await client.query(storeQuery, serverRemotePeerInfo) @@ -350,10 +350,10 @@ suite "Waku Store - End to End - Sorted Archive": let historyQuery2 = StoreQueryRequest( includeData: true, paginationCursor: queryResponse1.get().paginationCursor, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.FORWARD, - paginationLimit: none(uint64), + paginationLimit: Opt.none(uint64), ) # When making the next history query @@ -388,15 +388,15 @@ suite "Waku Store - End to End - Sorted Archive": extraMessages.mapIt( WakuMessageKeyValue( messageHash: computeMessageHash(pubsubTopic, it), - message: some(it), - pubsubTopic: some(pubsubTopic), + message: Opt.some(it), + pubsubTopic: Opt.some(pubsubTopic), ) ) # Given a query with default page size (1/2) storeQuery = StoreQueryRequest( includeData: true, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.FORWARD, ) @@ -412,7 +412,7 @@ suite "Waku Store - End to End - Sorted Archive": let historyQuery2 = StoreQueryRequest( includeData: true, paginationCursor: queryResponse.get().paginationCursor, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.FORWARD, ) @@ -429,8 +429,8 @@ suite "Waku Store - End to End - Sorted Archive": asyncTest "Starting Cursor": # Given a paginationCursor pointing to the first message let paginationCursor = archiveMessages[0].messageHash - storeQuery.paginationCursor = some(paginationCursor) - storeQuery.paginationLimit = some(uint64(1)) + storeQuery.paginationCursor = Opt.some(paginationCursor) + storeQuery.paginationLimit = Opt.some(uint64(1)) # When making a history query let queryResponse = await client.query(storeQuery, serverRemotePeerInfo) @@ -442,8 +442,8 @@ suite "Waku Store - End to End - Sorted Archive": asyncTest "Middle Cursor": # Given a paginationCursor pointing to the middle message1 let paginationCursor = archiveMessages[5].messageHash - storeQuery.paginationCursor = some(paginationCursor) - storeQuery.paginationLimit = some(uint64(1)) + storeQuery.paginationCursor = Opt.some(paginationCursor) + storeQuery.paginationLimit = Opt.some(uint64(1)) # When making a history query let queryResponse = await client.query(storeQuery, serverRemotePeerInfo) @@ -455,8 +455,8 @@ suite "Waku Store - End to End - Sorted Archive": asyncTest "Ending Cursor": # Given a paginationCursor pointing to the last message let paginationCursor = archiveMessages[9].messageHash - storeQuery.paginationCursor = some(paginationCursor) - storeQuery.paginationLimit = some(uint64(1)) + storeQuery.paginationCursor = Opt.some(paginationCursor) + storeQuery.paginationLimit = Opt.some(uint64(1)) # When making a history query let queryResponse = await client.query(storeQuery, serverRemotePeerInfo) @@ -497,10 +497,10 @@ suite "Waku Store - End to End - Sorted Archive": let otherHistoryQuery = StoreQueryRequest( includeData: true, paginationCursor: paginationCursor, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.FORWARD, - paginationLimit: some(uint64(5)), + paginationLimit: Opt.some(uint64(5)), ) let otherQueryResponse = await client.query(otherHistoryQuery, otherServerRemotePeerInfo) @@ -532,10 +532,10 @@ suite "Waku Store - End to End - Unsorted Archive": storeQuery = StoreQueryRequest( includeData: true, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.FORWARD, - paginationLimit: some(uint64(5)), + paginationLimit: Opt.some(uint64(5)), ) let timeOrigin = now() @@ -554,8 +554,8 @@ suite "Waku Store - End to End - Unsorted Archive": unsortedArchiveMessages = messages.mapIt( WakuMessageKeyValue( messageHash: computeMessageHash(pubsubTopic, it), - message: some(it), - pubsubTopic: some(pubsubTopic), + message: Opt.some(it), + pubsubTopic: Opt.some(pubsubTopic), ) ) @@ -617,10 +617,10 @@ suite "Waku Store - End to End - Unsorted Archive": var historyQuery2 = StoreQueryRequest( includeData: true, paginationCursor: queryResponse.get().paginationCursor, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.FORWARD, - paginationLimit: some(uint64(5)), + paginationLimit: Opt.some(uint64(5)), ) # When making the next history query @@ -660,7 +660,7 @@ suite "Waku Store - End to End - Unsorted Archive": cursor = unsortedArchiveMessages[5].messageHash storeQuery.paginationForward = PagingDirection.BACKWARD - storeQuery.paginationCursor = some(cursor) + storeQuery.paginationCursor = Opt.some(cursor) # When making a history query let queryResponse = await client.query(storeQuery, serverRemotePeerInfo) @@ -692,8 +692,8 @@ suite "Waku Store - End to End - Unsorted Archive": cursor = unsortedArchiveMessages[5].messageHash storeQuery.paginationForward = PagingDirection.FORWARD - storeQuery.paginationCursor = some(cursor) - storeQuery.paginationLimit = some(uint64(6)) + storeQuery.paginationCursor = Opt.some(cursor) + storeQuery.paginationLimit = Opt.some(uint64(6)) # When making a history query let queryResponse = await client.query(storeQuery, serverRemotePeerInfo) @@ -749,10 +749,10 @@ suite "Waku Store - End to End - Unsorted Archive without provided Timestamp": storeQuery = StoreQueryRequest( includeData: true, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.FORWARD, - paginationLimit: some(uint64(5)), + paginationLimit: Opt.some(uint64(5)), ) let messages = @[ @@ -771,8 +771,8 @@ suite "Waku Store - End to End - Unsorted Archive without provided Timestamp": unsortedArchiveMessages = messages.mapIt( WakuMessageKeyValue( messageHash: computeMessageHash(pubsubTopic, it), - message: some(it), - pubsubTopic: some(pubsubTopic), + message: Opt.some(it), + pubsubTopic: Opt.some(pubsubTopic), ) ) @@ -824,10 +824,10 @@ suite "Waku Store - End to End - Unsorted Archive without provided Timestamp": var historyQuery2 = StoreQueryRequest( includeData: true, paginationCursor: queryResponse.get().paginationCursor, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.FORWARD, - paginationLimit: some(uint64(5)), + paginationLimit: Opt.some(uint64(5)), ) # When making the next history query @@ -886,10 +886,10 @@ suite "Waku Store - End to End - Archive with Multiple Topics": storeQuery = StoreQueryRequest( includeData: true, - pubsubTopic: some(pubsubTopic), + pubsubTopic: Opt.some(pubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.FORWARD, - paginationLimit: some(uint64(5)), + paginationLimit: Opt.some(uint64(5)), ) let timeOrigin = now() @@ -914,8 +914,8 @@ suite "Waku Store - End to End - Archive with Multiple Topics": archiveMessages = messages.mapIt( WakuMessageKeyValue( messageHash: computeMessageHash(pubsubTopic, it), - message: some(it), - pubsubTopic: some(pubsubTopic), + message: Opt.some(it), + pubsubTopic: Opt.some(pubsubTopic), ) ) @@ -923,7 +923,7 @@ suite "Waku Store - End to End - Archive with Multiple Topics": archiveMessages[i].messagehash = computeMessageHash(pubsubTopicB, archiveMessages[i].message.get()) - archiveMessages[i].pubsubTopic = some(pubsubTopicB) + archiveMessages[i].pubsubTopic = Opt.some(pubsubTopicB) let serverKey = generateSecp256k1Key() @@ -993,10 +993,10 @@ suite "Waku Store - End to End - Archive with Multiple Topics": let historyQuery2 = StoreQueryRequest( includeData: true, paginationCursor: queryResponse.get().paginationCursor, - pubsubTopic: none(PubsubTopic), + pubsubTopic: Opt.none(PubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.FORWARD, - paginationLimit: some(uint64(5)), + paginationLimit: Opt.some(uint64(5)), ) # When making the next history query @@ -1019,7 +1019,7 @@ suite "Waku Store - End to End - Archive with Multiple Topics": asyncTest "Special Characters in Content Filtering": # Given a history query with special characters in content filtering - storeQuery.pubsubTopic = some(pubsubTopicB) + storeQuery.pubsubTopic = Opt.some(pubsubTopicB) storeQuery.contentTopics = @["!@#$%^&*()_+"] # When making a history query @@ -1031,7 +1031,7 @@ suite "Waku Store - End to End - Archive with Multiple Topics": asyncTest "PubsubTopic Specified": # Given a history query with pubsub topic specified - storeQuery.pubsubTopic = some(pubsubTopicB) + storeQuery.pubsubTopic = Opt.some(pubsubTopicB) # When making a history query let queryResponse = await client.query(storeQuery, serverRemotePeerInfo) @@ -1048,7 +1048,7 @@ suite "Waku Store - End to End - Archive with Multiple Topics": asyncTest "PubsubTopic Left Empty": # Given a history query with pubsub topic left empty - storeQuery.pubsubTopic = none(PubsubTopic) + storeQuery.pubsubTopic = Opt.none(PubsubTopic) # When making a history query let queryResponse = await client.query(storeQuery, serverRemotePeerInfo) @@ -1061,10 +1061,10 @@ suite "Waku Store - End to End - Archive with Multiple Topics": let historyQuery2 = StoreQueryRequest( includeData: true, paginationCursor: queryResponse.get().paginationCursor, - pubsubTopic: none(PubsubTopic), + pubsubTopic: Opt.none(PubsubTopic), contentTopics: contentTopicSeq, paginationForward: PagingDirection.FORWARD, - paginationLimit: some(uint64(5)), + paginationLimit: Opt.some(uint64(5)), ) # When making the next history query @@ -1077,8 +1077,8 @@ suite "Waku Store - End to End - Archive with Multiple Topics": suite "Validation of Time-based Filtering": asyncTest "Basic Time Filtering": # Given a history query with start and end time - storeQuery.startTime = some(originTs(20)) - storeQuery.endTime = some(originTs(40)) + storeQuery.startTime = Opt.some(originTs(20)) + storeQuery.endTime = Opt.some(originTs(40)) # When making a history query let queryResponse = await client.query(storeQuery, serverRemotePeerInfo) @@ -1090,8 +1090,8 @@ suite "Waku Store - End to End - Archive with Multiple Topics": asyncTest "Only Start Time Specified": # Given a history query with only start time - storeQuery.startTime = some(originTs(20)) - storeQuery.endTime = none(Timestamp) + storeQuery.startTime = Opt.some(originTs(20)) + storeQuery.endTime = Opt.none(Timestamp) # When making a history query let queryResponse = await client.query(storeQuery, serverRemotePeerInfo) @@ -1108,8 +1108,8 @@ suite "Waku Store - End to End - Archive with Multiple Topics": asyncTest "Only End Time Specified": # Given a history query with only end time - storeQuery.startTime = none(Timestamp) - storeQuery.endTime = some(originTs(40)) + storeQuery.startTime = Opt.none(Timestamp) + storeQuery.endTime = Opt.some(originTs(40)) # When making a history query let queryResponse = await client.query(storeQuery, serverRemotePeerInfo) @@ -1127,8 +1127,8 @@ suite "Waku Store - End to End - Archive with Multiple Topics": asyncTest "Invalid Time Range": # Given a history query with invalid time range - storeQuery.startTime = some(originTs(60)) - storeQuery.endTime = some(originTs(40)) + storeQuery.startTime = Opt.some(originTs(60)) + storeQuery.endTime = Opt.some(originTs(40)) # When making a history query let queryResponse = await client.query(storeQuery, serverRemotePeerInfo) @@ -1139,8 +1139,8 @@ suite "Waku Store - End to End - Archive with Multiple Topics": asyncTest "Time Filtering with Content Filtering": # Given a history query with time and content filtering - storeQuery.startTime = some(originTs(20)) - storeQuery.endTime = some(originTs(60)) + storeQuery.startTime = Opt.some(originTs(20)) + storeQuery.endTime = Opt.some(originTs(60)) storeQuery.contentTopics = @[contentTopicC] # When making a history query @@ -1152,8 +1152,8 @@ suite "Waku Store - End to End - Archive with Multiple Topics": asyncTest "Messages Outside of Time Range": # Given a history query with a valid time range which does not contain any messages - storeQuery.startTime = some(originTs(100)) - storeQuery.endTime = some(originTs(200)) + storeQuery.startTime = Opt.some(originTs(100)) + storeQuery.endTime = Opt.some(originTs(200)) # When making a history query let queryResponse = await client.query(storeQuery, serverRemotePeerInfo) @@ -1271,8 +1271,8 @@ suite "Waku Store - End to End - Archive with Multiple Topics": let voluminousArchiveMessages = messages.mapIt( WakuMessageKeyValue( messageHash: computeMessageHash(pubsubTopic, it), - message: some(it), - pubsubTopic: some(pubsubTopic), + message: Opt.some(it), + pubsubTopic: Opt.some(pubsubTopic), ) ) diff --git a/tests/node/utils.nim b/tests/node/utils.nim index e6addf9cf..22964921a 100644 --- a/tests/node/utils.nim +++ b/tests/node/utils.nim @@ -1,5 +1,5 @@ -import std/options, results import + results, logos_delivery/waku/ [node/peer_manager, node/waku_node, waku_enr/sharding, common/enr/typed_record], ../testlib/[wakucore] diff --git a/tests/persistency/test_backend.nim b/tests/persistency/test_backend.nim index d375bf3a4..9ca437466 100644 --- a/tests/persistency/test_backend.nim +++ b/tests/persistency/test_backend.nim @@ -1,8 +1,6 @@ {.used.} -import std/options -import results -import testutils/unittests +import results, testutils/unittests import logos_delivery/waku/persistency/[types, keys, backend_sqlite] template str(b: seq[byte]): string = diff --git a/tests/persistency/test_encoding.nim b/tests/persistency/test_encoding.nim index 4912bdcf1..291616d31 100644 --- a/tests/persistency/test_encoding.nim +++ b/tests/persistency/test_encoding.nim @@ -1,6 +1,6 @@ {.used.} -import std/[algorithm, options, os, times] +import std/[algorithm, os, times] import chronos, results import testutils/unittests import logos_delivery/waku/persistency/persistency @@ -142,7 +142,7 @@ suite "Persistency generic encoding": # Poll for the row, then read it back as raw bytes. let deadline = epochTime() + 1.0 - var got: Option[seq[byte]] + var got: Opt[seq[byte]] while epochTime() < deadline: let r = await job.get("msg", k) check r.isOk diff --git a/tests/persistency/test_facade.nim b/tests/persistency/test_facade.nim index a3af22d91..bf22a96ba 100644 --- a/tests/persistency/test_facade.nim +++ b/tests/persistency/test_facade.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, os, strutils, times] +import std/[os, strutils, times] import chronos, results import testutils/unittests import logos_delivery/waku/persistency/persistency diff --git a/tests/persistency/test_lifecycle.nim b/tests/persistency/test_lifecycle.nim index 3006672da..1abcdaccb 100644 --- a/tests/persistency/test_lifecycle.nim +++ b/tests/persistency/test_lifecycle.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, os, times] +import std/[os, times] import chronos, results import testutils/unittests import brokers/[event_broker, request_broker] diff --git a/tests/persistency/test_sds_persistency.nim b/tests/persistency/test_sds_persistency.nim index e5e0654d5..4a955310d 100644 --- a/tests/persistency/test_sds_persistency.nim +++ b/tests/persistency/test_sds_persistency.nim @@ -7,7 +7,7 @@ ## the op is queued, not applied — Persistency v1), so every read-back polls ## until the row appears/disappears. -import std/[options, os, times] +import std/[os, times] import chronos, results import testutils/unittests import logos_delivery/waku/persistency/persistency diff --git a/tests/persistency/test_string_lookup.nim b/tests/persistency/test_string_lookup.nim index 46bbce2b6..b8d1ff7b0 100644 --- a/tests/persistency/test_string_lookup.nim +++ b/tests/persistency/test_string_lookup.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, os, times] +import std/[os, times] import chronos, results import testutils/unittests import logos_delivery/waku/persistency/persistency diff --git a/tests/test_peer_manager.nim b/tests/test_peer_manager.nim index 1dc42d4ce..e2f5a5a26 100644 --- a/tests/test_peer_manager.nim +++ b/tests/test_peer_manager.nim @@ -1,7 +1,7 @@ {.used.} import - std/[sequtils, times, sugar, net, options], + std/[sequtils, times, sugar, net], results, testutils/unittests, chronos, @@ -379,7 +379,7 @@ procSuite "Peer Manager": let peerInfo2 = node2.switch.peerInfo var remotePeerInfo2 = peerInfo2.toRemotePeerInfo() - remotePeerInfo2.enr = some(node2.enr) + remotePeerInfo2.enr = Opt.some(node2.enr) let is12Connected = await node1.peerManager.connectPeer(remotePeerInfo2) assert is12Connected == true, "Node 1 and 2 not connected" @@ -462,7 +462,7 @@ procSuite "Peer Manager": let peerInfo2 = node2.switch.peerInfo var remotePeerInfo2 = peerInfo2.toRemotePeerInfo() - remotePeerInfo2.enr = some(node2.enr) + remotePeerInfo2.enr = Opt.some(node2.enr) let is12Connected = await node1.peerManager.connectPeer(remotePeerInfo2) assert is12Connected == true, "Node 1 and 2 not connected" @@ -636,7 +636,7 @@ procSuite "Peer Manager": let nodes = toSeq(0 ..< 4).mapIt( newTestWakuNode( nodeKey = generateSecp256k1Key(), - wakuFlags = some(CapabilitiesBitfield.init(@[Relay])), + wakuFlags = Opt.some(CapabilitiesBitfield.init(@[Relay])), ) ) @@ -649,7 +649,7 @@ procSuite "Peer Manager": let peerInfos = collect: for i in 0 .. nodes.high: let peerInfo = nodes[i].switch.peerInfo.toRemotePeerInfo() - peerInfo.enr = some(nodes[i].enr) + peerInfo.enr = Opt.some(nodes[i].enr) peerInfo # Add all peers (but self) to node 0 @@ -707,7 +707,7 @@ procSuite "Peer Manager": let nodes = toSeq(0 ..< 4).mapIt( newTestWakuNode( nodeKey = generateSecp256k1Key(), - wakuFlags = some(CapabilitiesBitfield.init(@[Relay])), + wakuFlags = Opt.some(CapabilitiesBitfield.init(@[Relay])), ) ) @@ -729,7 +729,7 @@ procSuite "Peer Manager": let peerInfos = collect: for i in 0 .. nodes.high: let peerInfo = nodes[i].switch.peerInfo.toRemotePeerInfo() - peerInfo.enr = some(nodes[i].enr) + peerInfo.enr = Opt.some(nodes[i].enr) peerInfo # Add all peers (but self) to node 0 @@ -1322,7 +1322,7 @@ procSuite "Peer Manager": let peerInfos = collect: for node in nodes: var peerInfo = node.switch.peerInfo.toRemotePeerInfo() - peerInfo.enr = some(node.enr) + peerInfo.enr = Opt.some(node.enr) peerInfo # Add all peers to node 0's peer manager and peerstore @@ -1334,7 +1334,7 @@ procSuite "Peer Manager": @[WakuRelayCodec] ## When: We select a peer for shard 0 - let shard0Topic = some(PubsubTopic("/waku/2/rs/0/0")) + let shard0Topic = Opt.some(PubsubTopic("/waku/2/rs/0/0")) let selectedPeer0 = nodes[0].peerManager.selectPeer(WakuRelayCodec, shard0Topic) ## Then: Only peers supporting shard 0 are considered (nodes 2, not node 1) @@ -1344,7 +1344,7 @@ procSuite "Peer Manager": selectedPeer0.get().peerId == peerInfos[2].peerId # node2 has shard 0 ## When: We select a peer for shard 1 - let shard1Topic = some(PubsubTopic("/waku/2/rs/0/1")) + let shard1Topic = Opt.some(PubsubTopic("/waku/2/rs/0/1")) let selectedPeer1 = nodes[0].peerManager.selectPeer(WakuRelayCodec, shard1Topic) ## Then: Only peer with shard 1 is selected @@ -1397,7 +1397,7 @@ procSuite "Peer Manager": pm.switch.peerStore.setShardInfo(peerInfo.peerId, peerInfo.shards) ## When: We select a peer for shard 0 - let shard0Topic = some(PubsubTopic("/waku/2/rs/0/0")) + let shard0Topic = Opt.some(PubsubTopic("/waku/2/rs/0/0")) let selectedPeer0 = pm.selectPeer(WakuRelayCodec, shard0Topic) ## Then: Peers with shard 0 in shards field are selected @@ -1406,7 +1406,7 @@ procSuite "Peer Manager": selectedPeer0.get().peerId in [peerInfos[0].peerId, peerInfos[2].peerId] ## When: We select a peer for shard 1 - let shard1Topic = some(PubsubTopic("/waku/2/rs/0/1")) + let shard1Topic = Opt.some(PubsubTopic("/waku/2/rs/0/1")) let selectedPeer1 = pm.selectPeer(WakuRelayCodec, shard1Topic) ## Then: Peer with shard 1 in shards field is selected @@ -1426,19 +1426,19 @@ procSuite "Peer Manager": discard await peer.mountRelay() var peerInfo = peer.switch.peerInfo.toRemotePeerInfo() - peerInfo.enr = some(peer.enr) + peerInfo.enr = Opt.some(peer.enr) node.peerManager.addPeer(peerInfo) node.peerManager.switch.peerStore[ProtoBook][peerInfo.peerId] = @[WakuRelayCodec] ## When: selectPeer is called with malformed pubsub topic let invalidTopics = @[ - some(PubsubTopic("invalid-topic")), - some(PubsubTopic("/waku/2/invalid")), - some(PubsubTopic("/waku/2/rs/abc/0")), # non-numeric cluster - some(PubsubTopic("")), # empty topic + Opt.some(PubsubTopic("invalid-topic")), + Opt.some(PubsubTopic("/waku/2/invalid")), + Opt.some(PubsubTopic("/waku/2/rs/abc/0")), # non-numeric cluster + Opt.some(PubsubTopic("")), # empty topic ] - ## Then: Returns none(RemotePeerInfo) without crashing + ## Then: Returns Opt.none(RemotePeerInfo) without crashing for invalidTopic in invalidTopics: let result = node.peerManager.selectPeer(WakuRelayCodec, invalidTopic) check: @@ -1468,7 +1468,7 @@ procSuite "Peer Manager": # Create peer info with ENR (shard 0) but set shards field to shard 1 var peerInfo = peer.switch.peerInfo.toRemotePeerInfo() - peerInfo.enr = some(peer.enr) # ENR has shard 0 + peerInfo.enr = Opt.some(peer.enr) # ENR has shard 0 peerInfo.shards = @[shardId1] # shards field has shard 1 node.peerManager.addPeer(peerInfo) @@ -1477,7 +1477,7 @@ procSuite "Peer Manager": node.peerManager.switch.peerStore.setShardInfo(peerInfo.peerId, peerInfo.shards) ## When: We select for shard 0 - let shard0Topic = some(PubsubTopic("/waku/2/rs/0/0")) + let shard0Topic = Opt.some(PubsubTopic("/waku/2/rs/0/0")) let selectedPeer = node.peerManager.selectPeer(WakuRelayCodec, shard0Topic) ## Then: Peer is selected because ENR (shard 0) takes precedence @@ -1486,7 +1486,7 @@ procSuite "Peer Manager": selectedPeer.get().peerId == peerInfo.peerId ## When: We select for shard 1 - let shard1Topic = some(PubsubTopic("/waku/2/rs/0/1")) + let shard1Topic = Opt.some(PubsubTopic("/waku/2/rs/0/1")) let selectedPeer1 = node.peerManager.selectPeer(WakuRelayCodec, shard1Topic) ## Then: Peer is still selected because shards field is checked as fallback diff --git a/tests/test_peer_storage.nim b/tests/test_peer_storage.nim index 123556b45..be2a3657a 100644 --- a/tests/test_peer_storage.nim +++ b/tests/test_peer_storage.nim @@ -1,6 +1,6 @@ {.used.} -import std/options, testutils/unittests, eth/p2p/discoveryv5/enr, libp2p/crypto/crypto +import results, testutils/unittests, eth/p2p/discoveryv5/enr, libp2p/crypto/crypto import logos_delivery/waku/[ common/databases/db_sqlite, @@ -33,7 +33,7 @@ suite "Peer Storage": let stored = RemotePeerInfo( peerId: peer.peerId, addrs: @[peerLoc], - enr: some(record), + enr: Opt.some(record), protocols: @[peerProto], publicKey: peerKey.getPublicKey().tryGet(), connectedness: connectedness, @@ -75,7 +75,7 @@ suite "Peer Storage": # Test replace and retrieve (update an existing entry) stored.connectedness = CannotConnect stored.disconnectTime = disconn + 10 - stored.enr = none(Record) + stored.enr = Opt.none(Record) require storage.put(stored).isOk responseCount = 0 diff --git a/tests/test_relay_peer_exchange.nim b/tests/test_relay_peer_exchange.nim index 058576d4c..95c13f39d 100644 --- a/tests/test_relay_peer_exchange.nim +++ b/tests/test_relay_peer_exchange.nim @@ -1,7 +1,8 @@ {.used.} import - std/[sequtils, options], + results, + std/sequtils, testutils/unittests, chronos, libp2p/peerid, @@ -28,7 +29,7 @@ procSuite "Relay (GossipSub) Peer Exchange": # When both client and server mount relay without a handler (await node1.mountRelay()).isOkOr: assert false, "Failed to mount relay" - (await node2.mountRelay(none(RoutingRecordsHandler))).isOkOr: + (await node2.mountRelay(Opt.none(RoutingRecordsHandler))).isOkOr: assert false, "Failed to mount relay" # Then the relays are mounted without a handler @@ -78,11 +79,11 @@ procSuite "Relay (GossipSub) Peer Exchange": peerExchangeHandle: RoutingRecordsHandler = peerExchangeHandler # Givem the nodes mount relay with a peer exchange handler - (await node1.mountRelay(some(emptyPeerExchangeHandle))).isOkOr: + (await node1.mountRelay(Opt.some(emptyPeerExchangeHandle))).isOkOr: assert false, "Failed to mount relay" - (await node2.mountRelay(some(emptyPeerExchangeHandle))).isOkOr: + (await node2.mountRelay(Opt.some(emptyPeerExchangeHandle))).isOkOr: assert false, "Failed to mount relay" - (await node3.mountRelay(some(peerExchangeHandle))).isOkOr: + (await node3.mountRelay(Opt.some(peerExchangeHandle))).isOkOr: assert false, "Failed to mount relay" # Ensure that node1 prunes all peers after the first connection diff --git a/tests/test_waku.nim b/tests/test_waku.nim index 7ddde8ad9..300a97417 100644 --- a/tests/test_waku.nim +++ b/tests/test_waku.nim @@ -1,6 +1,6 @@ {.used.} -import std/[net, options] +import results, std/net import chronos, testutils/unittests @@ -14,7 +14,7 @@ suite "LogosDelivery API - Create node": ## Given var nodeConf = MessagingClientConf().toWakuNodeConf(Core).valueOr: raiseAssert "toWakuNodeConf failed: " & error - nodeConf.clusterId = some(3'u16) + nodeConf.clusterId = Opt.some(3'u16) nodeConf.rest = false # This is the actual minimal config but as the node auto-start, it is not suitable for tests @@ -33,7 +33,7 @@ suite "LogosDelivery API - Create node": ## Given var nodeConf = MessagingClientConf().toWakuNodeConf(Core).valueOr: raiseAssert "toWakuNodeConf failed: " & error - nodeConf.clusterId = some(99'u16) + nodeConf.clusterId = Opt.some(99'u16) nodeConf.rest = false nodeConf.numShardsInNetwork = 16 nodeConf.maxMessageSize = "1024 KiB" @@ -64,7 +64,7 @@ suite "LogosDelivery API - Create node": ## Given var nodeConf = MessagingClientConf().toWakuNodeConf(Core).valueOr: raiseAssert "toWakuNodeConf failed: " & error - nodeConf.clusterId = some(42'u16) + nodeConf.clusterId = Opt.some(42'u16) nodeConf.rest = false nodeConf.entryNodes = @[ "enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im", diff --git a/tests/test_waku_enr.nim b/tests/test_waku_enr.nim index 5b1688682..0858f6461 100644 --- a/tests/test_waku_enr.nim +++ b/tests/test_waku_enr.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, sequtils], results, testutils/unittests +import std/sequtils, results, testutils/unittests import logos_delivery/waku/waku_core, logos_delivery/waku/waku_enr, ./testlib/wakucore suite "Waku ENR - Capabilities bitfield": diff --git a/tests/test_waku_metadata.nim b/tests/test_waku_metadata.nim index 1ae4ce7b7..d913f0919 100644 --- a/tests/test_waku_metadata.nim +++ b/tests/test_waku_metadata.nim @@ -1,7 +1,7 @@ {.used.} import - std/[options, sequtils, tables], + std/[sequtils, tables], testutils/unittests, chronos, chronicles, diff --git a/tests/test_waku_netconfig.nim b/tests/test_waku_netconfig.nim index 08d153ee7..91928927c 100644 --- a/tests/test_waku_netconfig.nim +++ b/tests/test_waku_netconfig.nim @@ -1,4 +1,4 @@ -import std/options +import results {.used.} import chronos, confutils/toml/std/net, libp2p/multiaddress, testutils/unittests @@ -24,23 +24,23 @@ suite "Waku NetConfig": let netConfigRes = NetConfig.init( bindIp = conf.endpointConf.p2pListenAddress, bindPort = conf.endpointConf.p2pTcpPort, - extIp = none(IpAddress), - extPort = none(Port), + extIp = Opt.none(IpAddress), + extPort = Opt.none(Port), extMultiAddrs = @[], wsBindPort = if conf.webSocketConf.isSome(): - some(conf.webSocketConf.get().port) + Opt.some(conf.webSocketConf.get().port) else: - none(Port), + Opt.none(Port), wsEnabled = conf.webSocketConf.isSome(), wssEnabled = if conf.webSocketConf.isSome(): conf.webSocketConf.get().secureConf.isSome() else: false, - dns4DomainName = none(string), - discv5UdpPort = none(Port), - wakuFlags = some(wakuFlags), + dns4DomainName = Opt.none(string), + discv5UdpPort = Opt.none(Port), + wakuFlags = Opt.some(wakuFlags), ) check: @@ -76,8 +76,8 @@ suite "Waku NetConfig": let netConfigRes = NetConfig.init( bindIp = conf.endpointConf.p2pListenAddress, bindPort = conf.endpointConf.p2pTcpPort, - extIp = some(extIp), - extPort = some(extPort), + extIp = Opt.some(extIp), + extPort = Opt.some(extPort), ) assert netConfigRes.isOk(), $netConfigRes.error @@ -97,8 +97,8 @@ suite "Waku NetConfig": let netConfigRes = NetConfig.init( bindIp = conf.endpointConf.p2pListenAddress, bindPort = conf.endpointConf.p2pTcpPort, - dns4DomainName = some(dns4DomainName), - extPort = some(extPort), + dns4DomainName = Opt.some(dns4DomainName), + extPort = Opt.some(extPort), ) assert netConfigRes.isOk(), $netConfigRes.error @@ -141,7 +141,7 @@ suite "Waku NetConfig": bindIp = conf.endpointConf.p2pListenAddress, bindPort = bindPort, quicEnabled = true, - quicBindPort = some(bindPort), + quicBindPort = Opt.some(bindPort), ) assert autoRes.isOk(), $autoRes.error check autoRes.get().announcedAddresses.filterIt(it.isQuicAddress()).len == 1 @@ -151,7 +151,7 @@ suite "Waku NetConfig": bindIp = conf.endpointConf.p2pListenAddress, bindPort = bindPort, quicEnabled = true, - quicBindPort = some(bindPort), + quicBindPort = Opt.some(bindPort), extMultiAddrs = @[operatorQuic], ) assert opRes.isOk(), $opRes.error @@ -170,11 +170,11 @@ suite "Waku NetConfig": let netConfigRes = NetConfig.init( bindIp = conf.endpointConf.p2pListenAddress, bindPort = conf.endpointConf.p2pTcpPort, - extIp = some(extIp), - extPort = some(Port(1234)), + extIp = Opt.some(extIp), + extPort = Opt.some(Port(1234)), quicEnabled = true, - quicBindPort = some(quicBindPort), - extQuicPort = some(natQuicPort), + quicBindPort = Opt.some(quicBindPort), + extQuicPort = Opt.some(natQuicPort), ) assert netConfigRes.isOk(), $netConfigRes.error @@ -194,9 +194,9 @@ suite "Waku NetConfig": let netConfigRes = NetConfig.init( bindIp = conf.endpointConf.p2pListenAddress, bindPort = conf.endpointConf.p2pTcpPort, - dns4DomainName = some(dns4DomainName), - extIp = some(extIp), - extPort = some(extPort), + dns4DomainName = Opt.some(dns4DomainName), + extIp = Opt.some(extIp), + extPort = Opt.some(extPort), ) assert netConfigRes.isOk(), $netConfigRes.error @@ -217,8 +217,8 @@ suite "Waku NetConfig": let netConfigRes = NetConfig.init( bindIp = conf.endpointConf.p2pListenAddress, bindPort = conf.endpointConf.p2pTcpPort, - dns4DomainName = some(dns4DomainName), - extPort = some(extPort), + dns4DomainName = Opt.some(dns4DomainName), + extPort = Opt.some(extPort), extMultiAddrs = @[dns4Address], ) @@ -301,8 +301,8 @@ suite "Waku NetConfig": let netConfigRes = NetConfig.init( bindIp = conf.endpointConf.p2pListenAddress, bindPort = conf.endpointConf.p2pTcpPort, - extIp = some(extIp), - extPort = some(extPort), + extIp = Opt.some(extIp), + extPort = Opt.some(extPort), wsEnabled = true, wssEnabled = wssEnabled, ) @@ -332,8 +332,8 @@ suite "Waku NetConfig": let netConfigRes = NetConfig.init( bindIp = conf.endpointConf.p2pListenAddress, bindPort = conf.endpointConf.p2pTcpPort, - dns4DomainName = some(dns4DomainName), - extPort = some(extPort), + dns4DomainName = Opt.some(dns4DomainName), + extPort = Opt.some(extPort), wsEnabled = true, wssEnabled = wssEnabled, ) @@ -366,9 +366,9 @@ suite "Waku NetConfig": let netConfigRes = NetConfig.init( bindIp = conf.endpointConf.p2pListenAddress, bindPort = conf.endpointConf.p2pTcpPort, - dns4DomainName = some(dns4DomainName), - extIp = some(extIp), - extPort = some(extPort), + dns4DomainName = Opt.some(dns4DomainName), + extIp = Opt.some(extIp), + extPort = Opt.some(extPort), wsEnabled = true, wssEnabled = wssEnabled, ) @@ -410,8 +410,8 @@ suite "Waku NetConfig": let netConfigRes = NetConfig.init( bindIp = conf.endpointConf.p2pListenAddress, bindPort = conf.endpointConf.p2pTcpPort, - extIp = some(extIp), - extPort = some(extPort), + extIp = Opt.some(extIp), + extPort = Opt.some(extPort), ) assert netConfigRes.isOk(), $netConfigRes.error @@ -431,8 +431,8 @@ suite "Waku NetConfig": let netConfigRes = NetConfig.init( bindIp = conf.endpointConf.p2pListenAddress, bindPort = conf.endpointConf.p2pTcpPort, - dns4DomainName = some(dns4DomainName), - extPort = some(extPort), + dns4DomainName = Opt.some(dns4DomainName), + extPort = Opt.some(extPort), ) assert netConfigRes.isOk(), $netConfigRes.error @@ -496,7 +496,7 @@ suite "Waku NetConfig": bindIp = conf.endpointConf.p2pListenAddress, bindPort = conf.endpointConf.p2pTcpPort, quicEnabled = true, - quicBindPort = some(Port(60000)), + quicBindPort = Opt.some(Port(60000)), extMultiAddrs = extMultiAddrs, extMultiAddrsOnly = true, ) diff --git a/tests/test_waku_protobufs.nim b/tests/test_waku_protobufs.nim index d893f0fde..5902b46b4 100644 --- a/tests/test_waku_protobufs.nim +++ b/tests/test_waku_protobufs.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, sequtils, tables], testutils/unittests, chronos, chronicles +import results, std/[sequtils, tables], testutils/unittests, chronos, chronicles import logos_delivery/waku/waku_metadata, logos_delivery/waku/waku_metadata/rpc, @@ -11,7 +11,7 @@ procSuite "Waku Protobufs": # TODO: Missing test coverage in many encode/decode protobuf functions test "WakuMetadataResponse": - let res = WakuMetadataResponse(clusterId: some(7), shards: @[10, 23, 33]) + let res = WakuMetadataResponse(clusterId: Opt.some(7), shards: @[10, 23, 33]) let buffer = res.encode() @@ -22,7 +22,7 @@ procSuite "Waku Protobufs": decodedBuff.get().shards == res.shards test "WakuMetadataRequest": - let req = WakuMetadataRequest(clusterId: some(5), shards: @[100, 2, 0]) + let req = WakuMetadataRequest(clusterId: Opt.some(5), shards: @[100, 2, 0]) let buffer = req.encode() diff --git a/tests/test_waku_rendezvous.nim b/tests/test_waku_rendezvous.nim index 4bdb90630..1dd3d3a88 100644 --- a/tests/test_waku_rendezvous.nim +++ b/tests/test_waku_rendezvous.nim @@ -1,11 +1,7 @@ {.used.} import - std/options, - chronos, - testutils/unittests, - libp2p/builders, - libp2p/protocols/rendezvous + results, chronos, testutils/unittests, libp2p/builders, libp2p/protocols/rendezvous import logos_delivery/waku/waku_core/peers, diff --git a/tests/test_wakunode.nim b/tests/test_wakunode.nim index 4279d9066..a607c9f2c 100644 --- a/tests/test_wakunode.nim +++ b/tests/test_wakunode.nim @@ -1,7 +1,8 @@ {.used.} import - std/[sequtils, strutils, net, options], + results, + std/[sequtils, strutils, net], stew/byteutils, testutils/unittests, chronicles, @@ -77,7 +78,7 @@ suite "WakuNode": assert false, "Failed to subscribe to topic" await sleepAsync(2000.millis) - var res = await node1.publish(some($shard), message) + var res = await node1.publish(Opt.some($shard), message) assert res.isOk(), $res.error await sleepAsync(2000.millis) @@ -180,8 +181,8 @@ suite "WakuNode": nodeKey = generateSecp256k1Key() bindIp = parseIpAddress("0.0.0.0") bindPort = Port(61006) - extIp = some(getPrimaryIPAddr()) - extPort = some(Port(61008)) + extIp = Opt.some(getPrimaryIPAddr()) + extPort = Opt.some(Port(61008)) # tcp-only: asserts exact single listen addr; quic variant below node = newTestWakuNode(nodeKey, bindIp, bindPort, extIp, extPort, quicEnabled = false) @@ -219,8 +220,8 @@ suite "WakuNode": nodeKey = generateSecp256k1Key() bindIp = parseIpAddress("0.0.0.0") bindPort = Port(0) - extIp = some(getPrimaryIPAddr()) - extPort = some(Port(61008)) + extIp = Opt.some(getPrimaryIPAddr()) + extPort = Opt.some(Port(61008)) node = newTestWakuNode(nodeKey, bindIp, bindPort, extIp, extPort, quicEnabled = true) @@ -287,13 +288,13 @@ suite "WakuNode": nodeKey = generateSecp256k1Key() bindIp = parseIpAddress("0.0.0.0") bindPort = Port(61010) - extIp = some(getPrimaryIPAddr()) - extPort = some(Port(61012)) + extIp = Opt.some(getPrimaryIPAddr()) + extPort = Opt.some(Port(61012)) domainName = "example.com" expectedDns4Addr = MultiAddress.init("/dns4/" & domainName & "/tcp/" & $(extPort.get())).get() node = newTestWakuNode( - nodeKey, bindIp, bindPort, extIp, extPort, dns4DomainName = some(domainName) + nodeKey, bindIp, bindPort, extIp, extPort, dns4DomainName = Opt.some(domainName) ) check: @@ -308,8 +309,9 @@ suite "WakuNode": bindPort = Port(0) domainName = "status.im" - node = - newTestWakuNode(nodeKey, bindIp, bindPort, dns4DomainName = some(domainName)) + node = newTestWakuNode( + nodeKey, bindIp, bindPort, dns4DomainName = Opt.some(domainName) + ) var ipStr = "" var enrIp = node.enr.tryGet("ip", array[4, byte]) @@ -339,15 +341,16 @@ suite "WakuNode": # Create node with inexistent domain try: let node = newTestWakuNode( - nodeKey, bindIp, bindPort, dns4DomainName = some(inexistentDomain) + nodeKey, bindIp, bindPort, dns4DomainName = Opt.some(inexistentDomain) ) except Exception as e: inexistentDomainErr = e.msg # Create node with invalid domain try: - let node = - newTestWakuNode(nodeKey, bindIp, bindPort, dns4DomainName = some(invalidDomain)) + let node = newTestWakuNode( + nodeKey, bindIp, bindPort, dns4DomainName = Opt.some(invalidDomain) + ) except Exception as e: invalidDomainErr = e.msg @@ -366,7 +369,7 @@ suite "WakuNode": let # node with custom agent string nodeKey1 = generateSecp256k1Key() - node1 = newTestWakuNode(nodeKey1, agentString = some(expectedAgentString1)) + node1 = newTestWakuNode(nodeKey1, agentString = Opt.some(expectedAgentString1)) # node with default agent string from libp2p nodeKey2 = generateSecp256k1Key() diff --git a/tests/testlib/tables.nim b/tests/testlib/tables.nim index c6eba9582..488106ed0 100644 --- a/tests/testlib/tables.nim +++ b/tests/testlib/tables.nim @@ -1,4 +1,4 @@ -import std/[tables, sequtils, options] +import std/[tables, sequtils] import logos_delivery/waku/waku_core/topics, ../testlib/wakucore diff --git a/tests/testlib/wakucore.nim b/tests/testlib/wakucore.nim index e1d0f8143..1286749aa 100644 --- a/tests/testlib/wakucore.nim +++ b/tests/testlib/wakucore.nim @@ -1,5 +1,5 @@ import - std/[options, times], + std/times, results, stew/byteutils, chronos, @@ -61,7 +61,7 @@ proc newStandardSwitch*( b.build() proc newTestSwitch*( - key = none(libp2p_keys.PrivateKey), address = none(MultiAddress) + key = Opt.none(libp2p_keys.PrivateKey), address = Opt.none(MultiAddress) ): Switch = let peerKey = key.get(generateSecp256k1Key()) let peerAddr = address.get(MultiAddress.init("/ip4/127.0.0.1/tcp/0").get()) diff --git a/tests/testlib/wakunode.nim b/tests/testlib/wakunode.nim index f269f6314..726ef89aa 100644 --- a/tests/testlib/wakunode.nim +++ b/tests/testlib/wakunode.nim @@ -1,5 +1,4 @@ import - std/options, results, chronos, libp2p/switch, @@ -53,8 +52,8 @@ proc newTestWakuNode*( nodeKey: crypto.PrivateKey, bindIp: IpAddress = parseIpAddress("0.0.0.0"), bindPort: Port = Port(0), - extIp = none(IpAddress), - extPort = none(Port), + extIp = Opt.none(IpAddress), + extPort = Opt.none(Port), extMultiAddrs = newSeq[MultiAddress](), peerStorage: PeerStorage = nil, maxConnections = MaxConnections, @@ -65,13 +64,13 @@ proc newTestWakuNode*( quicEnabled: bool = true, secureKey: string = "", secureCert: string = "", - wakuFlags = none(CapabilitiesBitfield), + wakuFlags = Opt.none(CapabilitiesBitfield), nameResolver: NameResolver = nil, sendSignedPeerRecord = false, - dns4DomainName = none(string), - discv5UdpPort = none(Port), - agentString = none(string), - peerStoreCapacity = none(int), + dns4DomainName = Opt.none(string), + discv5UdpPort = Opt.none(Port), + agentString = Opt.none(string), + peerStoreCapacity = Opt.none(int), clusterId = DefaultClusterId, subscribeShards = @[DefaultShardId], ): WakuNode = @@ -93,7 +92,7 @@ proc newTestWakuNode*( # Update extPort to default value if it's missing and there's an extIp or a DNS domain let extPort = if (extIp.isSome() or dns4DomainName.isSome()) and extPort.isNone(): - some(Port(0)) + Opt.some(Port(0)) else: extPort @@ -107,7 +106,7 @@ proc newTestWakuNode*( let dns = (waitFor dnsResolve(dns4DomainName.get(), conf.dnsAddrsNameServers)).valueOr: raise newException(Defect, error) - resolvedExtIp = some(parseIpAddress(dns)) + resolvedExtIp = Opt.some(parseIpAddress(dns)) let netConf = NetConfig.init( clusterId = conf.clusterId, @@ -116,10 +115,10 @@ proc newTestWakuNode*( extIp = resolvedExtIp, extPort = extPort, extMultiAddrs = extMultiAddrs, - wsBindPort = some(wsBindPort), + wsBindPort = Opt.some(wsBindPort), wsEnabled = wsEnabled, wssEnabled = wssEnabled, - quicBindPort = some(quicBindPort), + quicBindPort = Opt.some(quicBindPort), quicEnabled = quicEnabled, dns4DomainName = dns4DomainName, discv5UdpPort = discv5UdpPort, @@ -153,19 +152,19 @@ proc newTestWakuNode*( builder.withNetworkConfiguration(netConf) builder.withPeerStorage(peerStorage, capacity = peerStoreCapacity) builder.withSwitchConfiguration( - maxConnections = some(maxConnections), + maxConnections = Opt.some(maxConnections), nameResolver = nameResolver, sendSignedPeerRecord = sendSignedPeerRecord, secureKey = if secureKey != "": - some(secureKey) + Opt.some(secureKey) else: - none(string), + Opt.none(string), secureCert = if secureCert != "": - some(secureCert) + Opt.some(secureCert) else: - none(string), + Opt.none(string), agentString = agentString, ) diff --git a/tests/tools/test_confutils_envvar.nim b/tests/tools/test_confutils_envvar.nim index 76d9ddd31..bd1951144 100644 --- a/tests/tools/test_confutils_envvar.nim +++ b/tests/tools/test_confutils_envvar.nim @@ -1,22 +1,15 @@ {.used.} import - std/[os, options], - results, - testutils/unittests, - confutils, - confutils/defs, - confutils/std/net + std/os, results, testutils/unittests, confutils, confutils/defs, confutils/std/net import ../../tools/confutils/[envvar as confEnvvarDefs, envvar_net as confEnvvarNet] type ConfResult[T] = Result[T, string] type TestConf = object - configFile* {.desc: "Configuration file path", name: "config-file".}: - Option[InputFile] + configFile* {.desc: "Configuration file path", name: "config-file".}: Opt[InputFile] - testFile* {.desc: "Configuration test file path", name: "test-file".}: - Option[InputFile] + testFile* {.desc: "Configuration test file path", name: "test-file".}: Opt[InputFile] listenAddress* {. defaultValue: IpAddress(family: IpAddressFamily.IPv4, address_v4: [127u8, 0, 0, 1]), diff --git a/tests/waku_archive/archive_utils.nim b/tests/waku_archive/archive_utils.nim index 126607c59..3e60c8997 100644 --- a/tests/waku_archive/archive_utils.nim +++ b/tests/waku_archive/archive_utils.nim @@ -1,6 +1,6 @@ {.used.} -import std/options, results, chronos, libp2p/crypto/crypto +import results, chronos, libp2p/crypto/crypto import logos_delivery/waku/[ @@ -13,7 +13,7 @@ import ], ../testlib/[wakucore] -proc newSqliteDatabase*(path: Option[string] = string.none()): SqliteDatabase = +proc newSqliteDatabase*(path: Opt[string] = Opt.none(string)): SqliteDatabase = SqliteDatabase.new(path.get(":memory:")).tryGet() proc newSqliteArchiveDriver*(): ArchiveDriver = diff --git a/tests/waku_archive/test_driver_postgres.nim b/tests/waku_archive/test_driver_postgres.nim index 1295aebb6..09979d4ae 100644 --- a/tests/waku_archive/test_driver_postgres.nim +++ b/tests/waku_archive/test_driver_postgres.nim @@ -1,6 +1,6 @@ {.used.} -import std/[sequtils, options], testutils/unittests, chronos +import results, std/sequtils, testutils/unittests, chronos import logos_delivery/waku/[ waku_archive, @@ -114,14 +114,15 @@ suite "Postgres driver": # Get both content topics messagesRes = await driver.getMessages( contentTopics = @[contentTopic1, contentTopic2], - cursor = some(computeMessageHash(pubsubTopic1, messagesRes.get()[1][2])), + cursor = Opt.some(computeMessageHash(pubsubTopic1, messagesRes.get()[1][2])), ) assert messagesRes.isOk() assert messagesRes.get().len == 1 # Get both content topics but one pubsub topic messagesRes = await driver.getMessages( - contentTopics = @[contentTopic1, contentTopic2], pubsubTopic = some(pubsubTopic1) + contentTopics = @[contentTopic1, contentTopic2], + pubsubTopic = Opt.some(pubsubTopic1), ) assert messagesRes.isOk(), messagesRes.error diff --git a/tests/waku_archive/test_driver_postgres_query.nim b/tests/waku_archive/test_driver_postgres_query.nim index 9a015c2f2..487ace9e0 100644 --- a/tests/waku_archive/test_driver_postgres_query.nim +++ b/tests/waku_archive/test_driver_postgres_query.nim @@ -1,7 +1,8 @@ {.used.} import - std/[options, sequtils, strformat, random, algorithm], + results, + std/[sequtils, strformat, random, algorithm], testutils/unittests, chronos, chronicles @@ -237,11 +238,11 @@ suite "Postgres driver - queries": ## When var res = await driver.getMessages( contentTopics = @[contentTopic1, contentTopic2], - pubsubTopic = some(DefaultPubsubTopic), + pubsubTopic = Opt.some(DefaultPubsubTopic), maxPageSize = 2, ascendingOrder = true, - startTime = some(ts(00)), - endTime = some(ts(40)), + startTime = Opt.some(ts(00)), + endTime = Opt.some(ts(40)), ) ## Then @@ -254,11 +255,11 @@ suite "Postgres driver - queries": ## statement by querying one single content topic res = await driver.getMessages( contentTopics = @[contentTopic1], - pubsubTopic = some(DefaultPubsubTopic), + pubsubTopic = Opt.some(DefaultPubsubTopic), maxPageSize = 2, ascendingOrder = true, - startTime = some(ts(00)), - endTime = some(ts(40)), + startTime = Opt.some(ts(00)), + endTime = Opt.some(ts(40)), ) ## Then @@ -372,7 +373,7 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( - pubsubTopic = some(pubsubTopic), maxPageSize = 2, ascendingOrder = true + pubsubTopic = Opt.some(pubsubTopic), maxPageSize = 2, ascendingOrder = true ) ## Then @@ -483,7 +484,7 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - pubsubTopic = some(pubsubTopic), + pubsubTopic = Opt.some(pubsubTopic), maxPageSize = 2, ascendingOrder = true, ) @@ -526,7 +527,7 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( - cursor = some(cursor), maxPageSize = 2, ascendingOrder = true + cursor = Opt.some(cursor), maxPageSize = 2, ascendingOrder = true ) ## Then @@ -566,7 +567,7 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( - cursor = some(cursor), maxPageSize = 2, ascendingOrder = false + cursor = Opt.some(cursor), maxPageSize = 2, ascendingOrder = false ) ## Then @@ -607,10 +608,10 @@ suite "Postgres driver - queries": let res = await driver.getMessages( includeData = true, contentTopics = @[DefaultContentTopic], - pubsubTopic = none(PubsubTopic), - cursor = some(cursor), - startTime = none(Timestamp), - endTime = none(Timestamp), + pubsubTopic = Opt.none(PubsubTopic), + cursor = Opt.some(cursor), + startTime = Opt.none(Timestamp), + endTime = Opt.none(Timestamp), hashes = @[], maxPageSize = 5, ascendingOrder = true, @@ -653,7 +654,7 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - cursor = some(cursor), + cursor = Opt.some(cursor), maxPageSize = 10, ascendingOrder = true, ) @@ -696,7 +697,7 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - cursor = some(cursor), + cursor = Opt.some(cursor), maxPageSize = 10, ascendingOrder = false, ) @@ -764,8 +765,8 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( - pubsubTopic = some(pubsubTopic), - cursor = some(cursor), + pubsubTopic = Opt.some(pubsubTopic), + cursor = Opt.some(cursor), maxPageSize = 10, ascendingOrder = true, ) @@ -834,8 +835,8 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( - pubsubTopic = some(pubsubTopic), - cursor = some(cursor), + pubsubTopic = Opt.some(pubsubTopic), + cursor = Opt.some(cursor), maxPageSize = 10, ascendingOrder = false, ) @@ -913,7 +914,7 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( - startTime = some(ts(15, timeOrigin)), maxPageSize = 10, ascendingOrder = true + startTime = Opt.some(ts(15, timeOrigin)), maxPageSize = 10, ascendingOrder = true ) ## Then @@ -952,7 +953,7 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( - endTime = some(ts(45, timeOrigin)), maxPageSize = 10, ascendingOrder = true + endTime = Opt.some(ts(45, timeOrigin)), maxPageSize = 10, ascendingOrder = true ) ## Then @@ -1018,8 +1019,8 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( - startTime = some(ts(15, timeOrigin)), - endTime = some(ts(45, timeOrigin)), + startTime = Opt.some(ts(15, timeOrigin)), + endTime = Opt.some(ts(45, timeOrigin)), maxPageSize = 10, ascendingOrder = true, ) @@ -1063,8 +1064,8 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - startTime = some(ts(45, timeOrigin)), - endTime = some(ts(15, timeOrigin)), + startTime = Opt.some(ts(45, timeOrigin)), + endTime = Opt.some(ts(15, timeOrigin)), maxPageSize = 2, ascendingOrder = true, ) @@ -1105,7 +1106,7 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - startTime = some(ts(15, timeOrigin)), + startTime = Opt.some(ts(15, timeOrigin)), maxPageSize = 10, ascendingOrder = true, ) @@ -1149,7 +1150,7 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - startTime = some(ts(15, timeOrigin)), + startTime = Opt.some(ts(15, timeOrigin)), maxPageSize = 10, ascendingOrder = false, ) @@ -1196,8 +1197,8 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - cursor = some(cursor), - startTime = some(ts(15, timeOrigin)), + cursor = Opt.some(cursor), + startTime = Opt.some(ts(15, timeOrigin)), maxPageSize = 10, ascendingOrder = true, ) @@ -1244,8 +1245,8 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - cursor = some(cursor), - startTime = some(ts(15, timeOrigin)), + cursor = Opt.some(cursor), + startTime = Opt.some(ts(15, timeOrigin)), maxPageSize = 10, ascendingOrder = false, ) @@ -1310,10 +1311,10 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - pubsubTopic = some(pubsubTopic), - cursor = some(cursor), - startTime = some(ts(0, timeOrigin)), - endTime = some(ts(45, timeOrigin)), + pubsubTopic = Opt.some(pubsubTopic), + cursor = Opt.some(cursor), + startTime = Opt.some(ts(0, timeOrigin)), + endTime = Opt.some(ts(45, timeOrigin)), maxPageSize = 10, ascendingOrder = true, ) @@ -1378,10 +1379,10 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - pubsubTopic = some(pubsubTopic), - cursor = some(cursor), - startTime = some(ts(35, timeOrigin)), - endTime = some(ts(85, timeOrigin)), + pubsubTopic = Opt.some(pubsubTopic), + cursor = Opt.some(cursor), + startTime = Opt.some(ts(35, timeOrigin)), + endTime = Opt.some(ts(85, timeOrigin)), maxPageSize = 10, ascendingOrder = false, ) @@ -1447,10 +1448,10 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - pubsubTopic = some(pubsubTopic), - cursor = some(cursor), - startTime = some(ts(35, timeOrigin)), - endTime = some(ts(85, timeOrigin)), + pubsubTopic = Opt.some(pubsubTopic), + cursor = Opt.some(cursor), + startTime = Opt.some(ts(35, timeOrigin)), + endTime = Opt.some(ts(85, timeOrigin)), maxPageSize = 10, ascendingOrder = true, ) @@ -1517,10 +1518,10 @@ suite "Postgres driver - queries": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - pubsubTopic = some(pubsubTopic), - cursor = some(cursor), - startTime = some(ts(35, timeOrigin)), - endTime = some(ts(85, timeOrigin)), + pubsubTopic = Opt.some(pubsubTopic), + cursor = Opt.some(cursor), + startTime = Opt.some(ts(35, timeOrigin)), + endTime = Opt.some(ts(85, timeOrigin)), maxPageSize = 10, ascendingOrder = false, ) diff --git a/tests/waku_archive/test_driver_queue.nim b/tests/waku_archive/test_driver_queue.nim index 571b3790c..55c50fe1b 100644 --- a/tests/waku_archive/test_driver_queue.nim +++ b/tests/waku_archive/test_driver_queue.nim @@ -1,6 +1,6 @@ {.used.} -import std/options, results, testutils/unittests +import results, testutils/unittests import logos_delivery/waku/[ waku_archive, diff --git a/tests/waku_archive/test_driver_queue_pagination.nim b/tests/waku_archive/test_driver_queue_pagination.nim index 1cc18d9ec..ddfe0e1c3 100644 --- a/tests/waku_archive/test_driver_queue_pagination.nim +++ b/tests/waku_archive/test_driver_queue_pagination.nim @@ -1,7 +1,7 @@ {.used.} import - std/[options, sequtils, algorithm], testutils/unittests, libp2p/protobuf/minprotobuf + results, std/[sequtils, algorithm], testutils/unittests, libp2p/protobuf/minprotobuf import logos_delivery/waku/[ waku_archive, @@ -41,7 +41,7 @@ procSuite "Queue driver - pagination": ## Given let pageSize: uint = 2 - cursor: Option[Index] = some(indexList[3]) + cursor: Opt[Index] = Opt.some(indexList[3]) forward: bool = true ## When @@ -57,7 +57,7 @@ procSuite "Queue driver - pagination": ## Given let pageSize: uint = 2 - cursor: Option[Index] = none(Index) + cursor: Opt[Index] = Opt.none(Index) forward: bool = true ## When @@ -73,7 +73,7 @@ procSuite "Queue driver - pagination": ## Given let pageSize: uint = 13 - cursor: Option[Index] = none(Index) + cursor: Opt[Index] = Opt.none(Index) forward: bool = true ## When @@ -90,7 +90,7 @@ procSuite "Queue driver - pagination": let driver = getTestQueueDriver(0) let pageSize: uint = 2 - cursor: Option[Index] = none(Index) + cursor: Opt[Index] = Opt.none(Index) forward: bool = true ## When @@ -105,7 +105,7 @@ procSuite "Queue driver - pagination": ## Given let pageSize: uint = 10 - cursor: Option[Index] = some(indexList[3]) + cursor: Opt[Index] = Opt.some(indexList[3]) forward: bool = true ## When @@ -121,7 +121,7 @@ procSuite "Queue driver - pagination": ## Given let pageSize: uint = MaxPageSize + 1 - cursor: Option[Index] = some(indexList[3]) + cursor: Opt[Index] = Opt.some(indexList[3]) forward: bool = true ## When @@ -136,7 +136,7 @@ procSuite "Queue driver - pagination": ## Given let pageSize: uint = 10 - cursor: Option[Index] = some(indexList[9]) + cursor: Opt[Index] = Opt.some(indexList[9]) forward: bool = true ## When @@ -154,7 +154,7 @@ procSuite "Queue driver - pagination": let pageSize: uint = 10 - cursor: Option[Index] = some(index) + cursor: Opt[Index] = Opt.some(index) forward: bool = true ## When @@ -170,7 +170,7 @@ procSuite "Queue driver - pagination": let driver = getTestQueueDriver(1) let pageSize: uint = 10 - cursor: Option[Index] = none(Index) + cursor: Opt[Index] = Opt.none(Index) forward: bool = true ## When @@ -186,7 +186,7 @@ procSuite "Queue driver - pagination": let driver = getTestQueueDriver(1) let pageSize: uint = 10 - cursor: Option[Index] = some(indexList[0]) + cursor: Opt[Index] = Opt.some(indexList[0]) forward: bool = true ## When @@ -201,7 +201,7 @@ procSuite "Queue driver - pagination": ## Given let pageSize: uint = 3 - cursor: Option[Index] = none(Index) + cursor: Opt[Index] = Opt.none(Index) forward = true proc onlyEvenTimes(index: Index, msg: WakuMessage): bool = @@ -221,7 +221,7 @@ procSuite "Queue driver - pagination": ## Given let pageSize: uint = 2 - cursor: Option[Index] = some(indexList[3]) + cursor: Opt[Index] = Opt.some(indexList[3]) forward: bool = false ## When @@ -237,7 +237,7 @@ procSuite "Queue driver - pagination": let driver = getTestQueueDriver(0) let pageSize: uint = 2 - cursor: Option[Index] = none(Index) + cursor: Opt[Index] = Opt.none(Index) forward: bool = false ## When @@ -252,7 +252,7 @@ procSuite "Queue driver - pagination": ## Given let pageSize: uint = 2 - cursor: Option[Index] = none(Index) + cursor: Opt[Index] = Opt.none(Index) forward: bool = false ## When @@ -268,7 +268,7 @@ procSuite "Queue driver - pagination": ## Given let pageSize: uint = 13 - cursor: Option[Index] = none(Index) + cursor: Opt[Index] = Opt.none(Index) forward: bool = false ## When @@ -284,7 +284,7 @@ procSuite "Queue driver - pagination": ## Given let pageSize: uint = 5 - cursor: Option[Index] = some(indexList[3]) + cursor: Opt[Index] = Opt.some(indexList[3]) forward: bool = false ## When @@ -299,7 +299,7 @@ procSuite "Queue driver - pagination": ## Given let pageSize: uint = MaxPageSize + 1 - cursor: Option[Index] = some(indexList[3]) + cursor: Opt[Index] = Opt.some(indexList[3]) forward: bool = false ## When @@ -314,7 +314,7 @@ procSuite "Queue driver - pagination": ## Given let pageSize: uint = 5 - cursor: Option[Index] = some(indexList[0]) + cursor: Opt[Index] = Opt.some(indexList[0]) forward: bool = false ## When @@ -332,7 +332,7 @@ procSuite "Queue driver - pagination": let pageSize: uint = 2 - cursor: Option[Index] = some(index) + cursor: Opt[Index] = Opt.some(index) forward: bool = false ## When @@ -348,7 +348,7 @@ procSuite "Queue driver - pagination": let driver = getTestQueueDriver(1) let pageSize: uint = 10 - cursor: Option[Index] = none(Index) + cursor: Opt[Index] = Opt.none(Index) forward: bool = false ## When @@ -364,7 +364,7 @@ procSuite "Queue driver - pagination": let driver = getTestQueueDriver(1) let pageSize: uint = 10 - cursor: Option[Index] = some(indexList[0]) + cursor: Opt[Index] = Opt.some(indexList[0]) forward: bool = false ## When @@ -379,7 +379,7 @@ procSuite "Queue driver - pagination": ## Given let pageSize: uint = 3 - cursor: Option[Index] = none(Index) + cursor: Opt[Index] = Opt.none(Index) forward = false proc onlyOddTimes(index: Index, msg: WakuMessage): bool = diff --git a/tests/waku_archive/test_driver_queue_query.nim b/tests/waku_archive/test_driver_queue_query.nim index ee371da41..12cf407c7 100644 --- a/tests/waku_archive/test_driver_queue_query.nim +++ b/tests/waku_archive/test_driver_queue_query.nim @@ -1,7 +1,7 @@ {.used.} import - std/[options, sequtils, random, algorithm], testutils/unittests, chronos, chronicles + results, std/[sequtils, random, algorithm], testutils/unittests, chronos, chronicles import logos_delivery/waku/[ waku_archive, waku_archive/driver/queue_driver, waku_core, waku_core/message/digest @@ -313,7 +313,7 @@ suite "SQLite driver - query by pubsub topic": ## When let res = waitFor driver.getMessages( - pubsubTopic = some(pubsubTopic), maxPageSize = 2, ascendingOrder = true + pubsubTopic = Opt.some(pubsubTopic), maxPageSize = 2, ascendingOrder = true ) ## Then @@ -438,7 +438,7 @@ suite "SQLite driver - query by pubsub topic": ## When let res = waitFor driver.getMessages( contentTopics = @[contentTopic], - pubsubTopic = some(pubsubTopic), + pubsubTopic = Opt.some(pubsubTopic), maxPageSize = 2, ascendingOrder = true, ) @@ -487,7 +487,7 @@ suite "Queue driver - query by cursor": ## When let res = waitFor driver.getMessages( - cursor = some(cursor), maxPageSize = 2, ascendingOrder = true + cursor = Opt.some(cursor), maxPageSize = 2, ascendingOrder = true ) ## Then @@ -532,7 +532,7 @@ suite "Queue driver - query by cursor": ## When let res = waitFor driver.getMessages( - cursor = some(cursor), maxPageSize = 2, ascendingOrder = false + cursor = Opt.some(cursor), maxPageSize = 2, ascendingOrder = false ) ## Then @@ -578,10 +578,10 @@ suite "Queue driver - query by cursor": let res = waitFor driver.getMessages( includeData = true, contentTopics = @[DefaultContentTopic], - pubsubTopic = none(PubsubTopic), - cursor = some(cursor), - startTime = none(Timestamp), - endTime = none(Timestamp), + pubsubTopic = Opt.none(PubsubTopic), + cursor = Opt.some(cursor), + startTime = Opt.none(Timestamp), + endTime = Opt.none(Timestamp), hashes = @[], maxPageSize = 5, ascendingOrder = true, @@ -627,7 +627,7 @@ suite "Queue driver - query by cursor": ## When let res = waitFor driver.getMessages( contentTopics = @[contentTopic], - cursor = some(cursor), + cursor = Opt.some(cursor), maxPageSize = 10, ascendingOrder = true, ) @@ -675,7 +675,7 @@ suite "Queue driver - query by cursor": ## When let res = waitFor driver.getMessages( contentTopics = @[contentTopic], - cursor = some(cursor), + cursor = Opt.some(cursor), maxPageSize = 10, ascendingOrder = false, ) @@ -750,8 +750,8 @@ suite "Queue driver - query by cursor": ## When let res = waitFor driver.getMessages( - pubsubTopic = some(pubsubTopic), - cursor = some(cursor), + pubsubTopic = Opt.some(pubsubTopic), + cursor = Opt.some(cursor), maxPageSize = 10, ascendingOrder = true, ) @@ -827,8 +827,8 @@ suite "Queue driver - query by cursor": ## When let res = waitFor driver.getMessages( - pubsubTopic = some(pubsubTopic), - cursor = some(cursor), + pubsubTopic = Opt.some(pubsubTopic), + cursor = Opt.some(cursor), maxPageSize = 10, ascendingOrder = false, ) @@ -876,7 +876,7 @@ suite "Queue driver - query by time range": ## When let res = waitFor driver.getMessages( - startTime = some(ts(15, timeOrigin)), maxPageSize = 10, ascendingOrder = true + startTime = Opt.some(ts(15, timeOrigin)), maxPageSize = 10, ascendingOrder = true ) ## Then @@ -920,7 +920,7 @@ suite "Queue driver - query by time range": ## When let res = waitFor driver.getMessages( - endTime = some(ts(45, timeOrigin)), maxPageSize = 10, ascendingOrder = true + endTime = Opt.some(ts(45, timeOrigin)), maxPageSize = 10, ascendingOrder = true ) ## Then @@ -993,8 +993,8 @@ suite "Queue driver - query by time range": ## When let res = waitFor driver.getMessages( - startTime = some(ts(15, timeOrigin)), - endTime = some(ts(45, timeOrigin)), + startTime = Opt.some(ts(15, timeOrigin)), + endTime = Opt.some(ts(45, timeOrigin)), maxPageSize = 10, ascendingOrder = true, ) @@ -1043,8 +1043,8 @@ suite "Queue driver - query by time range": ## When let res = waitFor driver.getMessages( contentTopics = @[contentTopic], - startTime = some(ts(45, timeOrigin)), - endTime = some(ts(15, timeOrigin)), + startTime = Opt.some(ts(45, timeOrigin)), + endTime = Opt.some(ts(15, timeOrigin)), maxPageSize = 2, ascendingOrder = true, ) @@ -1090,7 +1090,7 @@ suite "Queue driver - query by time range": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - startTime = some(ts(15, timeOrigin)), + startTime = Opt.some(ts(15, timeOrigin)), maxPageSize = 10, ascendingOrder = true, ) @@ -1139,7 +1139,7 @@ suite "Queue driver - query by time range": ## When let res = waitFor driver.getMessages( contentTopics = @[contentTopic], - startTime = some(ts(15, timeOrigin)), + startTime = Opt.some(ts(15, timeOrigin)), maxPageSize = 10, ascendingOrder = false, ) @@ -1191,8 +1191,8 @@ suite "Queue driver - query by time range": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - cursor = some(cursor), - startTime = some(ts(15, timeOrigin)), + cursor = Opt.some(cursor), + startTime = Opt.some(ts(15, timeOrigin)), maxPageSize = 10, ascendingOrder = true, ) @@ -1244,8 +1244,8 @@ suite "Queue driver - query by time range": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - cursor = some(cursor), - startTime = some(ts(15, timeOrigin)), + cursor = Opt.some(cursor), + startTime = Opt.some(ts(15, timeOrigin)), maxPageSize = 10, ascendingOrder = false, ) @@ -1317,10 +1317,10 @@ suite "Queue driver - query by time range": ## When let res = waitFor driver.getMessages( contentTopics = @[contentTopic], - pubsubTopic = some(pubsubTopic), - cursor = some(cursor), - startTime = some(ts(0, timeOrigin)), - endTime = some(ts(45, timeOrigin)), + pubsubTopic = Opt.some(pubsubTopic), + cursor = Opt.some(cursor), + startTime = Opt.some(ts(0, timeOrigin)), + endTime = Opt.some(ts(45, timeOrigin)), maxPageSize = 10, ascendingOrder = true, ) @@ -1392,10 +1392,10 @@ suite "Queue driver - query by time range": ## When let res = waitFor driver.getMessages( contentTopics = @[contentTopic], - pubsubTopic = some(pubsubTopic), - cursor = some(cursor), - startTime = some(ts(35, timeOrigin)), - endTime = some(ts(85, timeOrigin)), + pubsubTopic = Opt.some(pubsubTopic), + cursor = Opt.some(cursor), + startTime = Opt.some(ts(35, timeOrigin)), + endTime = Opt.some(ts(85, timeOrigin)), maxPageSize = 10, ascendingOrder = false, ) @@ -1468,10 +1468,10 @@ suite "Queue driver - query by time range": ## When let res = waitFor driver.getMessages( contentTopics = @[contentTopic], - pubsubTopic = some(pubsubTopic), - cursor = some(cursor), - startTime = some(ts(35, timeOrigin)), - endTime = some(ts(85, timeOrigin)), + pubsubTopic = Opt.some(pubsubTopic), + cursor = Opt.some(cursor), + startTime = Opt.some(ts(35, timeOrigin)), + endTime = Opt.some(ts(85, timeOrigin)), maxPageSize = 10, ascendingOrder = true, ) @@ -1545,10 +1545,10 @@ suite "Queue driver - query by time range": ## When let res = waitFor driver.getMessages( contentTopics = @[contentTopic], - pubsubTopic = some(pubsubTopic), - cursor = some(cursor), - startTime = some(ts(35, timeOrigin)), - endTime = some(ts(85, timeOrigin)), + pubsubTopic = Opt.some(pubsubTopic), + cursor = Opt.some(cursor), + startTime = Opt.some(ts(35, timeOrigin)), + endTime = Opt.some(ts(85, timeOrigin)), maxPageSize = 10, ascendingOrder = false, ) diff --git a/tests/waku_archive/test_driver_sqlite_query.nim b/tests/waku_archive/test_driver_sqlite_query.nim index fcd52e7fb..6d7df3ddf 100644 --- a/tests/waku_archive/test_driver_sqlite_query.nim +++ b/tests/waku_archive/test_driver_sqlite_query.nim @@ -1,7 +1,7 @@ {.used.} import - std/[options, sequtils, random, algorithm], testutils/unittests, chronos, chronicles + results, std/[sequtils, random, algorithm], testutils/unittests, chronos, chronicles import logos_delivery/waku/[waku_archive, waku_core, waku_core/message/digest], @@ -371,7 +371,7 @@ suite "SQLite driver - query by pubsub topic": ## When let res = await driver.getMessages( - pubsubTopic = some(pubsubTopic), maxPageSize = 2, ascendingOrder = true + pubsubTopic = Opt.some(pubsubTopic), maxPageSize = 2, ascendingOrder = true ) ## Then @@ -494,7 +494,7 @@ suite "SQLite driver - query by pubsub topic": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - pubsubTopic = some(pubsubTopic), + pubsubTopic = Opt.some(pubsubTopic), maxPageSize = 2, ascendingOrder = true, ) @@ -544,7 +544,7 @@ suite "SQLite driver - query by cursor": ## When let res = await driver.getMessages( - cursor = some(cursor), maxPageSize = 2, ascendingOrder = true + cursor = Opt.some(cursor), maxPageSize = 2, ascendingOrder = true ) ## Then @@ -590,7 +590,7 @@ suite "SQLite driver - query by cursor": ## When let res = await driver.getMessages( - cursor = some(cursor), maxPageSize = 2, ascendingOrder = false + cursor = Opt.some(cursor), maxPageSize = 2, ascendingOrder = false ) ## Then @@ -637,10 +637,10 @@ suite "SQLite driver - query by cursor": let res = await driver.getMessages( includeData = true, contentTopics = @[DefaultContentTopic], - pubsubTopic = none(PubsubTopic), - cursor = some(cursor), - startTime = none(Timestamp), - endTime = none(Timestamp), + pubsubTopic = Opt.none(PubsubTopic), + cursor = Opt.some(cursor), + startTime = Opt.none(Timestamp), + endTime = Opt.none(Timestamp), hashes = @[], maxPageSize = 5, ascendingOrder = true, @@ -687,7 +687,7 @@ suite "SQLite driver - query by cursor": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - cursor = some(cursor), + cursor = Opt.some(cursor), maxPageSize = 10, ascendingOrder = true, ) @@ -736,7 +736,7 @@ suite "SQLite driver - query by cursor": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - cursor = some(cursor), + cursor = Opt.some(cursor), maxPageSize = 10, ascendingOrder = false, ) @@ -810,8 +810,8 @@ suite "SQLite driver - query by cursor": ## When let res = await driver.getMessages( - pubsubTopic = some(pubsubTopic), - cursor = some(cursor), + pubsubTopic = Opt.some(pubsubTopic), + cursor = Opt.some(cursor), maxPageSize = 10, ascendingOrder = true, ) @@ -886,8 +886,8 @@ suite "SQLite driver - query by cursor": ## When let res = await driver.getMessages( - pubsubTopic = some(pubsubTopic), - cursor = some(cursor), + pubsubTopic = Opt.some(pubsubTopic), + cursor = Opt.some(cursor), maxPageSize = 10, ascendingOrder = false, ) @@ -936,7 +936,7 @@ suite "SQLite driver - query by time range": ## When let res = await driver.getMessages( - startTime = some(ts(15, timeOrigin)), maxPageSize = 10, ascendingOrder = true + startTime = Opt.some(ts(15, timeOrigin)), maxPageSize = 10, ascendingOrder = true ) ## Then @@ -981,7 +981,7 @@ suite "SQLite driver - query by time range": ## When let res = await driver.getMessages( - endTime = some(ts(45, timeOrigin)), maxPageSize = 10, ascendingOrder = true + endTime = Opt.some(ts(45, timeOrigin)), maxPageSize = 10, ascendingOrder = true ) ## Then @@ -1053,8 +1053,8 @@ suite "SQLite driver - query by time range": ## When let res = await driver.getMessages( - startTime = some(ts(15, timeOrigin)), - endTime = some(ts(45, timeOrigin)), + startTime = Opt.some(ts(15, timeOrigin)), + endTime = Opt.some(ts(45, timeOrigin)), maxPageSize = 10, ascendingOrder = true, ) @@ -1104,8 +1104,8 @@ suite "SQLite driver - query by time range": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - startTime = some(ts(45, timeOrigin)), - endTime = some(ts(15, timeOrigin)), + startTime = Opt.some(ts(45, timeOrigin)), + endTime = Opt.some(ts(15, timeOrigin)), maxPageSize = 2, ascendingOrder = true, ) @@ -1152,7 +1152,7 @@ suite "SQLite driver - query by time range": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - startTime = some(ts(15, timeOrigin)), + startTime = Opt.some(ts(15, timeOrigin)), maxPageSize = 10, ascendingOrder = true, ) @@ -1202,7 +1202,7 @@ suite "SQLite driver - query by time range": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - startTime = some(ts(15, timeOrigin)), + startTime = Opt.some(ts(15, timeOrigin)), maxPageSize = 10, ascendingOrder = false, ) @@ -1255,8 +1255,8 @@ suite "SQLite driver - query by time range": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - cursor = some(cursor), - startTime = some(ts(15, timeOrigin)), + cursor = Opt.some(cursor), + startTime = Opt.some(ts(15, timeOrigin)), maxPageSize = 10, ascendingOrder = true, ) @@ -1309,8 +1309,8 @@ suite "SQLite driver - query by time range": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - cursor = some(cursor), - startTime = some(ts(15, timeOrigin)), + cursor = Opt.some(cursor), + startTime = Opt.some(ts(15, timeOrigin)), maxPageSize = 10, ascendingOrder = false, ) @@ -1381,10 +1381,10 @@ suite "SQLite driver - query by time range": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - pubsubTopic = some(pubsubTopic), - cursor = some(cursor), - startTime = some(ts(0, timeOrigin)), - endTime = some(ts(45, timeOrigin)), + pubsubTopic = Opt.some(pubsubTopic), + cursor = Opt.some(cursor), + startTime = Opt.some(ts(0, timeOrigin)), + endTime = Opt.some(ts(45, timeOrigin)), maxPageSize = 10, ascendingOrder = true, ) @@ -1455,10 +1455,10 @@ suite "SQLite driver - query by time range": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - pubsubTopic = some(pubsubTopic), - cursor = some(cursor), - startTime = some(ts(35, timeOrigin)), - endTime = some(ts(85, timeOrigin)), + pubsubTopic = Opt.some(pubsubTopic), + cursor = Opt.some(cursor), + startTime = Opt.some(ts(35, timeOrigin)), + endTime = Opt.some(ts(85, timeOrigin)), maxPageSize = 10, ascendingOrder = false, ) @@ -1530,10 +1530,10 @@ suite "SQLite driver - query by time range": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - pubsubTopic = some(pubsubTopic), - cursor = some(cursor), - startTime = some(ts(35, timeOrigin)), - endTime = some(ts(85, timeOrigin)), + pubsubTopic = Opt.some(pubsubTopic), + cursor = Opt.some(cursor), + startTime = Opt.some(ts(35, timeOrigin)), + endTime = Opt.some(ts(85, timeOrigin)), maxPageSize = 10, ascendingOrder = true, ) @@ -1606,10 +1606,10 @@ suite "SQLite driver - query by time range": ## When let res = await driver.getMessages( contentTopics = @[contentTopic], - pubsubTopic = some(pubsubTopic), - cursor = some(cursor), - startTime = some(ts(35, timeOrigin)), - endTime = some(ts(85, timeOrigin)), + pubsubTopic = Opt.some(pubsubTopic), + cursor = Opt.some(cursor), + startTime = Opt.some(ts(35, timeOrigin)), + endTime = Opt.some(ts(85, timeOrigin)), maxPageSize = 10, ascendingOrder = false, ) diff --git a/tests/waku_archive/test_waku_archive.nim b/tests/waku_archive/test_waku_archive.nim index b6eb8d98e..ee7e26d86 100644 --- a/tests/waku_archive/test_waku_archive.nim +++ b/tests/waku_archive/test_waku_archive.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, sequtils], testutils/unittests, chronos, libp2p/crypto/crypto +import results, std/sequtils, testutils/unittests, chronos, libp2p/crypto/crypto import logos_delivery/waku/[ @@ -287,7 +287,7 @@ procSuite "Waku Archive - find messages": # This query targets: pubsubtopic1 AND (contentTopic1 OR contentTopic3) let req = ArchiveQuery( includeData: true, - pubsubTopic: some(pubsubTopic1), + pubsubTopic: Opt.some(pubsubTopic1), contentTopics: @[contentTopic1, contentTopic3], ) @@ -323,7 +323,7 @@ procSuite "Waku Archive - find messages": waitFor archive.handleMessage(pubsubtopic2, msg3) ## Given - let req = ArchiveQuery(pubsubTopic: some(pubsubTopic1)) + let req = ArchiveQuery(pubsubTopic: Opt.some(pubsubTopic1)) ## When let res = waitFor archive.findMessages(req) @@ -354,7 +354,7 @@ procSuite "Waku Archive - find messages": waitFor archive.handleMessage(pubsubTopic, msg3) ## Given - let req = ArchiveQuery(includeData: true, pubsubTopic: some(pubsubTopic)) + let req = ArchiveQuery(includeData: true, pubsubTopic: Opt.some(pubsubTopic)) ## When let res = waitFor archive.findMessages(req) @@ -379,7 +379,7 @@ procSuite "Waku Archive - find messages": var nextReq = req # copy var pages = newSeq[seq[WakuMessage]](3) - var cursors = newSeq[Option[ArchiveCursor]](3) + var cursors = newSeq[Opt[ArchiveCursor]](3) for i in 0 ..< 3: let res = waitFor archiveA.findMessages(nextReq) @@ -395,9 +395,9 @@ procSuite "Waku Archive - find messages": ## Then check: - cursors[0] == some(computeMessageHash(DefaultPubsubTopic, msgListA[3])) - cursors[1] == some(computeMessageHash(DefaultPubsubTopic, msgListA[7])) - cursors[2] == none(ArchiveCursor) + cursors[0] == Opt.some(computeMessageHash(DefaultPubsubTopic, msgListA[3])) + cursors[1] == Opt.some(computeMessageHash(DefaultPubsubTopic, msgListA[7])) + cursors[2] == Opt.none(ArchiveCursor) check: pages[0] == msgListA[0 .. 3] @@ -413,7 +413,7 @@ procSuite "Waku Archive - find messages": var nextReq = req # copy var pages = newSeq[seq[WakuMessage]](3) - var cursors = newSeq[Option[ArchiveCursor]](3) + var cursors = newSeq[Opt[ArchiveCursor]](3) for i in 0 ..< 3: let res = waitFor archiveA.findMessages(nextReq) @@ -429,9 +429,9 @@ procSuite "Waku Archive - find messages": ## Then check: - cursors[0] == some(computeMessageHash(DefaultPubsubTopic, msgListA[6])) - cursors[1] == some(computeMessageHash(DefaultPubsubTopic, msgListA[2])) - cursors[2] == none(ArchiveCursor) + cursors[0] == Opt.some(computeMessageHash(DefaultPubsubTopic, msgListA[6])) + cursors[1] == Opt.some(computeMessageHash(DefaultPubsubTopic, msgListA[2])) + cursors[2] == Opt.none(ArchiveCursor) check: pages[0] == msgListA[6 .. 9] @@ -486,8 +486,8 @@ procSuite "Waku Archive - find messages": let req = ArchiveQuery( includeData: true, contentTopics: @[ContentTopic("1")], - startTime: some(ts(15, timeOrigin)), - endTime: some(ts(55, timeOrigin)), + startTime: Opt.some(ts(15, timeOrigin)), + endTime: Opt.some(ts(55, timeOrigin)), direction: PagingDirection.FORWARD, ) @@ -507,8 +507,8 @@ procSuite "Waku Archive - find messages": ## Given let req = ArchiveQuery( contentTopics: @[ContentTopic("1")], - startTime: some(Timestamp(2)), - endTime: some(Timestamp(2)), + startTime: Opt.some(Timestamp(2)), + endTime: Opt.some(Timestamp(2)), ) ## When @@ -526,8 +526,8 @@ procSuite "Waku Archive - find messages": ## Given let req = ArchiveQuery( contentTopics: @[ContentTopic("1")], - startTime: some(Timestamp(5)), - endTime: some(Timestamp(2)), + startTime: Opt.some(Timestamp(5)), + endTime: Opt.some(Timestamp(2)), ) ## When diff --git a/tests/waku_core/test_namespaced_topics.nim b/tests/waku_core/test_namespaced_topics.nim index 9cb378b57..1a1e23816 100644 --- a/tests/waku_core/test_namespaced_topics.nim +++ b/tests/waku_core/test_namespaced_topics.nim @@ -1,13 +1,13 @@ {.used.} -import std/options, results, testutils/unittests +import results, testutils/unittests import logos_delivery/waku/waku_core/topics suite "Waku Message - Content topics namespacing": test "Stringify namespaced content topic": ## Given var ns = NsContentTopic() - ns.generation = none(int) + ns.generation = Opt.none(int) ns.application = "toychat" ns.version = "2" ns.name = "huilong" @@ -32,7 +32,7 @@ suite "Waku Message - Content topics namespacing": let ns = nsRes.get() check: - ns.generation == none(int) + ns.generation == Opt.none(int) ns.application == "toychat" ns.version == "2" ns.name == "huilong" @@ -50,7 +50,7 @@ suite "Waku Message - Content topics namespacing": let ns = nsRes.get() check: - ns.generation == some(0) + ns.generation == Opt.some(0) ns.application == "toychat" ns.version == "2" ns.name == "huilong" diff --git a/tests/waku_core/test_peers.nim b/tests/waku_core/test_peers.nim index 246a1d6d8..8f3b00df0 100644 --- a/tests/waku_core/test_peers.nim +++ b/tests/waku_core/test_peers.nim @@ -1,6 +1,5 @@ {.used.} -import std/options import results, testutils/unittests, @@ -156,9 +155,9 @@ suite "Waku Core - Peers": ## When var builder = EnrBuilder.init(enrPrivKey, seqNum = enrSeqNum) builder.withIpAddressAndPorts( - ipAddr = some(parseIpAddress("127.0.0.1")), - tcpPort = some(Port(0)), - udpPort = some(Port(0)), + ipAddr = Opt.some(parseIpAddress("127.0.0.1")), + tcpPort = Opt.some(Port(0)), + udpPort = Opt.some(Port(0)), ) builder.withWakuCapabilities(Capabilities.Relay, Capabilities.Store) diff --git a/tests/waku_core/topics/test_pubsub_topic.nim b/tests/waku_core/topics/test_pubsub_topic.nim index 5ebf92b51..5aa5b4125 100644 --- a/tests/waku_core/topics/test_pubsub_topic.nim +++ b/tests/waku_core/topics/test_pubsub_topic.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options], testutils/unittests, results +import testutils/unittests, results import logos_delivery/waku/waku_core/topics/pubsub_topic, ../../testlib/[wakucore] diff --git a/tests/waku_core/topics/test_sharding.nim b/tests/waku_core/topics/test_sharding.nim index 5979269e8..c73d8c598 100644 --- a/tests/waku_core/topics/test_sharding.nim +++ b/tests/waku_core/topics/test_sharding.nim @@ -1,4 +1,4 @@ -import std/[options, tables], testutils/unittests +import results, std/tables, testutils/unittests import logos_delivery/waku/waku_core/topics, ../../testlib/[wakucore, tables, testutils] @@ -143,7 +143,7 @@ suite "Autosharding": let sharding = Sharding(clusterId: ClusterId, shardCountGenZero: GenerationZeroShardsCount) # When calling with contentTopic as string - let topicMap = sharding.parseSharding(some(pubsubTopic04), contentTopicShort) + let topicMap = sharding.parseSharding(Opt.some(pubsubTopic04), contentTopicShort) # Then the topicMap is valid check: @@ -154,7 +154,7 @@ suite "Autosharding": Sharding(clusterId: ClusterId, shardCountGenZero: GenerationZeroShardsCount) # When calling with contentTopic as string seq let topicMap = sharding.parseSharding( - some(pubsubTopic04), @[contentTopicShort, "/0/foo/1/bar/proto"] + Opt.some(pubsubTopic04), @[contentTopicShort, "/0/foo/1/bar/proto"] ) # Then the topicMap is valid @@ -165,7 +165,7 @@ suite "Autosharding": let sharding = Sharding(clusterId: ClusterId, shardCountGenZero: GenerationZeroShardsCount) # When calling with pubsubTopic as none - let topicMap = sharding.parseSharding(PubsubTopic.none(), contentTopicShort) + let topicMap = sharding.parseSharding(Opt.none(PubsubTopic), contentTopicShort) # Then the topicMap is valid check: @@ -175,7 +175,7 @@ suite "Autosharding": let sharding = Sharding(clusterId: ClusterId, shardCountGenZero: GenerationZeroShardsCount) # When calling with pubsubTopic as none with invalid content - let topicMap = sharding.parseSharding(PubsubTopic.none(), "invalid") + let topicMap = sharding.parseSharding(Opt.none(PubsubTopic), "invalid") # Then the topicMap is valid check: @@ -186,7 +186,7 @@ suite "Autosharding": let sharding = Sharding(clusterId: ClusterId, shardCountGenZero: GenerationZeroShardsCount) # When calling with pubsubTopic as none with invalid content - let topicMap = sharding.parseSharding(some("invalid"), contentTopicShort) + let topicMap = sharding.parseSharding(Opt.some("invalid"), contentTopicShort) # Then the topicMap is valid check: @@ -197,7 +197,7 @@ suite "Autosharding": let sharding = Sharding(clusterId: ClusterId, shardCountGenZero: GenerationZeroShardsCount) # When calling with pubsubTopic as none with invalid content - let topicMap = sharding.parseSharding(PubsubTopic.none(), contentTopicInvalid) + let topicMap = sharding.parseSharding(Opt.none(PubsubTopic), contentTopicInvalid) # Then the topicMap is valid check: diff --git a/tests/waku_discv5/test_waku_discv5.nim b/tests/waku_discv5/test_waku_discv5.nim index 7f42e3b80..be24ee9ad 100644 --- a/tests/waku_discv5/test_waku_discv5.nim +++ b/tests/waku_discv5/test_waku_discv5.nim @@ -2,7 +2,7 @@ import libp2p/crypto/rng {.used.} import - std/[sequtils, algorithm, options, net], + std/[sequtils, algorithm, net], results, chronos, chronicles, @@ -183,7 +183,7 @@ suite "Waku Discovery v5": bindIp: string = "0.0.0.0", extIp: string = "127.0.0.1", indices: seq[uint64] = @[], - recordFlags: Option[CapabilitiesBitfield] = none(CapabilitiesBitfield), + recordFlags: Opt[CapabilitiesBitfield] = Opt.none(CapabilitiesBitfield), bootstrapRecords: seq[waku_enr.Record] = @[], ): Future[Result[(WakuDiscoveryV5, waku_enr.Record), string]] {.async.} = let privKey = generateSecp256k1Key() @@ -265,7 +265,7 @@ suite "Waku Discovery v5": await buildNode( tcpPort = 61504u16, recordFlags = - some(CapabilitiesBitfield.init(Capabilities.Relay, Capabilities.Filter)), + Opt.some(CapabilitiesBitfield.init(Capabilities.Relay, Capabilities.Filter)), ) ).valueOr: raiseAssert "node3: " & error @@ -273,7 +273,7 @@ suite "Waku Discovery v5": await buildNode( tcpPort = 61506u16, recordFlags = - some(CapabilitiesBitfield.init(Capabilities.Relay, Capabilities.Store)), + Opt.some(CapabilitiesBitfield.init(Capabilities.Relay, Capabilities.Store)), ) ).valueOr: raiseAssert "node4: " & error @@ -281,7 +281,7 @@ suite "Waku Discovery v5": await buildNode( tcpPort = 61502u16, recordFlags = - some(CapabilitiesBitfield.init(Capabilities.Relay, Capabilities.Store)), + Opt.some(CapabilitiesBitfield.init(Capabilities.Relay, Capabilities.Store)), bootstrapRecords = @[record3, record4], ) ).valueOr: @@ -289,7 +289,7 @@ suite "Waku Discovery v5": let (node1, record1) = ( await buildNode( tcpPort = 61500u16, - recordFlags = some(CapabilitiesBitfield.init(Capabilities.Relay)), + recordFlags = Opt.some(CapabilitiesBitfield.init(Capabilities.Relay)), bootstrapRecords = @[record2], ) ).valueOr: @@ -298,7 +298,7 @@ suite "Waku Discovery v5": await sleepAsync(FUTURE_TIMEOUT) ## When - let peers = await node1.findRandomPeers(some(filterForStore)) + let peers = await node1.findRandomPeers(Opt.some(filterForStore)) ## Then check: @@ -317,7 +317,7 @@ suite "Waku Discovery v5": await buildNode( tcpPort = 61504u16, recordFlags = - some(CapabilitiesBitfield.init(Capabilities.Relay, Capabilities.Filter)), + Opt.some(CapabilitiesBitfield.init(Capabilities.Relay, Capabilities.Filter)), ) ).valueOr: raiseAssert "node3: " & error @@ -325,7 +325,7 @@ suite "Waku Discovery v5": await buildNode( tcpPort = 61506u16, recordFlags = - some(CapabilitiesBitfield.init(Capabilities.Relay, Capabilities.Store)), + Opt.some(CapabilitiesBitfield.init(Capabilities.Relay, Capabilities.Store)), ) ).valueOr: raiseAssert "node4: " & error @@ -333,7 +333,7 @@ suite "Waku Discovery v5": await buildNode( tcpPort = 61502u16, recordFlags = - some(CapabilitiesBitfield.init(Capabilities.Relay, Capabilities.Store)), + Opt.some(CapabilitiesBitfield.init(Capabilities.Relay, Capabilities.Store)), bootstrapRecords = @[record3, record4], ) ).valueOr: @@ -341,7 +341,7 @@ suite "Waku Discovery v5": let (node1, record1) = ( await buildNode( tcpPort = 61500u16, - recordFlags = some(CapabilitiesBitfield.init(Capabilities.Relay)), + recordFlags = Opt.some(CapabilitiesBitfield.init(Capabilities.Relay)), indices = @[0u64, 0u64, 1u64, 0u64, 0u64], bootstrapRecords = @[record2], ) diff --git a/tests/waku_discv5/utils.nim b/tests/waku_discv5/utils.nim index bbb47308e..ddea3896d 100644 --- a/tests/waku_discv5/utils.nim +++ b/tests/waku_discv5/utils.nim @@ -1,4 +1,4 @@ -import std/options, chronos, libp2p/crypto/crypto as libp2p_keys, eth/keys as eth_keys +import results, chronos, libp2p/crypto/crypto as libp2p_keys, eth/keys as eth_keys import logos_delivery/waku/ @@ -13,7 +13,7 @@ proc newTestDiscv5*( record: waku_enr.Record, bootstrapRecords = newSeq[waku_enr.Record](), queue = newAsyncEventQueue[SubscriptionEvent](30), - peerManager: Option[PeerManager] = none(PeerManager), + peerManager: Opt[PeerManager] = Opt.none(PeerManager), ): WakuDiscoveryV5 = let config = WakuDiscoveryV5Config( privateKey: eth_keys.PrivateKey(privKey.skkey), @@ -25,7 +25,7 @@ proc newTestDiscv5*( let discv5 = WakuDiscoveryV5.new( rng = rng(), conf = config, - record = some(record), + record = Opt.some(record), queue = queue, peerManager = peerManager, ) diff --git a/tests/waku_enr/utils.nim b/tests/waku_enr/utils.nim index c9948e268..a1c3d88d2 100644 --- a/tests/waku_enr/utils.nim +++ b/tests/waku_enr/utils.nim @@ -1,10 +1,5 @@ import - std/options, - sequtils, - results, - chronos, - libp2p/crypto/crypto as libp2p_keys, - eth/keys as eth_keys + sequtils, results, chronos, libp2p/crypto/crypto as libp2p_keys, eth/keys as eth_keys import logos_delivery/waku/[waku_enr, discovery/waku_discv5, waku_enr/sharding], @@ -16,13 +11,13 @@ proc newTestEnrRecord*( tcpPort: uint16, udpPort: uint16, indices: seq[uint64] = @[], - flags = none(CapabilitiesBitfield), + flags = Opt.none(CapabilitiesBitfield), ): waku_enr.Record = var builder = EnrBuilder.init(privKey) builder.withIpAddressAndPorts( - ipAddr = some(parseIpAddress(extIp)), - tcpPort = some(Port(tcpPort)), - udpPort = some(Port(udpPort)), + ipAddr = Opt.some(parseIpAddress(extIp)), + tcpPort = Opt.some(Port(tcpPort)), + udpPort = Opt.some(Port(udpPort)), ) if indices.len > 0: diff --git a/tests/waku_filter_v2/test_waku_client.nim b/tests/waku_filter_v2/test_waku_client.nim index 8a802d911..8141a139e 100644 --- a/tests/waku_filter_v2/test_waku_client.nim +++ b/tests/waku_filter_v2/test_waku_client.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, sequtils, json], testutils/unittests, results, chronos +import std/[sequtils, json], testutils/unittests, results, chronos import logos_delivery/waku/node/peer_manager, diff --git a/tests/waku_filter_v2/test_waku_filter_dos_protection.nim b/tests/waku_filter_v2/test_waku_filter_dos_protection.nim index c55a9b4cd..ab8d202bb 100644 --- a/tests/waku_filter_v2/test_waku_filter_dos_protection.nim +++ b/tests/waku_filter_v2/test_waku_filter_dos_protection.nim @@ -1,7 +1,7 @@ {.used.} import - std/[options, tables, json], + std/[tables, json], testutils/unittests, results, chronos, @@ -44,37 +44,37 @@ proc subscribe( serverRemotePeerInfo: RemotePeerInfo, pubsubTopic: PubsubTopic, contentTopicSeq: seq[ContentTopic], -): Option[FilterSubscribeErrorKind] = +): Opt[FilterSubscribeErrorKind] = let subscribeResponse = waitFor client.wakuFilterClient.subscribe( serverRemotePeerInfo, pubsubTopic, contentTopicSeq ) if subscribeResponse.isOk(): - return none[FilterSubscribeErrorKind]() + return Opt.none(FilterSubscribeErrorKind) - return some(subscribeResponse.error().kind) + return Opt.some(subscribeResponse.error().kind) proc unsubscribe( client: AFilterClient, serverRemotePeerInfo: RemotePeerInfo, pubsubTopic: PubsubTopic, contentTopicSeq: seq[ContentTopic], -): Option[FilterSubscribeErrorKind] = +): Opt[FilterSubscribeErrorKind] = let unsubscribeResponse = waitFor client.wakuFilterClient.unsubscribe( serverRemotePeerInfo, pubsubTopic, contentTopicSeq ) if unsubscribeResponse.isOk(): - return none[FilterSubscribeErrorKind]() + return Opt.none(FilterSubscribeErrorKind) - return some(unsubscribeResponse.error().kind) + return Opt.some(unsubscribeResponse.error().kind) proc ping( client: AFilterClient, serverRemotePeerInfo: RemotePeerInfo -): Option[FilterSubscribeErrorKind] = +): Opt[FilterSubscribeErrorKind] = let pingResponse = waitFor client.wakuFilterClient.ping(serverRemotePeerInfo) if pingResponse.isOk(): - return none[FilterSubscribeErrorKind]() + return Opt.none(FilterSubscribeErrorKind) - return some(pingResponse.error().kind) + return Opt.some(pingResponse.error().kind) suite "Waku Filter - DOS protection": var serverSwitch {.threadvar.}: Switch @@ -95,7 +95,7 @@ suite "Waku Filter - DOS protection": contentTopicSeq = @[contentTopic] serverSwitch = newStandardSwitch() wakuFilter = await newTestWakuFilter( - serverSwitch, rateLimitSetting = some((3, 1000.milliseconds)) + serverSwitch, rateLimitSetting = Opt.some((3, 1000.milliseconds)) ) await allFutures( @@ -118,9 +118,9 @@ suite "Waku Filter - DOS protection": asyncTest "Limit number of subscriptions requests": # Given check client1.subscribe(serverRemotePeerInfo, pubsubTopic, contentTopicSeq) == - none(FilterSubscribeErrorKind) + Opt.none(FilterSubscribeErrorKind) check client2.subscribe(serverRemotePeerInfo, pubsubTopic, contentTopicSeq) == - none(FilterSubscribeErrorKind) + Opt.none(FilterSubscribeErrorKind) # Avoid using tiny sleeps to control refill behavior: CI scheduling can # oversleep and mint additional tokens. Instead, issue a small burst of @@ -145,7 +145,7 @@ suite "Waku Filter - DOS protection": # Ensure the other client is not affected by client1's rate limit. check client2.subscribe(serverRemotePeerInfo, pubsubTopic, contentTopicSeq) == - none(FilterSubscribeErrorKind) + Opt.none(FilterSubscribeErrorKind) var c2SubscribeFutures = newSeq[Future[FilterSubscribeResult]]() for i in 0 ..< 6: @@ -168,9 +168,9 @@ suite "Waku Filter - DOS protection": # ensure period of time has passed and clients can again use the service await sleepAsync(1100.milliseconds) check client1.subscribe(serverRemotePeerInfo, pubsubTopic, contentTopicSeq) == - none(FilterSubscribeErrorKind) + Opt.none(FilterSubscribeErrorKind) check client2.subscribe(serverRemotePeerInfo, pubsubTopic, contentTopicSeq) == - none(FilterSubscribeErrorKind) + Opt.none(FilterSubscribeErrorKind) asyncTest "Ensure normal usage allowed": # Given @@ -180,28 +180,29 @@ suite "Waku Filter - DOS protection": # - refill rate = 3 tokens / second => ~1 token every ~333ms # - each request consumes 1 token (including UNSUBSCRIBE) check client1.subscribe(serverRemotePeerInfo, pubsubTopic, contentTopicSeq) == - none(FilterSubscribeErrorKind) + Opt.none(FilterSubscribeErrorKind) check wakuFilter.subscriptions.isSubscribed(client1.clientPeerId) # Expected remaining tokens (approx): 2 await sleepAsync(500.milliseconds) - check client1.ping(serverRemotePeerInfo) == none(FilterSubscribeErrorKind) + check client1.ping(serverRemotePeerInfo) == Opt.none(FilterSubscribeErrorKind) check wakuFilter.subscriptions.isSubscribed(client1.clientPeerId) # After ~500ms, ~1 token refilled; PING consumes 1 => expected remaining: 2 await sleepAsync(500.milliseconds) - check client1.ping(serverRemotePeerInfo) == none(FilterSubscribeErrorKind) + check client1.ping(serverRemotePeerInfo) == Opt.none(FilterSubscribeErrorKind) check wakuFilter.subscriptions.isSubscribed(client1.clientPeerId) # After another ~500ms, ~1 token refilled; PING consumes 1 => expected remaining: 2 check client1.unsubscribe(serverRemotePeerInfo, pubsubTopic, contentTopicSeq) == - none(FilterSubscribeErrorKind) + Opt.none(FilterSubscribeErrorKind) check wakuFilter.subscriptions.isSubscribed(client1.clientPeerId) == false - check client1.ping(serverRemotePeerInfo) == some(FilterSubscribeErrorKind.NOT_FOUND) + check client1.ping(serverRemotePeerInfo) == + Opt.some(FilterSubscribeErrorKind.NOT_FOUND) # After unsubscribing, PING is expected to return NOT_FOUND while still # counting towards the rate limit. @@ -225,5 +226,5 @@ suite "Waku Filter - DOS protection": check gotTooMany check client2.subscribe(serverRemotePeerInfo, pubsubTopic, contentTopicSeq) == - none(FilterSubscribeErrorKind) + Opt.none(FilterSubscribeErrorKind) check wakuFilter.subscriptions.isSubscribed(client2.clientPeerId) == true diff --git a/tests/waku_filter_v2/waku_filter_utils.nim b/tests/waku_filter_v2/waku_filter_utils.nim index d03922998..cabd6a10a 100644 --- a/tests/waku_filter_v2/waku_filter_utils.nim +++ b/tests/waku_filter_v2/waku_filter_utils.nim @@ -1,4 +1,4 @@ -import std/[options, tables, sets, algorithm], chronos, chronicles, os +import results, std/[tables, sets, algorithm], chronos, chronicles, os import logos_delivery/waku/[ @@ -16,7 +16,7 @@ proc newTestWakuFilter*( subscriptionTimeout: Duration = DefaultSubscriptionTimeToLiveSec, maxFilterPeers: uint32 = MaxFilterPeers, maxFilterCriteriaPerPeer: uint32 = MaxFilterCriteriaPerPeer, - rateLimitSetting: Option[RateLimitSetting] = none[RateLimitSetting](), + rateLimitSetting: Opt[RateLimitSetting] = Opt.none(RateLimitSetting), ): Future[WakuFilter] {.async.} = let peerManager = PeerManager.new(switch) diff --git a/tests/waku_kademlia/test_waku_kademlia.nim b/tests/waku_kademlia/test_waku_kademlia.nim index f4b84bf41..2ecfd47a7 100644 --- a/tests/waku_kademlia/test_waku_kademlia.nim +++ b/tests/waku_kademlia/test_waku_kademlia.nim @@ -1,5 +1,5 @@ import - std/[options, sequtils, strutils], + std/[sequtils, strutils], results, chronos, chronicles, diff --git a/tests/waku_kademlia/utils.nim b/tests/waku_kademlia/utils.nim index 1057872d8..5f4300432 100644 --- a/tests/waku_kademlia/utils.nim +++ b/tests/waku_kademlia/utils.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, sets] +import std/sets import chronos, chronicles, results import libp2p/[peerid, multiaddress, switch] import libp2p/extended_peer_record diff --git a/tests/waku_lightpush/lightpush_utils.nim b/tests/waku_lightpush/lightpush_utils.nim index d4a8b12e2..4d6ac76b9 100644 --- a/tests/waku_lightpush/lightpush_utils.nim +++ b/tests/waku_lightpush/lightpush_utils.nim @@ -1,6 +1,6 @@ {.used.} -import std/options, chronos, chronicles, libp2p/crypto/crypto +import results, chronos, chronicles, libp2p/crypto/crypto import logos_delivery/waku/node/peer_manager, @@ -14,13 +14,17 @@ import proc newTestWakuLightpushNode*( switch: Switch, handler: PushMessageHandler, - rateLimitSetting: Option[RateLimitSetting] = none[RateLimitSetting](), + rateLimitSetting: Opt[RateLimitSetting] = Opt.none(RateLimitSetting), ): Future[WakuLightPush] {.async.} = let peerManager = PeerManager.new(switch) wakuAutoSharding = Sharding(clusterId: 1, shardCountGenZero: 8) proto = WakuLightPush.new( - peerManager, crypto.newRng(), handler, some(wakuAutoSharding), rateLimitSetting + peerManager, + crypto.newRng(), + handler, + Opt.some(wakuAutoSharding), + rateLimitSetting, ) await proto.start() diff --git a/tests/waku_lightpush/test_client.nim b/tests/waku_lightpush/test_client.nim index c7bf7b4a6..3e8e1a359 100644 --- a/tests/waku_lightpush/test_client.nim +++ b/tests/waku_lightpush/test_client.nim @@ -1,11 +1,7 @@ {.used.} import - std/[options, strscans], - testutils/unittests, - chronos, - chronicles, - libp2p/crypto/crypto + results, std/strscans, testutils/unittests, chronos, chronicles, libp2p/crypto/crypto import logos_delivery/waku/[ @@ -80,7 +76,7 @@ suite "Waku Lightpush Client": # When publishing a valid payload let publishResponse = - await client.publish(some(pubsubTopic), message, serverRemotePeerInfo) + await client.publish(Opt.some(pubsubTopic), message, serverRemotePeerInfo) # Then the message is received by the server discard await handlerFuture.withTimeout(FUTURE_TIMEOUT) @@ -93,7 +89,7 @@ suite "Waku Lightpush Client": # When publishing a valid payload handlerFuture = newPushHandlerFuture() let publishResponse2 = await client.publish( - some(pubsub_topics.CURRENT), message2, serverRemotePeerInfo + Opt.some(pubsub_topics.CURRENT), message2, serverRemotePeerInfo ) # Then the message is received by the server @@ -107,7 +103,7 @@ suite "Waku Lightpush Client": # When publishing a valid payload handlerFuture = newPushHandlerFuture() let publishResponse3 = await client.publish( - some(pubsub_topics.CURRENT_NESTED), message3, serverRemotePeerInfo + Opt.some(pubsub_topics.CURRENT_NESTED), message3, serverRemotePeerInfo ) # Then the message is received by the server @@ -121,7 +117,7 @@ suite "Waku Lightpush Client": # When publishing a valid payload handlerFuture = newPushHandlerFuture() let publishResponse4 = await client.publish( - some(pubsub_topics.SHARDING), message4, serverRemotePeerInfo + Opt.some(pubsub_topics.SHARDING), message4, serverRemotePeerInfo ) # Then the message is received by the server @@ -134,8 +130,9 @@ suite "Waku Lightpush Client": # When publishing a valid payload handlerFuture = newPushHandlerFuture() - let publishResponse5 = - await client.publish(some(pubsub_topics.PLAIN), message5, serverRemotePeerInfo) + let publishResponse5 = await client.publish( + Opt.some(pubsub_topics.PLAIN), message5, serverRemotePeerInfo + ) # Then the message is received by the server discard await handlerFuture.withTimeout(FUTURE_TIMEOUT) @@ -147,8 +144,9 @@ suite "Waku Lightpush Client": # When publishing a valid payload handlerFuture = newPushHandlerFuture() - let publishResponse6 = - await client.publish(some(pubsub_topics.LEGACY), message6, serverRemotePeerInfo) + let publishResponse6 = await client.publish( + Opt.some(pubsub_topics.LEGACY), message6, serverRemotePeerInfo + ) # Then the message is received by the server discard await handlerFuture.withTimeout(FUTURE_TIMEOUT) @@ -161,7 +159,7 @@ suite "Waku Lightpush Client": # When publishing a valid payload handlerFuture = newPushHandlerFuture() let publishResponse7 = await client.publish( - some(pubsub_topics.LEGACY_NESTED), message7, serverRemotePeerInfo + Opt.some(pubsub_topics.LEGACY_NESTED), message7, serverRemotePeerInfo ) # Then the message is received by the server @@ -175,7 +173,7 @@ suite "Waku Lightpush Client": # When publishing a valid payload handlerFuture = newPushHandlerFuture() let publishResponse8 = await client.publish( - some(pubsub_topics.LEGACY_ENCODING), message8, serverRemotePeerInfo + Opt.some(pubsub_topics.LEGACY_ENCODING), message8, serverRemotePeerInfo ) # Then the message is received by the server @@ -189,7 +187,7 @@ suite "Waku Lightpush Client": # When publishing a valid payload handlerFuture = newPushHandlerFuture() let publishResponse9 = - await client.publish(some(pubsubTopic), message9, serverRemotePeerInfo) + await client.publish(Opt.some(pubsubTopic), message9, serverRemotePeerInfo) # Then the message is received by the server discard await handlerFuture.withTimeout(FUTURE_TIMEOUT) @@ -223,7 +221,7 @@ suite "Waku Lightpush Client": # When publishing the 1KiB payload let publishResponse1 = - await client.publish(some(pubsubTopic), message1, serverRemotePeerInfo) + await client.publish(Opt.some(pubsubTopic), message1, serverRemotePeerInfo) # Then the message is received by the server assertResultOk publishResponse1 @@ -232,7 +230,7 @@ suite "Waku Lightpush Client": # When publishing the 10KiB payload handlerFuture = newPushHandlerFuture() let publishResponse2 = - await client.publish(some(pubsubTopic), message2, serverRemotePeerInfo) + await client.publish(Opt.some(pubsubTopic), message2, serverRemotePeerInfo) # Then the message is received by the server assertResultOk publishResponse2 @@ -241,7 +239,7 @@ suite "Waku Lightpush Client": # When publishing the 100KiB payload handlerFuture = newPushHandlerFuture() let publishResponse3 = - await client.publish(some(pubsubTopic), message3, serverRemotePeerInfo) + await client.publish(Opt.some(pubsubTopic), message3, serverRemotePeerInfo) # Then the message is received by the server assertResultOk publishResponse3 @@ -250,7 +248,7 @@ suite "Waku Lightpush Client": # When publishing the 1MiB + 63KiB + 911B payload (1113999B) handlerFuture = newPushHandlerFuture() let publishResponse4 = - await client.publish(some(pubsubTopic), message4, serverRemotePeerInfo) + await client.publish(Opt.some(pubsubTopic), message4, serverRemotePeerInfo) # Then the message is received by the server assertResultOk publishResponse4 @@ -259,7 +257,7 @@ suite "Waku Lightpush Client": # When publishing the 1MiB + 63KiB + 912B payload (1114000B) handlerFuture = newPushHandlerFuture() let publishResponse5 = - await client.publish(some(pubsubTopic), message5, serverRemotePeerInfo) + await client.publish(Opt.some(pubsubTopic), message5, serverRemotePeerInfo) # Then the message is not received by the server check: @@ -302,12 +300,12 @@ suite "Waku Lightpush Client": # When publishing a payload let publishResponse = - await client.publish(some(pubsubTopic), message, serverRemotePeerInfo2) + await client.publish(Opt.some(pubsubTopic), message, serverRemotePeerInfo2) # Then the response is negative check: publishResponse.error.code == LightPushErrorCode.PAYLOAD_TOO_LARGE - publishResponse.error.desc == some(handlerError) + publishResponse.error.desc == Opt.some(handlerError) (await handlerFuture2.waitForResult()).isOk() # Cleanup @@ -325,7 +323,7 @@ suite "Waku Lightpush Client": # When publishing a valid payload let publishResponse = - await client.publish(some(pubsubTopic), message, serverRemotePeerInfo) + await client.publish(Opt.some(pubsubTopic), message, serverRemotePeerInfo) # Then the message is received by the server discard await handlerFuture.withTimeout(FUTURE_TIMEOUT) @@ -350,7 +348,7 @@ suite "Waku Lightpush Client": asyncTest "Positive Responses": # When sending a valid PushRequest let publishResponse = - await client.publish(some(pubsubTopic), message, serverRemotePeerInfo) + await client.publish(Opt.some(pubsubTopic), message, serverRemotePeerInfo) # Then the response is positive assertResultOk publishResponse @@ -366,7 +364,7 @@ suite "Waku Lightpush Client": # When sending an invalid PushRequest let publishResponse = - await client.publish(some(pubsubTopic), message, serverRemotePeerInfo2) + await client.publish(Opt.some(pubsubTopic), message, serverRemotePeerInfo2) # Then the response is negative check not publishResponse.isOk() diff --git a/tests/waku_lightpush/test_ratelimit.nim b/tests/waku_lightpush/test_ratelimit.nim index 8500ad8b2..143ee28b9 100644 --- a/tests/waku_lightpush/test_ratelimit.nim +++ b/tests/waku_lightpush/test_ratelimit.nim @@ -1,6 +1,6 @@ {.used.} -import std/options, testutils/unittests, chronos, libp2p/crypto/crypto +import results, testutils/unittests, chronos, libp2p/crypto/crypto import logos_delivery/waku/ @@ -27,8 +27,9 @@ suite "Rate limited push service": let tokenPeriod = 500.millis - server = - await newTestWakuLightpushNode(serverSwitch, handler, some((3, tokenPeriod))) + server = await newTestWakuLightpushNode( + serverSwitch, handler, Opt.some((3, tokenPeriod)) + ) client = newTestWakuLightpushClient(clientSwitch) let serverPeerId = serverSwitch.peerInfo.toRemotePeerInfo() @@ -38,7 +39,7 @@ suite "Rate limited push service": handlerFuture = newFuture[(string, WakuMessage)]() let requestRes = - await client.publish(some(DefaultPubsubTopic), message, serverPeerId) + await client.publish(Opt.some(DefaultPubsubTopic), message, serverPeerId) check await handlerFuture.withTimeout(50.millis) @@ -91,7 +92,7 @@ suite "Rate limited push service": let server = - await newTestWakuLightpushNode(serverSwitch, handler, some((3, 500.millis))) + await newTestWakuLightpushNode(serverSwitch, handler, Opt.some((3, 500.millis))) client = newTestWakuLightpushClient(clientSwitch) let serverPeerId = serverSwitch.peerInfo.toRemotePeerInfo() @@ -102,7 +103,7 @@ suite "Rate limited push service": for i in 0 ..< 10: let message = fakeWakuMessage() publishFutures.add( - client.publish(some(DefaultPubsubTopic), message, serverPeerId) + client.publish(Opt.some(DefaultPubsubTopic), message, serverPeerId) ) let finished = await allFinished(publishFutures) @@ -115,7 +116,7 @@ suite "Rate limited push service": gotOk = true else: check res.error.code == LightPushErrorCode.TOO_MANY_REQUESTS - check res.error.desc == some(TooManyRequestsMessage) + check res.error.desc == Opt.some(TooManyRequestsMessage) gotTooMany = true check gotOk @@ -123,8 +124,9 @@ suite "Rate limited push service": # ensure period of time has passed and the client can again use the service await sleepAsync(tokenPeriod + 100.millis) - let recoveryRes = - await client.publish(some(DefaultPubsubTopic), fakeWakuMessage(), serverPeerId) + let recoveryRes = await client.publish( + Opt.some(DefaultPubsubTopic), fakeWakuMessage(), serverPeerId + ) check recoveryRes.isOk() ## Cleanup diff --git a/tests/waku_lightpush_legacy/lightpush_utils.nim b/tests/waku_lightpush_legacy/lightpush_utils.nim index e64f5d69f..dd2ac977e 100644 --- a/tests/waku_lightpush_legacy/lightpush_utils.nim +++ b/tests/waku_lightpush_legacy/lightpush_utils.nim @@ -1,6 +1,6 @@ {.used.} -import std/options, chronos, chronicles, libp2p/crypto/crypto +import results, chronos, chronicles, libp2p/crypto/crypto logScope: topics = "test waku_lightpush_legacy" @@ -15,7 +15,7 @@ import proc newTestWakuLegacyLightpushNode*( switch: Switch, handler: PushMessageHandler, - rateLimitSetting: Option[RateLimitSetting] = none[RateLimitSetting](), + rateLimitSetting: Opt[RateLimitSetting] = Opt.none(RateLimitSetting), ): Future[WakuLegacyLightPush] {.async.} = let peerManager = PeerManager.new(switch) diff --git a/tests/waku_lightpush_legacy/test_client.nim b/tests/waku_lightpush_legacy/test_client.nim index d60595a1e..b6d406962 100644 --- a/tests/waku_lightpush_legacy/test_client.nim +++ b/tests/waku_lightpush_legacy/test_client.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, strscans], testutils/unittests, chronos, libp2p/crypto/crypto +import std/strscans, testutils/unittests, chronos, libp2p/crypto/crypto import logos_delivery/waku/[ diff --git a/tests/waku_lightpush_legacy/test_ratelimit.nim b/tests/waku_lightpush_legacy/test_ratelimit.nim index 345501d0b..29f647722 100644 --- a/tests/waku_lightpush_legacy/test_ratelimit.nim +++ b/tests/waku_lightpush_legacy/test_ratelimit.nim @@ -1,6 +1,6 @@ {.used.} -import std/options, testutils/unittests, chronos, libp2p/crypto/crypto +import results, testutils/unittests, chronos, libp2p/crypto/crypto import logos_delivery/waku/[ @@ -33,7 +33,7 @@ suite "Rate limited push service": let tokenPeriod = 500.millis server = await newTestWakuLegacyLightpushNode( - serverSwitch, handler, some((3, tokenPeriod)) + serverSwitch, handler, Opt.some((3, tokenPeriod)) ) client = newTestWakuLegacyLightpushClient(clientSwitch) @@ -94,7 +94,7 @@ suite "Rate limited push service": let tokenPeriod = 500.millis server = await newTestWakuLegacyLightpushNode( - serverSwitch, handler, some((3, tokenPeriod)) + serverSwitch, handler, Opt.some((3, tokenPeriod)) ) client = newTestWakuLegacyLightpushClient(clientSwitch) diff --git a/tests/waku_peer_exchange/test_protocol.nim b/tests/waku_peer_exchange/test_protocol.nim index d8083158b..fb77c3174 100644 --- a/tests/waku_peer_exchange/test_protocol.nim +++ b/tests/waku_peer_exchange/test_protocol.nim @@ -1,7 +1,8 @@ {.used.} import - std/[options, sequtils, net], + results, + std/[sequtils, net], testutils/unittests, chronos, libp2p/[switch, peerId, crypto/crypto], @@ -42,13 +43,16 @@ suite "Waku Peer Exchange": bindIp = parseIpAddress("0.0.0.0") nodeKey1 = generateSecp256k1Key() - node1 = newTestWakuNode(nodeKey1, bindIp, Port(0), wakuFlags = some(flags)) + node1 = + newTestWakuNode(nodeKey1, bindIp, Port(0), wakuFlags = Opt.some(flags)) nodeKey2 = generateSecp256k1Key() - node2 = newTestWakuNode(nodeKey2, bindIp, Port(0), wakuFlags = some(flags)) + node2 = + newTestWakuNode(nodeKey2, bindIp, Port(0), wakuFlags = Opt.some(flags)) nodeKey3 = generateSecp256k1Key() - node3 = newTestWakuNode(nodeKey3, bindIp, Port(0), wakuFlags = some(flags)) + node3 = + newTestWakuNode(nodeKey3, bindIp, Port(0), wakuFlags = Opt.some(flags)) await allFutures(node1.start(), node2.start(), node3.start()) @@ -115,12 +119,12 @@ suite "Waku Peer Exchange": # Simulate node1 discovering node3 via Discv5 var info3 = node3.peerInfo.toRemotePeerInfo() - info3.enr = some(node3.enr) + info3.enr = Opt.some(node3.enr) node1.peerManager.addPeer(info3, PeerOrigin.Discv5) # Simulate node1 discovering node4 via Discv5 var info4 = node4.peerInfo.toRemotePeerInfo() - info4.enr = some(node4.enr) + info4.enr = Opt.some(node4.enr) node1.peerManager.addPeer(info4, PeerOrigin.Discv5) # Request 2 peer from px. Test all request variants @@ -193,7 +197,7 @@ suite "Waku Peer Exchange": let key1 = generateSecp256k1Key() key2 = generateSecp256k1Key() - cluster: Option[uint16] = some(uint16(16)) + cluster: Opt[uint16] = Opt.some(uint16(16)) bindIp = parseIpAddress("0.0.0.0") nodeTcpPort = Port(64010) nodeUdpPort = Port(9000) @@ -202,8 +206,12 @@ suite "Waku Peer Exchange": builder1 = EnrBuilder.init(key1) builder2 = EnrBuilder.init(key2) - builder1.withIpAddressAndPorts(some(bindIp), some(nodeTcpPort), some(nodeUdpPort)) - builder2.withIpAddressAndPorts(some(bindIp), some(nodeTcpPort), some(nodeUdpPort)) + builder1.withIpAddressAndPorts( + Opt.some(bindIp), Opt.some(nodeTcpPort), Opt.some(nodeUdpPort) + ) + builder2.withIpAddressAndPorts( + Opt.some(bindIp), Opt.some(nodeTcpPort), Opt.some(nodeUdpPort) + ) builder1.withShardedTopics(@["/waku/2/rs/1/7"]).expect("valid topic") builder2.withShardedTopics(@["/waku/2/rs/16/32"]).expect("valid topic") @@ -241,7 +249,7 @@ suite "Waku Peer Exchange": # Simulate node1 discovering node3 via Discv5 var info3 = node3.peerInfo.toRemotePeerInfo() - info3.enr = some(node3.enr) + info3.enr = Opt.some(node3.enr) node1.peerManager.addPeer(info3, PeerOrigin.Discv5) # When requesting 0 peers @@ -308,7 +316,7 @@ suite "Waku Peer Exchange": # Simulate node1 discovering node3 via Discv5 var info3 = node3.peerInfo.toRemotePeerInfo() - info3.enr = some(node3.enr) + info3.enr = Opt.some(node3.enr) node1.peerManager.addPeer(info3, PeerOrigin.Discv5) # Create connection @@ -352,7 +360,7 @@ suite "Waku Peer Exchange": # Simulate node1 discovering nodeA via Discv5 var info3 = node3.peerInfo.toRemotePeerInfo() - info3.enr = some(node3.enr) + info3.enr = Opt.some(node3.enr) node1.peerManager.addPeer(info3, PeerOrigin.Discv5) # Create connection diff --git a/tests/waku_peer_exchange/test_rpc_codec.nim b/tests/waku_peer_exchange/test_rpc_codec.nim index ca86ce294..fa61a8d2a 100644 --- a/tests/waku_peer_exchange/test_rpc_codec.nim +++ b/tests/waku_peer_exchange/test_rpc_codec.nim @@ -1,7 +1,7 @@ {.used.} import - std/[options, net], + std/net, testutils/unittests, chronos, libp2p/switch, diff --git a/tests/waku_peer_exchange/utils.nim b/tests/waku_peer_exchange/utils.nim index f762541f8..a19dde7d6 100644 --- a/tests/waku_peer_exchange/utils.nim +++ b/tests/waku_peer_exchange/utils.nim @@ -1,7 +1,7 @@ {.used.} import - std/[options, net], + std/net, results, testutils/unittests, chronos, @@ -38,14 +38,15 @@ proc startDiscv5WithAutoPort*( record.update(key, udpPort = Opt.some(p)).isOkOr: return err("could not set discv5 udp port in enr: " & $error) let conf = WakuDiscoveryV5Config( - discv5Config: none(DiscoveryConfig), + discv5Config: Opt.none(DiscoveryConfig), address: bindIp, port: p, privateKey: key, bootstrapRecords: bootstrapRecords, autoupdateRecord: true, ) - let wd = WakuDiscoveryV5.new(node.rng, conf, some(record), some(node.peerManager)) + let wd = + WakuDiscoveryV5.new(node.rng, conf, Opt.some(record), Opt.some(node.peerManager)) (await wd.start()).isOkOr: return err(error) return ok(wd) diff --git a/tests/waku_relay/test_protocol.nim b/tests/waku_relay/test_protocol.nim index a2042627e..d3b94a996 100644 --- a/tests/waku_relay/test_protocol.nim +++ b/tests/waku_relay/test_protocol.nim @@ -1,7 +1,7 @@ {.used.} import - std/[options, strformat, sets, tables], + std/[strformat, sets, tables], testutils/unittests, chronos, libp2p/protocols/pubsub/[pubsub, gossipsub], diff --git a/tests/waku_relay/test_wakunode_relay.nim b/tests/waku_relay/test_wakunode_relay.nim index 6ec622f2a..dda3c65ae 100644 --- a/tests/waku_relay/test_wakunode_relay.nim +++ b/tests/waku_relay/test_wakunode_relay.nim @@ -1,7 +1,8 @@ {.used.} import - std/[os, strutils, sequtils, sysrand, math, options], + results, + std/[os, strutils, sequtils, sysrand, math], stew/byteutils, testutils/unittests, chronos, @@ -113,7 +114,7 @@ suite "WakuNode - Relay": assert false, "Failed to subscribe to topic: " & $error await sleepAsync(500.millis) - var res = await node1.publish(some($shard), message) + var res = await node1.publish(Opt.some($shard), message) assert res.isOk(), $res.error ## Then @@ -215,13 +216,13 @@ suite "WakuNode - Relay": assert false, "Failed to subscribe to topic: " & $error await sleepAsync(500.millis) - var res = await node1.publish(some($shard), message1) + var res = await node1.publish(Opt.some($shard), message1) assert res.isOk(), $res.error await sleepAsync(500.millis) # message2 never gets relayed because of the validator - res = await node1.publish(some($shard), message2) + res = await node1.publish(Opt.some($shard), message2) assert res.isOk(), $res.error await sleepAsync(500.millis) @@ -315,7 +316,7 @@ suite "WakuNode - Relay": assert false, "Failed to subscribe to topic: " & $error await sleepAsync(500.millis) - let res = await node2.publish(some($shard), message) + let res = await node2.publish(Opt.some($shard), message) assert res.isOk(), $res.error await sleepAsync(500.millis) @@ -367,7 +368,7 @@ suite "WakuNode - Relay": assert false, "Failed to subscribe to topic: " & $error await sleepAsync(500.millis) - let res = await node2.publish(some($shard), message) + let res = await node2.publish(Opt.some($shard), message) assert res.isOk(), $res.error await sleepAsync(500.millis) @@ -428,7 +429,7 @@ suite "WakuNode - Relay": assert false, "Failed to subscribe to topic: " & $error await sleepAsync(500.millis) - let res = await node2.publish(some($shard), message) + let res = await node2.publish(Opt.some($shard), message) check res.isErr() check contains($res.error, "NoPeersToPublish") @@ -487,7 +488,7 @@ suite "WakuNode - Relay": assert false, "Failed to subscribe to topic: " & $error await sleepAsync(500.millis) - let res = await node2.publish(some($shard), message) + let res = await node2.publish(Opt.some($shard), message) assert res.isOk(), $res.error await sleepAsync(500.millis) @@ -547,7 +548,7 @@ suite "WakuNode - Relay": assert false, "Failed to subscribe to topic: " & $error await sleepAsync(500.millis) - let res = await node2.publish(some($shard), message) + let res = await node2.publish(Opt.some($shard), message) assert res.isOk(), $res.error await sleepAsync(500.millis) diff --git a/tests/waku_relay/utils.nim b/tests/waku_relay/utils.nim index 663d06c18..4d40ae8b1 100644 --- a/tests/waku_relay/utils.nim +++ b/tests/waku_relay/utils.nim @@ -1,7 +1,8 @@ {.used.} import - std/[strutils, sequtils, tempfiles, options], + results, + std/[strutils, sequtils, tempfiles], stew/byteutils, chronos, chronicles, @@ -75,7 +76,7 @@ proc sendRlnMessage*( await client.rln.generateRLNProof(message.toRLNSignal(), epochTime()) ).valueOr: raiseAssert "generateRLNProof failed: " & error - discard await client.publish(some(pubsubTopic), message) + discard await client.publish(Opt.some(pubsubTopic), message) let isCompleted = await completionFuture.withTimeout(FUTURE_TIMEOUT) return isCompleted @@ -98,6 +99,6 @@ proc sendRlnMessageWithInvalidProof*( message = WakuMessage(payload: @payload, contentTopic: contentTopic, proof: rateLimitProof) - discard await client.publish(some(pubsubTopic), message) + discard await client.publish(Opt.some(pubsubTopic), message) let isCompleted = await completionFuture.withTimeout(FUTURE_TIMEOUT) return isCompleted diff --git a/tests/waku_rln_relay/rln/waku_rln_relay_utils.nim b/tests/waku_rln_relay/rln/waku_rln_relay_utils.nim index d7577b88a..07c85922d 100644 --- a/tests/waku_rln_relay/rln/waku_rln_relay_utils.nim +++ b/tests/waku_rln_relay/rln/waku_rln_relay_utils.nim @@ -1,4 +1,3 @@ -import std/options import std/tempfiles import results @@ -48,10 +47,10 @@ proc getWakuRlnConfig*( ethClientUrls: @[EthClient], ethContractAddress: manager.ethContractAddress, chainId: manager.chainId, - credIndex: some(index), + credIndex: Opt.some(index), userMessageLimit: userMessageLimit, epochSizeSec: epochSizeSec, - ethPrivateKey: some(manager.ethPrivateKey.get()), + ethPrivateKey: Opt.some(manager.ethPrivateKey.get()), onFatalErrorAction: proc(errStr: string) = warn "non-fatal onchain test error", errStr , diff --git a/tests/waku_rln_relay/test_rln_contract_deployment.nim b/tests/waku_rln_relay/test_rln_contract_deployment.nim index e5600e829..0a21a2264 100644 --- a/tests/waku_rln_relay/test_rln_contract_deployment.nim +++ b/tests/waku_rln_relay/test_rln_contract_deployment.nim @@ -2,7 +2,7 @@ {.push raises: [].} -import std/[options, os], results, testutils/unittests, chronos, web3 +import std/os, results, testutils/unittests, chronos, web3 import logos_delivery/waku/ @@ -12,7 +12,8 @@ import suite "Token and RLN Contract Deployment": test "anvil should dump state to file on exit": # git will ignore this file, if the contract has been updated and the state file needs to be regenerated then this file can be renamed to replace the one in the repo (tests/waku_rln_relay/anvil_state/tests/waku_rln_relay/anvil_state/state-deployed-contracts-mint-and-approved.json) - let testStateFile = some("tests/waku_rln_relay/anvil_state/anvil_state.ignore.json") + let testStateFile = + Opt.some("tests/waku_rln_relay/anvil_state/anvil_state.ignore.json") let anvilProc = runAnvil(stateFile = testStateFile, dumpStateOnExit = true) let manager = waitFor setupOnchainGroupManager(deployContracts = true) diff --git a/tests/waku_rln_relay/test_rln_group_manager_onchain.nim b/tests/waku_rln_relay/test_rln_group_manager_onchain.nim index bbd97217f..5f967bed8 100644 --- a/tests/waku_rln_relay/test_rln_group_manager_onchain.nim +++ b/tests/waku_rln_relay/test_rln_group_manager_onchain.nim @@ -3,7 +3,7 @@ {.push raises: [].} import - std/[options, sequtils, deques, random, locks, osproc, algorithm, exitprocs], + std/[sequtils, deques, random, locks, osproc, algorithm, exitprocs], results, stew/byteutils, testutils/unittests, @@ -46,7 +46,7 @@ suite "Onchain group manager": setup: if not anvilStarted: - sharedAnvilProc = runAnvil(stateFile = some(DEFAULT_ANVIL_STATE_PATH)) + sharedAnvilProc = runAnvil(stateFile = Opt.some(DEFAULT_ANVIL_STATE_PATH)) anvilStarted = true addExitProc( proc() = @@ -89,8 +89,8 @@ suite "Onchain group manager": raiseAssert "Expected error when contract address doesn't exist" test "should error when keystore path and password are provided but file doesn't exist": - manager.keystorePath = some("/inexistent/file") - manager.keystorePassword = some("password") + manager.keystorePath = Opt.some("/inexistent/file") + manager.keystorePassword = Opt.some("password") (waitFor manager.init()).isErrOr: raiseAssert "Expected error when keystore file doesn't exist" @@ -248,7 +248,7 @@ suite "Onchain group manager": registrations[0].rateCommitment == getRateCommitment(idCredentials, UserMessageLimit(20)).get() and registrations[0].index == 0: - manager.idCredentials = some(idCredentials) + manager.idCredentials = Opt.some(idCredentials) fut.complete() manager.onRegister(callback) @@ -293,9 +293,9 @@ suite "Onchain group manager": (waitFor manager.init()).isOkOr: raiseAssert $error - manager.userMessageLimit = some(UserMessageLimit(20)) - manager.membershipIndex = some(MembershipIndex(0)) - manager.idCredentials = some(idCredentials) + manager.userMessageLimit = Opt.some(UserMessageLimit(20)) + manager.membershipIndex = Opt.some(MembershipIndex(0)) + manager.idCredentials = Opt.some(idCredentials) manager.merkleProofCache = newSeq[byte](640) for i in 0 ..< 640: @@ -522,7 +522,7 @@ suite "Onchain group manager": raiseAssert $error # No registration → no membership index. Guard must error rather than - # crashing inside fetchMerkleProofElements (which unwraps the Option). + # crashing inside fetchMerkleProofElements (which unwraps the Opt). check: manager.membershipIndex.isNone() @@ -755,7 +755,7 @@ suite "Onchain group manager": registrations[0].rateCommitment == getRateCommitment(credentials, UserMessageLimit(20)).get() and registrations[0].index == 0: - manager.idCredentials = some(credentials) + manager.idCredentials = Opt.some(credentials) fut.complete() manager.onRegister(callback) @@ -835,7 +835,7 @@ suite "Onchain group manager": (waitFor manager.init()).isOkOr: raiseAssert $error - manager.ethRpc = none(Web3) + manager.ethRpc = Opt.none(Web3) var isReady = true try: diff --git a/tests/waku_rln_relay/test_waku_rln_relay.nim b/tests/waku_rln_relay/test_waku_rln_relay.nim index 10de8d4d6..d63c7c924 100644 --- a/tests/waku_rln_relay/test_waku_rln_relay.nim +++ b/tests/waku_rln_relay/test_waku_rln_relay.nim @@ -1,7 +1,8 @@ {.used.} import - std/[options, os, sequtils, tempfiles, strutils, osproc, algorithm], + results, + std/[os, sequtils, tempfiles, strutils, osproc, algorithm], stew/byteutils, testutils/unittests, chronos, @@ -25,7 +26,7 @@ suite "Waku rln relay": var manager {.threadVar.}: OnchainGroupManager setup: - anvilProc = runAnvil(stateFile = some(DEFAULT_ANVIL_STATE_PATH)) + anvilProc = runAnvil(stateFile = Opt.some(DEFAULT_ANVIL_STATE_PATH)) manager = waitFor setupOnchainGroupManager(deployContracts = false) teardown: diff --git a/tests/waku_rln_relay/test_wakunode_rln_relay.nim b/tests/waku_rln_relay/test_wakunode_rln_relay.nim index 4c02b4cbd..1490e16ce 100644 --- a/tests/waku_rln_relay/test_wakunode_rln_relay.nim +++ b/tests/waku_rln_relay/test_wakunode_rln_relay.nim @@ -1,7 +1,8 @@ {.used.} import - std/[options, os, sequtils, tempfiles, strutils, osproc], + results, + std/[os, sequtils, tempfiles, strutils, osproc], stew/byteutils, testutils/unittests, chronicles, @@ -33,7 +34,7 @@ procSuite "WakuNode - RLN relay": var manager {.threadVar.}: OnchainGroupManager setup: - anvilProc = runAnvil(stateFile = some(DEFAULT_ANVIL_STATE_PATH)) + anvilProc = runAnvil(stateFile = Opt.some(DEFAULT_ANVIL_STATE_PATH)) manager = waitFor setupOnchainGroupManager(deployContracts = false) teardown: @@ -149,7 +150,7 @@ procSuite "WakuNode - RLN relay": ## node1 publishes a message with a rate limit proof, the message is then relayed to node2 which in turn ## verifies the rate limit proof of the message and relays the message to node3 ## verification at node2 occurs inside a topic validator which is installed as part of the waku-rln-relay mount proc - discard await node1.publish(some(DefaultPubsubTopic), message) + discard await node1.publish(Opt.some(DefaultPubsubTopic), message) assert (await completionFut.withTimeout(15.seconds)), "completionFut timed out" await node1.stop() @@ -285,9 +286,9 @@ procSuite "WakuNode - RLN relay": # publish 3 messages from node[0] (last 2 are spam, window is 10 secs) # publish 3 messages from node[1] (last 2 are spam, window is 10 secs) for msg in messages1: - discard await node1.publish(some($shards[0]), msg) + discard await node1.publish(Opt.some($shards[0]), msg) for msg in messages2: - discard await node2.publish(some($shards[1]), msg) + discard await node2.publish(Opt.some($shards[1]), msg) # wait for gossip to propagate await sleepAsync(5000.millis) @@ -402,7 +403,7 @@ procSuite "WakuNode - RLN relay": # message.payload = "Invalid".toBytes() message.proof[0] = message.proof[0] xor 0x01 - discard await node1.publish(some(DefaultPubsubTopic), message) + discard await node1.publish(Opt.some(DefaultPubsubTopic), message) await sleepAsync(2000.millis) check: @@ -561,10 +562,10 @@ procSuite "WakuNode - RLN relay": ## node2 should detect either of wm1 or wm2 as spam and not relay it ## node2 should relay wm3 to node3 ## node2 should not relay wm4 because it has no valid rln proof - discard await node1.publish(some(DefaultPubsubTopic), wm1) - discard await node1.publish(some(DefaultPubsubTopic), wm2) - discard await node1.publish(some(DefaultPubsubTopic), wm3) - discard await node1.publish(some(DefaultPubsubTopic), wm4) + discard await node1.publish(Opt.some(DefaultPubsubTopic), wm1) + discard await node1.publish(Opt.some(DefaultPubsubTopic), wm2) + discard await node1.publish(Opt.some(DefaultPubsubTopic), wm3) + discard await node1.publish(Opt.some(DefaultPubsubTopic), wm4) await sleepAsync(2000.millis) let @@ -690,8 +691,8 @@ procSuite "WakuNode - RLN relay": node1.rln.unsafeAppendRLNProof(wm2, epoch_1, MessageId(0)).isOkOr: raiseAssert $error - discard await node1.publish(some(DefaultPubsubTopic), wm1) - discard await node1.publish(some(DefaultPubsubTopic), wm2) + discard await node1.publish(Opt.some(DefaultPubsubTopic), wm1) + discard await node1.publish(Opt.some(DefaultPubsubTopic), wm2) await sleepAsync(publishSleepDuration) check: await node1.waitForNullifierLog(0) @@ -702,7 +703,7 @@ procSuite "WakuNode - RLN relay": node1.rln.unsafeAppendRLNProof(wm3, epoch_2, MessageId(0)).isOkOr: raiseAssert $error - discard await node1.publish(some(DefaultPubsubTopic), wm3) + discard await node1.publish(Opt.some(DefaultPubsubTopic), wm3) await sleepAsync(publishSleepDuration) @@ -714,7 +715,7 @@ procSuite "WakuNode - RLN relay": node1.rln.unsafeAppendRLNProof(wm4, epoch_3, MessageId(0)).isOkOr: raiseAssert $error - discard await node1.publish(some(DefaultPubsubTopic), wm4) + discard await node1.publish(Opt.some(DefaultPubsubTopic), wm4) await sleepAsync(publishSleepDuration) check: await node1.waitForNullifierLog(0) @@ -724,7 +725,7 @@ procSuite "WakuNode - RLN relay": node1.rln.unsafeAppendRLNProof(wm5, epoch_4, MessageId(0)).isOkOr: raiseAssert $error - discard await node1.publish(some(DefaultPubsubTopic), wm5) + discard await node1.publish(Opt.some(DefaultPubsubTopic), wm5) await sleepAsync(publishSleepDuration) check: await node1.waitForNullifierLog(0) @@ -734,7 +735,7 @@ procSuite "WakuNode - RLN relay": node1.rln.unsafeAppendRLNProof(wm6, epoch_5, MessageId(0)).isOkOr: raiseAssert $error - discard await node1.publish(some(DefaultPubsubTopic), wm6) + discard await node1.publish(Opt.some(DefaultPubsubTopic), wm6) await sleepAsync(publishSleepDuration) check: await node1.waitForNullifierLog(0) diff --git a/tests/waku_rln_relay/utils.nim b/tests/waku_rln_relay/utils.nim index 8aed18f9b..1bc7e66f3 100644 --- a/tests/waku_rln_relay/utils.nim +++ b/tests/waku_rln_relay/utils.nim @@ -1,4 +1,4 @@ -import web3, chronos, stew/byteutils +import results, web3, chronos, stew/byteutils proc deployContract*( web3: Web3, code: string, gasPrice = 0, contractInput = "" diff --git a/tests/waku_rln_relay/utils_offchain.nim b/tests/waku_rln_relay/utils_offchain.nim index 9976ec783..2dbd31744 100644 --- a/tests/waku_rln_relay/utils_offchain.nim +++ b/tests/waku_rln_relay/utils_offchain.nim @@ -1,7 +1,8 @@ {.used.} import - std/[sequtils, tempfiles, options], + results, + std/[sequtils, tempfiles], stew/byteutils, chronos, chronicles, @@ -20,10 +21,10 @@ import proc setupStaticRln*( node: WakuNode, identifier: uint, - rlnRelayEthContractAddress: Option[string] = none(string), + rlnRelayEthContractAddress: Opt[string] = Opt.none(string), ) {.async.} = await node.setRlnValidator( - WakuRlnConfig(dynamic: false, credIndex: some(identifier), epochSizeSec: 1) + WakuRlnConfig(dynamic: false, credIndex: Opt.some(identifier), epochSizeSec: 1) ) proc setupRelayWithStaticRln*( @@ -40,7 +41,7 @@ proc subscribeCompletionHandler*(node: WakuNode, pubsubTopic: string): Future[bo if topic == pubsubTopic: completionFut.complete(true) - node.subscribe((kind: PubsubSub, topic: pubsubTopic), some(relayHandler)).isOkOr: + node.subscribe((kind: PubsubSub, topic: pubsubTopic), Opt.some(relayHandler)).isOkOr: error "failed to subscribe to relay", topic = pubsubTopic, error = error completionFut.complete(false) @@ -58,7 +59,7 @@ proc sendRlnMessage*( await client.rln.generateRLNProof(message.toRLNSignal(), epochTime()) ).valueOr: raiseAssert "generateRLNProof failed: " & error - discard await client.publish(some(pubsubTopic), message) + discard await client.publish(Opt.some(pubsubTopic), message) let isCompleted = await completionFuture.withTimeout(FUTURE_TIMEOUT) return isCompleted @@ -80,6 +81,6 @@ proc sendRlnMessageWithInvalidProof*( message = WakuMessage(payload: @payload, contentTopic: contentTopic, proof: rateLimitProof) - discard await client.publish(some(pubsubTopic), message) + discard await client.publish(Opt.some(pubsubTopic), message) let isCompleted = await completionFuture.withTimeout(FUTURE_TIMEOUT) return isCompleted diff --git a/tests/waku_rln_relay/utils_onchain.nim b/tests/waku_rln_relay/utils_onchain.nim index 4955d8d64..1a1086b8b 100644 --- a/tests/waku_rln_relay/utils_onchain.nim +++ b/tests/waku_rln_relay/utils_onchain.nim @@ -4,7 +4,7 @@ import libp2p/crypto/rng {.push raises: [].} import - std/[net, options, os, osproc, streams, strutils, strformat], + std/[net, os, osproc, streams, strutils, strformat], results, stew/byteutils, testutils/unittests, @@ -99,7 +99,7 @@ proc sendMintCall( tokenAddress: Address, recipientAddress: Address, amountTokens: UInt256, - recipientBalanceBeforeExpectedTokens: Option[UInt256] = none(UInt256), + recipientBalanceBeforeExpectedTokens: Opt[UInt256] = Opt.none(UInt256), ): Future[void] {.async.} = let doBalanceAssert = recipientBalanceBeforeExpectedTokens.isSome() @@ -235,7 +235,7 @@ proc approveTokenAllowanceAndVerify*( tokenAddress: Address, spender: Address, amountWei: UInt256, - expectedAllowanceBefore: Option[UInt256] = none(UInt256), + expectedAllowanceBefore: Opt[UInt256] = Opt.none(UInt256), ): Future[Result[TxHash, string]] {.async.} = var allowanceBefore: UInt256 if expectedAllowanceBefore.isSome(): @@ -372,7 +372,7 @@ proc sendEthTransfer*( accountFrom: Address, accountTo: Address, amountWei: UInt256, - accountToBalanceBeforeExpectedWei: Option[UInt256] = none(UInt256), + accountToBalanceBeforeExpectedWei: Opt[UInt256] = Opt.none(UInt256), ): Future[TxHash] {.async.} = let doBalanceAssert = accountToBalanceBeforeExpectedWei.isSome() @@ -482,7 +482,7 @@ proc compressGzipFile*(sourcePath: string, targetPath: string): Result[void, str proc runAnvil*( port: int = 8540, chainId: string = "1234", - stateFile: Option[string] = none(string), + stateFile: Opt[string] = Opt.none(string), dumpStateOnExit: bool = false, ): Process = # Gas/fee values mirror Linea Sepolia testnet. @@ -697,7 +697,7 @@ proc setupOnchainGroupManager*( (privateKey, acc) = createEthAccount(web3) discard await sendEthTransfer( - web3, web3.defaultAccount, acc, ethToWei(1000.u256), some(0.u256) + web3, web3.defaultAccount, acc, ethToWei(1000.u256), Opt.some(0.u256) ) testTokenAddress = (await deployTestToken(privateKey, acc, web3)).valueOr: @@ -710,7 +710,7 @@ proc setupOnchainGroupManager*( testTokenAddress, acc, ethToWei(1000.u256), - some(0.u256), + Opt.some(0.u256), ) contractAddress = (await executeForgeContractDeployScripts(privateKey, acc, web3)).valueOr: @@ -735,7 +735,7 @@ proc setupOnchainGroupManager*( testTokenAddress, contractAddress, ethToWei(2000.u256), - some(0.u256), + Opt.some(0.u256), ) assert tokenApprovalResult.isOk(), tokenApprovalResult.error @@ -744,7 +744,7 @@ proc setupOnchainGroupManager*( ethClientUrls: @[ethClientUrl], ethContractAddress: $contractAddress, chainId: CHAIN_ID, - ethPrivateKey: some($privateKey), + ethPrivateKey: Opt.some($privateKey), rlnInstance: rlnInstance, onFatalErrorAction: proc(errStr: string) = raiseAssert errStr @@ -768,7 +768,7 @@ proc buildOnchainGroupManager*( ethClientUrls: @[ethClientUrl], ethContractAddress: WAKU_RLNV2_PROXY_ADDRESS, chainId: CHAIN_ID, - ethPrivateKey: some(privateKey), + ethPrivateKey: Opt.some(privateKey), rlnInstance: rlnInstanceRes.get(), onFatalErrorAction: proc(errStr: string) = raiseAssert errStr diff --git a/tests/waku_store/store_utils.nim b/tests/waku_store/store_utils.nim index f7640ca04..dea142f2e 100644 --- a/tests/waku_store/store_utils.nim +++ b/tests/waku_store/store_utils.nim @@ -1,6 +1,6 @@ {.used.} -import std/options, chronos, chronicles +import chronos, chronicles import logos_delivery/waku/[node/peer_manager, waku_store, waku_store/client], diff --git a/tests/waku_store/test_client.nim b/tests/waku_store/test_client.nim index ce9f5f802..729ef6d1f 100644 --- a/tests/waku_store/test_client.nim +++ b/tests/waku_store/test_client.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, sets], testutils/unittests, chronos, libp2p/crypto/crypto +import results, std/sets, testutils/unittests, chronos, libp2p/crypto/crypto import logos_delivery/waku/ @@ -39,18 +39,18 @@ suite "Store Client": messageSeq = @[ WakuMessageKeyValue( messageHash: hash1, - message: some(message1), - pubsubTopic: some(DefaultPubsubTopic), + message: Opt.some(message1), + pubsubTopic: Opt.some(DefaultPubsubTopic), ), WakuMessageKeyValue( messageHash: hash2, - message: some(message2), - pubsubTopic: some(DefaultPubsubTopic), + message: Opt.some(message2), + pubsubTopic: Opt.some(DefaultPubsubTopic), ), WakuMessageKeyValue( messageHash: hash3, - message: some(message3), - pubsubTopic: some(DefaultPubsubTopic), + message: Opt.some(message3), + pubsubTopic: Opt.some(DefaultPubsubTopic), ), ] handlerFuture = newHistoryFuture() @@ -60,7 +60,7 @@ suite "Store Client": handlerFuture.complete(request) return ok(StoreQueryResponse(messages: messageSeq)) storeQuery = StoreQueryRequest( - pubsubTopic: some(DefaultPubsubTopic), + pubsubTopic: Opt.some(DefaultPubsubTopic), contentTopics: @[DefaultContentTopic], paginationForward: PagingDirection.FORWARD, ) @@ -109,36 +109,36 @@ suite "Store Client": # Given some invalid queries let invalidQuery1 = StoreQueryRequest( - pubsubTopic: some(DefaultPubsubTopic), + pubsubTopic: Opt.some(DefaultPubsubTopic), contentTopics: @[], paginationForward: PagingDirection.FORWARD, ) invalidQuery2 = StoreQueryRequest( - pubsubTopic: PubsubTopic.none(), + pubsubTopic: Opt.none(PubsubTopic), contentTopics: @[DefaultContentTopic], paginationForward: PagingDirection.FORWARD, ) invalidQuery3 = StoreQueryRequest( - pubsubTopic: some(DefaultPubsubTopic), + pubsubTopic: Opt.some(DefaultPubsubTopic), contentTopics: @[DefaultContentTopic], - paginationLimit: some(uint64(0)), + paginationLimit: Opt.some(uint64(0)), ) invalidQuery4 = StoreQueryRequest( - pubsubTopic: some(DefaultPubsubTopic), + pubsubTopic: Opt.some(DefaultPubsubTopic), contentTopics: @[DefaultContentTopic], - paginationLimit: some(uint64(0)), + paginationLimit: Opt.some(uint64(0)), ) invalidQuery5 = StoreQueryRequest( - pubsubTopic: some(DefaultPubsubTopic), + pubsubTopic: Opt.some(DefaultPubsubTopic), contentTopics: @[DefaultContentTopic], - startTime: some(0.Timestamp), - endTime: some(0.Timestamp), + startTime: Opt.some(0.Timestamp), + endTime: Opt.some(0.Timestamp), ) invalidQuery6 = StoreQueryRequest( - pubsubTopic: some(DefaultPubsubTopic), + pubsubTopic: Opt.some(DefaultPubsubTopic), contentTopics: @[DefaultContentTopic], - startTime: some(0.Timestamp), - endTime: some(-1.Timestamp), + startTime: Opt.some(0.Timestamp), + endTime: Opt.some(-1.Timestamp), ) # When the query is sent to the server diff --git a/tests/waku_store/test_resume.nim b/tests/waku_store/test_resume.nim index 612aa1e1d..c8bf1bbad 100644 --- a/tests/waku_store/test_resume.nim +++ b/tests/waku_store/test_resume.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, net], testutils/unittests, chronos, results +import std/net, testutils/unittests, chronos, results import logos_delivery/waku/[ diff --git a/tests/waku_store/test_rpc_codec.nim b/tests/waku_store/test_rpc_codec.nim index 43543560a..3821aea98 100644 --- a/tests/waku_store/test_rpc_codec.nim +++ b/tests/waku_store/test_rpc_codec.nim @@ -1,6 +1,6 @@ {.used.} -import std/options, testutils/unittests, chronos +import results, testutils/unittests, chronos import logos_delivery/waku/ [common/protobuf, common/paging, waku_core, waku_store/common, waku_store/rpc_codec], @@ -12,14 +12,14 @@ procSuite "Waku Store - RPC codec": let query = StoreQueryRequest( requestId: "0", includeData: true, - pubsubTopic: some(DefaultPubsubTopic), + pubsubTopic: Opt.some(DefaultPubsubTopic), contentTopics: @[DefaultContentTopic], - startTime: some(Timestamp(10)), - endTime: some(Timestamp(11)), + startTime: Opt.some(Timestamp(10)), + endTime: Opt.some(Timestamp(11)), messageHashes: @[], - paginationCursor: none(WakuMessageHash), + paginationCursor: Opt.none(WakuMessageHash), paginationForward: PagingDirection.FORWARD, - paginationLimit: some(DefaultPageSize), + paginationLimit: Opt.some(DefaultPageSize), ) ## When @@ -56,14 +56,16 @@ procSuite "Waku Store - RPC codec": message = fakeWakuMessage() hash = computeMessageHash(DefaultPubsubTopic, message) keyValue = WakuMessageKeyValue( - messageHash: hash, message: some(message), pubsubTopic: some(DefaultPubsubTopic) + messageHash: hash, + message: Opt.some(message), + pubsubTopic: Opt.some(DefaultPubsubTopic), ) res = StoreQueryResponse( requestId: "1", statusCode: 200, statusDesc: "it's fine", messages: @[keyValue], - paginationCursor: none(WakuMessageHash), + paginationCursor: Opt.none(WakuMessageHash), ) ## When diff --git a/tests/waku_store/test_waku_store.nim b/tests/waku_store/test_waku_store.nim index b210e6b44..74f8be6a6 100644 --- a/tests/waku_store/test_waku_store.nim +++ b/tests/waku_store/test_waku_store.nim @@ -1,6 +1,6 @@ {.used.} -import std/options, testutils/unittests, chronos, libp2p/crypto/crypto +import results, testutils/unittests, chronos, libp2p/crypto/crypto import logos_delivery/waku/[ @@ -30,7 +30,9 @@ suite "Waku Store - query handler": let msg = fakeWakuMessage(contentTopic = DefaultContentTopic) let hash = computeMessageHash(DefaultPubsubTopic, msg) let kv = WakuMessageKeyValue( - messageHash: hash, message: some(msg), pubsubTopic: some(DefaultPubsubTopic) + messageHash: hash, + message: Opt.some(msg), + pubsubTopic: Opt.some(DefaultPubsubTopic), ) var queryHandlerFut = newFuture[(StoreQueryRequest)]() diff --git a/tests/waku_store/test_wakunode_store.nim b/tests/waku_store/test_wakunode_store.nim index 9c067488a..9d5ab6981 100644 --- a/tests/waku_store/test_wakunode_store.nim +++ b/tests/waku_store/test_wakunode_store.nim @@ -1,7 +1,8 @@ {.used.} import - std/[sequtils, options], + results, + std/sequtils, testutils/unittests, chronicles, chronos, @@ -49,7 +50,9 @@ procSuite "WakuNode - Store": let kvs = zip(hashes, msgListA).mapIt( WakuMessageKeyValue( - messageHash: it[0], message: some(it[1]), pubsubTopic: some(DefaultPubsubTopic) + messageHash: it[0], + message: Opt.some(it[1]), + pubsubTopic: Opt.some(DefaultPubsubTopic), ) ) @@ -119,7 +122,7 @@ procSuite "WakuNode - Store": includeData: true, contentTopics: @[DefaultContentTopic], paginationForward: PagingDirection.FORWARD, - paginationLimit: some(uint64(7)), + paginationLimit: Opt.some(uint64(7)), ) let serverPeer = server.peerInfo.toRemotePeerInfo() @@ -127,7 +130,7 @@ procSuite "WakuNode - Store": var nextReq = req # copy var pages = newSeq[seq[WakuMessageKeyValue]](2) - var cursors = newSeq[Option[WakuMessageHash]](2) + var cursors = newSeq[Opt[WakuMessageHash]](2) for i in 0 ..< 2: let res = waitFor client.query(nextReq, peer = serverPeer) @@ -143,8 +146,8 @@ procSuite "WakuNode - Store": ## Then check: - cursors[0] == some(kvs[6].messageHash) - cursors[1] == none(WakuMessageHash) + cursors[0] == Opt.some(kvs[6].messageHash) + cursors[1] == Opt.none(WakuMessageHash) check: pages[0] == kvs[0 .. 6] @@ -174,7 +177,7 @@ procSuite "WakuNode - Store": let req = StoreQueryRequest( includeData: true, contentTopics: @[DefaultContentTopic], - paginationLimit: some(uint64(7)), + paginationLimit: Opt.some(uint64(7)), paginationForward: PagingDirection.BACKWARD, ) let serverPeer = server.peerInfo.toRemotePeerInfo() @@ -183,7 +186,7 @@ procSuite "WakuNode - Store": var nextReq = req # copy var pages = newSeq[seq[WakuMessageKeyValue]](2) - var cursors = newSeq[Option[WakuMessageHash]](2) + var cursors = newSeq[Opt[WakuMessageHash]](2) for i in 0 ..< 2: let res = waitFor client.query(nextReq, peer = serverPeer) @@ -199,8 +202,8 @@ procSuite "WakuNode - Store": ## Then check: - cursors[0] == some(kvs[3].messageHash) - cursors[1] == none(WakuMessageHash) + cursors[0] == Opt.some(kvs[3].messageHash) + cursors[1] == Opt.none(WakuMessageHash) check: pages[0] == kvs[3 .. 9] @@ -249,7 +252,7 @@ procSuite "WakuNode - Store": server.wakuFilterClient.registerPushHandler(filterHandler) let resp = waitFor server.filterSubscribe( - some(DefaultPubsubTopic), DefaultContentTopic, peer = filterSourcePeer + Opt.some(DefaultPubsubTopic), DefaultContentTopic, peer = filterSourcePeer ) waitFor sleepAsync(100.millis) @@ -272,8 +275,8 @@ procSuite "WakuNode - Store": response.messages[0] == WakuMessageKeyValue( messageHash: hash, - message: some(message), - pubsubTopic: some(DefaultPubSubTopic), + message: Opt.some(message), + pubsubTopic: Opt.some(DefaultPubSubTopic), ) let (handledPubsubTopic, handledMsg) = filterFut.read() @@ -309,7 +312,7 @@ procSuite "WakuNode - Store": ## Given let req = StoreQueryRequest( - contentTopics: @[DefaultContentTopic], paginationCursor: some(cursor) + contentTopics: @[DefaultContentTopic], paginationCursor: Opt.some(cursor) ) let serverPeer = server.peerInfo.toRemotePeerInfo() diff --git a/tests/waku_store_sync/sync_utils.nim b/tests/waku_store_sync/sync_utils.nim index 38538b354..21d75dd97 100644 --- a/tests/waku_store_sync/sync_utils.nim +++ b/tests/waku_store_sync/sync_utils.nim @@ -1,4 +1,4 @@ -import std/[options, random], chronos, chronicles +import std/random, chronos, chronicles import logos_delivery/waku/[ diff --git a/tests/waku_store_sync/test_codec.nim b/tests/waku_store_sync/test_codec.nim index c9bce7111..2d6d6185c 100644 --- a/tests/waku_store_sync/test_codec.nim +++ b/tests/waku_store_sync/test_codec.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, random], testutils/unittests, chronos +import std/random, testutils/unittests, chronos import ../../logos_delivery/waku/waku_core, diff --git a/tests/waku_store_sync/test_protocol.nim b/tests/waku_store_sync/test_protocol.nim index 62fd568a1..2d2eed707 100644 --- a/tests/waku_store_sync/test_protocol.nim +++ b/tests/waku_store_sync/test_protocol.nim @@ -1,7 +1,8 @@ {.used.} import - std/[options, sets, random, math, algorithm], + results, + std/[sets, random, math, algorithm], testutils/unittests, chronos, libp2p/crypto/crypto @@ -80,7 +81,7 @@ suite "Waku Sync: reconciliation": idsChannel.len == 0 remoteNeeds.len == 0 - let res = await client.storeSynchronization(some(serverPeerInfo)) + let res = await client.storeSynchronization(Opt.some(serverPeerInfo)) assert res.isOk(), res.error check: @@ -114,7 +115,7 @@ suite "Waku Sync: reconciliation": remoteNeeds.contains((clientPeerInfo.peerId, hash2)) == false remoteNeeds.contains((clientPeerInfo.peerId, hash3)) == false - let res = await client.storeSynchronization(some(serverPeerInfo)) + let res = await client.storeSynchronization(Opt.some(serverPeerInfo)) assert res.isOk(), res.error check: @@ -150,7 +151,7 @@ suite "Waku Sync: reconciliation": remoteNeeds.contains((serverPeerInfo.peerId, hash2)) == false remoteNeeds.contains((serverPeerInfo.peerId, hash3)) == false - let res = await client.storeSynchronization(some(serverPeerInfo)) + let res = await client.storeSynchronization(Opt.some(serverPeerInfo)) assert res.isOk(), res.error check: @@ -186,7 +187,7 @@ suite "Waku Sync: reconciliation": remoteNeeds.contains((serverPeerInfo.peerId, hash3)) == false remoteNeeds.contains((clientPeerInfo.peerId, hash2)) == false - var syncRes = await client.storeSynchronization(some(serverPeerInfo)) + var syncRes = await client.storeSynchronization(Opt.some(serverPeerInfo)) assert syncRes.isOk(), $syncRes.error check: @@ -240,7 +241,7 @@ suite "Waku Sync: reconciliation": check: remoteNeeds.len == 0 - var syncRes = await client.storeSynchronization(some(serverPeerInfo)) + var syncRes = await client.storeSynchronization(Opt.some(serverPeerInfo)) assert syncRes.isOk(), $syncRes.error check: @@ -270,7 +271,7 @@ suite "Waku Sync: reconciliation": check: remoteNeeds.len == 0 - let res = await client.storeSynchronization(some(serverPeerInfo)) + let res = await client.storeSynchronization(Opt.some(serverPeerInfo)) assert res.isOk(), $res.error check: @@ -312,7 +313,7 @@ suite "Waku Sync: reconciliation": remoteNeeds.len == 0 remoteNeeds.contains((clientPeerInfo.peerId, WakuMessageHash(diff))) == false - let res = await client.storeSynchronization(some(serverPeerInfo)) + let res = await client.storeSynchronization(Opt.some(serverPeerInfo)) assert res.isOk(), $res.error check: @@ -355,7 +356,7 @@ suite "Waku Sync: reconciliation": check remoteNeeds.len == 0 ## ── launch reconciliation from the client towards the server ───────── - let res = await client.storeSynchronization(some(serverPeerInfo)) + let res = await client.storeSynchronization(Opt.some(serverPeerInfo)) assert res.isOk(), $res.error ## ── verify that ≈1000 diffs were queued (allow 10 % slack) ──────────── @@ -398,7 +399,7 @@ suite "Waku Sync: reconciliation": check remoteNeeds.len == 0 - let res = await client.storeSynchronization(some(serverPeerInfo)) + let res = await client.storeSynchronization(Opt.some(serverPeerInfo)) assert res.isOk(), $res.error check remoteNeeds.len >= diffCount - tol and remoteNeeds.len < diffCount @@ -444,7 +445,7 @@ suite "Waku Sync: reconciliation": check remoteNeeds.len == 0 - let res = await client.storeSynchronization(some(serverPeerInfo)) + let res = await client.storeSynchronization(Opt.some(serverPeerInfo)) assert res.isOk(), $res.error check remoteNeeds.len == diffCount @@ -497,7 +498,7 @@ suite "Waku Sync: reconciliation": check remoteNeeds.len == 0 - let res = await client.storeSynchronization(some(serverPeerInfo)) + let res = await client.storeSynchronization(Opt.some(serverPeerInfo)) assert res.isOk(), $res.error check remoteNeeds.len == diffCount @@ -564,7 +565,7 @@ suite "Waku Sync: reconciliation": await server.stop() await client.stop() - let res = await client.storeSynchronization(some(serverPeerInfo)) + let res = await client.storeSynchronization(Opt.some(serverPeerInfo)) assert res.isOk(), $res.error check remoteNeeds.len == diffInWin @@ -613,7 +614,7 @@ suite "Waku Sync: reconciliation": await server.stop() await client.stop() - let res = await client.storeSynchronization(some(serverPeerInfo)) + let res = await client.storeSynchronization(Opt.some(serverPeerInfo)) assert res.isOk(), $res.error check remoteNeeds.len == 1 @@ -660,7 +661,7 @@ suite "Waku Sync: reconciliation": await server.stop() await client.stop() - let res = await client.storeSynchronization(some(serverPeerInfo)) + let res = await client.storeSynchronization(Opt.some(serverPeerInfo)) assert res.isOk(), $res.error check remoteNeeds.len == 1 @@ -704,7 +705,7 @@ suite "Waku Sync: reconciliation": await server.stop() await client.stop() - let res = await client.storeSynchronization(some(serverPeerInfo)) + let res = await client.storeSynchronization(Opt.some(serverPeerInfo)) assert res.isOk(), $res.error check remoteNeeds.len == 1 @@ -739,7 +740,7 @@ suite "Waku Sync: reconciliation": await server.stop() await client.stop() - let res = await client.storeSynchronization(some(serverPeerInfo)) + let res = await client.storeSynchronization(Opt.some(serverPeerInfo)) assert res.isOk(), $res.error check remoteNeeds.len == 1 @@ -776,7 +777,7 @@ suite "Waku Sync: reconciliation": await server.stop() await client.stop() - let res = await client.storeSynchronization(some(serverPeerInfo)) + let res = await client.storeSynchronization(Opt.some(serverPeerInfo)) assert res.isOk(), $res.error check needsQ.len == 0 diff --git a/tests/waku_store_sync/test_storage.nim b/tests/waku_store_sync/test_storage.nim index ba0879375..35b637215 100644 --- a/tests/waku_store_sync/test_storage.nim +++ b/tests/waku_store_sync/test_storage.nim @@ -1,6 +1,6 @@ {.used.} -import std/[options, random, sequtils, packedsets], testutils/unittests, chronos +import results, std/[random, sequtils, packedsets], testutils/unittests, chronos import ../../logos_delivery/waku/waku_core, @@ -218,7 +218,7 @@ suite "Waku Sync Storage": let before = getMonoTime() - discard storage.fingerprinting(some(0 .. count)) + discard storage.fingerprinting(Opt.some(0 .. count)) let after = getMonoTime() diff --git a/tests/wakunode2/test_app.nim b/tests/wakunode2/test_app.nim index 879dcd7b5..e9a0ecd47 100644 --- a/tests/wakunode2/test_app.nim +++ b/tests/wakunode2/test_app.nim @@ -1,4 +1,3 @@ -import logos_delivery/waku/compat/option_valueor {.used.} import diff --git a/tests/wakunode2/test_cli_args.nim b/tests/wakunode2/test_cli_args.nim index 5b21bd327..4578e1cec 100644 --- a/tests/wakunode2/test_cli_args.nim +++ b/tests/wakunode2/test_cli_args.nim @@ -1,7 +1,7 @@ {.used.} import - std/[options, strutils], + std/strutils, testutils/unittests, chronos, libp2p/crypto/[crypto, secp], diff --git a/tests/wakunode2/test_validators.nim b/tests/wakunode2/test_validators.nim index fc4c2cf57..95b07828e 100644 --- a/tests/wakunode2/test_validators.nim +++ b/tests/wakunode2/test_validators.nim @@ -1,7 +1,8 @@ {.used.} import - std/[sequtils, sysrand, math, options], + results, + std/[sequtils, sysrand, math], testutils/unittests, chronos, libp2p/crypto/crypto, @@ -86,7 +87,7 @@ suite "WakuNode2 - Validators": msg.meta = secretKey.sign(SkMessage(spamProtectedShard.msgHash(msg))).toRaw()[0 .. 63] - discard await nodes[i].publish(some($spamProtectedShard), msg) + discard await nodes[i].publish(Opt.some($spamProtectedShard), msg) # Wait for gossip await sleepAsync(2.seconds) @@ -177,7 +178,7 @@ suite "WakuNode2 - Validators": 0 .. 63 ] - discard await nodes[i].publish(some($spamProtectedShard), msg) + discard await nodes[i].publish(Opt.some($spamProtectedShard), msg) # Each node sends 5 messages that are not signed (total = 25) for i in 0 ..< 5: @@ -189,7 +190,7 @@ suite "WakuNode2 - Validators": timestamp: now(), ephemeral: true, ) - discard await nodes[i].publish(some($spamProtectedShard), unsignedMessage) + discard await nodes[i].publish(Opt.some($spamProtectedShard), unsignedMessage) # Each node sends 5 messages that dont contain timestamp (total = 25) for i in 0 ..< 5: @@ -201,7 +202,7 @@ suite "WakuNode2 - Validators": timestamp: 0, ephemeral: true, ) - discard await nodes[i].publish(some($spamProtectedShard), unsignedMessage) + discard await nodes[i].publish(Opt.some($spamProtectedShard), unsignedMessage) # Each node sends 5 messages way BEFORE than the current timestmap (total = 25) for i in 0 ..< 5: @@ -214,7 +215,7 @@ suite "WakuNode2 - Validators": timestamp: beforeTimestamp, ephemeral: true, ) - discard await nodes[i].publish(some($spamProtectedShard), unsignedMessage) + discard await nodes[i].publish(Opt.some($spamProtectedShard), unsignedMessage) # Each node sends 5 messages way LATER than the current timestmap (total = 25) for i in 0 ..< 5: @@ -227,7 +228,7 @@ suite "WakuNode2 - Validators": timestamp: afterTimestamp, ephemeral: true, ) - discard await nodes[i].publish(some($spamProtectedShard), unsignedMessage) + discard await nodes[i].publish(Opt.some($spamProtectedShard), unsignedMessage) # Since we have a full mesh with 5 nodes and each one publishes 25+25+25+25+25 msgs # there are 625 messages being sent. @@ -325,7 +326,7 @@ suite "WakuNode2 - Validators": timestamp: now(), ephemeral: true, ) - discard await nodes[0].publish(some($spamProtectedShard), unsignedMessage) + discard await nodes[0].publish(Opt.some($spamProtectedShard), unsignedMessage) # nodes[0] spams 50 wrongly signed messages (nodes[0] just knows of nodes[1]) for j in 0 ..< 50: @@ -339,7 +340,7 @@ suite "WakuNode2 - Validators": # Sign the message with a wrong key msg.meta = wrongSecretKey.sign(SkMessage(spamProtectedShard.msgHash(msg))).toRaw()[0 .. 63] - discard await nodes[0].publish(some($spamProtectedShard), msg) + discard await nodes[0].publish(Opt.some($spamProtectedShard), msg) # Wait for gossip await sleepAsync(2.seconds) diff --git a/tests/wakunode_rest/test_rest_cors.nim b/tests/wakunode_rest/test_rest_cors.nim index 5a57e0a9a..1ee92e804 100644 --- a/tests/wakunode_rest/test_rest_cors.nim +++ b/tests/wakunode_rest/test_rest_cors.nim @@ -1,4 +1,4 @@ -import std/options +import results {.used.} import @@ -28,7 +28,7 @@ proc testWakuNode(): WakuNode = extIp = parseIpAddress("127.0.0.1") port = Port(0) - newTestWakuNode(privkey, bindIp, port, some(extIp), some(port)) + newTestWakuNode(privkey, bindIp, port, Opt.some(extIp), Opt.some(port)) proc fetchWithHeader( request: HttpClientRequestRef @@ -52,7 +52,7 @@ proc fetchWithHeader( assert false proc issueRequest( - address: HttpAddress, reqOrigin: Option[string] = none(string) + address: HttpAddress, reqOrigin: Opt[string] = Opt.none(string) ): Future[TestResponseTuple] {.async.} = var session = HttpSessionRef.new({HttpClientFlag.Http11Pipeline}) @@ -72,7 +72,7 @@ proc issueRequest( return data proc checkResponse( - response: TestResponseTuple, expectedStatus: int, expectedOrigin: Option[string] + response: TestResponseTuple, expectedStatus: int, expectedOrigin: Opt[string] ): bool = if response.status != expectedStatus: echo( @@ -111,8 +111,9 @@ suite "Waku v2 REST API CORS Handling": .init( restAddress, restPort, - allowedOrigin = - some("test.net:1234,https://localhost:*,http://127.0.0.1:?8,?waku*.net:*80*"), + allowedOrigin = Opt.some( + "test.net:1234,https://localhost:*,http://127.0.0.1:?8,?waku*.net:*80*" + ), ) .tryGet() restPort = restServer.httpServer.address.port # update with bound port for client use @@ -124,29 +125,29 @@ suite "Waku v2 REST API CORS Handling": let ha = getAddress(srvAddr, HttpClientScheme.NonSecure, "/debug/v1/info") # When - var response = await issueRequest(ha, some("http://test.net:1234")) - check checkResponse(response, 200, some("http://test.net:1234")) + var response = await issueRequest(ha, Opt.some("http://test.net:1234")) + check checkResponse(response, 200, Opt.some("http://test.net:1234")) - response = await issueRequest(ha, some("https://test.net:1234")) - check checkResponse(response, 200, some("https://test.net:1234")) + response = await issueRequest(ha, Opt.some("https://test.net:1234")) + check checkResponse(response, 200, Opt.some("https://test.net:1234")) - response = await issueRequest(ha, some("https://localhost:8080")) - check checkResponse(response, 200, some("https://localhost:8080")) + response = await issueRequest(ha, Opt.some("https://localhost:8080")) + check checkResponse(response, 200, Opt.some("https://localhost:8080")) - response = await issueRequest(ha, some("https://localhost:80")) - check checkResponse(response, 200, some("https://localhost:80")) + response = await issueRequest(ha, Opt.some("https://localhost:80")) + check checkResponse(response, 200, Opt.some("https://localhost:80")) - response = await issueRequest(ha, some("http://127.0.0.1:78")) - check checkResponse(response, 200, some("http://127.0.0.1:78")) + response = await issueRequest(ha, Opt.some("http://127.0.0.1:78")) + check checkResponse(response, 200, Opt.some("http://127.0.0.1:78")) - response = await issueRequest(ha, some("http://wakuTHE.net:8078")) - check checkResponse(response, 200, some("http://wakuTHE.net:8078")) + response = await issueRequest(ha, Opt.some("http://wakuTHE.net:8078")) + check checkResponse(response, 200, Opt.some("http://wakuTHE.net:8078")) - response = await issueRequest(ha, some("http://nwaku.main.net:1980")) - check checkResponse(response, 200, some("http://nwaku.main.net:1980")) + response = await issueRequest(ha, Opt.some("http://nwaku.main.net:1980")) + check checkResponse(response, 200, Opt.some("http://nwaku.main.net:1980")) - response = await issueRequest(ha, some("http://nwaku.main.net:80")) - check checkResponse(response, 200, some("http://nwaku.main.net:80")) + response = await issueRequest(ha, Opt.some("http://nwaku.main.net:80")) + check checkResponse(response, 200, Opt.some("http://nwaku.main.net:80")) await restServer.stop() await restServer.closeWait() @@ -165,8 +166,9 @@ suite "Waku v2 REST API CORS Handling": .init( restAddress, restPort, - allowedOrigin = - some("test.net:1234,https://localhost:*,http://127.0.0.1:?8,?waku*.net:*80*"), + allowedOrigin = Opt.some( + "test.net:1234,https://localhost:*,http://127.0.0.1:?8,?waku*.net:*80*" + ), ) .tryGet() restPort = restServer.httpServer.address.port # update with bound port for client use @@ -178,32 +180,32 @@ suite "Waku v2 REST API CORS Handling": let ha = getAddress(srvAddr, HttpClientScheme.NonSecure, "/debug/v1/info") # When - var response = await issueRequest(ha, some("http://test.net:12334")) - check checkResponse(response, 403, none(string)) + var response = await issueRequest(ha, Opt.some("http://test.net:12334")) + check checkResponse(response, 403, Opt.none(string)) - response = await issueRequest(ha, some("http://test.net:12345")) - check checkResponse(response, 403, none(string)) + response = await issueRequest(ha, Opt.some("http://test.net:12345")) + check checkResponse(response, 403, Opt.none(string)) - response = await issueRequest(ha, some("xhttp://test.net:1234")) - check checkResponse(response, 403, none(string)) + response = await issueRequest(ha, Opt.some("xhttp://test.net:1234")) + check checkResponse(response, 403, Opt.none(string)) - response = await issueRequest(ha, some("https://xtest.net:1234")) - check checkResponse(response, 403, none(string)) + response = await issueRequest(ha, Opt.some("https://xtest.net:1234")) + check checkResponse(response, 403, Opt.none(string)) - response = await issueRequest(ha, some("http://localhost:8080")) - check checkResponse(response, 403, none(string)) + response = await issueRequest(ha, Opt.some("http://localhost:8080")) + check checkResponse(response, 403, Opt.none(string)) - response = await issueRequest(ha, some("https://127.0.0.1:78")) - check checkResponse(response, 403, none(string)) + response = await issueRequest(ha, Opt.some("https://127.0.0.1:78")) + check checkResponse(response, 403, Opt.none(string)) - response = await issueRequest(ha, some("http://127.0.0.1:89")) - check checkResponse(response, 403, none(string)) + response = await issueRequest(ha, Opt.some("http://127.0.0.1:89")) + check checkResponse(response, 403, Opt.none(string)) - response = await issueRequest(ha, some("http://the.waku.net:8078")) - check checkResponse(response, 403, none(string)) + response = await issueRequest(ha, Opt.some("http://the.waku.net:8078")) + check checkResponse(response, 403, Opt.none(string)) - response = await issueRequest(ha, some("http://nwaku.main.net:1900")) - check checkResponse(response, 403, none(string)) + response = await issueRequest(ha, Opt.some("http://nwaku.main.net:1900")) + check checkResponse(response, 403, Opt.none(string)) await restServer.stop() await restServer.closeWait() @@ -218,8 +220,9 @@ suite "Waku v2 REST API CORS Handling": var restPort = Port(0) let restAddress = parseIpAddress("0.0.0.0") - let restServer = - WakuRestServerRef.init(restAddress, restPort, allowedOrigin = some("*")).tryGet() + let restServer = WakuRestServerRef + .init(restAddress, restPort, allowedOrigin = Opt.some("*")) + .tryGet() restPort = restServer.httpServer.address.port # update with bound port for client use installDebugApiHandlers(restServer.router, node) @@ -229,29 +232,29 @@ suite "Waku v2 REST API CORS Handling": let ha = getAddress(srvAddr, HttpClientScheme.NonSecure, "/debug/v1/info") # When - var response = await issueRequest(ha, some("http://test.net:1234")) - check checkResponse(response, 200, some("*")) + var response = await issueRequest(ha, Opt.some("http://test.net:1234")) + check checkResponse(response, 200, Opt.some("*")) - response = await issueRequest(ha, some("https://test.net:1234")) - check checkResponse(response, 200, some("*")) + response = await issueRequest(ha, Opt.some("https://test.net:1234")) + check checkResponse(response, 200, Opt.some("*")) - response = await issueRequest(ha, some("https://localhost:8080")) - check checkResponse(response, 200, some("*")) + response = await issueRequest(ha, Opt.some("https://localhost:8080")) + check checkResponse(response, 200, Opt.some("*")) - response = await issueRequest(ha, some("https://localhost:80")) - check checkResponse(response, 200, some("*")) + response = await issueRequest(ha, Opt.some("https://localhost:80")) + check checkResponse(response, 200, Opt.some("*")) - response = await issueRequest(ha, some("http://127.0.0.1:78")) - check checkResponse(response, 200, some("*")) + response = await issueRequest(ha, Opt.some("http://127.0.0.1:78")) + check checkResponse(response, 200, Opt.some("*")) - response = await issueRequest(ha, some("http://wakuTHE.net:8078")) - check checkResponse(response, 200, some("*")) + response = await issueRequest(ha, Opt.some("http://wakuTHE.net:8078")) + check checkResponse(response, 200, Opt.some("*")) - response = await issueRequest(ha, some("http://nwaku.main.net:1980")) - check checkResponse(response, 200, some("*")) + response = await issueRequest(ha, Opt.some("http://nwaku.main.net:1980")) + check checkResponse(response, 200, Opt.some("*")) - response = await issueRequest(ha, some("http://nwaku.main.net:80")) - check checkResponse(response, 200, some("*")) + response = await issueRequest(ha, Opt.some("http://nwaku.main.net:80")) + check checkResponse(response, 200, Opt.some("*")) await restServer.stop() await restServer.closeWait() @@ -270,8 +273,9 @@ suite "Waku v2 REST API CORS Handling": .init( restAddress, restPort, - allowedOrigin = - some("test.net:1234,https://localhost:*,http://127.0.0.1:?8,?waku*.net:*80*"), + allowedOrigin = Opt.some( + "test.net:1234,https://localhost:*,http://127.0.0.1:?8,?waku*.net:*80*" + ), ) .tryGet() restPort = restServer.httpServer.address.port # update with bound port for client use @@ -283,8 +287,8 @@ suite "Waku v2 REST API CORS Handling": let ha = getAddress(srvAddr, HttpClientScheme.NonSecure, "/debug/v1/info") # When - var response = await issueRequest(ha, none(string)) - check checkResponse(response, 200, none(string)) + var response = await issueRequest(ha, Opt.none(string)) + check checkResponse(response, 200, Opt.none(string)) await restServer.stop() await restServer.closeWait() diff --git a/tests/wakunode_rest/test_rest_debug.nim b/tests/wakunode_rest/test_rest_debug.nim index 8885c8230..c10913cb8 100644 --- a/tests/wakunode_rest/test_rest_debug.nim +++ b/tests/wakunode_rest/test_rest_debug.nim @@ -1,7 +1,7 @@ {.used.} import - std/options, + results, testutils/unittests, presto, presto/client as presto_client, @@ -30,7 +30,7 @@ proc testWakuNode(): WakuNode = extIp = parseIpAddress("127.0.0.1") port = Port(0) - newTestWakuNode(privkey, bindIp, port, some(extIp), some(port)) + newTestWakuNode(privkey, bindIp, port, Opt.some(extIp), Opt.some(port)) suite "Waku v2 REST API - Debug": asyncTest "Get node info - GET /info": diff --git a/tests/wakunode_rest/test_rest_debug_serdes.nim b/tests/wakunode_rest/test_rest_debug_serdes.nim index bdc3ed57f..305bb984f 100644 --- a/tests/wakunode_rest/test_rest_debug_serdes.nim +++ b/tests/wakunode_rest/test_rest_debug_serdes.nim @@ -1,4 +1,3 @@ -import std/options {.used.} import results, stew/byteutils, testutils/unittests, json_serialization @@ -25,7 +24,7 @@ suite "Waku v2 REST API - Debug - serialization": suite "DebugWakuInfo - encode": test "optional field is none": # Given - let data = DebugWakuInfo(listenAddresses: @["GO"], enrUri: none(string)) + let data = DebugWakuInfo(listenAddresses: @["GO"], enrUri: Opt.none(string)) # When let res = encodeIntoJsonBytes(data) diff --git a/tests/wakunode_rest/test_rest_filter.nim b/tests/wakunode_rest/test_rest_filter.nim index b20e67e59..24af0572a 100644 --- a/tests/wakunode_rest/test_rest_filter.nim +++ b/tests/wakunode_rest/test_rest_filter.nim @@ -1,4 +1,4 @@ -import std/options +import results {.used.} import @@ -36,7 +36,7 @@ proc testWakuNode(): WakuNode = extIp = parseIpAddress("127.0.0.1") port = Port(0) - return newTestWakuNode(privkey, bindIp, port, some(extIp), some(port)) + return newTestWakuNode(privkey, bindIp, port, Opt.some(extIp), Opt.some(port)) type RestFilterTest = object serviceNode: WakuNode @@ -116,7 +116,7 @@ suite "Waku v2 Rest API - Filter V2": let requestBody = FilterSubscribeRequest( requestId: "1234", contentFilters: contentFilters, - pubsubTopic: some(DefaultPubsubTopic), + pubsubTopic: Opt.some(DefaultPubsubTopic), ) let response = await restFilterTest.client.filterPostSubscriptions(requestBody) @@ -148,7 +148,7 @@ suite "Waku v2 Rest API - Filter V2": # When - error case let badRequestBody = FilterSubscribeRequest( - requestId: "4567", contentFilters: @[], pubsubTopic: none(string) + requestId: "4567", contentFilters: @[], pubsubTopic: Opt.none(string) ) let badRequestResp = await restFilterTest.client.filterPostSubscriptions(badRequestBody) @@ -173,7 +173,7 @@ suite "Waku v2 Rest API - Filter V2": requestId: "1234", contentFilters: @[ContentTopic("1"), ContentTopic("2"), ContentTopic("3"), ContentTopic("4")], - pubsubTopic: some(DefaultPubsubTopic), + pubsubTopic: Opt.some(DefaultPubsubTopic), ) discard await restFilterTest.client.filterPostSubscriptions(requestBody) @@ -186,7 +186,7 @@ suite "Waku v2 Rest API - Filter V2": let requestBodyUnsub = FilterUnsubscribeRequest( requestId: "4321", contentFilters: contentFilters, - pubsubTopic: some(DefaultPubsubTopic), + pubsubTopic: Opt.some(DefaultPubsubTopic), ) let response = await restFilterTest.client.filterDeleteSubscriptions(requestBodyUnsub) @@ -243,7 +243,7 @@ suite "Waku v2 Rest API - Filter V2": var requestBody = FilterSubscribeRequest( requestId: "1234", contentFilters: @[ContentTopic("1")], - pubsubTopic: some(DefaultPubsubTopic), + pubsubTopic: Opt.some(DefaultPubsubTopic), ) discard await restFilterTest.client.filterPostSubscriptions(requestBody) @@ -294,7 +294,7 @@ suite "Waku v2 Rest API - Filter V2": var requestBody = FilterSubscribeRequest( requestId: "1234", contentFilters: @[ContentTopic("1")], - pubsubTopic: some(DefaultPubsubTopic), + pubsubTopic: Opt.some(DefaultPubsubTopic), ) discard await restFilterTest.client.filterPostSubscriptions(requestBody) @@ -346,7 +346,7 @@ suite "Waku v2 Rest API - Filter V2": let requestBody = FilterSubscribeRequest( requestId: "1001", contentFilters: @[DefaultContentTopic], - pubsubTopic: some(DefaultPubsubTopic), + pubsubTopic: Opt.some(DefaultPubsubTopic), ) let response = await restFilterTest.client.filterPostSubscriptions(requestBody) @@ -425,7 +425,7 @@ suite "Waku v2 Rest API - Filter V2": let requestBody = FilterSubscribeRequest( requestId: "1001", contentFilters: @[DefaultContentTopic], - pubsubTopic: some(DefaultPubsubTopic), + pubsubTopic: Opt.some(DefaultPubsubTopic), ) let response = await restFilterTest.client.filterPostSubscriptions(requestBody) diff --git a/tests/wakunode_rest/test_rest_health.nim b/tests/wakunode_rest/test_rest_health.nim index 4a2fa0250..bebdb9db7 100644 --- a/tests/wakunode_rest/test_rest_health.nim +++ b/tests/wakunode_rest/test_rest_health.nim @@ -1,7 +1,8 @@ {.used.} import - std/[tempfiles, osproc, options], + results, + std/[tempfiles, osproc], testutils/unittests, presto, presto/client as presto_client, @@ -34,7 +35,7 @@ proc testWakuNode(): WakuNode = extIp = parseIpAddress("127.0.0.1") port = Port(0) - newTestWakuNode(privkey, bindIp, port, some(extIp), some(port)) + newTestWakuNode(privkey, bindIp, port, Opt.some(extIp), Opt.some(port)) suite "Waku v2 REST API - health": # TODO: better test for health @@ -42,7 +43,7 @@ suite "Waku v2 REST API - health": var manager {.threadVar.}: OnchainGroupManager setup: - anvilProc = runAnvil(stateFile = some(DEFAULT_ANVIL_STATE_PATH)) + anvilProc = runAnvil(stateFile = Opt.some(DEFAULT_ANVIL_STATE_PATH)) manager = waitFor setupOnchainGroupManager(deployContracts = false) teardown: @@ -89,7 +90,7 @@ suite "Waku v2 REST API - health": report.protocolsHealth.len() == 13 report.getHealth(RelayProtocol).health == HealthStatus.NOT_READY - report.getHealth(RelayProtocol).desc == some("No connected peers") + report.getHealth(RelayProtocol).desc == Opt.some("No connected peers") report.getHealth(RlnRelayProtocol).health == HealthStatus.READY @@ -103,14 +104,14 @@ suite "Waku v2 REST API - health": report.getHealth(LightpushClientProtocol).health == HealthStatus.NOT_READY report.getHealth(LightpushClientProtocol).desc == - some("No Lightpush service peer available yet") + Opt.some("No Lightpush service peer available yet") report.getHealth(LegacyLightpushClientProtocol).health == HealthStatus.NOT_MOUNTED report.getHealth(StoreClientProtocol).health == HealthStatus.NOT_MOUNTED report.getHealth(FilterClientProtocol).health == HealthStatus.NOT_READY report.getHealth(FilterClientProtocol).desc == - some("No Filter service peer available yet") + Opt.some("No Filter service peer available yet") await restServer.stop() await restServer.closeWait() diff --git a/tests/wakunode_rest/test_rest_lightpush.nim b/tests/wakunode_rest/test_rest_lightpush.nim index ff602328a..2c03a10da 100644 --- a/tests/wakunode_rest/test_rest_lightpush.nim +++ b/tests/wakunode_rest/test_rest_lightpush.nim @@ -1,4 +1,4 @@ -import std/options +import results {.used.} import @@ -35,7 +35,7 @@ proc testWakuNode(): WakuNode = extIp = parseIpAddress("127.0.0.1") port = Port(0) - return newTestWakuNode(privkey, bindIp, port, some(extIp), some(port)) + return newTestWakuNode(privkey, bindIp, port, Opt.some(extIp), Opt.some(port)) type RestLightPushTest = object serviceNode: WakuNode @@ -112,7 +112,7 @@ suite "Waku v2 Rest API - lightpush": check message.proof.isSome() let requestBody = - PushRequest(pubsubTopic: some(DefaultPubsubTopic), message: message) + PushRequest(pubsubTopic: Opt.some(DefaultPubsubTopic), message: message) let response = await restLightPushTest.restClient.sendPushRequest(body = requestBody) @@ -122,8 +122,8 @@ suite "Waku v2 Rest API - lightpush": ## handling the proof message attribute within the REST request. check: response.status == 505 - response.data.statusDesc == some("No peers for topic, skipping publish") - response.data.relayPeerCount == none[uint32]() + response.data.statusDesc == Opt.some("No peers for topic, skipping publish") + response.data.relayPeerCount == Opt.none(uint32) asyncTest "Push message request": # Given @@ -153,7 +153,7 @@ suite "Waku v2 Rest API - lightpush": .toRelayWakuMessage() let requestBody = - PushRequest(pubsubTopic: some(DefaultPubsubTopic), message: message) + PushRequest(pubsubTopic: Opt.some(DefaultPubsubTopic), message: message) let response = await restLightPushTest.restClient.sendPushRequest(requestBody) echo "response", $response @@ -161,7 +161,7 @@ suite "Waku v2 Rest API - lightpush": # Then check: response.status == 200 - response.data.relayPeerCount == some(1.uint32) + response.data.relayPeerCount == Opt.some(1.uint32) await restLightPushTest.shutdown() @@ -186,15 +186,15 @@ suite "Waku v2 Rest API - lightpush": ) .toRelayWakuMessage() let badRequestBody1 = - PushRequest(pubsubTopic: some(DefaultPubsubTopic), message: badMessage1) + PushRequest(pubsubTopic: Opt.some(DefaultPubsubTopic), message: badMessage1) let badMessage2: RelayWakuMessage = fakeWakuMessage(contentTopic = "", payload = toBytes("Sthg")).toRelayWakuMessage() let badRequestBody2 = - PushRequest(pubsubTopic: some(DefaultPubsubTopic), message: badMessage2) + PushRequest(pubsubTopic: Opt.some(DefaultPubsubTopic), message: badMessage2) let badRequestBody3 = - PushRequest(pubsubTopic: none(PubsubTopic), message: badMessage2) + PushRequest(pubsubTopic: Opt.none(PubsubTopic), message: badMessage2) # var response: RestResponse[PushResponse] @@ -255,7 +255,7 @@ suite "Waku v2 Rest API - lightpush": .toRelayWakuMessage() let requestBody = - PushRequest(pubsubTopic: some(DefaultPubsubTopic), message: message) + PushRequest(pubsubTopic: Opt.some(DefaultPubsubTopic), message: message) let response = await restLightPushTest.restClient.sendPushRequest(requestBody) echo "response", $response @@ -263,7 +263,7 @@ suite "Waku v2 Rest API - lightpush": # Then check: response.status == 200 - response.data.relayPeerCount == some(1.uint32) + response.data.relayPeerCount == Opt.some(1.uint32) let pushRejectedProc = proc() {.async.} = let message: RelayWakuMessage = fakeWakuMessage( @@ -272,7 +272,7 @@ suite "Waku v2 Rest API - lightpush": .toRelayWakuMessage() let requestBody = - PushRequest(pubsubTopic: some(DefaultPubsubTopic), message: message) + PushRequest(pubsubTopic: Opt.some(DefaultPubsubTopic), message: message) let response = await restLightPushTest.restClient.sendPushRequest(requestBody) echo "response", $response diff --git a/tests/wakunode_rest/test_rest_lightpush_legacy.nim b/tests/wakunode_rest/test_rest_lightpush_legacy.nim index 5f29146c8..03679293f 100644 --- a/tests/wakunode_rest/test_rest_lightpush_legacy.nim +++ b/tests/wakunode_rest/test_rest_lightpush_legacy.nim @@ -1,4 +1,4 @@ -import std/options +import results {.used.} import @@ -35,7 +35,7 @@ proc testWakuNode(): WakuNode = extIp = parseIpAddress("127.0.0.1") port = Port(0) - return newTestWakuNode(privkey, bindIp, port, some(extIp), some(port)) + return newTestWakuNode(privkey, bindIp, port, Opt.some(extIp), Opt.some(port)) type RestLightPushTest = object serviceNode: WakuNode @@ -110,7 +110,7 @@ suite "Waku v2 Rest API - lightpush": check message.proof.isSome() let requestBody = - PushRequest(pubsubTopic: some(DefaultPubsubTopic), message: message) + PushRequest(pubsubTopic: Opt.some(DefaultPubsubTopic), message: message) let response = await restLightPushTest.client.sendPushRequest(body = requestBody) @@ -147,7 +147,7 @@ suite "Waku v2 Rest API - lightpush": .toRelayWakuMessage() let requestBody = - PushRequest(pubsubTopic: some(DefaultPubsubTopic), message: message) + PushRequest(pubsubTopic: Opt.some(DefaultPubsubTopic), message: message) let response = await restLightPushTest.client.sendPushRequest(requestBody) echo "response", $response @@ -180,15 +180,15 @@ suite "Waku v2 Rest API - lightpush": ) .toRelayWakuMessage() let badRequestBody1 = - PushRequest(pubsubTopic: some(DefaultPubsubTopic), message: badMessage1) + PushRequest(pubsubTopic: Opt.some(DefaultPubsubTopic), message: badMessage1) let badMessage2: RelayWakuMessage = fakeWakuMessage(contentTopic = "", payload = toBytes("Sthg")).toRelayWakuMessage() let badRequestBody2 = - PushRequest(pubsubTopic: some(DefaultPubsubTopic), message: badMessage2) + PushRequest(pubsubTopic: Opt.some(DefaultPubsubTopic), message: badMessage2) let badRequestBody3 = - PushRequest(pubsubTopic: none(PubsubTopic), message: badMessage2) + PushRequest(pubsubTopic: Opt.none(PubsubTopic), message: badMessage2) var response: RestResponse[string] @@ -252,7 +252,7 @@ suite "Waku v2 Rest API - lightpush": .toRelayWakuMessage() let requestBody = - PushRequest(pubsubTopic: some(DefaultPubsubTopic), message: message) + PushRequest(pubsubTopic: Opt.some(DefaultPubsubTopic), message: message) let response = await restLightPushTest.client.sendPushRequest(requestBody) echo "response", $response @@ -269,7 +269,7 @@ suite "Waku v2 Rest API - lightpush": .toRelayWakuMessage() let requestBody = - PushRequest(pubsubTopic: some(DefaultPubsubTopic), message: message) + PushRequest(pubsubTopic: Opt.some(DefaultPubsubTopic), message: message) let response = await restLightPushTest.client.sendPushRequest(requestBody) echo "response", $response diff --git a/tests/wakunode_rest/test_rest_relay.nim b/tests/wakunode_rest/test_rest_relay.nim index b59dc463d..7368545ba 100644 --- a/tests/wakunode_rest/test_rest_relay.nim +++ b/tests/wakunode_rest/test_rest_relay.nim @@ -1,7 +1,8 @@ {.used.} import - std/[sequtils, strformat, strutils, tempfiles, osproc, options], + results, + std/[sequtils, strformat, strutils, tempfiles, osproc], stew/byteutils, testutils/unittests, presto, @@ -35,14 +36,14 @@ proc testWakuNode(): WakuNode = extIp = parseIpAddress("127.0.0.1") port = Port(0) - newTestWakuNode(privkey, bindIp, port, some(extIp), some(port)) + newTestWakuNode(privkey, bindIp, port, Opt.some(extIp), Opt.some(port)) suite "Waku v2 Rest API - Relay": var anvilProc {.threadVar.}: Process var manager {.threadVar.}: OnchainGroupManager setup: - anvilProc = runAnvil(stateFile = some(DEFAULT_ANVIL_STATE_PATH)) + anvilProc = runAnvil(stateFile = Opt.some(DEFAULT_ANVIL_STATE_PATH)) manager = waitFor setupOnchainGroupManager(deployContracts = false) teardown: @@ -308,8 +309,8 @@ suite "Waku v2 Rest API - Relay": DefaultPubsubTopic, RelayWakuMessage( payload: base64.encode("TEST-PAYLOAD"), - contentTopic: some(DefaultContentTopic), - timestamp: some(now()), + contentTopic: Opt.some(DefaultContentTopic), + timestamp: Opt.some(now()), ), ) @@ -576,8 +577,8 @@ suite "Waku v2 Rest API - Relay": let response = await client.relayPostAutoMessagesV1( RelayWakuMessage( payload: base64.encode("TEST-PAYLOAD"), - contentTopic: some(DefaultContentTopic), - timestamp: some(now()), + contentTopic: Opt.some(DefaultContentTopic), + timestamp: Opt.some(now()), ) ) @@ -636,8 +637,8 @@ suite "Waku v2 Rest API - Relay": let response = await client.relayPostAutoMessagesV1( RelayWakuMessage( payload: base64.encode("TEST-PAYLOAD"), - contentTopic: some(invalidContentTopic), - timestamp: some(int64(2022)), + contentTopic: Opt.some(invalidContentTopic), + timestamp: Opt.some(int64(2022)), ) ) @@ -707,8 +708,8 @@ suite "Waku v2 Rest API - Relay": RelayWakuMessage( payload: base64.encode(getByteSequence(DefaultMaxWakuMessageSize)), # Message will be bigger than the max size - contentTopic: some(DefaultContentTopic), - timestamp: some(int64(2022)), + contentTopic: Opt.some(DefaultContentTopic), + timestamp: Opt.some(int64(2022)), ), ) @@ -778,8 +779,8 @@ suite "Waku v2 Rest API - Relay": RelayWakuMessage( payload: base64.encode(getByteSequence(DefaultMaxWakuMessageSize)), # Message will be bigger than the max size - contentTopic: some(DefaultContentTopic), - timestamp: some(int64(2022)), + contentTopic: Opt.some(DefaultContentTopic), + timestamp: Opt.some(int64(2022)), ) ) @@ -851,8 +852,8 @@ suite "Waku v2 Rest API - Relay": DefaultPubsubTopic, RelayWakuMessage( payload: base64.encode("TEST-PAYLOAD"), - contentTopic: some(DefaultContentTopic), - timestamp: some(now()), + contentTopic: Opt.some(DefaultContentTopic), + timestamp: Opt.some(now()), ), ) @@ -872,8 +873,8 @@ suite "Waku v2 Rest API - Relay": DefaultPubsubTopic, RelayWakuMessage( payload: base64.encode("TEST-PAYLOAD"), - contentTopic: some(DefaultContentTopic), - timestamp: some(now()), + contentTopic: Opt.some(DefaultContentTopic), + timestamp: Opt.some(now()), ), ) @@ -957,8 +958,8 @@ suite "Waku v2 Rest API - Relay": let response = await client.relayPostAutoMessagesV1( RelayWakuMessage( payload: base64.encode("TEST-PAYLOAD"), - contentTopic: some(DefaultContentTopic), - timestamp: some(now()), + contentTopic: Opt.some(DefaultContentTopic), + timestamp: Opt.some(now()), ) ) @@ -977,8 +978,8 @@ suite "Waku v2 Rest API - Relay": let retryResponse = await client.relayPostAutoMessagesV1( RelayWakuMessage( payload: base64.encode("TEST-PAYLOAD"), - contentTopic: some(DefaultContentTopic), - timestamp: some(now()), + contentTopic: Opt.some(DefaultContentTopic), + timestamp: Opt.some(now()), ) ) diff --git a/tests/wakunode_rest/test_rest_relay_serdes.nim b/tests/wakunode_rest/test_rest_relay_serdes.nim index ca0e45c30..e27ac444c 100644 --- a/tests/wakunode_rest/test_rest_relay_serdes.nim +++ b/tests/wakunode_rest/test_rest_relay_serdes.nim @@ -1,4 +1,3 @@ -import std/options {.used.} import results, stew/byteutils, unittest2, json_serialization @@ -34,10 +33,10 @@ suite "Waku v2 Rest API - Relay - serialization": let payload = base64.encode("MESSAGE") let data = RelayWakuMessage( payload: payload, - contentTopic: none(ContentTopic), - version: none(Natural), - timestamp: none(int64), - ephemeral: none(bool), + contentTopic: Opt.none(ContentTopic), + version: Opt.none(Natural), + timestamp: Opt.none(int64), + ephemeral: Opt.none(bool), ) # When diff --git a/tests/wakunode_rest/test_rest_store.nim b/tests/wakunode_rest/test_rest_store.nim index 0f4ed10ea..74847bf9b 100644 --- a/tests/wakunode_rest/test_rest_store.nim +++ b/tests/wakunode_rest/test_rest_store.nim @@ -1,7 +1,8 @@ {.used.} import - std/[options, sugar], + results, + std/sugar, chronicles, chronos/timer, testutils/unittests, @@ -51,7 +52,7 @@ proc testWakuNode(): WakuNode = extIp = parseIpAddress("127.0.0.1") port = Port(0) - return newTestWakuNode(privkey, bindIp, port, some(extIp), some(port)) + return newTestWakuNode(privkey, bindIp, port, Opt.some(extIp), Opt.some(port)) ################################################################################ # Beginning of the tests @@ -64,7 +65,7 @@ procSuite "Waku Rest API - Store v3": ) let messageHash = computeMessageHash(DefaultPubsubTopic, wakuMsg) - let restMsgHash = some(messageHash.toRestStringWakuMessageHash()) + let restMsgHash = Opt.some(messageHash.toRestStringWakuMessageHash()) let parsedMsgHashRes = parseHash(restMsgHash) assert parsedMsgHashRes.isOk(), $parsedMsgHashRes.error @@ -74,7 +75,7 @@ procSuite "Waku Rest API - Store v3": # Random validation. Obtained the raw values manually let expected = - some("0x9e0ea917677a3d2b8610b0126986d89824b6acf76008b5fb9aa8b99ac906c1a7") + Opt.some("0x9e0ea917677a3d2b8610b0126986d89824b6acf76008b5fb9aa8b99ac906c1a7") let msgHashRes = parseHash(expected) assert msgHashRes.isOk(), $msgHashRes.error @@ -98,7 +99,7 @@ procSuite "Waku Rest API - Store v3": # WakuStore setup let db: SqliteDatabase = - SqliteDatabase.new(string.none().get(":memory:")).expect("valid DB") + SqliteDatabase.new(Opt.none(string).get(":memory:")).expect("valid DB") let driver: ArchiveDriver = SqliteDriver.new(db).expect("valid driver") let mountArchiveRes = node.mountArchive(driver) assert mountArchiveRes.isOk(), mountArchiveRes.error @@ -282,7 +283,7 @@ procSuite "Waku Rest API - Store v3": var pages = newSeq[seq[WakuMessage]](2) - var reqHash = none(string) + var reqHash = Opt.none(string) for i in 0 ..< 2: let response = await client.getStoreMessagesV3( @@ -310,7 +311,7 @@ procSuite "Waku Rest API - Store v3": # populate the cursor for next page if response.data.paginationCursor.isSome(): - reqHash = some(response.data.paginationCursor.get()) + reqHash = Opt.some(response.data.paginationCursor.get()) check: response.status == 200 @@ -772,7 +773,7 @@ procSuite "Waku Rest API - Store v3": var pages = newSeq[seq[WakuMessage]](2) var reqPubsubTopic = DefaultPubsubTopic - var reqHash = none(string) + var reqHash = Opt.none(string) for i in 0 ..< 2: let response = await client.getStoreMessagesV3( diff --git a/tools/confutils/cli_args.nim b/tools/confutils/cli_args.nim index aa7b6cb1b..1774f1445 100644 --- a/tools/confutils/cli_args.nim +++ b/tools/confutils/cli_args.nim @@ -64,7 +64,7 @@ type WakuNodeConf* = object configFile* {. desc: "Loads configuration from a TOML file (cmd-line parameters take precedence)", name: "config-file" - .}: Option[InputFile] + .}: Opt[InputFile] ## Log configuration logLevel* {. @@ -119,23 +119,23 @@ type WakuNodeConf* = object name: "rln-relay-eth-private-key" .}: string - # Option-typed; desc states the default since the CLI can't auto-show it for none(). + # Opt-typed; desc states the default since the CLI can't auto-show it for Opt.none(). rlnRelayUserMessageLimit* {. desc: "Set a user message limit for the rln membership registration. Must be a positive integer. Default is " & $DefaultRlnRelayUserMessageLimit & ".", - defaultValue: none(uint64), + defaultValue: Opt.none(uint64), name: "rln-relay-user-message-limit" - .}: Option[uint64] + .}: Opt[uint64] - # Option-typed; desc states the default since the CLI can't auto-show it for none(). + # Opt-typed; desc states the default since the CLI can't auto-show it for Opt.none(). rlnEpochSizeSec* {. desc: "Epoch size in seconds used to rate limit RLN memberships. Default is " & $DefaultRlnRelayEpochSizeSec & " second.", - defaultValue: none(uint64), + defaultValue: Opt.none(uint64), name: "rln-relay-epoch-sec" - .}: Option[uint64] + .}: Opt[uint64] maxMessageSize* {. desc: @@ -168,15 +168,15 @@ type WakuNodeConf* = object name: "preset" .}: string - # Option-typed; desc states the default since the CLI can't auto-show it for none(). + # Opt-typed; desc states the default since the CLI can't auto-show it for Opt.none(). clusterId* {. desc: static( "Cluster id that the node is running in. Node in a different cluster id is disconnected. Default is " & $DefaultClusterId & "." ), - defaultValue: none(uint16), + defaultValue: Opt.none(uint16), name: "cluster-id" - .}: Option[uint16] + .}: Opt[uint16] agentString* {. defaultValue: DefaultAgentString, @@ -185,7 +185,7 @@ type WakuNodeConf* = object .}: string nodekey* {.desc: "P2P node private key as 64 char hex string.", name: "nodekey".}: - Option[PrivateKey] + Opt[PrivateKey] listenAddress* {. defaultValue: defaultListenAddress(), @@ -243,7 +243,7 @@ type WakuNodeConf* = object peerStoreCapacity* {. desc: "Maximum stored peers in the peerstore.", name: "peer-store-capacity" - .}: Option[int] + .}: Opt[int] peerPersistence* {. desc: "Enable peer persistence.", defaultValue: false, name: "peer-persistence" @@ -295,25 +295,25 @@ hence would have reachability issues.""", name: "relay-shard-manager" .}: bool - # Option-typed; desc states the default since the CLI can't auto-show it for none(). + # Opt-typed; desc states the default since the CLI can't auto-show it for Opt.none(). rlnRelay* {. desc: "Enable spam protection through rln-relay: true|false. Default is " & $DefaultRlnRelayEnabled & ".", - defaultValue: none(bool), + defaultValue: Opt.none(bool), name: "rln-relay" - .}: Option[bool] + .}: Opt[bool] rlnRelayCredIndex* {. desc: "the index of the onchain commitment to use", name: "rln-relay-membership-index" - .}: Option[uint] + .}: Opt[uint] rlnRelayDynamic* {. desc: "Enable waku-rln-relay with on-chain dynamic group management: true|false.", - defaultValue: none(bool), + defaultValue: Opt.none(bool), name: "rln-relay-dynamic" - .}: Option[bool] + .}: Opt[bool] entryNodes* {. desc: @@ -557,9 +557,10 @@ hence would have reachability issues.""", ## Discovery v5 config discv5Discovery* {. desc: "Enable discovering nodes via Node Discovery v5. Default is true.", - defaultValue: some(true), + defaultValue: Opt.some(true), + defaultValueDesc: "true", name: "discv5-discovery" - .}: Option[bool] + .}: Opt[bool] discv5UdpPort* {. desc: "Listening UDP port for Node Discovery v5.", @@ -625,18 +626,18 @@ hence would have reachability issues.""", .}: bool #Mix config - # Option-typed; desc states the default since the CLI can't auto-show it for none(). + # Opt-typed; desc states the default since the CLI can't auto-show it for Opt.none(). mix* {. desc: "Enable mix protocol: true|false. Default is " & $DefaultMix & ".", - defaultValue: none(bool), + defaultValue: Opt.none(bool), name: "mix" - .}: Option[bool] + .}: Opt[bool] mixkey* {. desc: "ED25519 private key as 64 char hex string , without 0x. If not provided, a random key will be generated.", name: "mixkey" - .}: Option[string] + .}: Opt[string] mixnodes* {. desc: @@ -645,14 +646,14 @@ hence would have reachability issues.""", .}: seq[MixNodePubInfo] # Kademlia Discovery config - # Option-typed; desc states the default since the CLI can't auto-show it for none(). + # Opt-typed; desc states the default since the CLI can't auto-show it for Opt.none(). enableKadDiscovery* {. desc: "Enable extended kademlia discovery. Can be enabled without bootstrap nodes for the first node in the network. Default is " & $DefaultKadEnabled & ".", - defaultValue: none(bool), + defaultValue: Opt.none(bool), name: "enable-kad-discovery" - .}: Option[bool] + .}: Opt[bool] kadBootstrapNodes* {. desc: @@ -915,6 +916,12 @@ proc readValue*( except CatchableError: raise newException(SerializationError, getCurrentExceptionMsg()) +proc readValue*[T]( + r: var TomlReader, value: var Opt[T] +) {.gcsafe, raises: [SerializationError, IOError].} = + mixin readValue + value = Opt.some(r.readValue(T)) + proc load*(T: type WakuNodeConf, version = ""): ConfResult[T] = try: let conf = WakuNodeConf.load( @@ -953,8 +960,8 @@ proc toKeystoreGeneratorConf*(n: WakuNodeConf): RlnKeystoreGeneratorConf = ) proc toNetworkPresetConf*( - preset: string, clusterId: Option[uint16] -): ConfResult[Option[NetworkPresetConf]] = + preset: string, clusterId: Opt[uint16] +): ConfResult[Opt[NetworkPresetConf]] = var lcPreset = toLowerAscii(preset) if clusterId.isSome() and clusterId.get() == 1: warn( @@ -969,15 +976,15 @@ proc toNetworkPresetConf*( case lcPreset of "": - ok(none(NetworkPresetConf)) + ok(Opt.none(NetworkPresetConf)) of "twn": - ok(some(NetworkPresetConf.TheWakuNetworkConf())) + ok(Opt.some(NetworkPresetConf.TheWakuNetworkConf())) of "logos.dev", "logosdev": - ok(some(NetworkPresetConf.LogosDevConf())) + ok(Opt.some(NetworkPresetConf.LogosDevConf())) of "logos.test", "logostest": - ok(some(NetworkPresetConf.LogosTestConf())) + ok(Opt.some(NetworkPresetConf.LogosTestConf())) of "status.prod", "statusprod": - ok(some(NetworkPresetConf.StatusProdConf())) + ok(Opt.some(NetworkPresetConf.StatusProdConf())) else: err("Invalid --preset value passed: " & lcPreset) @@ -1093,7 +1100,7 @@ proc toWakuConf*(n: WakuNodeConf): ConfResult[WakuConf] = b.storeServiceConf.withMaxNumDbConnections(n.storeMaxNumDbConnections) b.storeServiceConf.withResume(n.storeResume) - # TODO: can we just use `Option` on the CLI? + # TODO: can we just use `Opt` on the CLI? if n.storenode != "": b.withRemoteStoreNode(n.storenode) if n.filternode != "": diff --git a/tools/confutils/conf_from_json.nim b/tools/confutils/conf_from_json.nim index 7e78fd300..e51a943b6 100644 --- a/tools/confutils/conf_from_json.nim +++ b/tools/confutils/conf_from_json.nim @@ -1,4 +1,4 @@ -import std/[json, macros, options, strutils, tables] +import std/[json, macros, strutils, tables] import confutils, confutils/defs, confutils/std/net, results # The shared JSON walker is `raises: []` so the messaging FFI parser (also @@ -121,19 +121,20 @@ proc applyJsonFieldsToConf*[T]( # JSON null leaves the field unset; it keeps its default. jsonFields.del(matchKey) else: - when confValue is Option: + when confValue is Opt: type Inner = typeof(confValue.get()) when Inner is seq: type Elem = typeof(confValue.get()[0]) when compiles(parseCmdArg(Elem, "")): - confValue = - some(?parseSeqInto[Elem](jsonValue, confField, jsonKey, parseErrPrefix)) + confValue = Opt.some( + ?parseSeqInto[Elem](jsonValue, confField, jsonKey, parseErrPrefix) + ) jsonFields.del(matchKey) else: return err("config option '" & jsonKey & "' cannot be set via JSON") else: when compiles(parseCmdArg(Inner, "")): - confValue = some( + confValue = Opt.some( ?parseScalarInto[Inner](jsonValue, confField, jsonKey, parseErrPrefix) ) jsonFields.del(matchKey) diff --git a/tools/confutils/envvar_serialization/reader.nim b/tools/confutils/envvar_serialization/reader.nim index ef0f47ac1..72ff8faa8 100644 --- a/tools/confutils/envvar_serialization/reader.nim +++ b/tools/confutils/envvar_serialization/reader.nim @@ -1,7 +1,8 @@ {.push raises: [].} import - std/[tables, typetraits, options, os], + results, + std/[options, tables, typetraits, os], serialization/object_serialization, serialization/errors import ./utils @@ -49,6 +50,22 @@ proc readValue*[T](r: var EnvvarReader, value: var T) {.raises: [SerializationEr SerializationError, "Couldn't getValue SomePrimitives: " & getCurrentExceptionMsg(), ) + elif T is Opt: + template getUnderlyingType[T](_: Opt[T]): untyped = + T + + let key = constructKey(r.prefix, r.key) + if os.existsEnv(key): + type uType = getUnderlyingType(value) + when uType is string: + value = Opt.some(os.getEnv(key)) + else: + try: + value = Opt.some(r.readValue(uType)) + except ValueError, IOError: + raise newException( + SerializationError, "Couldn't read Opt value: " & getCurrentExceptionMsg() + ) elif T is Option: template getUnderlyingType[T](_: Option[T]): untyped = T @@ -57,10 +74,10 @@ proc readValue*[T](r: var EnvvarReader, value: var T) {.raises: [SerializationEr if os.existsEnv(key): type uType = getUnderlyingType(value) when uType is string: - value = some(os.getEnv(key)) + value = options.some(os.getEnv(key)) else: try: - value = some(r.readValue(uType)) + value = options.some(r.readValue(uType)) except ValueError, IOError: raise newException( SerializationError, diff --git a/tools/confutils/envvar_serialization/writer.nim b/tools/confutils/envvar_serialization/writer.nim index c497b5496..de4c135c8 100644 --- a/tools/confutils/envvar_serialization/writer.nim +++ b/tools/confutils/envvar_serialization/writer.nim @@ -1,4 +1,4 @@ -import typetraits, options, tables, os, serialization, ./utils +import results, std/options, typetraits, tables, os, serialization, ./utils type EnvvarWriter* = object prefix: string @@ -17,6 +17,9 @@ proc writeValue*(w: var EnvvarWriter, value: auto) = elif value is (SomePrimitives or range): let key = constructKey(w.prefix, w.key) setValue(key, value) + elif value is Opt: + if value.isSome: + w.writeValue value.get elif value is Option: if value.isSome: w.writeValue value.get diff --git a/tools/rln_keystore_generator/rln_keystore_generator.nim b/tools/rln_keystore_generator/rln_keystore_generator.nim index 9643f039f..22d7a35de 100644 --- a/tools/rln_keystore_generator/rln_keystore_generator.nim +++ b/tools/rln_keystore_generator/rln_keystore_generator.nim @@ -52,9 +52,9 @@ proc doRlnKeystoreGenerator*(conf: RlnKeystoreGeneratorConf) = ethClientUrls: conf.ethClientUrls, chainId: conf.chainId, ethContractAddress: conf.ethContractAddress, - keystorePath: none(string), - keystorePassword: none(string), - ethPrivateKey: some(conf.ethPrivateKey), + keystorePath: Opt.none(string), + keystorePassword: Opt.none(string), + ethPrivateKey: Opt.some(conf.ethPrivateKey), onFatalErrorAction: onFatalErrorAction, ) try: From 9827be59905bb86abae59705202b5b16816bf805 Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Fri, 17 Jul 2026 18:14:52 +0200 Subject: [PATCH 4/9] feat: logos_delivery_node app + messaging REST API with event observability (#4014) * WIP logosdeliverynode app initial commit * WIP - extra cli option * WIP: messaging client REST endpoints * Add event poll for messaging rest with cache mechanism * Messaging rest tests * test: assert 404 via raw string client in messaging REST test presto's typed REST client raises RestDecodingError when it cannot decode a non-2xx text error body into the response type. Add a RestResponse[string] stub (messagingGetSendEventsByIdRawV1) and point the "already-polled id -> 404" assertion at it, matching the relay REST test pattern. Co-Authored-By: Claude Opus 4.8 * remove customized cli args as confutils has no support for it * Introduce --entry-layer and re-introduce --mode flags into cli args, applied new driver into LogosDelivery + tests * Add messaging REST client test * Add docker image build of logosdeliverynode for CI builds * Fix tests * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Refactor Messaging REST API to better match Messaging Send and Receive APIs * chore: migrate messaging REST API to Opt[T] Follow-up to the rebase onto master's repo-wide Option[T] -> Opt[T] change (#4035). Converts the code this branch adds to the new convention: - messaging/rest_api/types.nim: MessagingJsonEnvelope fields to Opt[T], Opt.some/Opt.none, and json_serialization/pkg/results instead of json_serialization/std/options. - tests: WakuNodeConf.clusterId is now Opt[uint16]; DTO fields are Opt. `Option[ContentBody]` in the handlers is presto's own API and stays as-is. Co-Authored-By: Claude Opus 4.8 --------- Co-authored-by: Claude Opus 4.8 Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .github/workflows/container-image.yml | 11 +- Makefile | 15 +- .../logos_delivery_node/logosdeliverynode.nim | 98 +++++++ apps/logos_delivery_node/nim.cfg | 10 + logos_delivery.nimble | 4 + .../api/conf/logos_delivery_conf.nim | 12 +- .../api/conf/logos_delivery_conf_json.nim | 45 ++- logos_delivery/api/conf/messaging_conf.nim | 13 +- logos_delivery/api/conf/modes.nim | 18 ++ logos_delivery/logos_delivery.nim | 64 +++- logos_delivery/messaging/rest_api/client.nim | 63 ++++ .../messaging/rest_api/event_cache.nim | 115 ++++++++ .../messaging/rest_api/handlers.nim | 178 +++++++++++ logos_delivery/messaging/rest_api/types.nim | 276 ++++++++++++++++++ tests/api/test_all.nim | 4 +- tests/api/test_conf.nim | 40 +-- tests/api/test_entry_layer.nim | 128 ++++++++ tests/api/test_messaging_rest.nim | 174 +++++++++++ tools/confutils/cli_args.nim | 17 +- 19 files changed, 1226 insertions(+), 59 deletions(-) create mode 100644 apps/logos_delivery_node/logosdeliverynode.nim create mode 100644 apps/logos_delivery_node/nim.cfg create mode 100644 logos_delivery/api/conf/modes.nim create mode 100644 logos_delivery/messaging/rest_api/client.nim create mode 100644 logos_delivery/messaging/rest_api/event_cache.nim create mode 100644 logos_delivery/messaging/rest_api/handlers.nim create mode 100644 logos_delivery/messaging/rest_api/types.nim create mode 100644 tests/api/test_entry_layer.nim create mode 100644 tests/api/test_messaging_rest.nim diff --git a/.github/workflows/container-image.yml b/.github/workflows/container-image.yml index 4b0e7dcd2..432858cf5 100644 --- a/.github/workflows/container-image.yml +++ b/.github/workflows/container-image.yml @@ -87,19 +87,25 @@ jobs: id: build if: ${{ steps.secrets.outcome == 'success' }} run: | - make -j${NPROC} V=1 POSTGRES=1 NIMFLAGS="-d:disableMarchNative -d:chronicles_colors:none" wakunode2 + make -j${NPROC} V=1 POSTGRES=1 NIMFLAGS="-d:disableMarchNative -d:chronicles_colors:none" wakunode2 logosdeliverynode SHORT_REF=$(git rev-parse --short HEAD) TAG=$([ "${PR_NUMBER}" == "" ] && echo "${SHORT_REF}" || echo "${PR_NUMBER}") IMAGE=quay.io/wakuorg/nwaku-pr:${TAG} + LD_IMAGE=quay.io/wakuorg/nwaku-pr:${TAG}-logosdeliverynode echo "image=${IMAGE}" >> $GITHUB_OUTPUT + echo "ld_image=${LD_IMAGE}" >> $GITHUB_OUTPUT echo "commit_hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT docker login -u ${QUAY_USER} -p ${QUAY_PASSWORD} quay.io docker build -t ${IMAGE} -f docker/binaries/Dockerfile.bn.amd64 --label quay.expires-after=30d . docker push ${IMAGE} + + # logosdeliverynode image (same generic Dockerfile, selected via MAKE_TARGET) + docker build -t ${LD_IMAGE} --build-arg MAKE_TARGET=logosdeliverynode -f docker/binaries/Dockerfile.bn.amd64 --label quay.expires-after=30d . + docker push ${LD_IMAGE} env: QUAY_PASSWORD: ${{ secrets.QUAY_PASSWORD }} QUAY_USER: ${{ secrets.QUAY_USER }} @@ -110,10 +116,11 @@ jobs: if: ${{ github.event_name == 'pull_request' && steps.secrets.outcome == 'success' }} with: message: | - You can find the image built from this PR at + You can find the images built from this PR at ``` ${{steps.build.outputs.image}} + ${{steps.build.outputs.ld_image}} ``` Built from ${{ steps.build.outputs.commit_hash }} diff --git a/Makefile b/Makefile index daa8a8ad7..c7bda841d 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ endif .PHONY: all test clean examples deps nimble install-nim install-nimble # default target -all: | wakunode2 liblogosdelivery +all: | wakunode2 logosdeliverynode liblogosdelivery examples: | example2 chat2 chat2bridge @@ -219,7 +219,7 @@ testcommon: | build-deps build ########## ## Waku ## ########## -.PHONY: testwaku wakunode2 testwakunode2 example2 chat2 chat2bridge liteprotocoltester +.PHONY: testwaku wakunode2 logosdeliverynode testwakunode2 example2 chat2 chat2bridge liteprotocoltester testwaku: | build-deps build rln-deps librln echo -e $(BUILD_MSG) "build/$@" && \ @@ -236,6 +236,17 @@ else $(NIMBLE) wakunode2 endif +# Windows: build with nim directly — `nimble ` re-clones git deps every +# build and they intermittently hang on the MSYS2 runner. Flags mirror logos_delivery.nimble. +logosdeliverynode: | build-deps build deps librln +ifeq ($(detected_OS),Windows) + echo -e $(BUILD_MSG) "build/$@" && \ + nim c --out:build/logosdeliverynode --mm:refc --cpu:amd64 $(NIM_PARAMS) -d:chronicles_log_level=TRACE apps/logos_delivery_node/logosdeliverynode.nim +else + echo -e $(BUILD_MSG) "build/$@" && \ + $(NIMBLE) logosdeliverynode +endif + benchmarks: | build-deps build deps librln echo -e $(BUILD_MSG) "build/$@" && \ $(NIMBLE) benchmarks diff --git a/apps/logos_delivery_node/logosdeliverynode.nim b/apps/logos_delivery_node/logosdeliverynode.nim new file mode 100644 index 000000000..1a7f1e0df --- /dev/null +++ b/apps/logos_delivery_node/logosdeliverynode.nim @@ -0,0 +1,98 @@ +{.push raises: [].} + +import + std/[options, strutils, sequtils, net], + chronicles, + chronos, + metrics, + system/ansi_c, + libp2p/crypto/crypto +import + ../../tools/confutils/cli_args, + logos_delivery/logos_delivery, + logos_delivery/waku/common/logging + +logScope: + topics = "logosdeliverynode main" + +const git_version* {.strdefine.} = "n/a" + +{.pop.} + # @TODO confutils.nim(775, 17) Error: can raise an unlisted exception: ref IOError +when isMainModule: + ## Node setup happens in 6 phases: + ## 1. Set up storage + ## 2. Initialize node + ## 3. Mount and initialize configured protocols + ## 4. Start node and mounted protocols + ## 5. Start monitoring tools and external interfaces + ## 6. Setup graceful shutdown hooks + + const versionString = "version / git commit hash: " & git_version + + var wakuNodeConf = WakuNodeConf.load(version = versionString).valueOr: + error "failure while loading the configuration", error = error + quit(QuitFailure) + + ## Also called within LogosDelivery.new. The call to startRestServerEssentials + ## needs the following line + logging.setupLog(wakuNodeConf.logLevel, wakuNodeConf.logFormat) + + case wakuNodeConf.cmd + of generateRlnKeystore: + error "generateRlnKeystore not supported by logos_delivery_node; use wakunode2" + quit(QuitFailure) + of noCommand: + # `LogosDelivery` derives the per-layer config from `WakuNodeConf` itself + # (it runs `toWakuConf` internally), then builds the full stack bottom-up: + # Waku <- MessagingClient <- ReliableChannelManager + var node = (waitFor LogosDelivery.new(wakuNodeConf)).valueOr: + error "LogosDelivery initialization failed", error = error + quit(QuitFailure) + + (waitFor node.start()).isOkOr: + error "Starting LogosDelivery failed", error = error + quit(QuitFailure) + + info "Setting up shutdown hooks" + proc asyncStopper(node: LogosDelivery) {.async: (raises: [Exception]).} = + (await node.stop()).isOkOr: + error "LogosDelivery shutdown failed", error = error + quit(QuitSuccess) + + # Handle Ctrl-C SIGINT + proc handleCtrlC() {.noconv.} = + when defined(windows): + # workaround for https://github.com/nim-lang/Nim/issues/4057 + setupForeignThreadGc() + notice "Shutting down after receiving SIGINT" + asyncSpawn asyncStopper(node) + + setControlCHook(handleCtrlC) + + # Handle SIGTERM + when defined(posix): + proc handleSigterm(signal: cint) {.noconv.} = + notice "Shutting down after receiving SIGTERM" + asyncSpawn asyncStopper(node) + + c_signal(ansi_c.SIGTERM, handleSigterm) + + # Handle SIGSEGV + when defined(posix): + proc handleSigsegv(signal: cint) {.noconv.} = + # Require --debugger:native + fatal "Shutting down after receiving SIGSEGV" + + # Not available in -d:release mode + writeStackTrace() + + (waitFor node.stop()).isOkOr: + error "LogosDelivery shutdown failed", error = error + quit(QuitFailure) + + c_signal(ansi_c.SIGSEGV, handleSigsegv) + + info "Node setup complete" + + runForever() diff --git a/apps/logos_delivery_node/nim.cfg b/apps/logos_delivery_node/nim.cfg new file mode 100644 index 000000000..a6fab9c9b --- /dev/null +++ b/apps/logos_delivery_node/nim.cfg @@ -0,0 +1,10 @@ +-d:chronicles_line_numbers +-d:discv5_protocol_id="d5waku" +-d:chronicles_runtime_filtering=on +-d:chronicles_sinks="textlines,json" +-d:chronicles_default_output_device=dynamic +# Disabling the following topics from nim-eth and nim-dnsdisc since some types cannot be serialized +-d:chronicles_disabled_topics="eth,dnsdisc.client" +# Results in empty output for some reason +#-d:"chronicles_enabled_topics=GossipSub:TRACE,WakuRelay:TRACE" +path = "../.." diff --git a/logos_delivery.nimble b/logos_delivery.nimble index 8c4d32cb5..275bd1a89 100644 --- a/logos_delivery.nimble +++ b/logos_delivery.nimble @@ -388,6 +388,10 @@ task wakunode2, "Build Waku v2 cli node": let name = "wakunode2" buildBinary name, "apps/wakunode2/", " -d:chronicles_log_level=TRACE " +task logosdeliverynode, "Build Logos Delivery cli node": + let name = "logosdeliverynode" + buildBinary name, "apps/logos_delivery_node/", " -d:chronicles_log_level=TRACE " + task benchmarks, "Some benchmarks": let name = "benchmarks" buildBinary name, "apps/benchmarks/", "-p:../.." diff --git a/logos_delivery/api/conf/logos_delivery_conf.nim b/logos_delivery/api/conf/logos_delivery_conf.nim index bec9f9a78..eb2e5b9fa 100644 --- a/logos_delivery/api/conf/logos_delivery_conf.nim +++ b/logos_delivery/api/conf/logos_delivery_conf.nim @@ -2,10 +2,11 @@ import results +import logos_delivery/api/conf/modes import logos_delivery/api/conf/messaging_conf import logos_delivery/api/conf/channels_conf -export messaging_conf, channels_conf +export modes, messaging_conf, channels_conf type LogosDeliveryConf* = object ## Aggregates the per-layer config objects. A layer is mounted iff its config @@ -19,11 +20,14 @@ proc init*(T: type LogosDeliveryConf, kernelConf: KernelConf): LogosDeliveryConf proc init*( T: type LogosDeliveryConf, + entryLayer: EntryLayer = EntryLayer.channels, mode: LogosDeliveryMode, preset: string, messagingOverrides: MessagingClientConf, channelsOverrides: ReliableChannelManagerConf, ): ConfResult[LogosDeliveryConf] = + ## Structured (preset + overrides) entry. Only `messaging` / `channels` layers + ## reach here; the `kernel` layer uses `init(kernelConf)` (raw, mode ignored). let merged = merge(?resolvePreset(preset), messagingOverrides) var kernelConf = ?toWakuNodeConf(merged, mode) kernelConf.preset = preset @@ -31,7 +35,11 @@ proc init*( LogosDeliveryConf( kernelConf: KernelConf(kernelConf), messagingConf: Opt.some(merged), - channelsConf: Opt.some(channelsOverrides), + channelsConf: + if entryLayer == EntryLayer.channels: + Opt.some(channelsOverrides) + else: + Opt.none(ReliableChannelManagerConf), ) ) diff --git a/logos_delivery/api/conf/logos_delivery_conf_json.nim b/logos_delivery/api/conf/logos_delivery_conf_json.nim index 6440a63ac..307ca51c6 100644 --- a/logos_delivery/api/conf/logos_delivery_conf_json.nim +++ b/logos_delivery/api/conf/logos_delivery_conf_json.nim @@ -8,6 +8,7 @@ import logos_delivery/api/conf/logos_delivery_conf const # Lowercased, since `collectJsonFields` keys the object case-insensitively. + KeyEntryLayer = "entrylayer" KeyMode = "mode" KeyPreset = "preset" KeyKernelConf = "kernelconf" @@ -24,10 +25,21 @@ proc parseMode(s: string): Result[LogosDeliveryMode, string] = return ok(LogosDeliveryMode.Core) of "edge": return ok(LogosDeliveryMode.Edge) - of "fleet": - return ok(LogosDeliveryMode.Fleet) else: - return err("invalid mode: '" & s & "' (expected 'Core', 'Edge' or 'Fleet')") + return err("invalid mode: '" & s & "' (expected 'Core' or 'Edge')") + +proc parseEntryLayer(s: string): Result[EntryLayer, string] = + case s.strip().toLowerAscii() + of "kernel": + return ok(EntryLayer.kernel) + of "messaging": + return ok(EntryLayer.messaging) + of "channels": + return ok(EntryLayer.channels) + else: + return err( + "invalid entryLayer: '" & s & "' (expected 'kernel', 'messaging' or 'channels')" + ) proc parseOverrides[T](defaults: T, node: JsonNode, label: string): Result[T, string] = ## Parse the JSON object `node` as overrides on top of `defaults`. @@ -106,16 +118,25 @@ proc parseLogosDeliveryConf*(jsonStr: string): ConfResult[LogosDeliveryConf] = mode = ?parseMode(v.getStr()) top.del(KeyMode) - if mode == LogosDeliveryMode.Fleet: - # Kernel-only: a raw kernelConf and no upper layers. + var entryLayer = EntryLayer.channels + if top.hasKey(KeyEntryLayer): + let (_, v) = top.getOrDefault(KeyEntryLayer) + if v.kind != JString: + return err("entryLayer must be a string") + entryLayer = ?parseEntryLayer(v.getStr()) + top.del(KeyEntryLayer) + + if entryLayer == EntryLayer.kernel: + # Kernel-only: a raw kernelConf and no upper layers; mode is ignored. if not top.hasKey(KeyKernelConf): - return err("fleet mode requires a 'kernelConf' object") + return err("kernel entry layer requires a 'kernelConf' object") let (_, v) = top.getOrDefault(KeyKernelConf) let kernel = ?parseOverrides(?defaultWakuNodeConf(), v, "kernelConf") top.del(KeyKernelConf) if top.len > 0: - return - err(unknownKeysError(top, "fleet mode takes only 'kernelConf'; unexpected")) + return err( + unknownKeysError(top, "kernel entry layer takes only 'kernelConf'; unexpected") + ) return ok(LogosDeliveryConf.init(KernelConf(kernel))) # [Legacy flat JSON config] A wrapper key marks our structured shape. Otherwise any @@ -158,6 +179,12 @@ proc parseLogosDeliveryConf*(jsonStr: string): ConfResult[LogosDeliveryConf] = if top.len > 0: return err(unknownKeysError(top, "Unrecognized configuration option(s) found")) - return LogosDeliveryConf.init(mode, preset, messagingOverrides, channelsOverrides) + return LogosDeliveryConf.init( + entryLayer = entryLayer, + mode = mode, + preset = preset, + messagingOverrides = messagingOverrides, + channelsOverrides = channelsOverrides, + ) {.pop.} diff --git a/logos_delivery/api/conf/messaging_conf.nim b/logos_delivery/api/conf/messaging_conf.nim index a8c91acd7..ef254654a 100644 --- a/logos_delivery/api/conf/messaging_conf.nim +++ b/logos_delivery/api/conf/messaging_conf.nim @@ -7,10 +7,8 @@ import logos_delivery/waku/factory/networks_config export kernel_conf -type LogosDeliveryMode* {.pure.} = enum - Edge # client-only node - Core # full service node - Fleet # kernel-only node from a raw kernel config +# `LogosDeliveryMode` and `EntryLayer` are defined at the leaf (`cli_args`) so +# they can appear on `WakuNodeConf`; re-exported here via `kernel_conf`. type MessagingClientConf* = object clusterId* {.name: "cluster-id".}: Opt[uint16] ## Network cluster id. @@ -69,9 +67,6 @@ proc applyMode*(conf: var WakuNodeConf, mode: LogosDeliveryMode): ConfResult[voi conf.filter = false conf.lightpush = false conf.store = false - of LogosDeliveryMode.Fleet: - return - err("fleet mode takes a raw kernel config; use LogosDelivery.new(kernelConf)") return ok() proc toWakuNodeConf*( @@ -80,6 +75,10 @@ proc toWakuNodeConf*( ## Mode sets the protocol flags; set fields map to their kernel counterpart. var conf = ?defaultWakuNodeConf() ?applyMode(conf, mode) + # Keep the `mode` field consistent with the applied flags so a later + # `LogosDelivery.new(WakuNodeConf)` re-application is idempotent instead of + # clobbering these flags with the field's default (`Core`). + conf.mode = mode if self.store.isSome(): conf.store = self.store.get() diff --git a/logos_delivery/api/conf/modes.nim b/logos_delivery/api/conf/modes.nim new file mode 100644 index 000000000..56058aed9 --- /dev/null +++ b/logos_delivery/api/conf/modes.nim @@ -0,0 +1,18 @@ +## Leaf module for the app-level mode / entry-layer enums. +## +## These appear on `WakuNodeConf` (in the leaf `tools/confutils/cli_args`), so +## they must live in a module that `cli_args` can import without a cycle — i.e. +## a module that imports nothing from the config/api layers. `logos_delivery_conf` +## re-exports them so consumers still get them from there. + +type LogosDeliveryMode* {.pure.} = enum + ## Drives the kernel-internal protocol mountings. Applied only for the + ## `messaging` / `channels` entry layers; ignored when `entryLayer == kernel`. + Edge # client-only node + Core # full service node + +type EntryLayer* {.pure.} = enum + ## Selects which API layer `LogosDelivery` instantiates. + kernel # transport kernel only; ignores `mode` and uses the config as-is + messaging # kernel + messaging client + channels # kernel + messaging + reliable channels diff --git a/logos_delivery/logos_delivery.nim b/logos_delivery/logos_delivery.nim index 35e9f6a97..55867e582 100644 --- a/logos_delivery/logos_delivery.nim +++ b/logos_delivery/logos_delivery.nim @@ -39,6 +39,8 @@ import logos_delivery/messaging/[messaging_client, messaging_client_lifecycle] export messaging_client import logos_delivery/messaging/api/[subscription, send] export subscription, send +import logos_delivery/messaging/rest_api/handlers as messaging_rest_api +export messaging_rest_api import logos_delivery/api/events/messaging_client_events export messaging_client_events import logos_delivery/api/conf/messaging_conf @@ -106,21 +108,38 @@ proc new*( proc new*( T: type LogosDelivery, conf: WakuNodeConf, appCallbacks: AppCallbacks = nil ): Future[Result[LogosDelivery, string]] {.async.} = - ## Builds the full stack from a kernel `WakuNodeConf`. - return await LogosDelivery.new( - LogosDeliveryConf( - kernelConf: KernelConf(conf), - messagingConf: Opt.some(MessagingClientConf()), - channelsConf: Opt.some(ReliableChannelManagerConf()), - ), - appCallbacks, + ## Builds the stack from a kernel `WakuNodeConf`, selecting which API layers to + ## instantiate by `conf.entryLayer`: + ## kernel -> transport only; `conf.mode` is ignored and the config is used as-is + ## messaging -> kernel + messaging client + ## channels -> kernel + messaging + reliable channels + ## For `messaging`/`channels`, `conf.mode` (Edge/Core) sets the kernel protocol + ## flags first (messaging-level concern); for `kernel` it is skipped. + var kernelConf = conf + if conf.entryLayer != EntryLayer.kernel: + applyMode(kernelConf, conf.mode).isOkOr: + return err("failed to apply mode: " & error) + + let ldConf = LogosDeliveryConf( + kernelConf: KernelConf(kernelConf), + messagingConf: + if conf.entryLayer == EntryLayer.kernel: + Opt.none(MessagingClientConf) + else: + Opt.some(MessagingClientConf()), + channelsConf: + if conf.entryLayer == EntryLayer.channels: + Opt.some(ReliableChannelManagerConf()) + else: + Opt.none(ReliableChannelManagerConf), ) + return await LogosDelivery.new(ldConf, appCallbacks) proc new*( T: type LogosDelivery, kernelConf: KernelConf, appCallbacks: AppCallbacks = nil ): Future[Result[LogosDelivery, string]] {.async.} = - ## Fleet mode: mounts the kernel only from a raw `KernelConf`; no messaging client, - ## no channel manager. + ## Kernel entry layer: mounts the kernel only from a raw `KernelConf`; no + ## messaging client, no channel manager. return await LogosDelivery.new(LogosDeliveryConf.init(kernelConf), appCallbacks) proc new*( @@ -143,14 +162,23 @@ proc new*( proc new*( T: type LogosDelivery, + entryLayer: EntryLayer = EntryLayer.channels, mode: LogosDeliveryMode = LogosDeliveryMode.Core, preset: string = "", messagingOverrides: MessagingClientConf = MessagingClientConf(), channelsOverrides: ReliableChannelManagerConf = ReliableChannelManagerConf(), appCallbacks: AppCallbacks = nil, ): Future[Result[LogosDelivery, string]] {.async.} = - ## Messaging entry point (app dev). Builds the full stack from preset, mode and overrides. - let conf = LogosDeliveryConf.init(mode, preset, messagingOverrides, channelsOverrides).valueOr: + ## Messaging entry point (app dev). Builds the stack from preset, mode and + ## overrides; `entryLayer` selects messaging vs channels (use `new(kernelConf)` + ## for a kernel-only node). + let conf = LogosDeliveryConf.init( + entryLayer = entryLayer, + mode = mode, + preset = preset, + messagingOverrides = messagingOverrides, + channelsOverrides = channelsOverrides, + ).valueOr: return err("failed to synthesize configuration: " & error) return await LogosDelivery.new(conf, appCallbacks) @@ -165,6 +193,10 @@ proc start*(self: LogosDelivery): Future[Result[void, string]] {.async.} = if not self.messagingClient.isNil(): self.messagingClient.start().isOkOr: return err("failed to start MessagingClient: " & error) + # Mount the messaging REST endpoints onto the kernel's REST router (no-op if + # REST is disabled). Done here rather than in MessagingClient.start so the + # core messaging module need not depend on the REST layer above it. + self.messagingClient.mountRestApi() if not self.reliableChannelManager.isNil(): self.reliableChannelManager.start().isOkOr: @@ -190,15 +222,15 @@ proc isOnline*(self: LogosDelivery): Future[Result[bool, string]] {.async.} = return await self.waku.isOnline() proc ensureMessaging*(self: LogosDelivery): Result[void, string] = - ## Fails if the node has no messaging client (a kernel-only / fleet node). + ## Fails if the node has no messaging client (a kernel-only node). if self.isNil() or self.messagingClient.isNil(): - return err("node has no messaging client (kernel-only/fleet node)") + return err("node has no messaging client (kernel-only node)") ok() proc ensureChannels*(self: LogosDelivery): Result[void, string] = - ## Fails if the node has no reliable channel manager (a kernel-only / fleet node). + ## Fails if the node has no reliable channel manager (a kernel-only node). if self.isNil() or self.reliableChannelManager.isNil(): - return err("node has no reliable channel manager (kernel-only/fleet node)") + return err("node has no reliable channel manager (kernel-only node)") ok() # Compile-time check that each concrete type satisfies its API concept. diff --git a/logos_delivery/messaging/rest_api/client.nim b/logos_delivery/messaging/rest_api/client.nim new file mode 100644 index 000000000..c618849ca --- /dev/null +++ b/logos_delivery/messaging/rest_api/client.nim @@ -0,0 +1,63 @@ +{.push raises: [].} + +import chronicles, json_serialization, presto/[route, client, common] +import + logos_delivery/waku/rest_api/endpoint/serdes, + logos_delivery/waku/rest_api/endpoint/rest_serdes, + logos_delivery/api/types, + ./types + +export types + +logScope: + topics = "messaging rest client" + +proc encodeBytes*( + value: seq[ContentTopic], contentType: string +): RestResult[seq[byte]] = + return encodeBytesOf(value, contentType) + +proc encodeBytes*( + value: MessagingPostMessageRequest, contentType: string +): RestResult[seq[byte]] = + return encodeBytesOf(value, contentType) + +proc messagingPostSubscriptionsV1*( + body: seq[ContentTopic] +): RestResponse[string] {. + rest, endpoint: "/messaging/v1/subscriptions", meth: HttpMethod.MethodPost +.} + +proc messagingDeleteSubscriptionsV1*( + body: seq[ContentTopic] +): RestResponse[string] {. + rest, endpoint: "/messaging/v1/subscriptions", meth: HttpMethod.MethodDelete +.} + +proc messagingPostMessagesV1*( + body: MessagingPostMessageRequest +): RestResponse[MessagingSendResponse] {. + rest, endpoint: "/messaging/v1/messages", meth: HttpMethod.MethodPost +.} + +proc messagingGetSendEventsV1*(): RestResponse[seq[SendStatus]] {. + rest, endpoint: "/messaging/v1/events/send", meth: HttpMethod.MethodGet +.} + +proc messagingGetSendEventsByIdV1*( + requestId: string +): RestResponse[SendStatus] {. + rest, endpoint: "/messaging/v1/events/send/{requestId}", meth: HttpMethod.MethodGet +.} + +# Raw variant: the typed client above cannot decode a non-2xx text error body, +# so status-code assertions (e.g. 404) use this string form. +proc messagingGetSendEventsByIdRawV1*( + requestId: string +): RestResponse[string] {. + rest, endpoint: "/messaging/v1/events/send/{requestId}", meth: HttpMethod.MethodGet +.} + +proc messagingGetReceivedMessagesV1*(): RestResponse[seq[ReceivedMessageRecord]] {. + rest, endpoint: "/messaging/v1/events/received", meth: HttpMethod.MethodGet +.} diff --git a/logos_delivery/messaging/rest_api/event_cache.nim b/logos_delivery/messaging/rest_api/event_cache.nim new file mode 100644 index 000000000..3326ade88 --- /dev/null +++ b/logos_delivery/messaging/rest_api/event_cache.nim @@ -0,0 +1,115 @@ +## In-memory cache backing the messaging event REST endpoints. +## +## REST is a poll-based client/server surface, so the interactive MessagingClient +## events must be buffered here for later observation: +## * send-related events (sent / propagated / error) grouped by request id +## * received messages +## +## Both surfaces are evict-after-poll: a GET returns the buffered data and clears +## it. A generous overflow cap bounds memory if nobody polls. All access happens +## on the single chronos event loop (broker listeners + REST handlers), so the +## synchronous (no-await) ops below need no locking. + +{.push raises: [].} + +import std/[tables, deques, options] +import results +import logos_delivery/waku/waku_core/time +import ./types + +const + DefaultMaxReceived* = 50 ## Received messages kept between polls (spec default). + DefaultMaxSendRequests* = 10_000 + ## Overflow guard: distinct request ids retained between polls. + +type MessagingEventCache* = ref object + # Send events grouped by request id, with FIFO insertion order for overflow + # eviction. Cleared on poll. + sendByReqId: Table[string, SendStatus] + sendOrder: Deque[string] + maxSendRequests: int + # Received messages, bounded ring. Cleared on poll. + received: Deque[ReceivedMessageRecord] + maxReceived: int + +proc new*( + T: type MessagingEventCache, + maxReceived = DefaultMaxReceived, + maxSendRequests = DefaultMaxSendRequests, +): MessagingEventCache = + MessagingEventCache( + sendByReqId: initTable[string, SendStatus](), + sendOrder: initDeque[string](), + maxSendRequests: maxSendRequests, + received: initDeque[ReceivedMessageRecord](), + maxReceived: maxReceived, + ) + +proc recordSend*( + self: MessagingEventCache, + requestId: string, + messageHash: string, + kind: SendEventKind, + error = "", +) = + ## Append a send event to its request id's timeline, creating the entry (and + ## evicting the oldest request id past the overflow cap) as needed. + let record = SendEventRecord( + kind: kind, + messageHash: messageHash, + error: error, + timestamp: getNowInNanosecondTime(), + ) + + if not self.sendByReqId.hasKey(requestId): + self.sendByReqId[requestId] = SendStatus(requestId: requestId, events: @[]) + self.sendOrder.addLast(requestId) + + while self.sendOrder.len > self.maxSendRequests: + let evicted = self.sendOrder.popFirst() + self.sendByReqId.del(evicted) + + self.sendByReqId.withValue(requestId, status): + status[].events.add(record) + +proc recordReceived*( + self: MessagingEventCache, messageHash: string, message: RelayWakuMessage +) = + ## Buffer a received message, dropping the oldest past the ring capacity. + self.received.addLast( + ReceivedMessageRecord(messageHash: messageHash, message: message) + ) + + while self.received.len > self.maxReceived: + discard self.received.popFirst() + +proc pollAllSend*(self: MessagingEventCache): seq[SendStatus] = + ## Return all buffered send statuses and clear the store (evict-after-poll). + for reqId in self.sendOrder: + self.sendByReqId.withValue(reqId, status): + result.add(status[]) + self.sendByReqId.clear() + self.sendOrder.clear() + +proc pollSend*(self: MessagingEventCache, requestId: string): Opt[SendStatus] = + ## Return one request id's send status and remove it (evict-after-poll). + var status: SendStatus + if not self.sendByReqId.pop(requestId, status): + return Opt.none(SendStatus) + + # Deque has no random removal; rebuild order without the polled id. + var rebuilt = initDeque[string]() + for reqId in self.sendOrder: + if reqId != requestId: + rebuilt.addLast(reqId) + self.sendOrder = rebuilt + + return Opt.some(status) + +proc pollReceived*(self: MessagingEventCache): seq[ReceivedMessageRecord] = + ## Return buffered received messages (oldest first) and clear (evict-after-poll). + for record in self.received: + result.add(record) + self.received.clear() + +{.pop.} diff --git a/logos_delivery/messaging/rest_api/handlers.nim b/logos_delivery/messaging/rest_api/handlers.nim new file mode 100644 index 000000000..ea3d82001 --- /dev/null +++ b/logos_delivery/messaging/rest_api/handlers.nim @@ -0,0 +1,178 @@ +{.push raises: [].} + +import chronos, chronicles, results, json_serialization, json_serialization/std/options +import presto/[route, common] +import + logos_delivery/waku/waku, + logos_delivery/waku/rest_api/endpoint/serdes, + logos_delivery/waku/rest_api/endpoint/responses, + logos_delivery/waku/rest_api/endpoint/rest_serdes, + logos_delivery/messaging/messaging_client, + logos_delivery/messaging/api/subscription, + logos_delivery/messaging/api/send, + logos_delivery/api/types, + logos_delivery/api/events/messaging_client_events, + ./types, + ./event_cache + +export types + +logScope: + topics = "messaging rest api" + +#### Routes + +const ROUTE_MESSAGING_SUBSCRIPTIONSV1* = "/messaging/v1/subscriptions" +const ROUTE_MESSAGING_MESSAGESV1* = "/messaging/v1/messages" +const ROUTE_MESSAGING_EVENTS_SENDV1* = "/messaging/v1/events/send" +const ROUTE_MESSAGING_EVENTS_SEND_BY_IDV1* = "/messaging/v1/events/send/{requestId}" +const ROUTE_MESSAGING_EVENTS_RECEIVEDV1* = "/messaging/v1/events/received" + +proc installEventListeners(brokerCtx: BrokerContext, cache: MessagingEventCache) = + ## Buffers the MessagingClient events into `cache` so the poll-based REST + ## endpoints can observe them. Listeners live for the node's lifetime (the + ## captured `cache` keeps them and their data alive); no teardown is wired. + discard MessageSentEvent.listen( + brokerCtx, + proc(evt: MessageSentEvent): Future[void] {.async: (raises: []).} = + cache.recordSend($evt.requestId, evt.messageHash, SendEventKind.Sent), + ) + + discard MessagePropagatedEvent.listen( + brokerCtx, + proc(evt: MessagePropagatedEvent): Future[void] {.async: (raises: []).} = + cache.recordSend($evt.requestId, evt.messageHash, SendEventKind.Propagated), + ) + + discard MessageErrorEvent.listen( + brokerCtx, + proc(evt: MessageErrorEvent): Future[void] {.async: (raises: []).} = + cache.recordSend($evt.requestId, evt.messageHash, SendEventKind.Error, evt.error), + ) + + discard MessageReceivedEvent.listen( + brokerCtx, + proc(evt: MessageReceivedEvent): Future[void] {.async: (raises: []).} = + cache.recordReceived(evt.messageHash, toRelayWakuMessage(evt.message)), + ) + +proc installMessagingApiHandlers*(router: var RestRouter, client: MessagingClient) = + ## Mounts the MessagingClient subscribe / unsubscribe / send operations as + ## REST endpoints onto the given (kernel-owned) router. Subscriptions are + ## keyed by content topic, matching the messaging layer's content-topic API. + + # Event observability: buffer send/received events for the poll-based GETs. + let eventCache = MessagingEventCache.new() + installEventListeners(client.waku.brokerCtx, eventCache) + + router.api(MethodOptions, ROUTE_MESSAGING_SUBSCRIPTIONSV1) do() -> RestApiResponse: + return RestApiResponse.ok() + + router.api(MethodPost, ROUTE_MESSAGING_SUBSCRIPTIONSV1) do( + contentBody: Option[ContentBody] + ) -> RestApiResponse: + ## Subscribes the messaging client to a list of content topics. + let req: seq[ContentTopic] = decodeRequestBody[seq[ContentTopic]](contentBody).valueOr: + return error + + for contentTopic in req: + (await client.subscribe(contentTopic)).isOkOr: + let errorMsg = "Subscribe failed: " & error + error "messaging SUBSCRIBE failed", error = errorMsg + return RestApiResponse.internalServerError(errorMsg) + + return RestApiResponse.ok() + + router.api(MethodDelete, ROUTE_MESSAGING_SUBSCRIPTIONSV1) do( + contentBody: Option[ContentBody] + ) -> RestApiResponse: + ## Unsubscribes the messaging client from a list of content topics. + let req: seq[ContentTopic] = decodeRequestBody[seq[ContentTopic]](contentBody).valueOr: + return error + + for contentTopic in req: + client.unsubscribe(contentTopic).isOkOr: + let errorMsg = "Unsubscribe failed: " & error + error "messaging UNSUBSCRIBE failed", error = errorMsg + return RestApiResponse.internalServerError(errorMsg) + + return RestApiResponse.ok() + + router.api(MethodOptions, ROUTE_MESSAGING_MESSAGESV1) do() -> RestApiResponse: + return RestApiResponse.ok() + + router.api(MethodPost, ROUTE_MESSAGING_MESSAGESV1) do( + contentBody: Option[ContentBody] + ) -> RestApiResponse: + ## Sends a message through the messaging client, returning the request id. + let req: MessagingJsonEnvelope = decodeRequestBody[MessagingJsonEnvelope]( + contentBody + ).valueOr: + return error + + let envelope = req.toMessageEnvelope().valueOr: + return RestApiResponse.badRequest("Invalid message: " & error) + + let requestId = (await client.send(envelope)).valueOr: + error "messaging SEND failed", error = error + return RestApiResponse.internalServerError("Send failed: " & error) + + let data = MessagingSendResponse(requestId: $requestId) + return RestApiResponse.jsonResponse(data, status = Http200).valueOr: + error "An error occurred while building the json response", error = error + return RestApiResponse.internalServerError($error) + + #### Event observability endpoints (poll-based, evict-after-poll) + + router.api(MethodOptions, ROUTE_MESSAGING_EVENTS_SENDV1) do() -> RestApiResponse: + return RestApiResponse.ok() + + router.api(MethodGet, ROUTE_MESSAGING_EVENTS_SENDV1) do() -> RestApiResponse: + ## Returns all buffered send events grouped by request id, then clears them. + let data = eventCache.pollAllSend() + return RestApiResponse.jsonResponse(data, status = Http200).valueOr: + error "An error occurred while building the json response", error = error + return RestApiResponse.internalServerError($error) + + router.api(MethodOptions, ROUTE_MESSAGING_EVENTS_SEND_BY_IDV1) do( + requestId: string + ) -> RestApiResponse: + return RestApiResponse.ok() + + router.api(MethodGet, ROUTE_MESSAGING_EVENTS_SEND_BY_IDV1) do( + requestId: string + ) -> RestApiResponse: + ## Returns the buffered send events for one request id, then removes them. + let reqId = requestId.valueOr: + return RestApiResponse.badRequest("Invalid requestId") + + let status = eventCache.pollSend(reqId).valueOr: + return RestApiResponse.notFound("No send events for requestId: " & reqId) + + return RestApiResponse.jsonResponse(status, status = Http200).valueOr: + error "An error occurred while building the json response", error = error + return RestApiResponse.internalServerError($error) + + router.api(MethodOptions, ROUTE_MESSAGING_EVENTS_RECEIVEDV1) do() -> RestApiResponse: + return RestApiResponse.ok() + + router.api(MethodGet, ROUTE_MESSAGING_EVENTS_RECEIVEDV1) do() -> RestApiResponse: + ## Returns buffered received messages (up to the cache capacity, oldest + ## first), then clears them — optimized for polling. + let data = eventCache.pollReceived() + return RestApiResponse.jsonResponse(data, status = Http200).valueOr: + error "An error occurred while building the json response", error = error + return RestApiResponse.internalServerError($error) + +proc mountRestApi*(client: MessagingClient) = + ## Mounts the messaging REST endpoints onto the kernel-owned REST router, if + ## the REST server is enabled. Called by the `LogosDelivery` concentrator + ## after the messaging layer has started. Lives here (not in the core + ## `messaging_client` module) so the core need not depend on the REST layer + ## above it — that would form an import cycle. + if not client.waku.restServer.isNil(): + # The BTree route table is ref-backed, so mutating the copied router persists + # (same pattern as the waku REST builder). + var router = client.waku.restServer.router + installMessagingApiHandlers(router, client) + info "Mounted messaging REST API endpoints" diff --git a/logos_delivery/messaging/rest_api/types.nim b/logos_delivery/messaging/rest_api/types.nim new file mode 100644 index 000000000..0688db266 --- /dev/null +++ b/logos_delivery/messaging/rest_api/types.nim @@ -0,0 +1,276 @@ +{.push raises: [].} + +import + std/[sets, strformat], + chronicles, + results, + json_serialization, + json_serialization/pkg/results, + presto/[route, client, common] +import + logos_delivery/waku/common/base64, + logos_delivery/waku/rest_api/endpoint/serdes, + logos_delivery/waku/rest_api/endpoint/relay/types as relay_types, + logos_delivery/api/types + +export types, relay_types + +#### Types + +type MessagingJsonEnvelope* = object + ## REST wire (JSON) representation of the messaging API's `MessageEnvelope`. + ## `payload` / `meta` are base64. Fields mirror `MessageEnvelope` exactly. + payload*: Base64String + contentTopic*: ContentTopic + ephemeral*: Opt[bool] + meta*: Opt[Base64String] + +type MessagingPostMessageRequest* = MessagingJsonEnvelope + +type MessagingSendResponse* = object + ## Returned by the send endpoint on success; correlates with + ## `MessageSentEvent` / `MessageErrorEvent`. + requestId*: string + +#### Type conversion + +proc toMessageEnvelope*(msg: MessagingJsonEnvelope): Result[MessageEnvelope, string] = + let + payload = ?msg.payload.decode() + meta = ?msg.meta.get(Base64String("")).decode() + + return ok( + MessageEnvelope( + contentTopic: msg.contentTopic, + payload: payload, + ephemeral: msg.ephemeral.get(false), + meta: meta, + ) + ) + +#### Serialization and deserialization + +proc writeValue*( + writer: var JsonWriter[RestJson], value: MessagingJsonEnvelope +) {.raises: [IOError].} = + writer.beginRecord() + writer.writeField("payload", value.payload) + writer.writeField("contentTopic", value.contentTopic) + if value.ephemeral.isSome(): + writer.writeField("ephemeral", value.ephemeral.get()) + if value.meta.isSome(): + writer.writeField("meta", value.meta.get()) + writer.endRecord() + +proc readValue*( + reader: var JsonReader[RestJson], value: var MessagingJsonEnvelope +) {.raises: [SerializationError, IOError].} = + var + payload = Opt.none(Base64String) + contentTopic = Opt.none(ContentTopic) + ephemeral = Opt.none(bool) + meta = Opt.none(Base64String) + + var keys = initHashSet[string]() + for fieldName in readObjectFields(reader): + # Check for repeated keys + if keys.containsOrIncl(fieldName): + let err = + try: + fmt"Multiple `{fieldName}` fields found" + except CatchableError: + "Multiple fields with the same name found" + reader.raiseUnexpectedField(err, "MessagingJsonEnvelope") + + case fieldName + of "payload": + payload = Opt.some(reader.readValue(Base64String)) + of "contentTopic": + contentTopic = Opt.some(reader.readValue(ContentTopic)) + of "ephemeral": + ephemeral = Opt.some(reader.readValue(bool)) + of "meta": + meta = Opt.some(reader.readValue(Base64String)) + else: + unrecognizedFieldWarning(value) + + if payload.isNone() or isEmptyOrWhitespace(string(payload.get())): + reader.raiseUnexpectedValue("Field `payload` is missing or empty") + + if contentTopic.isNone() or contentTopic.get().isEmptyOrWhitespace(): + reader.raiseUnexpectedValue("Field `contentTopic` is missing or empty") + + value = MessagingJsonEnvelope( + payload: payload.get(), + contentTopic: contentTopic.get(), + ephemeral: ephemeral, + meta: meta, + ) + +proc writeValue*( + writer: var JsonWriter[RestJson], value: MessagingSendResponse +) {.raises: [IOError].} = + writer.beginRecord() + writer.writeField("requestId", value.requestId) + writer.endRecord() + +proc readValue*( + reader: var JsonReader[RestJson], value: var MessagingSendResponse +) {.raises: [SerializationError, IOError].} = + var requestId = Opt.none(string) + + var keys = initHashSet[string]() + for fieldName in readObjectFields(reader): + if keys.containsOrIncl(fieldName): + let err = + try: + fmt"Multiple `{fieldName}` fields found" + except CatchableError: + "Multiple fields with the same name found" + reader.raiseUnexpectedField(err, "MessagingSendResponse") + + case fieldName + of "requestId": + requestId = Opt.some(reader.readValue(string)) + else: + unrecognizedFieldWarning(value) + + if requestId.isNone(): + reader.raiseUnexpectedValue("Field `requestId` is missing") + + value = MessagingSendResponse(requestId: requestId.get()) + +#### Event observability DTOs +## +## Send-related events (sent / propagated / error) are grouped per request id. +## Received messages carry the full `WakuMessage` (serialized as +## `RelayWakuMessage`), matching the nim `MessageReceivedEvent`. Both surfaces +## are populated by the broker listeners installed in the messaging handlers. + +type + SendEventKind* {.pure.} = enum + Sent = "sent" + Propagated = "propagated" + Error = "error" + + SendEventRecord* = object + kind*: SendEventKind + messageHash*: string + error*: string ## populated only for `Error` + timestamp*: int64 ## nanoseconds, stamped when cached + + SendStatus* = object ## All send events observed so far for a single request id. + requestId*: string + events*: seq[SendEventRecord] + + ReceivedMessageRecord* = object + messageHash*: string + message*: RelayWakuMessage ## the received WakuMessage, full fidelity + +#### Event DTO serialization + +proc writeValue*( + writer: var JsonWriter[RestJson], value: SendEventRecord +) {.raises: [IOError].} = + writer.beginRecord() + writer.writeField("kind", $value.kind) + writer.writeField("messageHash", value.messageHash) + if value.error.len > 0: + writer.writeField("error", value.error) + writer.writeField("timestamp", value.timestamp) + writer.endRecord() + +proc writeValue*( + writer: var JsonWriter[RestJson], value: SendStatus +) {.raises: [IOError].} = + writer.beginRecord() + writer.writeField("requestId", value.requestId) + writer.writeField("events", value.events) + writer.endRecord() + +proc writeValue*( + writer: var JsonWriter[RestJson], value: ReceivedMessageRecord +) {.raises: [IOError].} = + writer.beginRecord() + writer.writeField("messageHash", value.messageHash) + writer.writeField("message", value.message) + writer.endRecord() + +proc readValue*( + reader: var JsonReader[RestJson], value: var SendEventKind +) {.raises: [SerializationError, IOError].} = + let s = reader.readValue(string) + case s + of "sent": + value = SendEventKind.Sent + of "propagated": + value = SendEventKind.Propagated + of "error": + value = SendEventKind.Error + else: + reader.raiseUnexpectedValue("Invalid send event kind: " & s) + +proc readValue*( + reader: var JsonReader[RestJson], value: var SendEventRecord +) {.raises: [SerializationError, IOError].} = + var + kind = Opt.none(SendEventKind) + messageHash = "" + error = "" + timestamp = int64(0) + + for fieldName in readObjectFields(reader): + case fieldName + of "kind": + kind = Opt.some(reader.readValue(SendEventKind)) + of "messageHash": + messageHash = reader.readValue(string) + of "error": + error = reader.readValue(string) + of "timestamp": + timestamp = reader.readValue(int64) + else: + unrecognizedFieldWarning(value) + + if kind.isNone(): + reader.raiseUnexpectedValue("Field `kind` is missing") + + value = SendEventRecord( + kind: kind.get(), messageHash: messageHash, error: error, timestamp: timestamp + ) + +proc readValue*( + reader: var JsonReader[RestJson], value: var SendStatus +) {.raises: [SerializationError, IOError].} = + var + requestId = "" + events: seq[SendEventRecord] = @[] + + for fieldName in readObjectFields(reader): + case fieldName + of "requestId": + requestId = reader.readValue(string) + of "events": + events = reader.readValue(seq[SendEventRecord]) + else: + unrecognizedFieldWarning(value) + + value = SendStatus(requestId: requestId, events: events) + +proc readValue*( + reader: var JsonReader[RestJson], value: var ReceivedMessageRecord +) {.raises: [SerializationError, IOError].} = + var + messageHash = "" + message = RelayWakuMessage() + + for fieldName in readObjectFields(reader): + case fieldName + of "messageHash": + messageHash = reader.readValue(string) + of "message": + message = reader.readValue(RelayWakuMessage) + else: + unrecognizedFieldWarning(value) + + value = ReceivedMessageRecord(messageHash: messageHash, message: message) diff --git a/tests/api/test_all.nim b/tests/api/test_all.nim index 108551bc2..3d7bdee4b 100644 --- a/tests/api/test_all.nim +++ b/tests/api/test_all.nim @@ -7,4 +7,6 @@ import ./test_api_send, ./test_api_subscription, ./test_api_receive, - ./test_api_health + ./test_api_health, + ./test_messaging_rest, + ./test_entry_layer diff --git a/tests/api/test_conf.nim b/tests/api/test_conf.nim index 06a115897..7f4f23315 100644 --- a/tests/api/test_conf.nim +++ b/tests/api/test_conf.nim @@ -246,9 +246,9 @@ suite "parseLogosDeliveryConf - JSON parsing": kc.storeMessageRetentionPolicy == "time:3600" kc.storeMaxNumDbConnections == 7 - test "fleet mode parses a raw kernelConf": + test "kernel entry layer parses a raw kernelConf": let lc = parseLogosDeliveryConf( - """{"mode": "fleet", "kernelConf": {"relay": false, "maxMessageSize": "150KiB"}}""" + """{"entrylayer": "kernel", "kernelConf": {"relay": false, "maxMessageSize": "150KiB"}}""" ).valueOr: raiseAssert error check: @@ -259,24 +259,25 @@ suite "parseLogosDeliveryConf - JSON parsing": kc.relay == false kc.maxMessageSize == "150KiB" - test "fleet mode requires a kernelConf": - check parseLogosDeliveryConf("""{"mode": "fleet"}""").isErr() + test "kernel entry layer requires a kernelConf": + check parseLogosDeliveryConf("""{"entrylayer": "kernel"}""").isErr() - test "fleet mode rejects anything besides kernelConf": + test "kernel entry layer rejects anything besides kernelConf": check parseLogosDeliveryConf( - """{"mode": "fleet", "kernelConf": {}, "messagingOverrides": {"clusterId": 1}}""" + """{"entrylayer": "kernel", "kernelConf": {}, "messagingOverrides": {"clusterId": 1}}""" ) .isErr() - # a preset for a fleet node goes inside kernelConf (WakuNodeConf.preset); fleet - # treats kernelConf as a finished object and overlays nothing onto it + # a preset for a kernel node goes inside kernelConf (WakuNodeConf.preset); the + # kernel entry layer treats kernelConf as a finished object and overlays nothing check parseLogosDeliveryConf( - """{"mode": "fleet", "kernelConf": {}, "preset": "twn"}""" + """{"entrylayer": "kernel", "kernelConf": {}, "preset": "twn"}""" ) .isErr() - test "kernelConf is rejected outside fleet mode": - # kernelConf is a fleet-only wrapper. Under Core/Edge it is neither consumed by the - # structured path nor a flat kernel field, so it must surface as an unknown key. + test "kernelConf is rejected outside the kernel entry layer": + # kernelConf is a kernel-entry-layer wrapper. Under messaging/channels it is + # neither consumed by the structured path nor a flat kernel field, so it must + # surface as an unknown key. check parseLogosDeliveryConf("""{"mode": "core", "kernelConf": {}}""").isErr() suite "LogosDelivery.new - construction (the app-dev entry)": @@ -285,9 +286,9 @@ suite "LogosDelivery.new - construction (the app-dev entry)": lockNewGlobalBrokerContext: node = ( await LogosDelivery.new( - LogosDeliveryMode.Core, - "", - MessagingClientConf( + mode = LogosDeliveryMode.Core, + preset = "", + messagingOverrides = MessagingClientConf( clusterId: Opt.some(3'u16), numShardsInCluster: Opt.some(1'u16), listenIpv4: Opt.some(parseIpAddress("0.0.0.0")), @@ -307,9 +308,10 @@ suite "LogosDelivery.new - construction (the app-dev entry)": lockNewGlobalBrokerContext: node = ( await LogosDelivery.new( - LogosDeliveryMode.Core, - "logostest", - MessagingClientConf(listenIpv4: Opt.some(parseIpAddress("0.0.0.0"))), + mode = LogosDeliveryMode.Core, + preset = "logostest", + messagingOverrides = + MessagingClientConf(listenIpv4: Opt.some(parseIpAddress("0.0.0.0"))), ) ).valueOr: raiseAssert error @@ -327,7 +329,7 @@ suite "MessagingClientConf - store override": kc.relay == false # protocols are owned by the mode, not overridable suite "LogosDelivery.new - raw kernel construction": - asyncTest "a fleet node mounts the kernel only; start/stop tolerate the nil layers": + asyncTest "a kernel-only node mounts the kernel only; start/stop tolerate the nil layers": let kernel = MessagingClientConf(listenIpv4: Opt.some(parseIpAddress("0.0.0.0"))).toWakuNodeConf( LogosDeliveryMode.Core ).valueOr: diff --git a/tests/api/test_entry_layer.nim b/tests/api/test_entry_layer.nim new file mode 100644 index 000000000..710a16653 --- /dev/null +++ b/tests/api/test_entry_layer.nim @@ -0,0 +1,128 @@ +{.used.} + +import std/[options, net] +import chronos, testutils/unittests, presto, presto/client as presto_client +import brokers/broker_context +import logos_delivery +import + logos_delivery/api/conf/logos_delivery_conf, + logos_delivery/messaging/rest_api/client as messaging_rest_client, + logos_delivery/waku/rest_api/endpoint/client +import tools/confutils/cli_args +import ../testlib/testasync + +## Validates the layer-selection invariant of `LogosDelivery.new(WakuNodeConf)`: +## `messagingClient` (and `reliableChannelManager`) are instantiated only for the +## entry layers that call for them. +## +## kernel -> waku only +## messaging -> waku + messagingClient +## channels -> waku + messagingClient + reliableChannelManager + +proc nodeConf(entryLayer: EntryLayer, rest = false): WakuNodeConf = + var conf = defaultWakuNodeConf().valueOr: + raiseAssert error + conf.entryLayer = entryLayer + conf.mode = LogosDeliveryMode.Core + conf.listenAddress = parseIpAddress("0.0.0.0") + conf.tcpPort = Port(0) + conf.discv5UdpPort = Port(0) + conf.clusterId = Opt.some(3'u16) + conf.numShardsInNetwork = 1 + conf.rest = rest + conf.restAddress = parseIpAddress("127.0.0.1") + conf.restPort = 0'u16 # bind to an ephemeral port + return conf + +proc restClientFor(node: LogosDelivery): RestClientRef = + let boundPort = node.waku.restServer.httpServer.address.port + newRestHttpClient(initTAddress(parseIpAddress("127.0.0.1"), boundPort)) + +suite "LogosDelivery - entry layer selection": + asyncTest "kernel: waku only, no messaging / channels": + var node: LogosDelivery + lockNewGlobalBrokerContext: + node = (await LogosDelivery.new(nodeConf(EntryLayer.kernel))).valueOr: + raiseAssert error + check: + not node.waku.isNil() + node.messagingClient.isNil() + node.reliableChannelManager.isNil() + node.ensureMessaging().isErr() + node.ensureChannels().isErr() + (await node.stop()).isOkOr: + raiseAssert "stop failed: " & error + + asyncTest "messaging: waku + messagingClient, no channels": + var node: LogosDelivery + lockNewGlobalBrokerContext: + node = (await LogosDelivery.new(nodeConf(EntryLayer.messaging))).valueOr: + raiseAssert error + check: + not node.waku.isNil() + not node.messagingClient.isNil() + node.reliableChannelManager.isNil() + node.ensureMessaging().isOk() + node.ensureChannels().isErr() + (await node.stop()).isOkOr: + raiseAssert "stop failed: " & error + + asyncTest "channels: full stack": + var node: LogosDelivery + lockNewGlobalBrokerContext: + node = (await LogosDelivery.new(nodeConf(EntryLayer.channels))).valueOr: + raiseAssert error + check: + not node.waku.isNil() + not node.messagingClient.isNil() + not node.reliableChannelManager.isNil() + node.ensureMessaging().isOk() + node.ensureChannels().isOk() + (await node.stop()).isOkOr: + raiseAssert "stop failed: " & error + + asyncTest "messaging + rest: messaging REST endpoints are installed and working": + ## entry-layer=messaging, mode=Core, rest=true -> `start` mounts the messaging + ## REST endpoints; they respond over HTTP. + var node: LogosDelivery + lockNewGlobalBrokerContext: + node = (await LogosDelivery.new(nodeConf(EntryLayer.messaging, rest = true))).valueOr: + raiseAssert error + (await node.start()).isOkOr: + raiseAssert "start failed: " & error + + check not node.messagingClient.isNil() + + let client = restClientFor(node) + + # A command endpoint and an observability endpoint both respond -> the + # handlers were installed onto the kernel router. + let subResp = + await client.messagingPostSubscriptionsV1(@["/test/1/entry-layer/proto"]) + check subResp.status == 200 + + let sendEventsResp = await client.messagingGetSendEventsV1() + check sendEventsResp.status == 200 + + (await node.stop()).isOkOr: + raiseAssert "stop failed: " & error + + asyncTest "kernel + rest: messaging REST endpoints are NOT installed": + ## Gating check: a kernel-only node still starts a REST server, but the + ## messaging endpoints must be absent (no messaging client to mount them). + var node: LogosDelivery + lockNewGlobalBrokerContext: + node = (await LogosDelivery.new(nodeConf(EntryLayer.kernel, rest = true))).valueOr: + raiseAssert error + (await node.start()).isOkOr: + raiseAssert "start failed: " & error + + check node.messagingClient.isNil() + + let client = restClientFor(node) + let subResp = + await client.messagingPostSubscriptionsV1(@["/test/1/entry-layer/proto"]) + check subResp.status == 404 # route not mounted + + (await node.stop()).isOkOr: + raiseAssert "stop failed: " & error diff --git a/tests/api/test_messaging_rest.nim b/tests/api/test_messaging_rest.nim new file mode 100644 index 000000000..fcad51d44 --- /dev/null +++ b/tests/api/test_messaging_rest.nim @@ -0,0 +1,174 @@ +{.used.} + +import + std/[options, net, sequtils], + chronos, + testutils/unittests, + presto, + presto/client as presto_client, + libp2p/crypto/crypto +import brokers/broker_context +import logos_delivery +import + logos_delivery/api/conf/logos_delivery_conf, + logos_delivery/messaging/rest_api/client as messaging_rest_client, + logos_delivery/waku/rest_api/endpoint/client, + logos_delivery/waku/common/base64 +import tools/confutils/cli_args +import ../testlib/[wakucore, testasync] + +## Integration test for the messaging REST endpoints and their event cache. +## +## A full `LogosDelivery` node is started with REST enabled (so `start` mounts +## the messaging handlers + event listeners), then driven through the generated +## `client.nim` stubs. Event observability is exercised deterministically by +## emitting the MessagingClient events directly on the node's broker context — +## the same context the send/recv services emit on — so we do not depend on real +## network delivery. + +proc restNodeConf(): WakuNodeConf = + var conf = defaultWakuNodeConf().valueOr: + raiseAssert error + conf.entryLayer = EntryLayer.messaging + conf.mode = LogosDeliveryMode.Core + conf.listenAddress = parseIpAddress("0.0.0.0") + conf.tcpPort = Port(0) + conf.discv5UdpPort = Port(0) + conf.clusterId = Opt.some(3'u16) + conf.numShardsInNetwork = 1 + conf.rest = true + conf.restAddress = parseIpAddress("127.0.0.1") + conf.restPort = 0'u16 # bind to an ephemeral port + return conf + +proc restClientFor(node: LogosDelivery): RestClientRef = + let boundPort = node.waku.restServer.httpServer.address.port + newRestHttpClient(initTAddress(parseIpAddress("127.0.0.1"), boundPort)) + +const settleDelay = 200.milliseconds + ## Event emit + listener run are asyncSpawned; give them a turn before polling. + +suite "Messaging REST API": + asyncTest "subscribe / unsubscribe / send endpoints respond": + var node: LogosDelivery + lockNewGlobalBrokerContext: + node = (await LogosDelivery.new(restNodeConf())).valueOr: + raiseAssert error + (await node.start()).isOkOr: + raiseAssert "Failed to start node: " & error + let client = restClientFor(node) + + let contentTopic = "/test/1/messaging-rest/proto" + + let subResp = await client.messagingPostSubscriptionsV1(@[contentTopic]) + check subResp.status == 200 + + let msg = MessagingJsonEnvelope( + payload: base64.encode("hello rest"), + contentTopic: contentTopic, + ephemeral: Opt.none(bool), + meta: Opt.none(Base64String), + ) + let sendResp = await client.messagingPostMessagesV1(msg) + check: + sendResp.status == 200 + sendResp.data.requestId.len > 0 + + let unsubResp = await client.messagingDeleteSubscriptionsV1(@[contentTopic]) + check unsubResp.status == 200 + + (await node.stop()).isOkOr: + raiseAssert "Failed to stop node: " & error + + asyncTest "send events are grouped by requestId and evict after poll": + var node: LogosDelivery + lockNewGlobalBrokerContext: + node = (await LogosDelivery.new(restNodeConf())).valueOr: + raiseAssert error + (await node.start()).isOkOr: + raiseAssert "Failed to start node: " & error + let client = restClientFor(node) + let brokerCtx = node.waku.brokerCtx + + let reqA = RequestId("req-A") + let reqB = RequestId("req-B") + + # reqA sees the full lifecycle; reqB only an error. + MessagePropagatedEvent.emit( + brokerCtx, MessagePropagatedEvent(requestId: reqA, messageHash: "0xaa") + ) + MessageSentEvent.emit( + brokerCtx, MessageSentEvent(requestId: reqA, messageHash: "0xaa") + ) + MessageErrorEvent.emit( + brokerCtx, MessageErrorEvent(requestId: reqB, messageHash: "0xbb", error: "boom") + ) + await sleepAsync(settleDelay) + + # GET by id returns only reqA and removes it. + let byIdResp = await client.messagingGetSendEventsByIdV1($reqA) + check: + byIdResp.status == 200 + byIdResp.data.requestId == $reqA + byIdResp.data.events.len == 2 + byIdResp.data.events.anyIt(it.kind == SendEventKind.Sent) + byIdResp.data.events.anyIt(it.kind == SendEventKind.Propagated) + + # Unknown / already-polled id → 404 (raw string client so the text error + # body decodes; the typed client would raise on a non-2xx body). + let missingResp = await client.messagingGetSendEventsByIdRawV1($reqA) + check missingResp.status == 404 + + # GET all now returns only reqB (with its error), then clears. + let allResp = await client.messagingGetSendEventsV1() + check: + allResp.status == 200 + allResp.data.len == 1 + allResp.data[0].requestId == $reqB + allResp.data[0].events.len == 1 + allResp.data[0].events[0].kind == SendEventKind.Error + allResp.data[0].events[0].error == "boom" + + let emptyResp = await client.messagingGetSendEventsV1() + check: + emptyResp.status == 200 + emptyResp.data.len == 0 + + (await node.stop()).isOkOr: + raiseAssert "Failed to stop node: " & error + + asyncTest "received messages are observable, capped, and evict after poll": + var node: LogosDelivery + lockNewGlobalBrokerContext: + node = (await LogosDelivery.new(restNodeConf())).valueOr: + raiseAssert error + (await node.start()).isOkOr: + raiseAssert "Failed to start node: " & error + let client = restClientFor(node) + let brokerCtx = node.waku.brokerCtx + + # Emit more than the cache capacity (50); oldest must be dropped. + const total = 55 + for i in 0 ..< total: + let wm = + fakeWakuMessage(payload = "msg-" & $i, contentTopic = "/test/1/recv/proto") + MessageReceivedEvent.emit( + brokerCtx, MessageReceivedEvent(messageHash: "0x" & $i, message: wm) + ) + await sleepAsync(settleDelay) + + let resp = await client.messagingGetReceivedMessagesV1() + check: + resp.status == 200 + resp.data.len == 50 # capped at DefaultMaxReceived + # oldest (0..4) evicted, newest retained, oldest-first ordering + resp.data[0].messageHash == "0x5" + resp.data[^1].messageHash == "0x" & $(total - 1) + + let emptyResp = await client.messagingGetReceivedMessagesV1() + check: + emptyResp.status == 200 + emptyResp.data.len == 0 + + (await node.stop()).isOkOr: + raiseAssert "Failed to stop node: " & error diff --git a/tools/confutils/cli_args.nim b/tools/confutils/cli_args.nim index 1774f1445..1cb6292d2 100644 --- a/tools/confutils/cli_args.nim +++ b/tools/confutils/cli_args.nim @@ -21,6 +21,7 @@ import json import + logos_delivery/api/conf/modes, logos_delivery/waku/factory/[waku_conf, conf_builder/conf_builder, networks_config], logos_delivery/waku/common/[logging], logos_delivery/waku/[ @@ -37,7 +38,7 @@ import ./envvar as confEnvvarDefs, ./envvar_net as confEnvvarNet export confTomlDefs, confTomlNet, confEnvvarDefs, confEnvvarNet, ProtectedShard, - DefaultMaxWakuMessageSizeStr, DefaultAgentString + DefaultMaxWakuMessageSizeStr, DefaultAgentString, modes logScope: topics = "waku cli args" @@ -168,6 +169,20 @@ type WakuNodeConf* = object name: "preset" .}: string + entryLayer* {. + desc: + "Top API layer to run: kernel (transport only), messaging, or channels (messaging + reliable channels).", + defaultValue: EntryLayer.channels, + name: "entry-layer" + .}: EntryLayer + + mode* {. + desc: + "Kernel operating mode: Edge (client-only) or Core (full service node). Applied only for --entry-layer=messaging|channels; ignored for kernel.", + defaultValue: LogosDeliveryMode.Core, + name: "mode" + .}: LogosDeliveryMode + # Opt-typed; desc states the default since the CLI can't auto-show it for Opt.none(). clusterId* {. desc: static( From 2dbf9a3cb51fb4cb6ec0c30a69c7b36ad8097dfe Mon Sep 17 00:00:00 2001 From: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> Date: Tue, 21 Jul 2026 00:00:36 +0200 Subject: [PATCH 5/9] fix(channels): default channels to unencrypted so messages flow (#4051) --- .../channels/reliable_channel_manager.nim | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/logos_delivery/channels/reliable_channel_manager.nim b/logos_delivery/channels/reliable_channel_manager.nim index 6f8ca14dc..37a53aaf1 100644 --- a/logos_delivery/channels/reliable_channel_manager.nim +++ b/logos_delivery/channels/reliable_channel_manager.nim @@ -18,6 +18,7 @@ import logos_delivery/api/reliable_channel_manager_api import logos_delivery/api/conf/channels_conf import ./reliable_channel +import ./encryption/noop_encryption export reliable_channel, channels_conf @@ -40,10 +41,15 @@ proc new*( ) proc start*(self: ReliableChannelManager): Result[void, string] = - ## Placeholder: per-channel listeners are installed in `ReliableChannel.new`, - ## so the manager has nothing to start at this layer. Kept for symmetry - ## with the `Waku` mount/start lifecycle and as a hook for future state. - discard + ## Per-channel listeners are installed in `ReliableChannel.new`, so the only + ## thing to wire up here is the encryption brokers. Channels encrypt on egress + ## and decrypt on ingress via the `Encrypt`/`Decrypt` request brokers; with no + ## provider registered every send and receive would fail, so `channel_send` + ## would never reach the wire and `ChannelMessageReceivedEvent` would never + ## fire. Install the pass-through noop so channels default to unencrypted + ## payloads. `setProvider` refuses to overwrite, so an application that + ## installed its own encryption before start keeps it. + setNoopEncryption() ok() proc stop*(self: ReliableChannelManager) {.async.} = From 54360d47bcf7d38a511aa0e19867a18fcb1a78c3 Mon Sep 17 00:00:00 2001 From: Tanya S <120410716+stubbsta@users.noreply.github.com> Date: Wed, 22 Jul 2026 14:38:33 +0200 Subject: [PATCH 6/9] Move rate-limit-manager to messaging client layer (#4021) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: drop rate-limit stage from reliable channel send pipeline Collapses the outgoing pipeline to `segmentation -> sds -> encryption -> dispatch` by folding the encrypt-and-dispatch tail of `onReadyToSend` directly into `send()`. Removes the `RateLimitManager` field, its constructor param, the `ReadyToSendEvent` listener, and the `awaitingDispatch` accounting that only existed to bridge the event-bus hop between `send()` and `onReadyToSend`. The `rate_limit_manager.nim` module itself is untouched — it will be relocated to the messaging layer (co-located with RLN) in a follow-up commit, where per-epoch admission actually belongs. Co-Authored-By: Claude Opus 4.7 (1M context) * chore: relocate RateLimitManager to messaging layer Moves rate_limit_manager.nim from `logos_delivery/channels/` to `logos_delivery/messaging/rate_limit_manager/` — the correct owner now that admission sits alongside RLN in the messaging layer instead of being fanned out to per-channel event listeners. The API surface changes: - `enqueueToSend` + `ReadyToSendEvent` (broker-based fan-out to a ReliableChannel listener) is replaced by `admit(msg): Future[Result[ void, RateLimitError]]`. Callers now branch directly on the result instead of subscribing to an event. - `channelId`, `SdsChannelID` and the SDS import are dropped — the messaging layer has no notion of channels; SDS was a channels-layer concern that only survived on this type because of the old broker fan-out. - `brokerCtx` is dropped for the same reason. Epoch config (`epochPeriodSec`), the wall-clock `currentEpochStart`, `queue`, `dequeueReady`, and `resetEpoch` are preserved exactly as the original owner designed them — this refactor is intentionally scoped to the API surface, not the epoch mechanism. Co-Authored-By: Claude Opus 4.7 (1M context) * feat: meter SendService transmissions through RateLimitManager Wires the relocated RateLimitManager into the messaging layer at the transmission stage rather than the API entry point: - MessagingClientConf gains a rateLimit: RateLimitConfig field (defaulting to DefaultEpochPeriodSec / DefaultMessagesPerEpoch), and MessagingClient.new hands the constructed manager to SendService. - SendService consults admit() before the first transmission of a task, both in send() and in the retry loop. Re-publishes of an already-propagated message (firstPropagatedTime set) skip admission: they resend the same bytes, which reuse the same RLN proof/nullifier and consume no fresh epoch slot. - An over-budget task parks in the task cache as NextRoundRetry; the service loop re-admits it as the epoch budget frees up. The skeleton admit() is a pass-through, so behaviour is unchanged today. Gating transmissions instead of MessagingClient.send keeps SDS repair rebroadcasts free of API-entry rejection (SDS decides that a repair is needed; the transmission scheduler decides when it fits the budget) while every wire transmission still draws from one node-wide budget -- which network-side RLN enforcement applies to repairs regardless of any local bypass. It is also where RLN proof attachment must happen, since proofs bind to the epoch current at transmission time. Adds tests/messaging/test_rate_limit_manager.nim covering the current disabled + enabled pass-through behaviour, wired into all_tests_waku.nim. Co-Authored-By: Claude Opus 4.7 (1M context) Co-Authored-By: Claude Opus 4.8 (1M context) * fix: make MessagingClientConf.rateLimit reachable, warn on dead channel knobs Addresses two review findings on the move PR: - `rateLimit` was a plain `RateLimitConfig`, but `merge` only copies `Opt` fields (`when oField is Opt`), so every override path (`LogosDeliveryConf.init`, JSON `messagingOverrides`) silently dropped it and the field was always taken from `base` — unsettable by any caller. Make it `Opt[RateLimitConfig]` like every other field; `MessagingClient.new` falls back to `DefaultRateLimitConfig` (new const, rate limiting disabled) when unset. Adds a merge test. - The channel-level knobs (`rateLimitEnabled` / `rateLimitEpochPeriodSec` / `rateLimitMessagesPerEpoch`) are still parsed but unread since rate limiting moved to the messaging client, so setting them was silently ignored. `ReliableChannelManager.new` now logs a deprecation warning when any is set. Full removal remains a follow-up API decision. Co-Authored-By: Claude Opus 4.8 (1M context) --------- Co-authored-by: Claude Opus 4.7 (1M context) --- logos_delivery/api/conf/messaging_conf.nim | 7 +- .../channels/api/channel_lifecycle.nim | 10 - logos_delivery/channels/api/send.nim | 2 +- .../rate_limit_manager/rate_limit_manager.nim | 80 -------- logos_delivery/channels/reliable_channel.nim | 191 +++++------------- .../channels/reliable_channel_manager.nim | 5 + .../send_service/send_service.nim | 25 ++- logos_delivery/messaging/messaging_client.nim | 7 +- .../rate_limit_manager/rate_limit_manager.nim | 58 ++++++ tests/all_tests_waku.nim | 3 + tests/api/test_conf.nim | 14 ++ .../test_reliable_channel_send_receive.nim | 17 +- tests/messaging/test_all.nim | 3 + tests/messaging/test_rate_limit_manager.nim | 26 +++ 14 files changed, 205 insertions(+), 243 deletions(-) delete mode 100644 logos_delivery/channels/rate_limit_manager/rate_limit_manager.nim create mode 100644 logos_delivery/messaging/rate_limit_manager/rate_limit_manager.nim create mode 100644 tests/messaging/test_all.nim create mode 100644 tests/messaging/test_rate_limit_manager.nim diff --git a/logos_delivery/api/conf/messaging_conf.nim b/logos_delivery/api/conf/messaging_conf.nim index ef254654a..62abea75e 100644 --- a/logos_delivery/api/conf/messaging_conf.nim +++ b/logos_delivery/api/conf/messaging_conf.nim @@ -4,8 +4,9 @@ import results, libp2p/crypto/crypto import logos_delivery/api/conf/kernel_conf import logos_delivery/waku/common/logging import logos_delivery/waku/factory/networks_config +import logos_delivery/messaging/rate_limit_manager/rate_limit_manager -export kernel_conf +export kernel_conf, rate_limit_manager # `LogosDeliveryMode` and `EntryLayer` are defined at the leaf (`cli_args`) so # they can appear on `WakuNodeConf`; re-exported here via `kernel_conf`. @@ -50,6 +51,10 @@ type MessagingClientConf* = object ## Process log format (TEXT or JSON); applied by the kernel on node creation. nodeKey* {.name: "nodekey".}: Opt[crypto.PrivateKey] ## P2P node private key (64-char hex): stable identity / peerId across restarts. + rateLimit*: Opt[RateLimitConfig] + ## Per-epoch message rate limit enforced by the send service. `Opt` like + ## every other field so `merge` propagates a caller's override; unset falls + ## back to `DefaultRateLimitConfig` (rate limiting disabled). proc applyMode*(conf: var WakuNodeConf, mode: LogosDeliveryMode): ConfResult[void] = ## Sets the protocol flags implied by the mode. diff --git a/logos_delivery/channels/api/channel_lifecycle.nim b/logos_delivery/channels/api/channel_lifecycle.nim index 0d32e2acf..57d4e83fe 100644 --- a/logos_delivery/channels/api/channel_lifecycle.nim +++ b/logos_delivery/channels/api/channel_lifecycle.nim @@ -51,15 +51,6 @@ proc createReliableChannel*( causalHistorySize: cc.sdsCausalHistorySize.get(DefaultCausalHistorySize), persistence: sdsPersistence(), ) - let rateConfig = RateLimitConfig( - # Setting a rate-limit parameter implies enabling; an explicit - # rateLimitEnabled still wins. - enabled: cc.rateLimitEnabled.get( - cc.rateLimitEpochPeriodSec.isSome() or cc.rateLimitMessagesPerEpoch.isSome() - ), - epochPeriodSec: cc.rateLimitEpochPeriodSec.get(DefaultEpochPeriodSec), - messagesPerEpoch: cc.rateLimitMessagesPerEpoch.get(DefaultMessagesPerEpoch), - ) let chn = ReliableChannel.new( channelId = channelId, @@ -67,7 +58,6 @@ proc createReliableChannel*( senderId = senderId, segConfig = segConfig, sdsConfig = sdsConfig, - rateConfig = rateConfig, brokerCtx = self.brokerCtx, ) diff --git a/logos_delivery/channels/api/send.nim b/logos_delivery/channels/api/send.nim index 23c41ac13..7af5fdca0 100644 --- a/logos_delivery/channels/api/send.nim +++ b/logos_delivery/channels/api/send.nim @@ -14,7 +14,7 @@ proc send*( ): Future[Result[RequestId, string]] {.async: (raises: []).} = ## Spec-level entry point. Looks the channel up by id and delegates ## to `ReliableChannel.send`, which exposes the visible pipeline - ## segmentation -> sds -> rate_limit_manager -> encryption. + ## segmentation -> sds -> encryption -> dispatch. let chn = self.channels.getOrDefault(channelId) if chn.isNil(): return err("unknown channel: " & channelId) diff --git a/logos_delivery/channels/rate_limit_manager/rate_limit_manager.nim b/logos_delivery/channels/rate_limit_manager/rate_limit_manager.nim deleted file mode 100644 index ab5a9f67b..000000000 --- a/logos_delivery/channels/rate_limit_manager/rate_limit_manager.nim +++ /dev/null @@ -1,80 +0,0 @@ -## Rate Limit Manager for the Reliable Channel API. -## -## Tracks messages sent per RLN epoch and delays dispatch when the -## limit is approached, ensuring RLN compliance on enforcing relays. -## -## For the skeleton this is a pass-through: messages are immediately -## released as ready-to-send. Real epoch budgeting will be added later. -## -## See: https://lip.logos.co/messaging/raw/reliable-channel-api.html - -import std/times -import message -import brokers/event_broker -import brokers/broker_context - -export event_broker, broker_context -export message.SdsChannelID - -const - DefaultEpochPeriodSec* = 600 - DefaultMessagesPerEpoch* = 1 - -EventBroker: - ## Emitted by `enqueueToSend` carrying the batch of opaque message - ## blobs that may now leave the rate limiter and continue down the - ## outgoing pipeline (encryption -> dispatch). Bytes only: the rate - ## limiter is intentionally agnostic of SDS, so anything serialisable - ## can flow through it. - ## - ## `channelId` lets listeners filter to their own channel, since all - ## reliable channels share the underlying Waku node's broker context. - type ReadyToSendEvent* = ref object - channelId*: SdsChannelID - msgs*: seq[seq[byte]] - -type - RateLimitConfig* = object - enabled*: bool ## spec: rate limiting opt-in; SHOULD be true when RLN active - epochPeriodSec*: int - messagesPerEpoch*: int - - RateLimitManager* = ref object - config*: RateLimitConfig - queue*: seq[seq[byte]] - currentEpochStart*: Time - sentInCurrentEpoch*: int - channelId*: SdsChannelID ## tag for the emitted `ReadyToSendEvent` - brokerCtx: BrokerContext - -proc new*( - T: type RateLimitManager, - config: RateLimitConfig, - channelId: SdsChannelID, - brokerCtx: BrokerContext = globalBrokerContext(), -): T = - return T( - config: config, - queue: @[], - currentEpochStart: getTime(), - sentInCurrentEpoch: 0, - channelId: channelId, - brokerCtx: brokerCtx, - ) - -proc enqueueToSend*(self: RateLimitManager, msg: seq[byte]) = - ## Skeleton behaviour: enqueue and immediately release as a single - ## ready batch. Real per-epoch budgeting will park messages on - ## `self.queue` and emit only when the budget allows. - ReadyToSendEvent.emit( - self.brokerCtx, ReadyToSendEvent(channelId: self.channelId, msgs: @[msg]) - ) - -proc dequeueReady*(self: RateLimitManager): seq[seq[byte]] = - ## Returns the set of queued messages that may be dispatched now - ## without exceeding the configured rate limit. - discard - -proc resetEpoch*(self: RateLimitManager) = - self.currentEpochStart = getTime() - self.sentInCurrentEpoch = 0 diff --git a/logos_delivery/channels/reliable_channel.nim b/logos_delivery/channels/reliable_channel.nim index ca74f9df4..0286e8f27 100644 --- a/logos_delivery/channels/reliable_channel.nim +++ b/logos_delivery/channels/reliable_channel.nim @@ -1,10 +1,10 @@ ## Reliable Channel type. ## ## A `ReliableChannel` orchestrates segmentation, SDS (end-to-end -## reliability), optional encryption, and rate-limited dispatch on top -## of the Messaging API for a single channel. +## reliability), optional encryption, and dispatch on top of the +## Messaging API for a single channel. ## -## Outgoing pipeline: Segment -> SDS -> Rate Limit -> Encrypt -> Dispatch +## Outgoing pipeline: Segment -> SDS -> Encrypt -> Dispatch ## Incoming pipeline: Decrypt -> SDS -> Reassemble -> Emit event ## ## Channels are owned by a `ReliableChannelManager`. Lifecycle and send @@ -29,12 +29,9 @@ import logos_delivery/waku/waku_core/topics import ./segmentation/segmentation import ./scalable_data_sync/scalable_data_sync -import ./rate_limit_manager/rate_limit_manager import ./encryption/encryption -export - types, reliable_channel_manager_api, segmentation, scalable_data_sync, - rate_limit_manager, encryption +export types, reliable_channel_manager_api, segmentation, scalable_data_sync, encryption const LipWireReliableChannelVersion* = "RELIABLE-CHANNEL-API/1" ## Wire-format spec marker for the Reliable Channel layer, as defined @@ -51,33 +48,22 @@ type ChannelReqState = object ## Per channel-level request, tracks how many of its segments are - ## still queued, in flight, or have terminated. The channel-level - ## final event fires when `confirmedCount + failedCount` reaches - ## `totalExpectedSegments` AND no segments are still awaiting dispatch - ## or in flight. + ## still in flight or have terminated. The channel-level final event + ## fires when `confirmedCount + failedCount` reaches + ## `totalExpectedSegments` AND no segments are still in flight. persistenceReqType: MessagePersistence totalExpectedSegments: int ## Total segments produced by `segmentation.performSegmentation` ## for this `channelReqId`. Set once in `send`, never mutated. - awaitingDispatch: int - ## Segments enqueued in `rate_limit_manager` but not yet claimed - ## by `onReadyToSend`. Decremented when `onReadyToSend` picks a - ## message and assigns it to this `channelReqId`. inflightMessagingIds: seq[RequestId] ## Messaging-layer ids minted by the send handler that have not ## yet produced a final event. Removed on `MessageSentEvent` / `MessageErrorEvent`. confirmedCount: int failedCount: int - ChannelReqs = OrderedTable[RequestId, ChannelReqState] + ChannelReqs = Table[RequestId, ChannelReqState] ## Key: channelReqId (the parent id returned by channel `send`). Value: ## per-request state, see `ChannelReqState`. - ## - ## `OrderedTable` preserves insertion order, which matches the FIFO - ## order `rate_limit_manager` re-emits messages in: `onReadyToSend` - ## routes each segment to the first entry with `awaitingDispatch > 0`, - ## and that scan is correct precisely because the outer iteration - ## order matches the order `send` pushed entries. ReliableChannel* = ref object ## Spec-defined public type. Fields are private so callers cannot @@ -89,7 +75,6 @@ type rng: libp2p_crypto.Rng segmentation: SegmentationHandler sdsHandler: SdsHandler - rateLimit: RateLimitManager channelReqs: ChannelReqs brokerCtx: BrokerContext @@ -102,7 +87,6 @@ func init( return ChannelReqState( persistenceReqType: persistenceReqType, totalExpectedSegments: totalExpectedSegments, - awaitingDispatch: totalExpectedSegments, inflightMessagingIds: @[], confirmedCount: 0, failedCount: 0, @@ -123,8 +107,8 @@ proc stop*(self: ReliableChannel) {.async: (raises: []).} = proc tryFinalizeChannelReq(self: ReliableChannel, channelReqId: RequestId) = ## Tries to finalize the channel-level request identified by `channelReqId` if - ## certain conditions are met, i.e., no segments are still awaiting dispatch or in flight, - ## and the total number of confirmed + failed segments equals the total expected segments. + ## certain conditions are met, i.e., no segments are still in flight and the + ## total number of confirmed + failed segments equals the total expected segments. ## Therefore, the channel-level request is removed from `self.channelReqs` ## and the appropriate final event is emitted. ## @@ -132,7 +116,7 @@ proc tryFinalizeChannelReq(self: ReliableChannel, channelReqId: RequestId) = if state.totalExpectedSegments == 0: ## Either already finalized (and removed) or never inserted. return - if state.awaitingDispatch != 0 or state.inflightMessagingIds.len != 0: + if state.inflightMessagingIds.len != 0: return if state.confirmedCount + state.failedCount < state.totalExpectedSegments: return @@ -154,22 +138,6 @@ proc tryFinalizeChannelReq(self: ReliableChannel, channelReqId: RequestId) = ChannelMessageSentEvent(channelId: self.channelId, requestId: channelReqId), ) -type ClaimedSegment = object - channelReqId: RequestId - isEphemeral: bool - -proc claimAwaitingChannelReq(self: ReliableChannel): Opt[ClaimedSegment] = - for channelReqId, state in self.channelReqs.mpairs: - if state.awaitingDispatch > 0: - state.awaitingDispatch.dec() - return Opt.some( - ClaimedSegment( - channelReqId: channelReqId, - isEphemeral: state.persistenceReqType == MessagePersistence.Ephemeral, - ) - ) - return Opt.none(ClaimedSegment) - type MessagingOutcome {.pure.} = enum Sent Failed @@ -208,62 +176,61 @@ proc markSegmentInflight( error "unreachable: channelReqId not found in markSegmentInflight", channelReqId = $channelReqId, error = e.msg -proc onReadyToSend( - self: ReliableChannel, readyToSendEvent: ReadyToSendEvent -) {.async: (raises: []).} = - ## Tail of the outgoing pipeline. Invoked from the `ReadyToSendEvent` - ## listener once `rate_limit_manager` releases a batch of opaque - ## blobs (already-encoded SDS messages): +proc send*( + self: ReliableChannel, payload: seq[byte], ephemeral: bool = false +): Future[Result[RequestId, string]] {.async: (raises: []).} = + ## Single application-level send: ## - ## ... -> rate_limit_manager -> [encryption] -> dispatch + ## segmentation -> sds -> encryption -> dispatch ## - ## For each `m`, the next channelReqId still queued in rate-limit - ## claims the slot (FIFO across sibling sends). The channelReqId is - ## captured up front and used as a stable key for every later state - ## update — no positional index is ever held across an `await`, so - ## sibling events mutating other entries (or even this one's - ## `inflightMessagingIds`) cannot corrupt this fiber's view. - for m in readyToSendEvent.msgs: - let claimed = self.claimAwaitingChannelReq().valueOr: - ## rate_limit_manager emitted more messages than we have pending — - ## should not happen given `send` increments `awaitingDispatch` - ## once per enqueued SDS payload. Drop silently rather than - ## corrupt state. - break - let channelReqId = claimed.channelReqId - let isEphemeral = claimed.isEphemeral + ## The returned `RequestId` is the channel-level parent of one-or-more + ## messaging-layer `RequestId`s; the mapping is held in + ## `self.channelReqs` until every segment is final. + if payload.len == 0: + return err("empty payload") + let channelReqId = RequestId.new(self.rng) + let persistenceReqType = + if ephemeral: MessagePersistence.Ephemeral else: MessagePersistence.Persistent + + var sdsSegments: seq[seq[byte]] + for segmentBytes in self.segmentation.performSegmentation(payload): + ## Segments arrive already encoded; the segmentation module owns + ## the wire format so SDS only ever sees opaque bytes. + let sdsBytes = (await self.sdsHandler.wrapOutgoing(segmentBytes)).valueOr: + return err("SDS wrap failed: " & error) + sdsSegments.add(sdsBytes) + + self.channelReqs[channelReqId] = + ChannelReqState.init(persistenceReqType, sdsSegments.len) + + for sdsBytes in sdsSegments: ## TODO: revisit which fields of the SDS message must be encrypted. ## Encrypting the whole encoded blob forces every receiver to attempt ## decryption before it can route, which breaks selective dispatch. ## Leave routing metadata (channelId, causal-history references) in ## clear and encrypt only the application payload. - let encRes = await Encrypt.request(m) - let encrypted = encRes.valueOr: + let encrypted = (await Encrypt.request(sdsBytes)).valueOr: MessageErrorEvent.emit( self.brokerCtx, MessageErrorEvent( requestId: channelReqId, messageHash: "", error: "encryption failed: " & error ), ) - ## Encryption failed *before* we could hand the segment to the self.markSegmentFailed(channelReqId) continue - let wireBytes = seq[byte](encrypted) ## The `meta` field carries the Reliable Channel wire-format spec ## marker so the ingress side of any peer can route this WakuMessage ## to its Reliable Channel layer. let envelope = MessageEnvelope( contentTopic: self.contentTopic, - payload: wireBytes, - ephemeral: isEphemeral, + payload: seq[byte](encrypted), + ephemeral: ephemeral, meta: LipWireReliableChannelVersion.toBytes(), ) - let sendRes = await MessagingSend.request(self.brokerCtx, envelope) - - let messagingReqId = sendRes.valueOr: + let messagingReqId = (await MessagingSend.request(self.brokerCtx, envelope)).valueOr: MessageErrorEvent.emit( self.brokerCtx, MessageErrorEvent( @@ -277,45 +244,6 @@ proc onReadyToSend( self.markSegmentInflight(channelReqId, messagingReqId) -proc send*( - self: ReliableChannel, payload: seq[byte], ephemeral: bool = false -): Future[Result[RequestId, string]] {.async: (raises: []).} = - ## Single application-level send. The first three stages of the - ## outgoing pipeline are chained explicitly so the flow is visible - ## at a glance: - ## - ## segmentation -> sds -> rate_limit_manager - ## - ## `rate_limit_manager.enqueueToSend` emits a `ReadyToSendEvent` with - ## the SDS messages cleared for transmission; the channel's listener - ## then runs the final stage (encryption -> dispatch). - ## - ## The returned `RequestId` is the channel-level parent of one-or-more - ## messaging-layer `RequestId`s; the mapping is held in - ## `self.channelReqs` until every segment is final. - if payload.len == 0: - return err("empty payload") - - let channelReqId = RequestId.new(self.rng) - let persistenceReqType = - if ephemeral: MessagePersistence.Ephemeral else: MessagePersistence.Persistent - - var segmentCount = 0 - var enqueued: seq[seq[byte]] - for segmentBytes in self.segmentation.performSegmentation(payload): - ## Segments arrive already encoded; the segmentation module owns - ## the wire format so SDS only ever sees opaque bytes. - let sdsBytes = (await self.sdsHandler.wrapOutgoing(segmentBytes)).valueOr: - return err("SDS wrap failed: " & error) - enqueued.add(sdsBytes) - segmentCount.inc() - - self.channelReqs[channelReqId] = - ChannelReqState.init(persistenceReqType, segmentCount) - - for sdsBytes in enqueued: - self.rateLimit.enqueueToSend(sdsBytes) - return ok(channelReqId) proc reportReceived(self: ReliableChannel, content: seq[byte]) = @@ -335,8 +263,7 @@ proc reportReceived(self: ReliableChannel, content: seq[byte]) = ) proc dispatchRepair(self: ReliableChannel, wire: seq[byte]) {.async: (raises: []).} = - ## Repair rebroadcasts skip the rate-limit queue — its emissions are - ## claimed FIFO by pending sends. Pacing is done by SDS itself. + ## SDS-driven repair rebroadcast. Pacing is done by SDS itself. let encRes = await Encrypt.request(wire) let encrypted = encRes.valueOr: debug "SDS repair rebroadcast dropped: encryption failed", @@ -406,15 +333,13 @@ proc new*( senderId: SdsParticipantID, segConfig: SegmentationConfig, sdsConfig: SdsConfig, - rateConfig: RateLimitConfig, brokerCtx: BrokerContext = globalBrokerContext(), ): T = - ## Pipeline handlers (segmentation/SDS/rate-limit) are constructed - ## inside the channel rather than handed in by the caller — they are - ## implementation details of the channel, not knobs the API consumer - ## should be wiring up. Encryption is delegated to the `Encrypt`/ - ## `Decrypt` request brokers, so the channel keeps no per-instance - ## encryption state either. + ## Pipeline handlers (segmentation/SDS) are constructed inside the + ## channel rather than handed in by the caller — they are implementation + ## details of the channel, not knobs the API consumer should be wiring + ## up. Encryption is delegated to the `Encrypt`/`Decrypt` request + ## brokers, so the channel keeps no per-instance encryption state either. let chn = T( channelId: channelId, contentTopic: contentTopic, @@ -422,8 +347,7 @@ proc new*( rng: libp2p_crypto.newRng(), segmentation: SegmentationHandler.new(segConfig), sdsHandler: SdsHandler.new(sdsConfig, channelId, senderId), - rateLimit: RateLimitManager.new(rateConfig, channelId, brokerCtx), - channelReqs: initOrderedTable[RequestId, ChannelReqState](), + channelReqs: initTable[RequestId, ChannelReqState](), brokerCtx: brokerCtx, ) @@ -432,20 +356,11 @@ proc new*( asyncSpawn chn.dispatchRepair(wire) chn.sdsHandler.start() - ## Each channel owns its own egress + ingress + send-completion - ## listeners on `chn.brokerCtx`, filtered to traffic addressed to - ## this channel. Keeping the listeners (and the handler procs they - ## call) inside the channel lets `onReadyToSend` / - ## `onMessageReceived` / `onMessageFinal` stay private — the - ## manager doesn't need to know about them. - discard ReadyToSendEvent.listen( - chn.brokerCtx, - proc(evt: ReadyToSendEvent): Future[void] {.async: (raises: []).} = - if evt.channelId == chn.channelId: - await chn.onReadyToSend(evt) - , - ) - + ## Each channel owns its own ingress + send-completion listeners on + ## `chn.brokerCtx`, filtered to traffic addressed to this channel. + ## Keeping the listeners (and the handler procs they call) inside the + ## channel lets `onMessageReceived` / `onMessageFinal` stay private — + ## the manager doesn't need to know about them. discard MessageReceivedEvent.listen( chn.brokerCtx, proc(evt: MessageReceivedEvent): Future[void] {.async: (raises: []).} = diff --git a/logos_delivery/channels/reliable_channel_manager.nim b/logos_delivery/channels/reliable_channel_manager.nim index 37a53aaf1..13f5d5937 100644 --- a/logos_delivery/channels/reliable_channel_manager.nim +++ b/logos_delivery/channels/reliable_channel_manager.nim @@ -32,6 +32,11 @@ proc new*( conf: ReliableChannelManagerConf, brokerCtx: BrokerContext = globalBrokerContext(), ): Result[T, string] = + if conf.rateLimitEnabled.isSome() or conf.rateLimitEpochPeriodSec.isSome() or + conf.rateLimitMessagesPerEpoch.isSome(): + warn "channel-level rate-limit config is deprecated and ignored; " & + "rate limiting moved to the messaging client (MessagingClientConf.rateLimit)" + return ok( T( channels: initTable[ChannelId, ReliableChannel](), diff --git a/logos_delivery/messaging/delivery_service/send_service/send_service.nim b/logos_delivery/messaging/delivery_service/send_service/send_service.nim index 097bb0752..feec01953 100644 --- a/logos_delivery/messaging/delivery_service/send_service/send_service.nim +++ b/logos_delivery/messaging/delivery_service/send_service/send_service.nim @@ -8,7 +8,8 @@ import ./[send_processor, relay_processor, lightpush_processor, delivery_task], logos_delivery/waku/[waku_core, waku_store/common], logos_delivery/waku/waku, - logos_delivery/waku/api/[store, subscriptions, publish] + logos_delivery/waku/api/[store, subscriptions, publish], + logos_delivery/messaging/rate_limit_manager/rate_limit_manager import logos_delivery/api/events/messaging_client_events logScope: @@ -46,6 +47,9 @@ type SendService* = ref object of RootObj serviceLoopHandle: Future[void] ## handle that allows to stop the async task sendProcessor: BaseSendProcessor + rateLimitManager: RateLimitManager + ## Meters first transmissions against the per-epoch budget; re-publishes + ## of an already-propagated message resend the same bytes and are free. waku: Waku checkStoreForMessages: bool @@ -77,7 +81,10 @@ proc setupSendProcessorChain( return ok(processors[0]) proc new*( - T: typedesc[SendService], preferP2PReliability: bool, waku: Waku + T: typedesc[SendService], + preferP2PReliability: bool, + waku: Waku, + rateLimitManager: RateLimitManager, ): Result[T, string] = if not waku.hasRelay() and not waku.hasLightpush(): return err( @@ -94,6 +101,7 @@ proc new*( taskCache: newSeq[DeliveryTask](), serviceLoopHandle: nil, sendProcessor: sendProcessorChain, + rateLimitManager: rateLimitManager, waku: waku, checkStoreForMessages: checkStoreForMessages, lastStoreCheckTime: Moment.now(), @@ -245,6 +253,12 @@ proc trySendMessages(self: SendService) {.async.} = for task in tasksToSend: # Todo, check if it has any perf gain to run them concurrent... + if task.firstPropagatedTime.isNone(): + ## Never propagated: this transmission consumes a fresh epoch slot, so + ## it must be admitted. Tasks that stay over budget remain in + ## `NextRoundRetry` and are retried as the epoch rolls over. + (await self.rateLimitManager.admit(task.msg.payload)).isOkOr: + continue await self.sendProcessor.process(task) proc serviceLoop(self: SendService) {.async.} = @@ -274,6 +288,13 @@ proc send*(self: SendService, task: DeliveryTask) {.async.} = error "SendService.send: failed to subscribe to content topic", contentTopic = task.msg.contentTopic, error = error + (await self.rateLimitManager.admit(task.msg.payload)).isOkOr: + info "SendService.send: over rate-limit budget, parking task", + requestId = task.requestId, msgHash = task.msgHash.to0xHex() + task.state = DeliveryState.NextRoundRetry + self.addTask(task) + return + await self.sendProcessor.process(task) reportTaskResult(self, task) if task.state != DeliveryState.FailedToDeliver: diff --git a/logos_delivery/messaging/messaging_client.nim b/logos_delivery/messaging/messaging_client.nim index d883878fb..c33b3ff6a 100644 --- a/logos_delivery/messaging/messaging_client.nim +++ b/logos_delivery/messaging/messaging_client.nim @@ -7,7 +7,8 @@ import logos_delivery/api/messaging_client_api, logos_delivery/waku/waku, logos_delivery/waku/factory/conf_builder/waku_conf_builder, - logos_delivery/messaging/delivery_service/[recv_service, send_service] + logos_delivery/messaging/delivery_service/[recv_service, send_service], + logos_delivery/messaging/rate_limit_manager/rate_limit_manager export messaging_client_api, messaging_conf @@ -24,7 +25,9 @@ proc new*( ## The messaging layer chains onto Waku: it drives the underlying Waku kernel ## for transport while exposing its own send/recv API. let reliability = conf.reliabilityEnabled.get(DefaultP2pReliability) - let sendService = ?SendService.new(reliability, waku) + let sendService = ?SendService.new( + reliability, waku, RateLimitManager.new(conf.rateLimit.get(DefaultRateLimitConfig)) + ) let recvService = RecvService.new(waku) return ok( T( diff --git a/logos_delivery/messaging/rate_limit_manager/rate_limit_manager.nim b/logos_delivery/messaging/rate_limit_manager/rate_limit_manager.nim new file mode 100644 index 000000000..ba4944dca --- /dev/null +++ b/logos_delivery/messaging/rate_limit_manager/rate_limit_manager.nim @@ -0,0 +1,58 @@ +## Rate Limit Manager for the Messaging API. +## +## Tracks messages sent per RLN epoch and rejects admission when the +## limit is approached, ensuring RLN compliance on enforcing relays. +## +## For the skeleton this is a pass-through: every call is admitted. +## Real per-epoch budgeting will use `queue`, `currentEpochStart`, +## `sentInCurrentEpoch`, and `resetEpoch` to park messages and admit +## them as the epoch rolls over. +## +## See: https://lip.logos.co/messaging/raw/reliable-channel-api.html + +import std/times +import results, chronos + +type + RateLimitError* {.pure.} = enum + OverBudget + + RateLimitConfig* = object + enabled*: bool ## spec: rate limiting opt-in; SHOULD be true when RLN active + epochPeriodSec*: int + messagesPerEpoch*: int + + RateLimitManager* = ref object + config*: RateLimitConfig + queue*: seq[seq[byte]] + currentEpochStart*: Time + sentInCurrentEpoch*: int + +const + DefaultEpochPeriodSec* = 600 + DefaultMessagesPerEpoch* = 1 + + DefaultRateLimitConfig* = RateLimitConfig( + epochPeriodSec: DefaultEpochPeriodSec, messagesPerEpoch: DefaultMessagesPerEpoch + ) ## Used when no rate-limit config is supplied; `enabled` defaults false. + +proc new*(T: type RateLimitManager, config: RateLimitConfig): T = + return + T(config: config, queue: @[], currentEpochStart: getTime(), sentInCurrentEpoch: 0) + +proc admit*( + self: RateLimitManager, msg: seq[byte] +): Future[Result[void, RateLimitError]] {.async: (raises: []).} = + ## Skeleton behaviour: admits immediately. Real per-epoch budgeting + ## will consult `config`, `sentInCurrentEpoch`, and the elapsed + ## `epochPeriodSec` window before admitting or parking `msg`. + return ok() + +proc dequeueReady*(self: RateLimitManager): seq[seq[byte]] = + ## Returns the set of queued messages that may be dispatched now + ## without exceeding the configured rate limit. + discard + +proc resetEpoch*(self: RateLimitManager) = + self.currentEpochStart = getTime() + self.sentInCurrentEpoch = 0 diff --git a/tests/all_tests_waku.nim b/tests/all_tests_waku.nim index 5498db307..b3f72fe90 100644 --- a/tests/all_tests_waku.nim +++ b/tests/all_tests_waku.nim @@ -88,5 +88,8 @@ import ./tools/test_all # Persistency library tests import ./persistency/test_all +# Messaging API tests +import ./messaging/test_all + # Reliable Channel API tests import ./channels/test_all diff --git a/tests/api/test_conf.nim b/tests/api/test_conf.nim index 7f4f23315..ba1bf6f91 100644 --- a/tests/api/test_conf.nim +++ b/tests/api/test_conf.nim @@ -112,6 +112,20 @@ suite "MessagingClientConf - merge (override wins)": mc.clusterId == Opt.some(2'u16) # override wins mc.maxMessageSize == Opt.some("1MB") # base preserved + test "a rateLimit override propagates through merge": + ## Regression: rateLimit must be `Opt` so `merge` copies it; as a plain + ## object it was always taken from base, leaving the field unreachable. + let overrides = MessagingClientConf( + rateLimit: Opt.some( + RateLimitConfig(enabled: true, epochPeriodSec: 30, messagesPerEpoch: 5) + ) + ) + let mc = merge(MessagingClientConf(), overrides) + check: + mc.rateLimit == overrides.rateLimit + mc.rateLimit.get().enabled + mc.rateLimit.get().messagesPerEpoch == 5 + suite "parseLogosDeliveryConf - JSON parsing": test "empty object resolves to a full Core node conf": let lc = parseLogosDeliveryConf("{}").valueOr: diff --git a/tests/channels/test_reliable_channel_send_receive.nim b/tests/channels/test_reliable_channel_send_receive.nim index 53a88f27a..8a7b02231 100644 --- a/tests/channels/test_reliable_channel_send_receive.nim +++ b/tests/channels/test_reliable_channel_send_receive.nim @@ -336,9 +336,9 @@ suite "Reliable Channel - send state machine": asyncTest "sibling MessageSentEvent during sendHandler await does not corrupt state": ## Regression test for the prune-during-await race ## (PR #3914 review comment r3324891059). Locks in that a sibling - ## `MessageSentEvent` firing while `onReadyToSend` is paused at an - ## `await` does not lose the second `channelReqId`'s terminal - ## event. + ## `MessageSentEvent` firing while `send` is paused at a + ## `MessagingSend.request` await does not lose the second + ## `channelReqId`'s terminal event. const channelId = ChannelId("sm-race-channel") contentTopic = ContentTopic("/reliable-channel/test/sm-race") @@ -360,8 +360,8 @@ suite "Reliable Channel - send state machine": proc(envelope: MessageEnvelope): Future[Result[RequestId, string]] {.async.} = ## Call 2 fires the first segment's terminal event and then ## yields, so the listener task runs while the second segment - ## is still mid-`await` in `onReadyToSend` — the exact race - ## window the regression test targets. + ## is still mid-`await` inside `send` — the exact race window + ## the regression test targets. let id = RequestId("race-msg-req-" & $(msgReqIds.len + 1)) msgReqIds.add(id) if msgReqIds.len == 2: @@ -396,8 +396,7 @@ suite "Reliable Channel - send state machine": (await manager.send(channelId, "first".toBytes())).expect("send 1") ## Drain the first segment fully before queueing the second, so - ## the rate-limit FIFO between sibling sends isn't itself under - ## test here. + ## inter-send ordering isn't itself under test here. let firstDispatched = Moment.now() + 1.seconds while Moment.now() < firstDispatched and msgReqIds.len < 1: await sleepAsync(5.milliseconds) @@ -407,8 +406,8 @@ suite "Reliable Channel - send state machine": (await manager.send(channelId, "second".toBytes())).expect("send 2") ## Wait until `fakeSend(m2)` has fully returned and yield once - ## more so `onReadyToSend`'s post-await continuation gets a chance - ## to register `id2` in `inflightMessagingIds` before we emit its + ## more so `send`'s post-await continuation gets a chance to + ## register `id2` in `inflightMessagingIds` before we emit its ## terminal event. let dispatchDeadline = Moment.now() + 1.seconds while Moment.now() < dispatchDeadline and sendsReturned < 2: diff --git a/tests/messaging/test_all.nim b/tests/messaging/test_all.nim new file mode 100644 index 000000000..3cf508033 --- /dev/null +++ b/tests/messaging/test_all.nim @@ -0,0 +1,3 @@ +{.used.} + +import ./test_rate_limit_manager diff --git a/tests/messaging/test_rate_limit_manager.nim b/tests/messaging/test_rate_limit_manager.nim new file mode 100644 index 000000000..895fcb49d --- /dev/null +++ b/tests/messaging/test_rate_limit_manager.nim @@ -0,0 +1,26 @@ +{.used.} + +import chronos, testutils/unittests, stew/byteutils + +import logos_delivery/messaging/rate_limit_manager/rate_limit_manager + +suite "RateLimitManager - admission": + asyncTest "admit is a pass-through when disabled": + let rl = RateLimitManager.new( + RateLimitConfig(enabled: false, epochPeriodSec: 600, messagesPerEpoch: 1) + ) + for _ in 0 ..< 10: + let res = await rl.admit("payload".toBytes()) + check res.isOk() + + asyncTest "admit is a pass-through in the skeleton even when enabled": + ## Documents the current skeleton behaviour: per-epoch enforcement is + ## not wired yet, so every call is admitted regardless of the + ## configured budget. This test flips to red as soon as real + ## enforcement lands, at which point it should be replaced with + ## budget-boundary assertions. + let rl = RateLimitManager.new( + RateLimitConfig(enabled: true, epochPeriodSec: 600, messagesPerEpoch: 1) + ) + check (await rl.admit("first".toBytes())).isOk() + check (await rl.admit("second".toBytes())).isOk() From 8ad99f10f41e813253ba1146efc83ca4cfdb3510 Mon Sep 17 00:00:00 2001 From: Egor Rachkovskii <32649334+at0m1x19@users.noreply.github.com> Date: Thu, 23 Jul 2026 11:06:01 +0100 Subject: [PATCH 7/9] Add in-repo API/e2e test suite (tests-e2e) (#4027) Migrate the liblogosdelivery API/wrapper pytest suite into tests-e2e/ and run it in CI (e2e-api-tests.yml) against the built library. Edge senders use the real lightpush path (relay=False). --- .github/workflows/ci.yml | 10 +- .github/workflows/e2e-api-tests.yml | 34 + tests-e2e/README.md | 32 + tests-e2e/log/.gitkeep | 0 tests-e2e/pytest.ini | 15 + tests-e2e/requirements.txt | 44 + tests-e2e/scripts/prepare_lib.sh | 22 + tests-e2e/src/__init__.py | 0 tests-e2e/src/data_storage.py | 3 + tests-e2e/src/env_vars.py | 36 + tests-e2e/src/libs/__init__.py | 0 tests-e2e/src/libs/common.py | 52 + tests-e2e/src/libs/custom_logger.py | 31 + tests-e2e/src/node/__init__.py | 0 tests-e2e/src/node/api_clients/__init__.py | 0 tests-e2e/src/node/api_clients/base_client.py | 37 + tests-e2e/src/node/api_clients/rest.py | 190 +++ tests-e2e/src/node/docker_mananger.py | 145 +++ tests-e2e/src/node/store_response.py | 103 ++ tests-e2e/src/node/waku_message.py | 46 + tests-e2e/src/node/waku_node.py | 683 +++++++++++ tests-e2e/src/node/wrapper_helpers.py | 218 ++++ tests-e2e/src/node/wrappers_manager.py | 98 ++ tests-e2e/src/postgres_setup.py | 44 + tests-e2e/src/steps/__init__.py | 0 tests-e2e/src/steps/common.py | 80 ++ tests-e2e/src/steps/filter.py | 197 ++++ tests-e2e/src/steps/light_push.py | 148 +++ tests-e2e/src/steps/metrics.py | 68 ++ tests-e2e/src/steps/network_conditions.py | 201 ++++ tests-e2e/src/steps/peer_exchange.py | 30 + tests-e2e/src/steps/relay.py | 187 +++ tests-e2e/src/steps/rln.py | 203 ++++ tests-e2e/src/steps/sharding.py | 212 ++++ tests-e2e/src/steps/store.py | 382 +++++++ tests-e2e/src/test_data.py | 356 ++++++ tests-e2e/tests/__init__.py | 0 tests-e2e/tests/conftest.py | 100 ++ tests-e2e/tests/wrappers_tests/conftest.py | 35 + .../wrappers_tests/test_basic_life_cycle.py | 26 + .../wrappers_tests/test_send_e2e_part1.py | 1018 +++++++++++++++++ .../wrappers_tests/test_send_e2e_part2.py | 699 +++++++++++ .../lib/.gitkeep | 0 .../waku/wrapper.py | 392 +++++++ 44 files changed, 6173 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/e2e-api-tests.yml create mode 100644 tests-e2e/README.md create mode 100644 tests-e2e/log/.gitkeep create mode 100644 tests-e2e/pytest.ini create mode 100644 tests-e2e/requirements.txt create mode 100755 tests-e2e/scripts/prepare_lib.sh create mode 100644 tests-e2e/src/__init__.py create mode 100644 tests-e2e/src/data_storage.py create mode 100644 tests-e2e/src/env_vars.py create mode 100644 tests-e2e/src/libs/__init__.py create mode 100644 tests-e2e/src/libs/common.py create mode 100644 tests-e2e/src/libs/custom_logger.py create mode 100644 tests-e2e/src/node/__init__.py create mode 100644 tests-e2e/src/node/api_clients/__init__.py create mode 100644 tests-e2e/src/node/api_clients/base_client.py create mode 100644 tests-e2e/src/node/api_clients/rest.py create mode 100644 tests-e2e/src/node/docker_mananger.py create mode 100644 tests-e2e/src/node/store_response.py create mode 100644 tests-e2e/src/node/waku_message.py create mode 100644 tests-e2e/src/node/waku_node.py create mode 100644 tests-e2e/src/node/wrapper_helpers.py create mode 100644 tests-e2e/src/node/wrappers_manager.py create mode 100644 tests-e2e/src/postgres_setup.py create mode 100644 tests-e2e/src/steps/__init__.py create mode 100644 tests-e2e/src/steps/common.py create mode 100644 tests-e2e/src/steps/filter.py create mode 100644 tests-e2e/src/steps/light_push.py create mode 100644 tests-e2e/src/steps/metrics.py create mode 100644 tests-e2e/src/steps/network_conditions.py create mode 100644 tests-e2e/src/steps/peer_exchange.py create mode 100644 tests-e2e/src/steps/relay.py create mode 100644 tests-e2e/src/steps/rln.py create mode 100644 tests-e2e/src/steps/sharding.py create mode 100644 tests-e2e/src/steps/store.py create mode 100644 tests-e2e/src/test_data.py create mode 100644 tests-e2e/tests/__init__.py create mode 100644 tests-e2e/tests/conftest.py create mode 100644 tests-e2e/tests/wrappers_tests/conftest.py create mode 100644 tests-e2e/tests/wrappers_tests/test_basic_life_cycle.py create mode 100644 tests-e2e/tests/wrappers_tests/test_send_e2e_part1.py create mode 100644 tests-e2e/tests/wrappers_tests/test_send_e2e_part2.py create mode 100644 tests-e2e/vendor/logos-delivery-python-bindings/lib/.gitkeep create mode 100644 tests-e2e/vendor/logos-delivery-python-bindings/waku/wrapper.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index af7f256fb..7ff06833d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,6 +46,7 @@ jobs: - 'tools/**' - 'tests/all_tests_v2.nim' - 'tests/**' + - 'tests-e2e/**' docker: - 'docker/**' @@ -205,12 +206,13 @@ jobs: secrets: inherit - # Send API E2E tests run the wrapper suite against the liblogosdelivery.so - # built by the `build` job (downloaded as the `liblogosdelivery` artifact). - # Gated on `build`, so it is skipped on docker-only PRs where no lib is built. + # Send API E2E tests run the in-repo tests-e2e/ wrapper suite against the + # liblogosdelivery.so built by the `build` job (downloaded as the + # `liblogosdelivery` artifact). Gated on `build`, so it is skipped on + # docker-only PRs where no lib is built. send-api-e2e-tests: needs: build - uses: logos-messaging/logos-delivery-interop-tests/.github/workflows/send_api_e2e_PR.yml@SMOKE_TEST_2026.06.25 + uses: ./.github/workflows/e2e-api-tests.yml secrets: inherit lint: diff --git a/.github/workflows/e2e-api-tests.yml b/.github/workflows/e2e-api-tests.yml new file mode 100644 index 000000000..00c5a4cfe --- /dev/null +++ b/.github/workflows/e2e-api-tests.yml @@ -0,0 +1,34 @@ +name: e2e-api-tests + +on: + workflow_call: + +jobs: + api-e2e: + runs-on: ubuntu-22.04 + timeout-minutes: 45 + name: api-e2e + steps: + - name: Checkout code + uses: actions/checkout@v4 + + # Consumes the shared library built by ci.yml's `build` job (same run). + - name: Download liblogosdelivery.so + uses: actions/download-artifact@v4 + with: + name: liblogosdelivery + path: tests-e2e/vendor/logos-delivery-python-bindings/lib + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + cache: 'pip' + cache-dependency-path: tests-e2e/requirements.txt + + - name: Install Python deps + run: pip install -r tests-e2e/requirements.txt + + - name: Run API/e2e tests (non-docker subset) + working-directory: tests-e2e + run: pytest tests/wrappers_tests -m "not docker_required" --reruns 2 diff --git a/tests-e2e/README.md b/tests-e2e/README.md new file mode 100644 index 000000000..c52ea2a1d --- /dev/null +++ b/tests-e2e/README.md @@ -0,0 +1,32 @@ +# tests-e2e — logos-delivery API/e2e tests (Python) + +End-to-end tests for `liblogosdelivery`, driven through the Python bindings (C-FFI). +Migrated from [`logos-delivery-interop-tests`](https://github.com/logos-messaging/logos-delivery-interop-tests) (the wrapper / send-API suite). + +## Layout + +- `src/` — test framework (node wrappers, steps, helpers) +- `tests/wrappers_tests/` — the API/e2e scenario tests (`test_s02…s31`) +- `vendor/logos-delivery-python-bindings/waku/wrapper.py` — CFFI binding (`NodeWrapper`); it `dlopen`s `../lib/liblogosdelivery.so` + +## Run locally + +```bash +# 1. Build the shared library and place it where the binding looks for it +./tests-e2e/scripts/prepare_lib.sh + +# 2. Python env + deps +python -m venv .venv && source .venv/bin/activate +pip install -r tests-e2e/requirements.txt + +# 3. Run (from tests-e2e/) +cd tests-e2e +pytest tests/wrappers_tests -m "not docker_required" # 18 pure-binding tests +pytest tests/wrappers_tests -m docker_required # 3 tests that also need a Docker nwaku peer (S19/S20/S31) +``` + +## CI + +`.github/workflows/e2e-api-tests.yml` (called from `ci.yml`, `needs: build`) downloads the +`liblogosdelivery` artifact produced by the `build` job and runs the non-docker subset on every PR — +so a protocol change and its e2e test land in the same PR. diff --git a/tests-e2e/log/.gitkeep b/tests-e2e/log/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/tests-e2e/pytest.ini b/tests-e2e/pytest.ini new file mode 100644 index 000000000..2406bfb06 --- /dev/null +++ b/tests-e2e/pytest.ini @@ -0,0 +1,15 @@ +[pytest] +addopts = --instafail --tb=short --color=auto +log_level = DEBUG +log_cli = True +norecursedirs = + vendor + nimbledeps + *.egg-info +log_file = log/test.log +log_cli_format = %(asctime)s.%(msecs)03d %(levelname)s [%(name)s] %(message)s +log_file_format = %(asctime)s.%(msecs)03d %(levelname)s [%(name)s] %(message)s +timeout = 300 +markers = + smoke: marks tests as smoke test (deselect with '-m "not smoke"') + docker_required: test requires Docker nodes (WakuNode) diff --git a/tests-e2e/requirements.txt b/tests-e2e/requirements.txt new file mode 100644 index 000000000..53c1e36af --- /dev/null +++ b/tests-e2e/requirements.txt @@ -0,0 +1,44 @@ +allure-pytest==2.13.2 +allure-python-commons==2.13.2 +attrs==23.1.0 +black==24.3.0 +certifi==2024.7.4 +cfgv==3.4.0 +charset-normalizer==3.3.2 +click==8.1.7 +distlib==0.3.8 +docker==7.0.0 +execnet==2.0.2 +filelock==3.13.1 +identify==2.5.33 +idna==3.7 +iniconfig==2.0.0 +marshmallow==3.20.1 +marshmallow-dataclass==8.6.0 +mypy-extensions==1.0.0 +nodeenv==1.8.0 +packaging==23.2 +pathspec==0.12.1 +platformdirs==4.1.0 +pluggy==1.3.0 +pre-commit==3.6.2 +pyright==1.1.352 +pytest==8.0.2 +pytest-instafail==0.5.0 +pytest-rerunfailures==13.0 +pytest-timeout==2.2.0 +pytest-xdist==3.5.0 +python-dotenv==1.0.1 +pytest-dependency==0.6.0 +PyYAML==6.0.1 +requests==2.31.0 +setuptools==70.0.0 +tenacity==8.2.3 +typeguard==4.1.5 +typing-inspect==0.9.0 +typing_extensions==4.9.0 +urllib3==2.2.2 +virtualenv==20.25.0 +pytest-shard==0.1.2 +result==0.17.0 +cffi \ No newline at end of file diff --git a/tests-e2e/scripts/prepare_lib.sh b/tests-e2e/scripts/prepare_lib.sh new file mode 100755 index 000000000..62a6f2cd2 --- /dev/null +++ b/tests-e2e/scripts/prepare_lib.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +# Build liblogosdelivery from this repo and place it where the Python binding expects it. +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +LIBDIR="$ROOT/tests-e2e/vendor/logos-delivery-python-bindings/lib" + +cd "$ROOT" +make update +make V=1 liblogosdelivery + +mkdir -p "$LIBDIR" +if [ -f build/liblogosdelivery.so ]; then + cp build/liblogosdelivery.so "$LIBDIR/liblogosdelivery.so" +elif [ -f build/liblogosdelivery.dylib ]; then + cp build/liblogosdelivery.dylib "$LIBDIR/liblogosdelivery.dylib" + ln -sf liblogosdelivery.dylib "$LIBDIR/liblogosdelivery.so" +else + echo "ERROR: built library not found in build/" >&2 + exit 1 +fi +echo "Placed liblogosdelivery in $LIBDIR" diff --git a/tests-e2e/src/__init__.py b/tests-e2e/src/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests-e2e/src/data_storage.py b/tests-e2e/src/data_storage.py new file mode 100644 index 000000000..1b69a4631 --- /dev/null +++ b/tests-e2e/src/data_storage.py @@ -0,0 +1,3 @@ +# We use this class for global variables +class DS: + waku_nodes = [] diff --git a/tests-e2e/src/env_vars.py b/tests-e2e/src/env_vars.py new file mode 100644 index 000000000..32e96a7e1 --- /dev/null +++ b/tests-e2e/src/env_vars.py @@ -0,0 +1,36 @@ +import os +from dotenv import load_dotenv + +load_dotenv() # This will load environment variables from a .env file if it exists + + +def get_env_var(var_name, default=None): + env_var = os.getenv(var_name, default) + if env_var in [None, ""]: + print(f"{var_name} is not set; using default value: {default}") + env_var = default + print(f"{var_name}: {env_var}") + return env_var + + +# Configuration constants. Need to be upercase to appear in reports +DEFAULT_NWAKU = "wakuorg/nwaku:latest" +STRESS_ENABLED = False +USE_WRAPPERS = True +NODE_1 = get_env_var("NODE_1", DEFAULT_NWAKU) +NODE_2 = get_env_var("NODE_2", DEFAULT_NWAKU) +ADDITIONAL_NODES = get_env_var("ADDITIONAL_NODES", f"{DEFAULT_NWAKU},{DEFAULT_NWAKU},{DEFAULT_NWAKU}") +# more nodes need to follow the NODE_X pattern +DOCKER_LOG_DIR = get_env_var("DOCKER_LOG_DIR", "./log/docker") +NETWORK_NAME = get_env_var("NETWORK_NAME", "waku") +SUBNET = get_env_var("SUBNET", "172.18.0.0/16") +IP_RANGE = get_env_var("IP_RANGE", "172.18.0.0/24") +GATEWAY = get_env_var("GATEWAY", "172.18.0.1") +RUNNING_IN_CI = get_env_var("CI") +API_REQUEST_TIMEOUT = get_env_var("API_REQUEST_TIMEOUT", 20) +RLN_CREDENTIALS = get_env_var("RLN_CREDENTIALS") +PG_USER = get_env_var("POSTGRES_USER", "postgres") +PG_PASS = get_env_var("POSTGRES_PASSWORD", "test123") + +# example for .env file +# RLN_CREDENTIALS = {"rln-relay-cred-password": "password", "rln-relay-eth-client-address": "https://rpc.sepolia.linea.build", "rln-relay-eth-contract-address": "0xB9cd878C90E49F797B4431fBF4fb333108CB90e6", "rln-relay-eth-private-key-1": "", "rln-relay-eth-private-key-2": "", "rln-relay-eth-private-key-3": "", "rln-relay-eth-private-key-4": "", "rln-relay-eth-private-key-5": ""} diff --git a/tests-e2e/src/libs/__init__.py b/tests-e2e/src/libs/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests-e2e/src/libs/common.py b/tests-e2e/src/libs/common.py new file mode 100644 index 000000000..cd0dfc19c --- /dev/null +++ b/tests-e2e/src/libs/common.py @@ -0,0 +1,52 @@ +import uuid +from datetime import datetime +from time import sleep +from src.libs.custom_logger import get_custom_logger +import os +import base64 +import allure + +logger = get_custom_logger(__name__) + + +def bytes_to_hex(byte_array): + return "".join(format(byte, "02x") for byte in byte_array) + + +def to_base64(input_data): + if isinstance(input_data, str): + input_bytes = input_data.encode() + elif isinstance(input_data, int): + input_bytes = str(input_data).encode() + elif isinstance(input_data, bytes): + input_bytes = input_data + else: + input_bytes = str(input_data).encode() + base64_encoded = base64.b64encode(input_bytes) + return base64_encoded.decode() + + +def to_hex(input_data): + if isinstance(input_data, str): + input_bytes = input_data.encode() + elif isinstance(input_data, int): + input_bytes = str(input_data).encode() + elif isinstance(input_data, bytes): + input_bytes = input_data + else: + input_bytes = str(input_data).encode() + return "0x" + input_bytes.hex() + + +def attach_allure_file(file): + logger.debug(f"Attaching file {file}") + allure.attach.file(file, name=os.path.basename(file), attachment_type=allure.attachment_type.TEXT) + + +def delay(num_seconds): + logger.debug(f"Sleeping for {num_seconds} seconds") + sleep(num_seconds) + + +def gen_step_id(): + return f"{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}__{str(uuid.uuid4())}" diff --git a/tests-e2e/src/libs/custom_logger.py b/tests-e2e/src/libs/custom_logger.py new file mode 100644 index 000000000..ecdd7ecc6 --- /dev/null +++ b/tests-e2e/src/libs/custom_logger.py @@ -0,0 +1,31 @@ +import logging + +max_log_line_length = 5000 + + +def log_length_filter(max_length): + class logLengthFilter(logging.Filter): + def filter(self, record): + if len(record.getMessage()) > max_length: + logging.getLogger(record.name).log( + record.levelno, f"Log line was discarded because it's longer than max_log_line_length={max_log_line_length}" + ) + return False + return True + + return logLengthFilter() + + +def get_custom_logger(name): + logging.getLogger("urllib3").setLevel(logging.WARNING) + logging.getLogger("docker").setLevel(logging.WARNING) + logger = logging.getLogger(name) + logger.addFilter(log_length_filter(max_log_line_length)) + + # Define a formatter with millisecond precision + ch = logging.StreamHandler() + formatter = logging.Formatter("%(asctime)s.%(msecs)03d %(levelname)s [%(name)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") + ch.setFormatter(formatter) + logger.addHandler(ch) + + return logger diff --git a/tests-e2e/src/node/__init__.py b/tests-e2e/src/node/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests-e2e/src/node/api_clients/__init__.py b/tests-e2e/src/node/api_clients/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests-e2e/src/node/api_clients/base_client.py b/tests-e2e/src/node/api_clients/base_client.py new file mode 100644 index 000000000..b731e0f3f --- /dev/null +++ b/tests-e2e/src/node/api_clients/base_client.py @@ -0,0 +1,37 @@ +import json +import requests +from src.env_vars import API_REQUEST_TIMEOUT +from src.libs.custom_logger import get_custom_logger + +logger = get_custom_logger(__name__) + + +class BaseClient: + def make_request(self, method, url, headers=None, data=None): + self.log_request_as_curl(method, url, headers, data) + response = requests.request(method.upper(), url, headers=headers, data=data, timeout=API_REQUEST_TIMEOUT) + try: + response.raise_for_status() + except requests.HTTPError as http_err: + logger.error(f"HTTP error occurred: {http_err}. Response content: {response.content}") + raise Exception(f"Error: {http_err} with response: {response.content}") + except Exception as err: + logger.error(f"An error occurred: {err}. Response content: {response.content}") + raise Exception(f"Error: {err} with response: {response.content}") + else: + logger.info(f"Response status code: {response.status_code}. Response content: {response.content}") + return response + + def log_request_as_curl(self, method, url, headers, data): + if data: + try: + data_dict = json.loads(data) + if "timestamp" in data_dict: + data_dict["timestamp"] = "TIMESTAMP_PLACEHOLDER" + data = json.dumps(data_dict) + data = data.replace('"TIMESTAMP_PLACEHOLDER"', "'$(date +%s%N)'") + except json.JSONDecodeError: + logger.error("Invalid JSON data provided") + headers_str_for_log = " ".join([f'-H "{key}: {value}"' for key, value in headers.items()]) if headers else "" + curl_cmd = f"curl -v -X {method.upper()} \"{url}\" {headers_str_for_log} -d '{data}'" + logger.info(curl_cmd) diff --git a/tests-e2e/src/node/api_clients/rest.py b/tests-e2e/src/node/api_clients/rest.py new file mode 100644 index 000000000..c0bd2f7f6 --- /dev/null +++ b/tests-e2e/src/node/api_clients/rest.py @@ -0,0 +1,190 @@ +from src.libs.custom_logger import get_custom_logger +import json +from urllib.parse import quote +from src.node.api_clients.base_client import BaseClient + +logger = get_custom_logger(__name__) + + +class REST(BaseClient): + def __init__(self, rest_port): + self._rest_port = rest_port + + def rest_call(self, method, endpoint, payload=None): + url = f"http://127.0.0.1:{self._rest_port}/{endpoint}" + headers = {"Content-Type": "application/json"} + return self.make_request(method, url, headers=headers, data=payload) + + def rest_call_text(self, method, endpoint, payload=None): + url = f"http://127.0.0.1:{self._rest_port}/{endpoint}" + headers = {"accept": "text/plain"} + return self.make_request(method, url, headers=headers, data=payload) + + def info(self): + info_response = self.rest_call("get", "debug/v1/info") + return info_response.json() + + def health(self): + health_response = self.rest_call("get", "health") + return health_response.content + + def get_peers(self): + get_peers_response = self.rest_call("get", "admin/v1/peers") + return get_peers_response.json() + + def add_peers(self, peers): + return self.rest_call("post", "admin/v1/peers", json.dumps(peers)) + + def set_relay_subscriptions(self, pubsub_topics): + return self.rest_call("post", "relay/v1/subscriptions", json.dumps(pubsub_topics)) + + def set_relay_auto_subscriptions(self, content_topics): + return self.rest_call("post", "relay/v1/auto/subscriptions", json.dumps(content_topics)) + + def delete_relay_subscriptions(self, pubsub_topics): + return self.rest_call("delete", "relay/v1/subscriptions", json.dumps(pubsub_topics)) + + def delete_relay_auto_subscriptions(self, content_topics): + return self.rest_call("delete", "relay/v1/auto/subscriptions", json.dumps(content_topics)) + + def send_relay_message(self, message, pubsub_topic): + return self.rest_call("post", f"relay/v1/messages/{quote(pubsub_topic, safe='')}", json.dumps(message)) + + def send_relay_auto_message(self, message): + return self.rest_call("post", "relay/v1/auto/messages", json.dumps(message)) + + def send_light_push_message(self, payload): + return self.rest_call("post", "lightpush/v1/message", json.dumps(payload)) + + def get_relay_messages(self, pubsub_topic): + get_messages_response = self.rest_call("get", f"relay/v1/messages/{quote(pubsub_topic, safe='')}") + return get_messages_response.json() + + def get_relay_auto_messages(self, content_topic): + get_messages_response = self.rest_call("get", f"relay/v1/auto/messages/{quote(content_topic, safe='')}") + return get_messages_response.json() + + def set_filter_subscriptions(self, subscription): + set_subscriptions_response = self.rest_call("post", "filter/v2/subscriptions", json.dumps(subscription)) + return set_subscriptions_response.json() + + def update_filter_subscriptions(self, subscription): + update_subscriptions_response = self.rest_call("put", "filter/v2/subscriptions", json.dumps(subscription)) + return update_subscriptions_response.json() + + def delete_filter_subscriptions(self, subscription): + delete_subscriptions_response = self.rest_call("delete", "filter/v2/subscriptions", json.dumps(subscription)) + return delete_subscriptions_response.json() + + def delete_all_filter_subscriptions(self, request_id): + delete_all_subscriptions_response = self.rest_call("delete", "filter/v2/subscriptions/all", json.dumps(request_id)) + return delete_all_subscriptions_response.json() + + def ping_filter_subscriptions(self, request_id): + ping_subscriptions_response = self.rest_call("get", f"filter/v2/subscriptions/{quote(request_id, safe='')}") + return ping_subscriptions_response.json() + + def get_filter_messages(self, content_topic, pubsub_topic=None): + if pubsub_topic is not None: + endpoint = f"filter/v2/messages/{quote(pubsub_topic, safe='')}/{quote(content_topic, safe='')}" + else: + endpoint = f"filter/v2/messages/{quote(content_topic, safe='')}" + get_messages_response = self.rest_call("get", endpoint) + return get_messages_response.json() + + def get_store_messages( + self, + peer_addr, + include_data, + pubsub_topic, + content_topics, + start_time, + end_time, + hashes, + cursor, + page_size, + ascending, + store_v, + encode_pubsubtopic=True, + **kwargs, + ): + base_url = f"store/{store_v}/messages" + params = [] + + if peer_addr is not None: + params.append(f"peerAddr={quote(peer_addr, safe='')}") + if include_data is not None: + params.append(f"includeData={include_data}") + if pubsub_topic is not None: + if encode_pubsubtopic: + params.append(f"pubsubTopic={quote(pubsub_topic, safe='')}") + else: + params.append(f"pubsubTopic={pubsub_topic}") + if content_topics is not None: + params.append(f"contentTopics={quote(content_topics, safe='')}") + if start_time is not None: + params.append(f"startTime={start_time}") + if end_time is not None: + params.append(f"endTime={end_time}") + if hashes is not None: + params.append(f"hashes={quote(hashes, safe='')}") + if cursor is not None: + params.append(f"cursor={quote(cursor, safe='')}") + if page_size is not None: + params.append(f"pageSize={page_size}") + if ascending is not None: + params.append(f"ascending={ascending}") + + # Append any additional keyword arguments to the parameters list + for key, value in kwargs.items(): + if value is not None: + params.append(f"{key}={quote(str(value), safe='')}") + + if params: + base_url += "?" + "&".join(params) + + get_messages_response = self.rest_call("get", base_url) + return get_messages_response.json() + + def set_log_level(self, log_level): + return self.rest_call("post", f"admin/v1/log-level/{quote(log_level)}") + + def get_service_peers(self): + return self.rest_call("get", "admin/v1/peers/service").json() + + def get_connected_peers(self): + return self.rest_call("get", "admin/v1/peers/connected").json() + + def get_connected_peers_on_shard(self, shard_id): + return self.rest_call("get", f"admin/v1/peers/connected/on/{quote(str(shard_id))}").json() + + def get_relay_peers(self): + return self.rest_call("get", "admin/v1/peers/relay").json() + + def get_relay_peers_on_shard(self, shard_id): + return self.rest_call("get", f"admin/v1/peers/relay/on/{quote(str(shard_id))}").json() + + def get_mesh_peers(self): + return self.rest_call("get", "admin/v1/peers/mesh").json() + + def get_mesh_peers_on_shard(self, shard_id): + return self.rest_call("get", f"admin/v1/peers/mesh/on/{quote(str(shard_id))}").json() + + def get_peer_stats(self): + return self.rest_call("get", "admin/v1/peers/stats").json() + + def get_filter_subscriptions(self): + return self.rest_call("get", "admin/v1/filter/subscriptions").json() + + def get_info(self): + return self.rest_call("get", "info").json() + + def get_version(self): + return self.rest_call("get", "version").text.strip() + + def get_debug_version(self): + return self.rest_call("get", "debug/v1/version").text.strip() + + def get_peer(self, peer_id: str): + resp = self.rest_call("get", f"admin/v1/peer/{peer_id}") + return resp.json() diff --git a/tests-e2e/src/node/docker_mananger.py b/tests-e2e/src/node/docker_mananger.py new file mode 100644 index 000000000..44329d098 --- /dev/null +++ b/tests-e2e/src/node/docker_mananger.py @@ -0,0 +1,145 @@ +import os +import re +import time +from src.libs.custom_logger import get_custom_logger +import random +import threading +import docker +from src.env_vars import NETWORK_NAME, SUBNET, IP_RANGE, GATEWAY +from docker.types import IPAMConfig, IPAMPool +from docker.errors import NotFound, APIError + +logger = get_custom_logger(__name__) + + +class DockerManager: + def __init__(self, image): + self._image = image + self._client = docker.from_env() + logger.debug(f"Docker client initialized with image {self._image}") + + def create_network(self, network_name=NETWORK_NAME): + logger.debug(f"Attempting to create or retrieve network {network_name}") + networks = self._client.networks.list(names=[network_name]) + if networks: + logger.debug(f"Network {network_name} already exists") + return networks[0] + + network = self._client.networks.create( + network_name, + driver="bridge", + ipam=IPAMConfig(driver="default", pool_configs=[IPAMPool(subnet=SUBNET, iprange=IP_RANGE, gateway=GATEWAY)]), + ) + logger.debug(f"Network {network_name} created") + return network + + def start_container(self, image_name, ports, args, log_path, container_ip, volumes, remove_container=True): + cli_args = [] + for key, value in args.items(): + if isinstance(value, list): # Check if value is a list + cli_args.extend([f"--{key}={item}" for item in value]) # Add a command for each item in the list + elif value is None: + cli_args.append(f"{key}") # Add simple command as it is passed in the key + else: + cli_args.append(f"--{key}={value}") # Add a single command + + port_bindings = {f"{port}/tcp": ("", port) for port in ports} + port_bindings_for_log = " ".join(f"-p {port}:{port}" for port in ports) + cli_args_str_for_log = " ".join(cli_args) + logger.debug(f"docker run -i -t {port_bindings_for_log} {image_name} {cli_args_str_for_log}") + container = self._client.containers.run( + image_name, command=cli_args, ports=port_bindings, detach=True, remove=remove_container, auto_remove=remove_container, volumes=volumes + ) + + network = self._client.networks.get(NETWORK_NAME) + logger.debug(f"docker network connect --ip {container_ip} {NETWORK_NAME} {container.id}") + network.connect(container, ipv4_address=container_ip) + + logger.debug(f"Container started with ID {container.short_id}. Setting up logs at {log_path}") + log_thread = threading.Thread(target=self._log_container_output, args=(container, log_path)) + log_thread.daemon = True + log_thread.start() + + return container + + def _log_container_output(self, container, log_path): + os.makedirs(os.path.dirname(log_path), exist_ok=True) + retry_count = 0 + start_time = time.time() + try: + with open(log_path, "wb+") as log_file: + while True: + if container.status in ["exited", "dead"]: + logger.info(f"Container {container.short_id} has stopped. Exiting log stream.") + return + try: + for chunk in container.logs(stream=True): + if chunk: + log_file.write(chunk) + log_file.flush() + start_time = time.time() + retry_count = 0 + else: + if time.time() - start_time > 5: + logger.warning(f"Log stream timeout for container {container.short_id}") + return + except (APIError, IOError) as e: + retry_count += 1 + if retry_count >= 5: + logger.error(f"Max retries reached for container {container.short_id}. Exiting log stream.") + return + time.sleep(0.2) + except Exception as e: + return + except Exception as e: + logger.error(f"Failed to set up logging for container {container.short_id}: {e}") + + def generate_ports(self, base_port=None, count=5): + if base_port is None: + base_port = random.randint(1024, 65535 - count) + ports = [str(base_port + i) for i in range(count)] + logger.debug(f"Generated ports {ports}") + return ports + + @staticmethod + def generate_random_ext_ip(): + base_ip_fragments = ["172", "18"] + ext_ip = ".".join(base_ip_fragments + [str(random.randint(0, 255)) for _ in range(2)]) + logger.debug(f"Generated random external IP {ext_ip}") + return ext_ip + + def is_container_running(self, container): + try: + refreshed_container = self._client.containers.get(container.id) + return refreshed_container.status == "running" + except NotFound: + logger.error(f"Container with ID {container.id} not found") + return False + + @property + def image(self): + return self._image + + def search_log_for_keywords(self, log_path, keywords, use_regex=False): + matches = {keyword: [] for keyword in keywords} + + # Open the log file and search line by line + with open(log_path, "r") as log_file: + for line in log_file: + for keyword in keywords: + if use_regex: + if re.search(keyword, line, re.IGNORECASE): + matches[keyword].append(line.strip()) + else: + if keyword.lower() in line.lower(): + matches[keyword].append(line.strip()) + + # Check if there were any matches + if any(matches[keyword] for keyword in keywords): + for keyword, lines in matches.items(): + if lines: + logger.debug(f"Found matches for keyword '{keyword}': {lines}") + return matches + else: + logger.debug("No errors found in the waku logs.") + return None diff --git a/tests-e2e/src/node/store_response.py b/tests-e2e/src/node/store_response.py new file mode 100644 index 000000000..d6274ce78 --- /dev/null +++ b/tests-e2e/src/node/store_response.py @@ -0,0 +1,103 @@ +class StoreResponse: + def __init__(self, store_response, node): + self.response = store_response + self.node = node + + @property + def request_id(self): + try: + if self.node.is_nwaku(): + return self.response.get("requestId") + else: + return self.response.get("request_id") + except: + return None + + @property + def status_code(self): + try: + if self.node.is_nwaku(): + return self.response.get("statusCode") + else: + return self.response.get("status_code") + except: + return None + + @property + def status_desc(self): + try: + if self.node.is_nwaku(): + return self.response.get("statusDesc") + else: + return self.response.get("status_desc") + except: + return None + + @property + def messages(self): + try: + return self.response.get("messages") + except: + return None + + @property + def pagination_cursor(self): + try: + if self.node.is_nwaku(): + return self.response.get("paginationCursor") + else: + return self.response.get("pagination_cursor") + except: + return None + + def message_hash(self, index): + if self.messages is not None: + if self.node.is_nwaku(): + return self.messages[index]["messageHash"] + else: + return self.messages[index]["message_hash"] + else: + return None + + def message_content(self, index): + try: + if self.messages is not None: + payload = self.messages[index]["message"]["contentTopic"] + return payload + else: + return None + except IndexError: + return None + + def message_payload(self, index): + try: + if self.messages is not None: + payload = self.messages[index]["message"]["payload"] + return payload + else: + return None + except IndexError: + return None + + def message_at(self, index): + try: + if self.messages is not None: + message = self.messages[index]["message"] + return message + else: + return None + except IndexError: + return None + + def message_pubsub_topic(self, index): + if self.messages is not None: + if self.node.is_nwaku(): + return self.messages[index]["pubsubTopic"] + else: + return self.messages[index]["pubsub_topic"] + else: + return None + + @property + def resp_json(self): + return self.response diff --git a/tests-e2e/src/node/waku_message.py b/tests-e2e/src/node/waku_message.py new file mode 100644 index 000000000..ea6703ccf --- /dev/null +++ b/tests-e2e/src/node/waku_message.py @@ -0,0 +1,46 @@ +from dataclasses import dataclass, field +from marshmallow_dataclass import class_schema +from typing import Optional, Union +import math +import allure + + +@dataclass +class MessageRpcResponse: + payload: str + contentTopic: str + version: Optional[int] + timestamp: Optional[int] + ephemeral: Optional[bool] + meta: Optional[str] + proof: Optional[str] = field(default_factory=dict) + rateLimitProof: Optional[str] = field(default_factory=dict) + rate_limit_proof: Optional[dict] = field(default_factory=dict) + + +class WakuMessage: + def __init__(self, message_response, schema=MessageRpcResponse): + self.schema = schema + self.received_messages = message_response + self.message_rpc_response_schema = class_schema(self.schema)() + + @allure.step + def assert_received_message(self, sent_message, index=0): + message = self.message_rpc_response_schema.load(self.received_messages[index]) + + def assert_fail_message(field_name): + return f"Incorrect field: {field_name}. Published: {sent_message[field_name]} Received: {getattr(message, field_name)}" + + assert message.payload == sent_message["payload"], assert_fail_message("payload") + assert message.contentTopic == sent_message["contentTopic"], assert_fail_message("contentTopic") + if sent_message.get("timestamp") is not None: + if isinstance(sent_message["timestamp"], float): + assert math.isclose(float(message.timestamp), sent_message["timestamp"], rel_tol=1e-9), assert_fail_message("timestamp") + else: + assert str(message.timestamp) == str(sent_message["timestamp"]), assert_fail_message("timestamp") + if "version" in sent_message: + assert str(message.version) == str(sent_message["version"]), assert_fail_message("version") + if "meta" in sent_message: + assert str(message.meta) == str(sent_message["meta"]), assert_fail_message("meta") + if "ephemeral" in sent_message: + assert str(message.ephemeral) == str(sent_message["ephemeral"]), assert_fail_message("ephemeral") diff --git a/tests-e2e/src/node/waku_node.py b/tests-e2e/src/node/waku_node.py new file mode 100644 index 000000000..8e73fe4cd --- /dev/null +++ b/tests-e2e/src/node/waku_node.py @@ -0,0 +1,683 @@ +import errno +import json +import os +import random +import re +import shutil +import string +import subprocess +import pytest +import requests +from src.libs.common import delay +from src.libs.custom_logger import get_custom_logger +from tenacity import retry, stop_after_delay, wait_fixed, sleep +from docker.errors import NotFound as DockerNotFound +from src.node.api_clients.rest import REST +from src.node.docker_mananger import DockerManager +from src.env_vars import DOCKER_LOG_DIR +from src.data_storage import DS +from src.test_data import DEFAULT_CLUSTER_ID, LOG_ERROR_KEYWORDS, VALID_PUBSUB_TOPICS + +logger = get_custom_logger(__name__) + + +def select_private_key(prv_keys, key_id): + for key in prv_keys: + if key.endswith(key_id): + return key + + raise ValueError("No matching key was found") + + +def sanitize_docker_flags(input_flags): + output_flags = {} + for key, value in input_flags.items(): + key = key.replace("_", "-") + output_flags[key] = value + + return output_flags + + +@retry(stop=stop_after_delay(180), wait=wait_fixed(0.5), reraise=True) +def rln_credential_store_ready(creds_file_path, single_check=False, require_credentials=False): + if os.path.exists(creds_file_path): + subprocess.run(["sudo", "-n", "chmod", "a+r", creds_file_path], check=False) + if require_credentials: + try: + with open(creds_file_path, "r", encoding="utf-8") as creds_file: + keystore_data = json.load(creds_file) + except (OSError, json.JSONDecodeError) as ex: + if single_check: + return False + raise ValueError(f"Failed to parse RLN keystore at {creds_file_path}: {ex}") + + credentials = keystore_data.get("credentials", {}) if isinstance(keystore_data, dict) else {} + if not credentials: + if single_check: + return False + raise ValueError(f"RLN keystore exists but has no credentials yet: {creds_file_path}") + + return True + elif not single_check: + raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), creds_file_path) + + return False + + +def peer_info2multiaddr(peer, is_nwaku=True): + if is_nwaku: + return peer["multiaddr"] + else: + return peer["multiaddrs"][0] + + +def peer_info2id(peer, is_nwaku=True): + return peer_info2multiaddr(peer, is_nwaku).split("/")[-1] + + +def multiaddr2id(multiaddr): + return multiaddr.split("/")[-1] + + +def resolve_sharding_flags(kwargs): + if "pubsub_topic" in kwargs and kwargs["pubsub_topic"]: + pubsub_topic = kwargs["pubsub_topic"] + if not "cluster_id" in kwargs: + try: + if isinstance(pubsub_topic, list): + pubsub_topic = pubsub_topic[0] + cluster_id = pubsub_topic.split("/")[4] + logger.debug(f"Cluster id was resolved to: {cluster_id}") + kwargs["cluster_id"] = cluster_id + except Exception as ex: + raise Exception("Could not resolve cluster_id from pubsub_topic") + return kwargs + + +class WakuNode: + def __init__(self, docker_image, docker_log_prefix=""): + self._image_name = docker_image + self._log_path = os.path.join(DOCKER_LOG_DIR, f"{docker_log_prefix}__{self._image_name.replace('/', '_')}.log") + self._docker_manager = DockerManager(self._image_name) + self._container = None + self.rln_membership_index = None + self.start_args = {} + self._rln_creds_set = False + logger.debug(f"WakuNode instance initialized with log path {self._log_path}") + + @retry(stop=stop_after_delay(60), wait=wait_fixed(0.1), reraise=True) + def start(self, wait_for_node_sec=20, **kwargs): + logger.debug("Starting Node...") + default_args, remove_container = self._prepare_start_context(**kwargs) + self._start_docker(default_args, remove_container, wait_for_node_sec) + + def _prepare_start_context(self, **kwargs): + self._docker_manager.create_network() + self._ext_ip = self._docker_manager.generate_random_ext_ip() + self._ports = self._docker_manager.generate_ports() + self._rest_port = self._ports[0] + self._tcp_port = self._ports[1] + self._websocket_port = self._ports[2] + self._discv5_port = self._ports[3] + self._metrics_port = self._ports[4] + self._api = REST(self._rest_port) + self._volumes = [] + + default_args = { + "listen-address": "0.0.0.0", + "rest": "true", + "rest-admin": "true", + "websocket-support": "true", + "log-level": "TRACE", + "rest-relay-cache-capacity": "100", + "websocket-port": self._websocket_port, + "rest-port": self._rest_port, + "tcp-port": self._tcp_port, + "discv5-udp-port": self._discv5_port, + "rest-address": "0.0.0.0", + "nat": f"extip:{self._ext_ip}", + "peer-exchange": "true", + "discv5-discovery": "true", + "cluster-id": DEFAULT_CLUSTER_ID, + "rln-creds-id": None, + "rln-creds-source": None, + "nodekey": self.generate_random_nodekey(), + # "max-connections": "50", + # "filter-subscription-timeout": "600", + } + + store_sync = kwargs.pop("store_sync", "false").lower() == "true" + store_sync_range = kwargs.pop("store_sync_range", None) + store_sync_interval = kwargs.pop("store_sync_interval", None) + + if store_sync: + default_args["store-sync"] = "true" + default_args.setdefault("store", "true") + + if store_sync_range: + default_args["store-sync-range"] = store_sync_range + + if store_sync_interval: + default_args["store-sync-interval"] = store_sync_interval + + if self.is_nwaku(): + nwaku_args = { + "shard": "0", + "metrics-server": "true", + "metrics-server-address": "0.0.0.0", + "metrics-server-port": self._metrics_port, + "metrics-logging": "true", + } + default_args.update(nwaku_args) + else: + raise NotImplementedError("Not implemented for this node type") + + if "remove_container" in kwargs: + remove_container = kwargs["remove_container"] + del kwargs["remove_container"] + else: + remove_container = True + + kwargs = self.parse_peer_persistence_config(kwargs) + kwargs = resolve_sharding_flags(kwargs) + + default_args.update(sanitize_docker_flags(kwargs)) + + if self.is_nwaku() and "pubsub-topic" in default_args: + logger.debug("Removing pubsub-topic from nwaku args") + del default_args["pubsub-topic"] + + rln_args, rln_creds_set, keystore_path = self.parse_rln_credentials(default_args, False) + self._rln_creds_set = rln_creds_set + + default_args.pop("rln-creds-id", None) + default_args.pop("rln-creds-source", None) + default_args.pop("rln-keystore-prefix", None) + + if rln_creds_set: + rln_credential_store_ready(keystore_path, require_credentials=True) + default_args.update(rln_args) + else: + logger.info(f"RLN credentials not set or credential store not available, starting without RLN") + + self.start_args = dict(default_args) + return default_args, remove_container + + def _start_docker(self, default_args, remove_container, wait_for_node_sec): + logger.debug(f"Using volumes {self._volumes}") + + self._container = self._docker_manager.start_container( + self._docker_manager.image, + ports=self._ports, + args=default_args, + log_path=self._log_path, + container_ip=self._ext_ip, + volumes=self._volumes, + remove_container=remove_container, + ) + logger.debug(f"Started container from image {self._image_name}. REST: {self._rest_port}") + DS.waku_nodes.append(self) + delay(1) + try: + self.ensure_ready(timeout_duration=wait_for_node_sec, rln_required=self._rln_creds_set) + except Exception as ex: + logger.error(f"REST service did not become ready in time: {ex}") + raise + + @retry(stop=stop_after_delay(250), wait=wait_fixed(0.1), reraise=True) + def register_rln(self, **kwargs): + logger.debug("Registering RLN credentials...") + self._docker_manager.create_network() + self._ext_ip = self._docker_manager.generate_random_ext_ip() + self._ports = self._docker_manager.generate_ports() + self._rest_port = self._ports[0] + self._api = REST(self._rest_port) + self._volumes = [] + + default_args = {"rln-creds-id": None, "rln-creds-source": None, "rln-relay-user-message-limit-registration": 100} + + default_args.update(sanitize_docker_flags(kwargs)) + + rln_args, rln_creds_set, keystore_path = self.parse_rln_credentials(default_args, True) + + if rln_creds_set: + self._container = self._docker_manager.start_container( + self._docker_manager.image, self._ports, rln_args, self._log_path, self._ext_ip, self._volumes + ) + + logger.debug(f"Executed container from image {self._image_name}. REST: {self._rest_port} to register RLN") + + logger.debug(f"Waiting for keystore {keystore_path}") + try: + rln_credential_store_ready(keystore_path, require_credentials=True) + self.rln_membership_index = str(self.get_rln_membership_index_from_log()) + logger.debug(f"Detected RLN membership index from registration logs: {self.rln_membership_index}") + self.stop() + except Exception as ex: + logger.error(f"File {keystore_path} with RLN credentials did not become available in time {ex}") + raise + else: + logger.warn("RLN credentials not set, no action performed") + + return self.rln_membership_index + + @retry(stop=stop_after_delay(10), wait=wait_fixed(0.2), reraise=True) + def get_rln_membership_index_from_log(self): + if not os.path.exists(self._log_path): + raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), self._log_path) + + with open(self._log_path, "r", encoding="utf-8", errors="ignore") as log_file: + log_data = log_file.read() + + matches = re.findall(r"membershipIndex=(\d+)", log_data) + if not matches: + raise ValueError("Could not infer RLN membership index from registration logs") + + return int(matches[-1]) + + @retry(stop=stop_after_delay(5), wait=wait_fixed(0.1), reraise=True) + def stop(self): + if self._container: + logger.debug(f"Stopping container with id {self._container.short_id}") + try: + self._container.stop() + except DockerNotFound: + logger.debug(f"Container {self._container.short_id} already exited and removed, treating as stopped.") + self._container = None + return + try: + self._container.remove() + except: + pass + self._container = None + logger.debug("Container stopped.") + + @retry(stop=stop_after_delay(5), wait=wait_fixed(0.1), reraise=True) + def kill(self): + if self._container: + logger.debug(f"Killing container with id {self._container.short_id}") + self._container.kill() + try: + self._container.remove() + except: + pass + self._container = None + logger.debug("Container killed.") + + def restart(self): + if self._container: + logger.debug(f"Restarting container with id {self._container.short_id}") + self._container.restart() + + def pause(self): + if self._container: + logger.debug(f"Pausing container with id {self._container.short_id}") + self._container.pause() + + def unpause(self): + if self._container: + logger.debug(f"Unpause container with id {self._container.short_id}") + self._container.unpause() + + def ensure_ready(self, timeout_duration=10, rln_required=False): + @retry(stop=stop_after_delay(timeout_duration), wait=wait_fixed(0.1), reraise=True) + def check_healthy(node=self): + self.health_response = node.health() + + try: + self.health_response = json.loads(self.health_response) + except Exception as ex: + raise AttributeError(f"Unknown health response format {ex}") + + if self.health_response.get("nodeHealth") != "READY": + raise AssertionError("Waiting for the node health status: READY") + + for p in self.health_response.get("protocolsHealth"): + if rln_required and "Rln Relay" in p: + if p["Rln Relay"] != "READY": + raise AssertionError("Waiting for the Rln relay status: READY") + # TODO: Remove once Rln Relay reflects true RLN status + sleep(20) + + logger.info("Node protocols are initialized !!") + + @retry(stop=stop_after_delay(timeout_duration), wait=wait_fixed(0.1), reraise=True) + def check_ready(node=self): + node.info_response = node.info() + logger.info("REST service is ready !!") + + if self.is_nwaku(): + check_healthy() + check_ready() + + def get_id(self): + try: + return self.info_response["listenAddresses"][0].split("/")[-1] + except Exception as ex: + raise AttributeError(f"Could not find ID in the info call because of error: {str(ex)}") + + def get_enr_uri(self): + try: + return self.info_response["enrUri"] + except Exception as ex: + raise AttributeError(f"Could not find enrUri in the info call because of error: {str(ex)}") + + def get_multiaddr_with_id(self): + addresses = self.info_response.get("listenAddresses", []) + ws_address = next((addr for addr in addresses if "/ws" not in addr), None) + if ws_address: + identifier = ws_address.split("/p2p/")[-1] + new_address = f"{self.get_tcp_address()}/p2p/{identifier}" + return new_address + else: + raise AttributeError("No '/ws' address found") + + def get_tcp_address(self): + return f"/ip4/{self._ext_ip}/tcp/{self._tcp_port}" + + def subscribe_content_topic(self, content_topic: str): + return self._api.set_relay_auto_subscriptions([content_topic]) + + def unsubscribe_content_topic(self, content_topic: str): + return self._api.delete_relay_auto_subscriptions([content_topic]) + + def send_message(self, message: dict): + return self._api.send_relay_auto_message(message) + + def info(self): + return self._api.info() + + def health(self): + return self._api.health() + + def get_peers(self): + return self._api.get_peers() + + def add_peers(self, peers): + return self._api.add_peers(peers) + + def set_relay_subscriptions(self, pubsub_topics): + return self._api.set_relay_subscriptions(pubsub_topics) + + def set_relay_auto_subscriptions(self, content_topics): + return self._api.set_relay_auto_subscriptions(content_topics) + + def delete_relay_subscriptions(self, pubsub_topics): + return self._api.delete_relay_subscriptions(pubsub_topics) + + def delete_relay_auto_subscriptions(self, content_topics): + return self._api.delete_relay_auto_subscriptions(content_topics) + + def send_relay_message(self, message, pubsub_topic): + return self._api.send_relay_message(message, pubsub_topic) + + def send_relay_auto_message(self, message): + return self._api.send_relay_auto_message(message) + + def send_light_push_message(self, payload): + return self._api.send_light_push_message(payload) + + def get_relay_messages(self, pubsub_topic): + return self._api.get_relay_messages(pubsub_topic) + + def get_relay_auto_messages(self, content_topic): + return self._api.get_relay_auto_messages(content_topic) + + def set_filter_subscriptions(self, subscription): + return self._api.set_filter_subscriptions(subscription) + + def update_filter_subscriptions(self, subscription): + return self._api.update_filter_subscriptions(subscription) + + def delete_filter_subscriptions(self, subscription): + return self._api.delete_filter_subscriptions(subscription) + + def delete_all_filter_subscriptions(self, request_id): + return self._api.delete_all_filter_subscriptions(request_id) + + def ping_filter_subscriptions(self, request_id): + return self._api.ping_filter_subscriptions(request_id) + + def get_filter_messages(self, content_topic, pubsub_topic=None): + return self._api.get_filter_messages(content_topic, pubsub_topic) + + def get_store_messages( + self, + peer_addr=None, + include_data=None, + pubsub_topic=None, + content_topics=None, + start_time=None, + end_time=None, + hashes=None, + cursor=None, + page_size=None, + ascending=None, + store_v="v3", + **kwargs, + ): + return self._api.get_store_messages( + peer_addr=peer_addr, + include_data=include_data, + pubsub_topic=pubsub_topic, + content_topics=content_topics, + start_time=start_time, + end_time=end_time, + hashes=hashes, + cursor=cursor, + page_size=page_size, + ascending=ascending, + store_v=store_v, + **kwargs, + ) + + def get_metrics(self): + if self.is_nwaku(): + metrics = requests.get(f"http://localhost:{self._metrics_port}/metrics") + metrics.raise_for_status() + return metrics.content.decode("utf-8") + else: + pytest.skip(f"This method doesn't exist for node {self.type()}") + + @property + def image(self): + return self._image_name + + def type(self): + if self.is_nwaku(): + return "nwaku" + else: + raise ValueError("Unknown node type!!!") + + def is_nwaku(self): + return "nwaku" in self.image + + def prepare_rln_storage_paths(self, cwd, keystore_prefix, selected_id, reset_existing=False): + keystore_dir = os.path.join(cwd, f"keystore_{keystore_prefix}_{selected_id}") + rln_tree_dir = os.path.join(cwd, f"rln_tree_{keystore_prefix}_{selected_id}") + + if reset_existing: + for path, path_name in [(keystore_dir, "keystore"), (rln_tree_dir, "rln tree")]: + if os.path.exists(path): + logger.warning(f"Resetting existing RLN {path_name} directory before registration: {path}") + shutil.rmtree(path, ignore_errors=True) + + os.makedirs(keystore_dir, exist_ok=True) + os.makedirs(rln_tree_dir, exist_ok=True) + + return keystore_dir, rln_tree_dir + + def parse_rln_credentials(self, default_args, is_registration): + rln_args = {} + keystore_path = None + + rln_creds_source = default_args["rln-creds-source"] + selected_id = default_args["rln-creds-id"] + + if rln_creds_source is None or selected_id is None: + logger.debug(f"RLN credentials were not set") + return rln_args, False, keystore_path + + imported_creds = json.loads(rln_creds_source) + rln_chain_id = imported_creds.get("rln-relay-chain-id") + if rln_chain_id is None: + eth_client_address = imported_creds.get("rln-relay-eth-client-address", "") + if "linea" in eth_client_address: + rln_chain_id = "59141" + elif "sepolia" in eth_client_address: + rln_chain_id = "11155111" + + if len(imported_creds) < 4 or any(value is None for value in imported_creds.values()): + logger.warn(f"One or more of required RLN credentials were not set properly") + return rln_args, False, keystore_path + + eth_private_key = select_private_key(imported_creds, selected_id) + + cwd = os.getcwd() + keystore_prefix = default_args.get("rln-keystore-prefix") + + if not keystore_prefix: + logger.warn("rln-keystore-prefix is missing, cannot mount RLN state and keystore") + return rln_args, False, keystore_path + + keystore_dir, rln_tree_dir = self.prepare_rln_storage_paths(cwd, keystore_prefix, selected_id, reset_existing=is_registration) + + if self.is_nwaku(): + if is_registration: + rln_args.update( + { + "generateRlnKeystore": None, + "--execute": None, + "rln-relay-user-message-limit": default_args["rln-relay-user-message-limit-registration"], + } + ) + else: + rln_args.update( + { + "rln-relay": "true", + } + ) + + if not default_args.get("rln-relay-dynamic") and not is_registration: + rln_args.update( + { + "rln-relay-cred-path": "/keystore/keystore.json", + "rln-relay-cred-password": imported_creds["rln-relay-cred-password"], + "rln-relay-eth-client-address": imported_creds["rln-relay-eth-client-address"], + "rln-relay-eth-contract-address": imported_creds["rln-relay-eth-contract-address"], + } + ) + else: + rln_args.update( + { + "rln-relay-cred-path": "/keystore/keystore.json", + "rln-relay-cred-password": imported_creds["rln-relay-cred-password"], + "rln-relay-eth-client-address": imported_creds["rln-relay-eth-client-address"], + "rln-relay-eth-contract-address": imported_creds["rln-relay-eth-contract-address"], + "rln-relay-eth-private-key": imported_creds[eth_private_key], + } + ) + + if rln_chain_id is not None: + rln_args["rln-relay-chain-id"] = str(rln_chain_id) + + keystore_path = os.path.join(keystore_dir, "keystore.json") + + self._volumes.extend( + [ + f"{rln_tree_dir}:/etc/rln_tree", + f"{keystore_dir}:/keystore", + ] + ) + + else: + raise NotImplementedError("Not implemented for type other than Nim Waku ") + + return rln_args, True, keystore_path + + def parse_peer_persistence_config(self, kwargs): + if kwargs.get("peer_persistence") == "true": + cwd = os.getcwd() + # Please note, as of now, peerdb is stored directly at / which is not shareable between containers. + # Volume related code is usable after https://github.com/waku-org/nwaku/issues/2792 would be resolved. + self._volumes.extend( + [ + cwd + "/peerdb" + ":/shared", + ] + ) + + shutil.rmtree(cwd + "/peerdb") + + return kwargs + + @property + def container(self): + return self._container + + def generate_random_nodekey(self): + # Define the set of hexadecimal characters + hex_chars = string.hexdigits.lower() + # Generate a random 64-character string from the hex characters + random_key = "".join(random.choice(hex_chars) for _ in range(64)) + return random_key + + def search_waku_log_for_string(self, search_pattern, use_regex=False): + return self._docker_manager.search_log_for_keywords(self._log_path, [search_pattern], use_regex) + + def check_waku_log_errors(self, whitelist=None): + keywords = LOG_ERROR_KEYWORDS + + # If a whitelist is provided, remove those keywords from the keywords list + if whitelist: + keywords = [keyword for keyword in keywords if keyword not in whitelist] + + matches = self._docker_manager.search_log_for_keywords(self._log_path, keywords, False) + assert not matches, f"Found errors {matches}" + + def set_log_level(self, log_level): + return self._api.set_log_level(log_level) + + def get_service_peers(self): + return self._api.get_service_peers() + + def get_connected_peers(self): + return self._api.get_connected_peers() + + def get_connected_peers_on_shard(self, shard_id): + return self._api.get_connected_peers_on_shard(shard_id) + + def get_relay_peers(self): + return self._api.get_relay_peers() + + def get_relay_peers_on_shard(self, shard_id): + return self._api.get_relay_peers_on_shard(shard_id) + + def get_mesh_peers(self): + return self._api.get_mesh_peers() + + def get_mesh_peers_on_shard(self, shard_id): + return self._api.get_mesh_peers_on_shard(shard_id) + + def get_peer_stats(self): + return self._api.get_peer_stats() + + def get_filter_subscriptions(self): + return self._api.get_filter_subscriptions() + + def get_info(self): + return self._api.get_info() + + def get_version(self): + return self._api.get_version() + + def get_debug_version(self): + return self._api.get_debug_version() + + def get_peer_info(self, peer_id: str): + return self._api.get_peer(peer_id) + + @property + def container_id(self) -> str: + if not self._container: + raise RuntimeError("Node container not started yet") + return self._container.id diff --git a/tests-e2e/src/node/wrapper_helpers.py b/tests-e2e/src/node/wrapper_helpers.py new file mode 100644 index 000000000..7c9dd1a2d --- /dev/null +++ b/tests-e2e/src/node/wrapper_helpers.py @@ -0,0 +1,218 @@ +from __future__ import annotations + +import json +import threading +import time +from typing import Optional +from src.libs.common import to_base64 + +DEFAULT_CONTENT_TOPIC = "/test/1/default/proto" +DEFAULT_PAYLOAD = to_base64("test payload") +EVENT_PROPAGATED = "message_propagated" +EVENT_SENT = "message_sent" +EVENT_ERROR = "message_error" + +# MaxTimeInCache from send_service.nim. +MAX_TIME_IN_CACHE_S = 60.0 +# Extra slack to cover the background retry loop tick after the window expires. +CACHE_EXPIRY_SLACK_S = 10.0 +ERROR_AFTER_CACHE_EXPIRY_TIMEOUT_S = MAX_TIME_IN_CACHE_S + CACHE_EXPIRY_SLACK_S +RETRY_WINDOW_EXPIRED_MSG = "Unable to send within retry time window" + + +class EventCollector: + """Thread-safe collector for async node events. + + Pass `collector.event_callback` as the `event_cb` argument to + WrapperManager.create_and_start(). Every event fired by the library + is decoded from JSON and appended to `self.events`. + """ + + def __init__(self): + self._lock = threading.Lock() + self.events: list[dict] = [] + + def event_callback(self, ret: int, raw: bytes) -> None: + try: + payload = json.loads(raw.decode("utf-8")) + except Exception: + payload = {"_raw": raw.decode("utf-8", errors="replace"), "_ret": ret} + + with self._lock: + self.events.append(payload) + + def get_events_for_request(self, request_id: str) -> list[dict]: + with self._lock: + return [e for e in self.events if e.get("requestId") == request_id] + + def snapshot(self) -> list[dict]: + """Return a thread-safe copy of all collected events. + + Use this whenever you need to iterate over every event (rather than + events for a single request_id). Iterating `self.events` directly is + unsafe because `event_callback` appends from the wrapper's event + thread. + """ + with self._lock: + return list(self.events) + + +def is_propagated_event(event: dict) -> bool: + return event.get("eventType") == EVENT_PROPAGATED + + +def is_sent_event(event: dict) -> bool: + return event.get("eventType") == EVENT_SENT + + +def is_error_event(event: dict) -> bool: + return event.get("eventType") == EVENT_ERROR + + +def wait_for_event( + collector: EventCollector, + request_id: str, + predicate, + timeout_s: float, + poll_interval_s: float = 0.5, +) -> Optional[dict]: + """Poll until an event matching `predicate` arrives for `request_id`, + or until `timeout_s` elapses. Returns the matching event or None. + """ + deadline = time.monotonic() + timeout_s + + while True: + for event in collector.get_events_for_request(request_id): + if predicate(event): + return event + if time.monotonic() >= deadline: + return None + time.sleep(poll_interval_s) + + +def wait_for_propagated(collector: EventCollector, request_id: str, timeout_s: float) -> Optional[dict]: + return wait_for_event(collector, request_id, is_propagated_event, timeout_s) + + +def wait_for_sent(collector: EventCollector, request_id: str, timeout_s: float) -> Optional[dict]: + return wait_for_event(collector, request_id, is_sent_event, timeout_s) + + +def wait_for_error(collector: EventCollector, request_id: str, timeout_s: float) -> Optional[dict]: + return wait_for_event(collector, request_id, is_error_event, timeout_s) + + +def assert_no_error(collector: EventCollector, request_id: str, context: str = "") -> None: + """Assert that no message_error event is currently buffered for `request_id`.""" + event = wait_for_error(collector, request_id, timeout_s=0) + suffix = f" ({context})" if context else "" + assert event is None, f"Unexpected message_error event{suffix}: {event}" + + +def assert_no_sent(collector: EventCollector, request_id: str, context: str = "") -> None: + """Assert that no message_sent event is currently buffered for `request_id`.""" + event = wait_for_sent(collector, request_id, timeout_s=0) + suffix = f" ({context})" if context else "" + assert event is None, f"Unexpected message_sent event{suffix}: {event}" + + +def assert_no_propagated(collector: EventCollector, request_id: str, context: str = "") -> None: + """Assert that no message_propagated event is currently buffered for `request_id`.""" + event = wait_for_propagated(collector, request_id, timeout_s=0) + suffix = f" ({context})" if context else "" + assert event is None, f"Unexpected message_propagated event{suffix}: {event}" + + +def wait_for_connected( + collector: EventCollector, + timeout_s: float = 10.0, + poll_interval_s: float = 0.3, +) -> Optional[dict]: + """Wait until a connection_status_change event with PartiallyConnected or Connected arrives.""" + deadline = time.monotonic() + timeout_s + while time.monotonic() < deadline: + for event in collector.snapshot(): + if event.get("eventType") == "connection_status_change" and event.get("connectionStatus") in ("PartiallyConnected", "Connected"): + return event + time.sleep(poll_interval_s) + return None + + +TERMINAL_EVENT_TYPES = {EVENT_PROPAGATED, EVENT_SENT, EVENT_ERROR} + + +def assert_event_invariants(collector: EventCollector, request_id: str) -> None: + """Check per-request event invariants (issue #163): + - All events carry the correct requestId. + - No duplicate terminal events (Propagated, Sent, Error). + - Sent never appears before Propagated. + """ + events = collector.get_events_for_request(request_id) + assert events, f"No events found for request {request_id}" + + counts: dict[str, int] = {} + first_index: dict[str, int] = {} + for i, event in enumerate(events): + assert event.get("requestId") == request_id, ( + f"Event at index {i} has wrong requestId: " f"expected {request_id!r}, got {event.get('requestId')!r}" + ) + event_type = event.get("eventType", "") + if event_type in TERMINAL_EVENT_TYPES: + counts[event_type] = counts.get(event_type, 0) + 1 + if event_type not in first_index: + first_index[event_type] = i + + for event_type, count in counts.items(): + assert count == 1, f"Duplicate {event_type} events for request {request_id}: " f"got {count}, expected 1. Events: {events}" + + if EVENT_SENT in first_index and EVENT_PROPAGATED in first_index: + assert first_index[EVENT_PROPAGATED] < first_index[EVENT_SENT], ( + f"message_sent (index {first_index[EVENT_SENT]}) arrived before " + f"message_propagated (index {first_index[EVENT_PROPAGATED]}) " + f"for request {request_id}. Events: {events}" + ) + + +def get_node_multiaddr(node) -> str: + """Return the TCP multiaddr (with peer-id) from a WrapperManager node. + + Asserts that the wrapper returned exactly one address. If the wrapper ever + starts returning multiple addresses (newline/comma-separated or a JSON + list), this fails loudly instead of silently passing a malformed string + downstream to staticnodes / add_peers. + """ + result = node.get_node_info_raw("MyMultiaddresses") + if result.is_err(): + raise RuntimeError(f"get_node_info_raw failed: {result.err()}") + + addr = result.ok_value.strip() + if not addr or not addr.startswith("/"): + raise RuntimeError(f"Unexpected multiaddr format: {addr!r}") + + if "\n" in addr or "," in addr or addr.startswith("["): + raise AssertionError(f"Expected a single multiaddr from MyMultiaddresses, got multiple: {addr!r}") + + return addr + + +def create_message_bindings(**overrides) -> dict: + envelope = { + "contentTopic": DEFAULT_CONTENT_TOPIC, + "payload": DEFAULT_PAYLOAD, + "ephemeral": False, + } + envelope.update(overrides) + return envelope + + +def assert_no_unknown_request_ids(collector: EventCollector, issued_request_ids) -> None: + """Cross-association guard: every event carrying a requestId must belong + to one of the request ids we issued. Catches events that get attached to + the wrong request id under concurrency. + """ + issued = set(issued_request_ids) + for event in collector.snapshot(): + event_request_id = event.get("requestId") + if event_request_id is None: + continue + assert event_request_id in issued, f"Event carries an unknown requestId={event_request_id!r}, " f"not in issued set {issued}. Event: {event}" diff --git a/tests-e2e/src/node/wrappers_manager.py b/tests-e2e/src/node/wrappers_manager.py new file mode 100644 index 000000000..a0d20e0d6 --- /dev/null +++ b/tests-e2e/src/node/wrappers_manager.py @@ -0,0 +1,98 @@ +import sys +from pathlib import Path +from result import Result, Ok, Err + +_BINDINGS_PATH = Path(__file__).resolve().parents[2] / "vendor" / "logos-delivery-python-bindings" / "waku" +if str(_BINDINGS_PATH) not in sys.path: + sys.path.insert(0, str(_BINDINGS_PATH)) + +from wrapper import NodeWrapper as _NodeWrapper # type: ignore[import] + +"""" +thin manager/wrapper layer around NodeWrapper from the bindings. +It simplifies create, start, and interaction with a Waku node while returning consistent Result objects (Ok / Err). +""" + + +class WrapperManager: + def __init__(self, node: _NodeWrapper): + self._node = node + + @classmethod + def create( + cls, + config: dict, + event_cb=None, + *, + timeout_s: float = 20.0, + ) -> Result["WrapperManager", str]: + result = _NodeWrapper.create_node(config, event_cb, timeout_s=timeout_s) + if result.is_err(): + return Err(result.err()) + return Ok(cls(result.ok_value)) + + @classmethod + def create_and_start( + cls, + config: dict, + event_cb=None, + *, + timeout_s: float = 20.0, + ) -> Result["WrapperManager", str]: + result = _NodeWrapper.create_and_start(config, event_cb, timeout_s=timeout_s) + if result.is_err(): + return Err(result.err()) + return Ok(cls(result.ok_value)) + + def __enter__(self) -> "WrapperManager": + return self + + def __exit__(self, *_) -> None: + self.stop_and_destroy() + + def start_node(self, *, timeout_s: float = 20.0) -> Result[int, str]: + return self._node.start_node(timeout_s=timeout_s) + + def stop_node(self, *, timeout_s: float = 20.0) -> Result[int, str]: + return self._node.stop_node(timeout_s=timeout_s) + + def destroy(self, *, timeout_s: float = 20.0) -> Result[int, str]: + return self._node.destroy(timeout_s=timeout_s) + + def stop_and_destroy(self, *, timeout_s: float = 20.0) -> Result[int, str]: + return self._node.stop_and_destroy(timeout_s=timeout_s) + + def subscribe_content_topic(self, content_topic: str, *, timeout_s: float = 20.0) -> Result[int, str]: + return self._node.subscribe_content_topic(content_topic, timeout_s=timeout_s) + + def unsubscribe_content_topic(self, content_topic: str, *, timeout_s: float = 20.0) -> Result[int, str]: + return self._node.unsubscribe_content_topic(content_topic, timeout_s=timeout_s) + + def send_message(self, message: dict, *, timeout_s: float = 20.0) -> Result[str, str]: + return self._node.send_message(message, timeout_s=timeout_s) + + def get_available_node_info_ids(self, *, timeout_s: float = 20.0) -> Result[list[str], str]: + return self._node.get_available_node_info_ids(timeout_s=timeout_s) + + def get_node_info(self, node_info_id: str, *, timeout_s: float = 20.0) -> Result[dict, str]: + return self._node.get_node_info(node_info_id, timeout_s=timeout_s) + + def get_node_info_raw(self, node_info_id: str, *, timeout_s: float = 20.0) -> Result[str, str]: + """Like get_node_info but returns the raw string without JSON parsing.""" + from wrapper import lib, ffi, _new_cb_state, _wait_cb_raw # type: ignore[import] + + state = _new_cb_state() + cb = self._node._make_waiting_cb(state) + rc = lib.logosdelivery_get_node_info(self._node.ctx, cb, ffi.NULL, node_info_id.encode("utf-8")) + if rc != 0: + return Err(f"get_node_info_raw: immediate call failed (ret={rc})") + wait_result = _wait_cb_raw(state, "get_node_info_raw", timeout_s) + if wait_result.is_err(): + return Err(wait_result.err()) + cb_ret, cb_msg = wait_result.ok_value + if cb_ret != 0: + return Err(f"get_node_info_raw: callback failed (ret={cb_ret})") + return Ok(cb_msg.decode("utf-8") if cb_msg else "") + + def get_available_configs(self, *, timeout_s: float = 20.0) -> Result[dict, str]: + return self._node.get_available_configs(timeout_s=timeout_s) diff --git a/tests-e2e/src/postgres_setup.py b/tests-e2e/src/postgres_setup.py new file mode 100644 index 000000000..97d47c954 --- /dev/null +++ b/tests-e2e/src/postgres_setup.py @@ -0,0 +1,44 @@ +import docker +import os +from src.env_vars import NETWORK_NAME, PG_PASS, PG_USER +from src.libs.custom_logger import get_custom_logger + +logger = get_custom_logger(__name__) + + +def start_postgres(): + pg_env = {"POSTGRES_USER": PG_USER, "POSTGRES_PASSWORD": PG_PASS} + + base_path = os.path.abspath(".") + volumes = {os.path.join(base_path, "postgresql"): {"bind": "/var/lib/postgresql/data", "mode": "Z"}} + + client = docker.from_env() + + postgres_container = client.containers.run( + "postgres:15.4-alpine3.18", + name="postgres", + environment=pg_env, + volumes=volumes, + command="postgres", + ports={"5432/tcp": ("127.0.0.1", 5432)}, + restart_policy={"Name": "on-failure", "MaximumRetryCount": 5}, + healthcheck={ + "Test": ["CMD-SHELL", "pg_isready -U postgres -d postgres"], + "Interval": 30000000000, # 30 seconds in nanoseconds + "Timeout": 60000000000, # 60 seconds in nanoseconds + "Retries": 5, + "StartPeriod": 80000000000, # 80 seconds in nanoseconds + }, + detach=True, + network_mode=NETWORK_NAME, + ) + + logger.debug("Postgres container started") + + return postgres_container + + +def stop_postgres(postgres_container): + postgres_container.stop() + postgres_container.remove() + logger.debug("Postgres container stopped and removed.") diff --git a/tests-e2e/src/steps/__init__.py b/tests-e2e/src/steps/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests-e2e/src/steps/common.py b/tests-e2e/src/steps/common.py new file mode 100644 index 000000000..ccdfcf533 --- /dev/null +++ b/tests-e2e/src/steps/common.py @@ -0,0 +1,80 @@ +import base64 +import hashlib +import inspect +from time import time +from time import time_ns +import allure +import pytest +from datetime import timedelta, datetime +from tenacity import retry, stop_after_delay, wait_fixed +from src.libs.common import delay, to_base64 +from src.libs.custom_logger import get_custom_logger + +logger = get_custom_logger(__name__) + + +class StepsCommon: + @pytest.fixture(scope="function", autouse=True) + def common_setup(self): + logger.debug(f"Running fixture setup: {inspect.currentframe().f_code.co_name}") + if not hasattr(self, "test_payload"): + self.test_payload = "Default Payload" + if not hasattr(self, "test_content_topic"): + self.test_content_topic = "/test/1/default/proto" + + @allure.step + @retry(stop=stop_after_delay(20), wait=wait_fixed(0.5), reraise=True) + def add_node_peer(self, node, multiaddr_list, shards=[0, 1, 2, 3, 4, 5, 6, 7, 8]): + if node.is_nwaku(): + for multiaddr in multiaddr_list: + node.add_peers([multiaddr]) + + @allure.step + @retry(stop=stop_after_delay(70), wait=wait_fixed(1), reraise=True) + def wait_for_autoconnection(self, node_list, hard_wait=None): + for node in node_list: + get_peers = node.get_peers() + assert len(get_peers) >= 1 + if hard_wait: + delay(hard_wait) + + @allure.step + def create_message(self, **kwargs): + ts_ns = time_ns() + ts_ns = int(f"{ts_ns:019d}") + message = {"payload": to_base64(self.test_payload), "contentTopic": self.test_content_topic, "timestamp": ts_ns} + message.update(kwargs) + return message + + @allure.step + def compute_message_hash(self, pubsub_topic, msg, hash_type="hex"): + ctx = hashlib.sha256() + ctx.update(pubsub_topic.encode("utf-8")) + ctx.update(base64.b64decode(msg["payload"])) + ctx.update(msg["contentTopic"].encode("utf-8")) + if "meta" in msg: + ctx.update(base64.b64decode(msg["meta"])) + ctx.update(int(msg["timestamp"]).to_bytes(8, byteorder="big")) + hash_bytes = ctx.digest() + if hash_type == "hex": + return "0x" + hash_bytes.hex() + else: + return base64.b64encode(hash_bytes).decode("utf-8") + + def get_time_list_pass(self): + ts_pass = [ + {"description": "3 sec Past", "value": int((datetime.now() - timedelta(seconds=3)).timestamp() * 1e9)}, + {"description": "1 sec Past", "value": int((datetime.now() - timedelta(seconds=1)).timestamp() * 1e9)}, + {"description": "0.1 sec Past", "value": int((datetime.now() - timedelta(seconds=0.1)).timestamp() * 1e9)}, + {"description": "0.1 sec Future", "value": int((datetime.now() + timedelta(seconds=0.1)).timestamp() * 1e9)}, + {"description": "2 sec Future", "value": int((datetime.now() + timedelta(seconds=2)).timestamp() * 1e9)}, + {"description": "10 sec Future", "value": int((datetime.now() + timedelta(seconds=10)).timestamp() * 1e9)}, + ] + return ts_pass + + def get_time_list_fail(self): + ts_fail = [ + {"description": "20 sec Past", "value": int((datetime.now() - timedelta(seconds=20)).timestamp() * 1e9)}, + {"description": "40 sec Future", "value": int((datetime.now() + timedelta(seconds=40)).timestamp() * 1e9)}, + ] + return ts_fail diff --git a/tests-e2e/src/steps/filter.py b/tests-e2e/src/steps/filter.py new file mode 100644 index 000000000..8a5d90c41 --- /dev/null +++ b/tests-e2e/src/steps/filter.py @@ -0,0 +1,197 @@ +import inspect +from uuid import uuid4 +from src.libs.custom_logger import get_custom_logger +from time import time +import pytest +import allure +from src.libs.common import to_base64, delay +from src.node.waku_message import WakuMessage +from src.env_vars import NODE_1, NODE_2, ADDITIONAL_NODES +from src.node.waku_node import WakuNode +from tenacity import retry, stop_after_delay, wait_fixed +from src.steps.common import StepsCommon +from src.test_data import VALID_PUBSUB_TOPICS + +logger = get_custom_logger(__name__) + + +class StepsFilter(StepsCommon): + test_pubsub_topic = VALID_PUBSUB_TOPICS[1] + second_pubsub_topic = VALID_PUBSUB_TOPICS[2] + another_cluster_pubsub_topic = "/waku/2/rs/2/2" + test_content_topic = "/test/1/waku-filter/proto" + second_content_topic = "/test/2/waku-filter/proto" + test_payload = "Filter works!!" + + @pytest.fixture(scope="function", autouse=True) + def filter_setup(self): + logger.debug(f"Running fixture setup: {inspect.currentframe().f_code.co_name}") + self.main_nodes = [] + self.optional_nodes = [] + + @pytest.fixture(scope="function") + def setup_main_relay_node(self): + logger.debug(f"Running fixture setup: {inspect.currentframe().f_code.co_name}") + self.relay_node_start(NODE_1) + + @pytest.fixture(scope="function") + def setup_main_filter_node(self): + logger.debug(f"Running fixture setup: {inspect.currentframe().f_code.co_name}") + self.node2 = WakuNode(NODE_2, f"node2_{self.test_id}") + self.node2.start(relay="false", discv5_bootstrap_node=self.enr_uri, filternode=self.multiaddr_with_id) + self.add_node_peer(self.node2, [self.multiaddr_with_id]) + self.main_nodes.append(self.node2) + + @pytest.fixture(scope="function") + def subscribe_main_nodes(self): + logger.debug(f"Running fixture setup: {inspect.currentframe().f_code.co_name}") + self.wait_for_subscriptions_on_main_nodes([self.test_content_topic]) + + @pytest.fixture(scope="function") + @retry(stop=stop_after_delay(20), wait=wait_fixed(1), reraise=True) + def filter_warm_up(self): + try: + self.ping_filter_subscriptions("1") + except Exception as ex: + if "peer has no subscriptions" in str(ex): + logger.info("WARM UP successful!!") + else: + raise TimeoutError(f"WARM UP FAILED WITH: {ex}") + + def relay_node_start(self, node): + self.node1 = WakuNode(node, f"node1_{self.test_id}") + start_args = {"relay": "true", "filter": "true"} + self.node1.start(**start_args) + self.enr_uri = self.node1.get_enr_uri() + self.multiaddr_with_id = self.node1.get_multiaddr_with_id() + return self.node1 + + def setup_optional_filter_nodes(self, node_list=ADDITIONAL_NODES): + if node_list: + nodes = [node.strip() for node in node_list.split(",") if node] + else: + pytest.skip("ADDITIONAL_NODES/node_list is empty, cannot run test") + for index, node in enumerate(nodes): + node = WakuNode(node, f"node{index + 3}_{self.test_id}") + node.start(relay="false", discv5_bootstrap_node=self.enr_uri, filternode=self.multiaddr_with_id) + self.add_node_peer(node, [self.multiaddr_with_id]) + self.optional_nodes.append(node) + + @allure.step + def check_published_message_reaches_filter_peer( + self, message=None, pubsub_topic=None, message_propagation_delay=0.1, sender=None, peer_list=None + ): + if message is None: + message = self.create_message() + if pubsub_topic is None: + pubsub_topic = self.test_pubsub_topic + if not sender: + sender = self.node1 + if not peer_list: + peer_list = self.main_nodes + self.optional_nodes + + sender.send_relay_message(message, pubsub_topic) + delay(message_propagation_delay) + for index, peer in enumerate(peer_list): + logger.debug(f"Checking that peer NODE_{index + 2}:{peer.image} can find the published message") + get_messages_response = self.get_filter_messages(message["contentTopic"], pubsub_topic=pubsub_topic, node=peer) + assert get_messages_response, f"Peer NODE_{index + 2}:{peer.image} couldn't find any messages" + assert len(get_messages_response) == 1, f"Expected 1 message but got {len(get_messages_response)}" + waku_message = WakuMessage(get_messages_response) + waku_message.assert_received_message(message) + + @allure.step + def check_publish_without_filter_subscription(self, message=None, pubsub_topic=None, peer_list=None): + try: + self.check_published_message_reaches_filter_peer(message=message, pubsub_topic=pubsub_topic, peer_list=peer_list) + raise AssertionError("Publish with no subscription worked!!!") + except Exception as ex: + assert "Bad Request" in str(ex) or "Not Found" in str(ex) or "couldn't find any messages" in str(ex) + + @allure.step + def wait_for_subscriptions_on_main_nodes(self, content_topic_list, pubsub_topic=None): + if pubsub_topic is None: + pubsub_topic = self.test_pubsub_topic + self.node1.set_relay_subscriptions([pubsub_topic]) + request_id = str(uuid4()) + filter_sub_response = self.create_filter_subscription_with_retry( + {"requestId": request_id, "contentFilters": content_topic_list, "pubsubTopic": pubsub_topic} + ) + assert filter_sub_response["requestId"] == request_id + assert filter_sub_response["statusDesc"] in ["OK"] + + @allure.step + def subscribe_optional_filter_nodes(self, content_topic_list, pubsub_topic=None): + if pubsub_topic is None: + pubsub_topic = self.test_pubsub_topic + for node in self.optional_nodes: + request_id = str(uuid4()) + self.create_filter_subscription_with_retry( + {"requestId": request_id, "contentFilters": content_topic_list, "pubsubTopic": pubsub_topic}, node=node + ) + + @retry(stop=stop_after_delay(60), wait=wait_fixed(1), reraise=True) + @allure.step + def create_filter_subscription_with_retry(self, subscription, node=None): + return self.create_filter_subscription(subscription, node) + + @allure.step + def create_filter_subscription(self, subscription, node=None): + if node is None: + node = self.node2 + return node.set_filter_subscriptions(subscription) + + @allure.step + def update_filter_subscription(self, subscription, node=None): + if node is None: + node = self.node2 + return node.update_filter_subscriptions(subscription) + + @allure.step + def delete_filter_subscription(self, subscription, status=None, node=None): + if node is None: + node = self.node2 + delete_sub_response = node.delete_filter_subscriptions(subscription) + assert delete_sub_response["requestId"] == subscription["requestId"] + if status is None: + assert delete_sub_response["statusDesc"] in ["OK"] + else: + assert status in delete_sub_response["statusDesc"] + + @allure.step + def delete_all_filter_subscriptions(self, request_id, node=None): + if node is None: + node = self.node2 + delete_sub_response = node.delete_all_filter_subscriptions(request_id) + assert delete_sub_response["requestId"] == request_id["requestId"] + assert delete_sub_response["statusDesc"] in ["OK"] + + @allure.step + def ping_filter_subscriptions(self, request_id, node=None): + if node is None: + node = self.node2 + ping_sub_response = node.ping_filter_subscriptions(request_id) + assert ping_sub_response["requestId"] == request_id + assert ping_sub_response["statusDesc"] in ["OK"] + + def ping_without_filter_subscription(self, node=None): + try: + self.ping_filter_subscriptions(str(uuid4()), node=node) + raise AssertionError("Ping without any subscription worked") + except Exception as ex: + assert "peer has no subscription" in str(ex) or "ping request failed" in str(ex) + + @allure.step + def add_new_relay_subscription(self, pubsub_topics, node=None): + if node is None: + node = self.node1 + self.node1.set_relay_subscriptions(pubsub_topics) + + @allure.step + def get_filter_messages(self, content_topic, pubsub_topic=None, node=None): + if node is None: + node = self.node2 + if node.is_nwaku(): + return node.get_filter_messages(content_topic) + else: + raise NotImplementedError("Not implemented for this node type") diff --git a/tests-e2e/src/steps/light_push.py b/tests-e2e/src/steps/light_push.py new file mode 100644 index 000000000..fd7da42d0 --- /dev/null +++ b/tests-e2e/src/steps/light_push.py @@ -0,0 +1,148 @@ +import inspect +from src.libs.custom_logger import get_custom_logger +from time import time +import pytest +import allure +from src.libs.common import to_base64, delay +from src.node.waku_message import WakuMessage +from src.env_vars import ( + ADDITIONAL_NODES, + NODE_1, + NODE_2, +) +from src.node.waku_node import WakuNode +from src.steps.common import StepsCommon +from src.test_data import VALID_PUBSUB_TOPICS +from tenacity import retry, stop_after_delay, wait_fixed + +logger = get_custom_logger(__name__) + + +class StepsLightPush(StepsCommon): + test_content_topic = "/myapp/1/latest/proto" + test_pubsub_topic = VALID_PUBSUB_TOPICS[0] + test_payload = "Light push works!!" + + @pytest.fixture(scope="function", autouse=True) + def light_push_setup(self): + logger.debug(f"Running fixture setup: {inspect.currentframe().f_code.co_name}") + self.main_receiving_nodes = [] + self.optional_nodes = [] + self.multiaddr_list = [] + + @allure.step + def start_receiving_node(self, image, node_index, **kwargs): + node = WakuNode(image, f"receiving_node{node_index}_{self.test_id}") + node.start(**kwargs) + if kwargs["relay"] == "true": + self.main_receiving_nodes.extend([node]) + self.add_node_peer(node, self.multiaddr_list) + self.multiaddr_list.extend([node.get_multiaddr_with_id()]) + return node + + @allure.step + def setup_lightpush_node(self, image, node_index, **kwargs): + node = WakuNode(image, f"lightpush_node{node_index}_{self.test_id}") + node.start(discv5_bootstrap_node=self.enr_uri, lightpushnode=self.multiaddr_list[0], **kwargs) + if kwargs["relay"] == "true": + self.main_receiving_nodes.extend([node]) + self.add_node_peer(node, self.multiaddr_list) + return node + + @allure.step + def setup_first_receiving_node(self, lightpush="true", relay="true", **kwargs): + self.receiving_node1 = self.start_receiving_node(NODE_1, node_index=1, lightpush=lightpush, relay=relay, **kwargs) + self.enr_uri = self.receiving_node1.get_enr_uri() + + @allure.step + def setup_second_receiving_node(self, lightpush, relay, **kwargs): + self.receiving_node2 = self.start_receiving_node(NODE_1, node_index=2, lightpush=lightpush, relay=relay, **kwargs) + + @allure.step + def setup_additional_receiving_nodes(self, node_list=ADDITIONAL_NODES, **kwargs): + if node_list: + nodes = [node.strip() for node in node_list.split(",") if node] + else: + pytest.skip("ADDITIONAL_NODES/node_list is empty, cannot run test") + for index, node in enumerate(nodes): + self.start_receiving_node(node, node_index=index + 2, lightpush="true", relay="true", pubsub_topic=self.test_pubsub_topic, **kwargs) + + @allure.step + def setup_first_lightpush_node(self, lightpush="true", relay="true", **kwargs): + self.light_push_node1 = self.setup_lightpush_node(NODE_2, node_index=1, lightpush=lightpush, relay=relay, **kwargs) + + @allure.step + def setup_second_lightpush_node(self, lightpush="true", relay="true", **kwargs): + self.light_push_node2 = self.setup_lightpush_node(NODE_2, node_index=2, lightpush=lightpush, relay=relay, **kwargs) + + @allure.step + def setup_additional_lightpush_nodes(self, node_list=ADDITIONAL_NODES, **kwargs): + if node_list: + nodes = [node.strip() for node in node_list.split(",") if node] + else: + pytest.skip("ADDITIONAL_NODES/node_list is empty, cannot run test") + self.additional_lightpush_nodes = [] + for index, node in enumerate(nodes): + node = self.setup_lightpush_node(node, node_index=index + 2, lightpush="true", relay="true", **kwargs) + self.additional_lightpush_nodes.append(node) + + @allure.step + def subscribe_to_pubsub_topics_via_relay(self, node=None, pubsub_topics=None): + if pubsub_topics is None: + pubsub_topics = [self.test_pubsub_topic] + if not node: + node = self.main_receiving_nodes + if isinstance(node, list): + for node in node: + node.set_relay_subscriptions(pubsub_topics) + else: + node.set_relay_subscriptions(pubsub_topics) + + @allure.step + def subscribe_to_pubsub_topics_via_filter(self, node, pubsub_topic=None, content_topic=None): + if pubsub_topic is None: + pubsub_topic = self.test_pubsub_topic + if content_topic is None: + content_topic = [self.test_content_topic] + subscription = {"requestId": "1", "contentFilters": content_topic, "pubsubTopic": pubsub_topic} + node.set_filter_subscriptions(subscription) + + @allure.step + def check_light_pushed_message_reaches_receiving_peer( + self, pubsub_topic=None, message=None, message_propagation_delay=0.1, sender=None, peer_list=None + ): + if pubsub_topic is None: + pubsub_topic = self.test_pubsub_topic + if not sender: + sender = self.light_push_node1 + if not peer_list: + peer_list = self.main_receiving_nodes + self.optional_nodes + payload = self.create_payload(pubsub_topic, message) + logger.debug("Lightpushing message") + sender.send_light_push_message(payload) + delay(message_propagation_delay) + for index, peer in enumerate(peer_list): + logger.debug(f"Checking that peer NODE_{index + 1}:{peer.image} can find the lightpushed message") + get_messages_response = peer.get_relay_messages(pubsub_topic) + assert get_messages_response, f"Peer NODE_{index + 1}:{peer.image} couldn't find any messages" + assert len(get_messages_response) == 1, f"Expected 1 message but got {len(get_messages_response)}" + waku_message = WakuMessage(get_messages_response) + waku_message.assert_received_message(payload["message"]) + + @allure.step + def create_payload(self, pubsub_topic=None, message=None, **kwargs): + if message is None: + message = self.create_message() + if pubsub_topic is None: + pubsub_topic = self.test_pubsub_topic + payload = {"pubsubTopic": pubsub_topic, "message": message} + payload.update(kwargs) + return payload + + @allure.step + @retry(stop=stop_after_delay(120), wait=wait_fixed(1), reraise=True) + def subscribe_and_light_push_with_retry(self): + self.subscribe_to_pubsub_topics_via_relay() + self.light_push_node1.send_light_push_message(self.create_payload()) + get_messages_response = self.main_receiving_nodes[0].get_relay_messages(self.test_pubsub_topic) + assert len(get_messages_response) >= 1, f"Expected al least 1 message but got {len(get_messages_response)}" diff --git a/tests-e2e/src/steps/metrics.py b/tests-e2e/src/steps/metrics.py new file mode 100644 index 000000000..f53686999 --- /dev/null +++ b/tests-e2e/src/steps/metrics.py @@ -0,0 +1,68 @@ +import re +from src.libs.custom_logger import get_custom_logger +import allure +from tenacity import retry, stop_after_delay, wait_fixed + +from src.test_data import METRICS_WITH_INITIAL_VALUE_ZERO + + +logger = get_custom_logger(__name__) + + +class StepsMetrics: + @allure.step + def check_metric(self, node, metric_name, expected_value, exact=False): + logger.debug(f"Checking metric: {metric_name} has {expected_value}") + response = node.get_metrics() + lines = response.split("\n") + actual_value = None + for line in lines: + if line.startswith(metric_name): + parts = line.split(" ") + if len(parts) >= 2: + actual_value = float(parts[1]) + break + if actual_value is None: + raise AttributeError(f"Metric '{metric_name}' not found") + logger.debug(f"Found metric: {metric_name} with value {actual_value}") + if exact: + assert actual_value == expected_value, f"Expected value for '{metric_name}' is {expected_value}, but got {actual_value}" + else: + assert actual_value >= expected_value, f"Expected value for '{metric_name}' is >= {expected_value}, but got {actual_value}" + + @allure.step + def wait_for_metric(self, node, metric_name, expected_value, timeout_duration=90): + @retry(stop=stop_after_delay(timeout_duration), wait=wait_fixed(1), reraise=True) + def check_metric_with_retry(): + self.check_metric(node, metric_name, expected_value) + + check_metric_with_retry() + + def validate_initial_metrics(self, node): + metrics_data = node.get_metrics() + + # Regular expression to match metric lines, accounting for optional labels + metric_pattern = re.compile(r"^(?P[a-zA-Z0-9_:]+(?:{[^}]+})?)\s+(?P[0-9]+\.?[0-9]*)$", re.MULTILINE) + + # Dictionary to store the metrics and their values + metrics_dict = {} + for match in metric_pattern.finditer(metrics_data): + metric_name = match.group("metric_name") + value = float(match.group("value")) + metrics_dict[metric_name] = value + + errors = [] + # Assert that specific metrics have a value of 0.0 + for metric in METRICS_WITH_INITIAL_VALUE_ZERO: + if metric not in metrics_dict: + errors.append(f"Metric {metric} is missing from the metrics data") + elif metrics_dict[metric] != 0.0: + errors.append(f"Expected {metric} to be 0.0, but got {metrics_dict[metric]}") + + # Assert that all other metrics have a value greater than 0.0 + for metric, value in metrics_dict.items(): + if metric not in METRICS_WITH_INITIAL_VALUE_ZERO and value <= 0.0: + errors.append(f"Expected {metric} to have a positive value, but got {value}") + + assert not errors, f"Metrics validation failed:\n" + "\n".join(errors) + logger.debug(f"All metrics are present and have valid values.") diff --git a/tests-e2e/src/steps/network_conditions.py b/tests-e2e/src/steps/network_conditions.py new file mode 100644 index 000000000..b96d9a0cc --- /dev/null +++ b/tests-e2e/src/steps/network_conditions.py @@ -0,0 +1,201 @@ +import subprocess +from src.env_vars import NETWORK_NAME +from src.libs.custom_logger import get_custom_logger + +logger = get_custom_logger(__name__) + + +class TrafficController: + def _pid(self, node) -> int: + if not node.container: + raise RuntimeError("Node container not started yet") + + node.container.reload() + pid = node.container.attrs.get("State", {}).get("Pid") + if not pid or pid == 0: + raise RuntimeError("Container PID not available (container not running?)") + return int(pid) + + def _exec(self, node, tc_args: list[str], iface: str = "eth0"): + pid = self._pid(node) + + cmd = ["sudo", "-n", "nsenter", "-t", str(pid), "-n", "tc"] + tc_args + logger.info(f"TC exec: {cmd}") + + res = subprocess.run(cmd, capture_output=True, text=True) + if res.returncode != 0: + raise RuntimeError(f"TC failed: {' '.join(cmd)}\n" f"stdout: {res.stdout}\n" f"stderr: {res.stderr}") + + return res.stdout + + def log_tc_stats(self, node, iface: str = "eth0"): + """ + Log tc statistics for an interface (best-effort). + Useful to confirm netem loss/delay counters (sent/dropped/etc.). + """ + try: + out = self._exec(node, ["-s", "qdisc", "show", "dev", iface], iface=iface) + out = (out or "").strip() + if out: + logger.debug(f"tc -s qdisc show dev {iface}:\n{out}") + else: + logger.debug(f"tc -s qdisc show dev {iface}: (no output)") + except Exception as e: + logger.debug(f"Failed to read tc stats for {iface}: {e}") + + def clear(self, node, iface: str = "eth0"): + try: + self._exec(node, ["qdisc", "del", "dev", iface, "root"], iface=iface) + except RuntimeError as e: + msg = str(e) + if "Cannot delete qdisc with handle of zero" in msg or "No such file or directory" in msg: + return + raise + + def add_latency(self, node, ms: int, iface: str = "eth0"): + self.clear(node, iface=iface) + self._exec(node, ["qdisc", "add", "dev", iface, "root", "netem", "delay", f"{ms}ms"], iface=iface) + + def add_packet_loss(self, node, percent: float, iface: str = "eth0"): + self.clear(node, iface=iface) + + self._exec( + node, + ["qdisc", "add", "dev", iface, "root", "netem", "loss", f"{percent}%"], + iface=iface, + ) + try: + stats = self._exec(node, ["-s", "qdisc", "show", "dev", iface], iface=iface) + if stats is not None: + if isinstance(stats, (bytes, bytearray)): + stats = stats.decode(errors="replace") + logger.debug(f"tc -s qdisc show dev {iface}:\n{stats}") + else: + logger.debug(f"Executed: tc -s qdisc show dev {iface} (no output returned by _exec)") + except Exception as e: + logger.debug(f"Failed to read tc stats for {iface}: {e}") + + def add_bandwidth(self, node, rate: str, iface: str = "eth0"): + self.clear(node, iface=iface) + self._exec( + node, + ["qdisc", "add", "dev", iface, "root", "tbf", "rate", rate, "burst", "32kbit", "limit", "12500"], + iface=iface, + ) + + def add_packet_loss_correlated( + self, + node, + percent: float, + correlation: float, + iface: str = "eth0", + ): + self.clear(node, iface=iface) + self._exec( + node, + [ + "qdisc", + "add", + "dev", + iface, + "root", + "netem", + "loss", + f"{percent}%", + f"{correlation}%", + ], + iface=iface, + ) + + def add_packet_reordering( + self, + node, + percent: int = 25, + correlation: int = 50, + delay_ms: int = 10, + iface: str = "eth0", + ): + self.clear(node, iface=iface) + + self._exec( + node, + [ + "qdisc", + "add", + "dev", + iface, + "root", + "netem", + "delay", + f"{delay_ms}ms", + "reorder", + f"{percent}%", + f"{correlation}%", + ], + iface=iface, + ) + + def _p2p_iface(self, node) -> str: + """ + Return the name of the container interface attached to the waku + network (where libp2p traffic flows). + + DockerManager attaches each node to two networks: the default bridge + (where host-published ports land, typically `eth0`) and the waku + network (where inter-container libp2p/gossipsub traffic flows, typically + `eth1`). tc on the default bridge only affects REST control plane; for + a packet loss test targeting libp2p we need the waku interface. + + This helper resolves the correct interface by looking up the node's + waku-network IP via Docker and matching it against `ip -o -4 addr` + output from inside the container. + """ + if not node.container: + raise RuntimeError("Node container not started yet") + node.container.reload() + networks = node.container.attrs.get("NetworkSettings", {}).get("Networks", {}) + waku_net = networks.get(NETWORK_NAME) + if not waku_net or not waku_net.get("IPAddress"): + raise RuntimeError(f"Container is not attached to the '{NETWORK_NAME}' docker network") + waku_ip = waku_net["IPAddress"] + + exit_code, output = node.container.exec_run(["ip", "-o", "-4", "addr"]) + if exit_code != 0: + raise RuntimeError(f"ip addr failed inside container: {output}") + for line in output.decode().splitlines(): + if f" {waku_ip}/" in line: + tokens = line.split() + if len(tokens) >= 2: + return tokens[1] + raise RuntimeError(f"No interface inside container holds waku IP {waku_ip}") + + def clear_p2p(self, node): + """ + Remove any tc rule previously installed on the node's waku (libp2p) + interface. Paired with add_packet_loss_p2p_only / + add_packet_loss_correlated_p2p_only. + """ + self.clear(node, iface=self._p2p_iface(node)) + + def add_packet_loss_p2p_only(self, node, percent: float): + """ + Apply uncorrelated packet loss to the waku (libp2p) network interface + of a node. REST API traffic rides a separate docker interface and is + not affected, so the test harness's control plane stays reliable. + """ + iface = self._p2p_iface(node) + self.clear(node, iface=iface) + self._exec(node, f"qdisc add dev {iface} root netem loss {percent}%".split(), iface=iface) + + def add_packet_loss_correlated_p2p_only(self, node, percent: float, correlation: float): + """ + Correlated packet loss on the waku (libp2p) network interface. See + add_packet_loss_p2p_only for why REST stays unaffected. + """ + iface = self._p2p_iface(node) + self.clear(node, iface=iface) + self._exec( + node, + f"qdisc add dev {iface} root netem loss {percent}% {correlation}%".split(), + iface=iface, + ) diff --git a/tests-e2e/src/steps/peer_exchange.py b/tests-e2e/src/steps/peer_exchange.py new file mode 100644 index 000000000..6504ba3ef --- /dev/null +++ b/tests-e2e/src/steps/peer_exchange.py @@ -0,0 +1,30 @@ +from uuid import uuid4 + +from src.env_vars import NODE_2 +from src.node.waku_node import WakuNode + +import allure + +from src.steps.relay import StepsRelay + + +class StepsPeerExchange(StepsRelay): + responder_multiaddr = "" + + @allure.step + def setup_third_node_as_peer_exchange_requester(self, **kwargs): + self.node3 = WakuNode(NODE_2, f"node3_{self.test_id}") + self.node3.start( + relay="false", + peer_exchange_node=self.responder_multiaddr, + **kwargs, + ) + self.add_node_peer(self.node3, [self.multiaddr_with_id]) + self.main_nodes.extend([self.node3]) + + @allure.step + def setup_fourth_node_as_filter(self, **kwargs): + self.node4 = WakuNode(NODE_2, f"node4_{self.test_id}") + self.node4.start(relay="false", **kwargs) + self.add_node_peer(self.node4, [self.multiaddr_with_id]) + self.main_nodes.extend([self.node4]) diff --git a/tests-e2e/src/steps/relay.py b/tests-e2e/src/steps/relay.py new file mode 100644 index 000000000..840461bbe --- /dev/null +++ b/tests-e2e/src/steps/relay.py @@ -0,0 +1,187 @@ +import inspect +from src.libs.custom_logger import get_custom_logger +from time import time +import pytest +import allure +from src.libs.common import to_base64, delay +from src.node.waku_message import WakuMessage +from src.env_vars import ( + NODE_1, + NODE_2, + ADDITIONAL_NODES, +) +from src.node.waku_node import WakuNode +from tenacity import retry, stop_after_delay, wait_fixed +from src.steps.common import StepsCommon +from src.test_data import VALID_PUBSUB_TOPICS + +logger = get_custom_logger(__name__) + + +class StepsRelay(StepsCommon): + test_pubsub_topic = VALID_PUBSUB_TOPICS[1] + test_content_topic = "/test/1/waku-relay/proto" + test_payload = "Relay works!!" + + @pytest.fixture(scope="function", autouse=True) + def relay_setup(self): + logger.debug(f"Running fixture setup: {inspect.currentframe().f_code.co_name}") + self.main_nodes = [] + self.optional_nodes = [] + + @pytest.fixture(scope="function") + def setup_main_relay_nodes(self, request): + logger.debug(f"Running fixture setup: {inspect.currentframe().f_code.co_name}") + self.node1 = WakuNode(NODE_1, f"node1_{request.cls.test_id}") + self.node1.start(relay="true") + self.enr_uri = self.node1.get_enr_uri() + self.multiaddr_with_id = self.node1.get_multiaddr_with_id() + self.node2 = WakuNode(NODE_2, f"node2_{request.cls.test_id}") + self.node2.start(relay="true", discv5_bootstrap_node=self.enr_uri) + self.add_node_peer(self.node2, [self.multiaddr_with_id]) + self.main_nodes.extend([self.node1, self.node2]) + + @pytest.fixture(scope="function") + def setup_optional_relay_nodes(self, request): + logger.debug(f"Running fixture setup: {inspect.currentframe().f_code.co_name}") + if ADDITIONAL_NODES: + nodes = [node.strip() for node in ADDITIONAL_NODES.split(",")] + else: + pytest.skip("ADDITIONAL_NODES is empty, cannot run test") + for index, node in enumerate(nodes): + node = WakuNode(node, f"node{index + 3}_{request.cls.test_id}") + node.start(relay="true", discv5_bootstrap_node=self.enr_uri) + self.add_node_peer(node, [self.multiaddr_with_id]) + self.optional_nodes.append(node) + + @pytest.fixture(scope="function") + def subscribe_main_relay_nodes(self): + logger.debug(f"Running fixture setup: {inspect.currentframe().f_code.co_name}") + self.ensure_relay_subscriptions_on_nodes(self.main_nodes, [self.test_pubsub_topic]) + + @pytest.fixture(scope="function") + def subscribe_optional_relay_nodes(self): + logger.debug(f"Running fixture setup: {inspect.currentframe().f_code.co_name}") + self.ensure_relay_subscriptions_on_nodes(self.optional_nodes, [self.test_pubsub_topic]) + + @pytest.fixture(scope="function") + def relay_warm_up(self): + try: + self.wait_for_published_message_to_reach_relay_peer() + logger.info("WARM UP successful!!") + except Exception as ex: + raise TimeoutError(f"WARM UP FAILED WITH: {ex}") + + # Refactor candidate + @allure.step + def setup_first_relay_node(self, **kwargs): + self.node1 = WakuNode(NODE_1, f"node1_{self.test_id}") + self.node1.start(relay="true", **kwargs) + self.enr_uri = self.node1.get_enr_uri() + self.multiaddr_with_id = self.node1.get_multiaddr_with_id() + self.main_nodes.extend([self.node1]) + + # Refactor candidate + @allure.step + def setup_second_relay_node(self, **kwargs): + self.node2 = WakuNode(NODE_2, f"node2_{self.test_id}") + self.node2.start( + relay="true", + discv5_bootstrap_node=self.enr_uri, + **kwargs, + ) + self.add_node_peer(self.node2, [self.multiaddr_with_id]) + self.main_nodes.extend([self.node2]) + + @allure.step + def setup_third_relay_node(self, **kwargs): + self.node3 = WakuNode(NODE_1, f"node3_{self.test_id}") + self.node3.start( + relay="true", + discv5_bootstrap_node=self.enr_uri, + **kwargs, + ) + self.add_node_peer(self.node3, [self.multiaddr_with_id]) + self.optional_nodes.extend([self.node3]) + + # this method should be used only for the tests that use the relay_warm_up fixture + # otherwise use wait_for_published_message_to_reach_relay_peer + @allure.step + def check_published_message_reaches_relay_peer(self, message=None, pubsub_topic=None, message_propagation_delay=0.1, sender=None, peer_list=None): + if message is None: + message = self.create_message() + if pubsub_topic is None: + pubsub_topic = self.test_pubsub_topic + if not sender: + sender = self.node1 + if not peer_list: + peer_list = self.main_nodes + self.optional_nodes + + sender.send_relay_message(message, pubsub_topic) + delay(message_propagation_delay) + for index, peer in enumerate(peer_list): + logger.debug(f"Checking that peer NODE_{index + 1}:{peer.image} can find the published message") + get_messages_response = peer.get_relay_messages(pubsub_topic) + assert get_messages_response, f"Peer NODE_{index + 1}:{peer.image} couldn't find any messages" + assert len(get_messages_response) == 1, f"Expected 1 message but got {len(get_messages_response)}" + waku_message = WakuMessage(get_messages_response) + waku_message.assert_received_message(message) + + @allure.step + def check_publish_without_relay_subscription(self, pubsub_topic): + try: + self.node1.send_relay_message(self.create_message(), pubsub_topic) + raise AssertionError("Publish with no subscription worked!!!") + except Exception as ex: + assert "Bad Request" in str(ex) or "Internal Server Error" in str(ex) + + # we need much bigger timeout in CI because we run tests in parallel there and the machine itself is slower + @allure.step + def wait_for_published_message_to_reach_relay_peer( + self, timeout_duration=120, time_between_retries=1, pubsub_topic=None, sender=None, peer_list=None + ): + @retry(stop=stop_after_delay(timeout_duration), wait=wait_fixed(time_between_retries), reraise=True) + def publish_and_check_relay_peer(): + message = {"payload": to_base64(self.test_payload), "contentTopic": self.test_content_topic, "timestamp": int(time() * 1e9)} + self.check_published_message_reaches_relay_peer(message, pubsub_topic=pubsub_topic, sender=sender, peer_list=peer_list) + + publish_and_check_relay_peer() + + @allure.step + def ensure_relay_subscriptions_on_nodes(self, node_list, pubsub_topic_list): + for node in node_list: + node.set_relay_subscriptions(pubsub_topic_list) + + @allure.step + def delete_relay_subscriptions_on_nodes(self, node_list, pubsub_topic_list): + for node in node_list: + node.delete_relay_subscriptions(pubsub_topic_list) + + @allure.step + @retry(stop=stop_after_delay(120), wait=wait_fixed(1), reraise=True) + def subscribe_and_publish_with_retry(self, node_list, pubsub_topic_list): + self.ensure_relay_subscriptions_on_nodes(node_list, pubsub_topic_list) + self.check_published_message_reaches_relay_peer() + + @allure.step + def setup_main_nodes(self, **kwargs): + self.node1 = WakuNode(NODE_1, f"node1_{self.test_id}") + self.node1.start(relay="true", **kwargs) + self.enr_uri = self.node1.get_enr_uri() + self.multiaddr_with_id = self.node1.get_multiaddr_with_id() + self.node2 = WakuNode(NODE_2, f"node2_{self.test_id}") + self.node2.start(relay="true", discv5_bootstrap_node=self.enr_uri, **kwargs) + self.add_node_peer(self.node2, [self.multiaddr_with_id]) + self.main_nodes.extend([self.node1, self.node2]) + + @allure.step + def setup_optional_nodes(self, **kwargs): + if ADDITIONAL_NODES: + nodes = [node.strip() for node in ADDITIONAL_NODES.split(",")] + else: + pytest.skip("ADDITIONAL_NODES is empty, cannot run test") + for index, node in enumerate(nodes): + node = WakuNode(node, f"node{index + 3}_{self.test_id}") + node.start(relay="true", discv5_bootstrap_node=self.enr_uri, **kwargs) + self.add_node_peer(node, [self.multiaddr_with_id]) + self.optional_nodes.append(node) diff --git a/tests-e2e/src/steps/rln.py b/tests-e2e/src/steps/rln.py new file mode 100644 index 000000000..1bf051df2 --- /dev/null +++ b/tests-e2e/src/steps/rln.py @@ -0,0 +1,203 @@ +import os +import inspect +import random +import string + +import pytest +import allure + +from src.steps.common import StepsCommon +from src.test_data import PUBSUB_TOPICS_RLN +from src.env_vars import DEFAULT_NWAKU, RLN_CREDENTIALS, NODE_1, NODE_2, ADDITIONAL_NODES +from src.libs.common import gen_step_id, delay +from src.libs.custom_logger import get_custom_logger +from src.node.waku_node import WakuNode, rln_credential_store_ready + +logger = get_custom_logger(__name__) + + +class StepsRLN(StepsCommon): + test_pubsub_topic = PUBSUB_TOPICS_RLN[0] + test_content_topic = "/test/1/waku-rln-relay/proto" + test_payload = "RLN relay works!!" + + main_nodes = [] + optional_nodes = [] + multiaddr_list = [] + lightpush_nodes = [] + keystore_prefixes = [] + rln_membership_indexes = [] + + @allure.step + def generate_keystore_prefixes(self, count=2): + new_prefixes = [] + for _ in range(count): + new_prefixes.append("".join(random.choices(string.ascii_lowercase, k=4))) + + return new_prefixes + + @allure.step + def register_rln_relay_nodes(self, count, orig_prefixes): + if count > 0: + self.keystore_prefixes = self.generate_keystore_prefixes(count) + self.rln_membership_indexes = [] + for i, prefix in enumerate(self.keystore_prefixes): + membership_index = self.register_rln_single_node(prefix=prefix, rln_creds_source=RLN_CREDENTIALS, rln_creds_id=f"{i+1}") + self.rln_membership_indexes.append(membership_index) + else: + self.keystore_prefixes = orig_prefixes.get("keystore_prefixes", []) + self.rln_membership_indexes = orig_prefixes.get("rln_membership_indexes", []) + + return { + "keystore_prefixes": self.keystore_prefixes, + "rln_membership_indexes": self.rln_membership_indexes, + } + + @allure.step + def setup_main_rln_relay_nodes(self, **kwargs): + self.setup_first_rln_relay_node(**kwargs) + self.setup_second_rln_relay_node(**kwargs) + + @allure.step + def setup_first_rln_relay_node(self, **kwargs): + self.node1 = WakuNode(NODE_1, f"node1_{self.test_id}") + self.node1.start( + relay="true", + rln_creds_source=RLN_CREDENTIALS, + rln_creds_id="1", + rln_relay_membership_index=self.resolve_rln_membership_index(0, **kwargs), + rln_keystore_prefix=self.keystore_prefixes[0], + **kwargs, + ) + self.enr_uri = self.node1.get_enr_uri() + self.multiaddr_with_id = self.node1.get_multiaddr_with_id() + self.main_nodes.extend([self.node1]) + + self.multiaddr_list.extend([self.node1.get_multiaddr_with_id()]) + + @allure.step + def setup_second_rln_relay_node(self, **kwargs): + self.node2 = WakuNode(NODE_2, f"node2_{self.test_id}") + self.node2.start( + relay="true", + discv5_bootstrap_node=self.enr_uri, + rln_creds_source=RLN_CREDENTIALS, + rln_creds_id="2", + rln_relay_membership_index=self.resolve_rln_membership_index(1, **kwargs), + rln_keystore_prefix=self.keystore_prefixes[1], + **kwargs, + ) + self.add_node_peer(self.node2, [self.multiaddr_with_id]) + self.main_nodes.extend([self.node2]) + + @allure.step + def setup_optional_rln_relay_nodes(self, **kwargs): + if ADDITIONAL_NODES: + nodes = [node.strip() for node in ADDITIONAL_NODES.split(",")] + else: + pytest.skip("ADDITIONAL_NODES is empty, cannot run test") + if len(nodes) > 3: + logger.debug("More than 3 nodes are not supported for RLN tests, using first 3") + nodes = nodes[:3] + for index, node in enumerate(nodes): + node = WakuNode(node, f"node{index + 3}_{self.test_id}") + node.start( + relay="true", + discv5_bootstrap_node=self.enr_uri, + rln_creds_source=RLN_CREDENTIALS, + rln_creds_id=f"{index + 3}", + rln_relay_membership_index=self.resolve_rln_membership_index(index + 2, **kwargs), + rln_keystore_prefix=self.keystore_prefixes[index + 2], + **kwargs, + ) + self.add_node_peer(node, [self.multiaddr_with_id]) + self.optional_nodes.append(node) + + @allure.step + def setup_second_rln_lightpush_node(self, relay="true", **kwargs): + self.light_push_node2 = WakuNode(NODE_2, f"lightpush_node2_{self.test_id}") + self.light_push_node2.start( + relay=relay, + discv5_bootstrap_node=self.enr_uri, + lightpush="true", + lightpushnode=self.multiaddr_list[0], + rln_creds_source=RLN_CREDENTIALS, + rln_creds_id="2", + rln_relay_membership_index=self.resolve_rln_membership_index(1, **kwargs), + rln_keystore_prefix=self.keystore_prefixes[1], + **kwargs, + ) + if relay == "true": + self.main_nodes.extend([self.light_push_node2]) + self.lightpush_nodes.extend([self.light_push_node2]) + self.add_node_peer(self.light_push_node2, self.multiaddr_list) + + @allure.step + def register_rln_single_node(self, prefix="", **kwargs): + logger.debug("Registering RLN credentials for single node") + self.node = WakuNode(DEFAULT_NWAKU, f"node_{gen_step_id()}") + return self.node.register_rln(rln_keystore_prefix=prefix, rln_creds_source=kwargs["rln_creds_source"], rln_creds_id=kwargs["rln_creds_id"]) + + @allure.step + def resolve_rln_membership_index(self, index, **kwargs): + explicit_index = kwargs.get("rln_relay_membership_index") + if explicit_index is not None: + return str(explicit_index) + + if len(self.rln_membership_indexes) > index and self.rln_membership_indexes[index] is not None: + inferred_index = str(self.rln_membership_indexes[index]) + logger.debug(f"Using inferred RLN membership index for position {index}: {inferred_index}") + return inferred_index + + raise ValueError( + f"RLN membership index for position {index} is not available. " + "Register credentials and persist rln_membership_indexes together with keystore_prefixes before node startup." + ) + + @allure.step + def check_rln_registration(self, prefix, key_id): + cwd = os.getcwd() + creds_file_path = f"{cwd}/keystore_{prefix}_{key_id}/keystore.json" + try: + rln_credential_store_ready(creds_file_path) + except Exception as ex: + logger.error(f"Credentials at {creds_file_path} not available: {ex}") + raise + + @allure.step + def publish_message(self, message=None, pubsub_topic=None, sender=None, use_lightpush=False): + if message is None: + message = self.create_message() + if pubsub_topic is None: + pubsub_topic = self.test_pubsub_topic + if not sender: + sender = self.node1 + + if use_lightpush: + payload = self.create_payload(pubsub_topic, message) + sender.send_light_push_message(payload) + else: + sender.send_relay_message(message, pubsub_topic) + + @allure.step + def ensure_relay_subscriptions_on_nodes(self, node_list, pubsub_topic_list): + for node in node_list: + node.set_relay_subscriptions(pubsub_topic_list) + + @allure.step + def subscribe_main_relay_nodes(self): + self.ensure_relay_subscriptions_on_nodes(self.main_nodes, [self.test_pubsub_topic]) + + @allure.step + def subscribe_optional_relay_nodes(self): + self.ensure_relay_subscriptions_on_nodes(self.optional_nodes, [self.test_pubsub_topic]) + + @allure.step + def create_payload(self, pubsub_topic=None, message=None, **kwargs): + if message is None: + message = self.create_message() + if pubsub_topic is None: + pubsub_topic = self.test_pubsub_topic + payload = {"pubsubTopic": pubsub_topic, "message": message} + payload.update(kwargs) + return payload diff --git a/tests-e2e/src/steps/sharding.py b/tests-e2e/src/steps/sharding.py new file mode 100644 index 000000000..7c8aabc25 --- /dev/null +++ b/tests-e2e/src/steps/sharding.py @@ -0,0 +1,212 @@ +import inspect +from uuid import uuid4 +from src.libs.custom_logger import get_custom_logger +from time import time +import pytest +import allure +from src.libs.common import to_base64, delay +from src.node.waku_message import WakuMessage +from src.env_vars import ( + DEFAULT_NWAKU, + NODE_2, + ADDITIONAL_NODES, +) +from src.node.waku_node import WakuNode +from src.steps.common import StepsCommon +from src.steps.relay import StepsRelay + +logger = get_custom_logger(__name__) + + +class StepsSharding(StepsRelay): + test_content_topic = "/myapp/1/latest/proto" + test_pubsub_topic = "/waku/2/rs/199/0" + test_payload = "Sharding works!!" + auto_cluster = 199 + num_shards_in_network = 8 + + @pytest.fixture(scope="function", autouse=True) + def sharding_setup(self): + logger.debug(f"Running fixture setup: {inspect.currentframe().f_code.co_name}") + self.main_nodes = [] + self.optional_nodes = [] + self.main_filter_nodes = [] + self.optional_filter_nodes = [] + + @allure.step + def setup_first_relay_node_with_filter(self, **kwargs): + self.setup_first_relay_node(filter="true", **kwargs) + + @allure.step + def setup_second_node_as_filter(self, **kwargs): + self.node2 = WakuNode(NODE_2, f"node2_{self.test_id}") + self.node2.start(relay="false", discv5_bootstrap_node=self.enr_uri, filternode=self.multiaddr_with_id, **kwargs) + self.add_node_peer(self.node2, [self.multiaddr_with_id]) + self.main_filter_nodes.extend([self.node2]) + + @allure.step + def setup_main_relay_nodes(self, **kwargs): + self.setup_first_relay_node_with_filter(**kwargs) + self.setup_second_relay_node(**kwargs) + + @allure.step + def setup_optional_relay_nodes(self, **kwargs): + if ADDITIONAL_NODES: + nodes = [node.strip() for node in ADDITIONAL_NODES.split(",")] + else: + pytest.skip("ADDITIONAL_NODES is empty, cannot run test") + for index, node in enumerate(nodes): + node = WakuNode(node, f"node{index + 3}_{self.test_id}") + node.start(relay="true", discv5_bootstrap_node=self.enr_uri, **kwargs) + self.add_node_peer(node, [self.multiaddr_with_id]) + self.optional_nodes.append(node) + + @allure.step + def setup_nwaku_relay_nodes(self, num_nodes, **kwargs): + for index in range(num_nodes): + node = WakuNode(DEFAULT_NWAKU, f"node{index + 3}_{self.test_id}") + node.start(relay="true", discv5_bootstrap_node=self.enr_uri, **kwargs) + self.add_node_peer(node, [self.multiaddr_with_id]) + self.optional_nodes.append(node) + + @allure.step + def subscribe_relay_node(self, node, content_topics, pubsub_topics): + if content_topics: + node.set_relay_auto_subscriptions(content_topics) + elif pubsub_topics: + node.set_relay_subscriptions(pubsub_topics) + else: + raise AttributeError("content_topics or pubsub_topics need to be passed") + + @allure.step + def subscribe_first_relay_node(self, content_topics=None, pubsub_topics=None): + self.subscribe_relay_node(self.node1, content_topics, pubsub_topics) + + @allure.step + def subscribe_second_relay_node(self, content_topics=None, pubsub_topics=None): + self.subscribe_relay_node(self.node2, content_topics, pubsub_topics) + + @allure.step + def subscribe_main_relay_nodes(self, content_topics=None, pubsub_topics=None): + for node in self.main_nodes: + self.subscribe_relay_node(node, content_topics, pubsub_topics) + + @allure.step + def subscribe_optional_relay_nodes(self, content_topics=None, pubsub_topics=None): + for node in self.optional_nodes: + self.subscribe_relay_node(node, content_topics, pubsub_topics) + + @allure.step + def unsubscribe_relay_node(self, node, content_topics, pubsub_topics): + if content_topics: + node.delete_relay_auto_subscriptions(content_topics) + elif pubsub_topics: + node.delete_relay_subscriptions(pubsub_topics) + else: + raise AttributeError("content_topics or pubsub_topics need to be passed") + + @allure.step + def unsubscribe_first_relay_node(self, content_topics=None, pubsub_topics=None): + self.unsubscribe_relay_node(self.node1, content_topics, pubsub_topics) + + @allure.step + def unsubscribe_second_relay_node(self, content_topics=None, pubsub_topics=None): + self.unsubscribe_relay_node(self.node2, content_topics, pubsub_topics) + + @allure.step + def unsubscribe_main_relay_nodes(self, content_topics=None, pubsub_topics=None): + for node in self.main_nodes: + self.unsubscribe_relay_node(node, content_topics, pubsub_topics) + + @allure.step + def unsubscribe_optional_relay_nodes(self, content_topics=None, pubsub_topics=None): + for node in self.optional_nodes: + self.unsubscribe_relay_node(node, content_topics, pubsub_topics) + + @allure.step + def subscribe_filter_node(self, node, content_topics=None, pubsub_topic=None): + subscription = {"requestId": str(uuid4()), "contentFilters": content_topics, "pubsubTopic": pubsub_topic} + node.set_filter_subscriptions(subscription) + + @allure.step + def relay_message(self, node, message, pubsub_topic=None): + if pubsub_topic: + node.send_relay_message(message, pubsub_topic) + else: + node.send_relay_auto_message(message) + + @allure.step + def retrieve_relay_message(self, node, content_topic=None, pubsub_topic=None): + if content_topic: + return node.get_relay_auto_messages(content_topic) + elif pubsub_topic: + return node.get_relay_messages(pubsub_topic) + else: + raise AttributeError("content_topic or pubsub_topic needs to be passed") + + @allure.step + def check_published_message_reaches_relay_peer(self, content_topic=None, pubsub_topic=None, sender=None, peer_list=None): + message = self.create_message(contentTopic=content_topic) if content_topic else self.create_message() + if not sender: + sender = self.node1 + if not peer_list: + peer_list = self.main_nodes + self.optional_nodes + + self.relay_message(sender, message, pubsub_topic) + delay(0.1) + for index, peer in enumerate(peer_list): + logger.debug(f"Checking that peer NODE_{index + 1}:{peer.image} can find the published message") + get_messages_response = self.retrieve_relay_message(peer, content_topic, pubsub_topic) + assert get_messages_response, f"Peer NODE_{index + 1}:{peer.image} couldn't find any messages" + assert len(get_messages_response) == 1, f"Expected 1 message but got {len(get_messages_response)}" + waku_message = WakuMessage(get_messages_response) + waku_message.assert_received_message(message) + + @allure.step + def get_filter_messages(self, content_topic, pubsub_topic=None, node=None): + if node is None: + node = self.node2 + if node.is_nwaku(): + return node.get_filter_messages(content_topic) + else: + raise NotImplementedError("Not implemented for this node type") + + @allure.step + def check_published_message_reaches_filter_peer(self, content_topic=None, pubsub_topic=None, sender=None, peer_list=None): + message = self.create_message(contentTopic=content_topic) if content_topic else self.create_message() + if not sender: + sender = self.node1 + if not peer_list: + peer_list = self.main_filter_nodes + self.optional_filter_nodes + + self.relay_message(sender, message, pubsub_topic) + delay(0.1) + for index, peer in enumerate(peer_list): + logger.debug(f"Checking that peer NODE_{index + 2}:{peer.image} can find the published message") + get_messages_response = self.get_filter_messages(message["contentTopic"], pubsub_topic=pubsub_topic, node=peer) + assert get_messages_response, f"Peer NODE_{index + 2}:{peer.image} couldn't find any messages" + assert len(get_messages_response) == 1, f"Expected 1 message but got {len(get_messages_response)}" + waku_message = WakuMessage(get_messages_response) + waku_message.assert_received_message(message) + + @allure.step + def check_published_message_doesnt_reach_relay_peer(self, pubsub_topic=None, content_topic=None): + try: + self.check_published_message_reaches_relay_peer(pubsub_topic=pubsub_topic, content_topic=content_topic) + raise AssertionError("Retrieving messages on not subscribed content topic worked!!!") + except Exception as ex: + error_message = str(ex) + expected_errors = [ + "Not Found", + "NoPeersToPublish", + "Failed to publish: publish failed in relay: NoPeersToPublish", + ] + assert any(expected in error_message for expected in expected_errors), error_message + + @allure.step + def check_publish_fails_on_not_subscribed_pubsub_topic(self, pubsub_topic): + try: + self.check_published_message_reaches_relay_peer(pubsub_topic=pubsub_topic) + raise AssertionError("Publishing messages on unsubscribed shard worked!!!") + except Exception as ex: + assert "Failed to publish: Node not subscribed to topic" in str(ex), "Expected Bad Request because the node is not subscribed" diff --git a/tests-e2e/src/steps/store.py b/tests-e2e/src/steps/store.py new file mode 100644 index 000000000..311932ae5 --- /dev/null +++ b/tests-e2e/src/steps/store.py @@ -0,0 +1,382 @@ +import inspect + +import requests + +from src.libs.custom_logger import get_custom_logger +import pytest +import allure +from src.libs.common import delay +from src.node.store_response import StoreResponse +from src.node.waku_message import WakuMessage +from src.env_vars import ( + ADDITIONAL_NODES, + NODE_1, + NODE_2, +) +from src.node.waku_node import WakuNode +from src.steps.common import StepsCommon +from src.test_data import VALID_PUBSUB_TOPICS +from tenacity import retry, stop_after_delay, wait_fixed + +logger = get_custom_logger(__name__) + + +class StepsStore(StepsCommon): + test_content_topic = "/myapp/1/latest/proto" + test_pubsub_topic = VALID_PUBSUB_TOPICS[0] + test_payload = "Store works!!" + + @pytest.fixture(scope="function", autouse=True) + def store_setup(self): + logger.debug(f"Running fixture setup: {inspect.currentframe().f_code.co_name}") + self.main_publishing_nodes = [] + self.store_nodes = [] + self.optional_nodes = [] + self.multiaddr_list = [] + + @pytest.fixture(scope="function", autouse=False) + def node_setup(self, store_setup): + logger.debug(f"Running fixture setup: {inspect.currentframe().f_code.co_name}") + self.setup_first_publishing_node(store="true", relay="true") + self.setup_first_store_node(store="true", relay="true") + self.subscribe_to_pubsub_topics_via_relay(node=self.main_publishing_nodes) + + @allure.step + def start_publishing_node(self, image, node_index, **kwargs): + node = WakuNode(image, f"publishing_node{node_index}_{self.test_id}") + node.start(**kwargs) + if kwargs["relay"] == "true": + self.main_publishing_nodes.extend([node]) + if kwargs["store"] == "true": + self.store_nodes.extend([node]) + self.add_node_peer(node, self.multiaddr_list) + self.multiaddr_list.extend([node.get_multiaddr_with_id()]) + return node + + @allure.step + def setup_store_node(self, image, node_index, **kwargs): + node = WakuNode(image, f"store_node{node_index}_{self.test_id}") + node.start(discv5_bootstrap_node=self.enr_uri, storenode=self.multiaddr_list[0], **kwargs) + if kwargs["relay"] == "true": + self.main_publishing_nodes.extend([node]) + self.store_nodes.extend([node]) + self.add_node_peer(node, self.multiaddr_list) + return node + + @allure.step + def setup_first_publishing_node(self, store="true", relay="true", **kwargs): + self.publishing_node1 = self.start_publishing_node(NODE_1, node_index=1, store=store, relay=relay, **kwargs) + self.enr_uri = self.publishing_node1.get_enr_uri() + + @allure.step + def setup_second_publishing_node(self, store, relay, **kwargs): + self.publishing_node2 = self.start_publishing_node(NODE_1, node_index=2, store=store, relay=relay, **kwargs) + + @allure.step + def setup_additional_publishing_nodes(self, node_list=ADDITIONAL_NODES, **kwargs): + if node_list: + nodes = [node.strip() for node in node_list.split(",") if node] + else: + pytest.skip("ADDITIONAL_NODES/node_list is empty, cannot run test") + for index, node in enumerate(nodes): + self.start_publishing_node(node, node_index=index + 2, store="true", relay="true", **kwargs) + + @allure.step + def setup_first_store_node(self, store="true", relay="true", **kwargs): + self.store_node1 = self.setup_store_node(NODE_2, node_index=1, store=store, relay=relay, **kwargs) + + @allure.step + def setup_second_store_node(self, store="true", relay="false", **kwargs): + self.store_node2 = self.setup_store_node(NODE_2, node_index=2, store=store, relay=relay, **kwargs) + + @allure.step + def setup_additional_store_nodes(self, node_list=ADDITIONAL_NODES, **kwargs): + if node_list: + nodes = [node.strip() for node in node_list.split(",") if node] + else: + pytest.skip("ADDITIONAL_NODES/node_list is empty, cannot run test") + self.additional_store_nodes = [] + for index, node in enumerate(nodes): + node = self.setup_store_node(node, node_index=index + 2, store="true", relay="false", **kwargs) + self.additional_store_nodes.append(node) + + @allure.step + def subscribe_to_pubsub_topics_via_relay(self, node=None, pubsub_topics=None): + if pubsub_topics is None: + pubsub_topics = [self.test_pubsub_topic] + if not node: + node = self.main_publishing_nodes + if isinstance(node, list): + for node in node: + node.set_relay_subscriptions(pubsub_topics) + else: + node.set_relay_subscriptions(pubsub_topics) + + @allure.step + def subscribe_to_pubsub_topics_via_filter(self, node, pubsub_topic=None, content_topic=None): + if pubsub_topic is None: + pubsub_topic = self.test_pubsub_topic + if content_topic is None: + content_topic = [self.test_content_topic] + subscription = {"requestId": "1", "contentFilters": content_topic, "pubsubTopic": pubsub_topic} + node.set_filter_subscriptions(subscription) + + @allure.step + def publish_message(self, via="relay", pubsub_topic=None, message=None, message_propagation_delay=0.2, sender=None): + self.message = self.create_message() if message is None else message + if pubsub_topic is None: + pubsub_topic = self.test_pubsub_topic + if not sender: + sender = self.publishing_node1 + if via == "relay": + logger.debug("Relaying message") + sender.send_relay_message(self.message, pubsub_topic) + elif via == "lightpush": + payload = self.create_payload(pubsub_topic, self.message) + sender.send_light_push_message(payload) + delay(message_propagation_delay) + return self.message + + @retry(stop=stop_after_delay(30), wait=wait_fixed(1), reraise=True) + @allure.step + def get_messages_from_store_with_retry(self, node): + return self.get_messages_from_store(node, page_size=5) + + @allure.step + def get_messages_from_store( + self, + node=None, + peer_addr=None, + include_data=None, + pubsub_topic=None, + content_topics=None, + start_time=None, + end_time=None, + hashes=None, + cursor=None, + page_size=None, + ascending="true", + store_v="v3", + **kwargs, + ): + if pubsub_topic is None: + pubsub_topic = self.test_pubsub_topic + store_response = node.get_store_messages( + peer_addr=peer_addr, + include_data=include_data, + pubsub_topic=pubsub_topic, + content_topics=content_topics, + start_time=start_time, + end_time=end_time, + hashes=hashes, + cursor=cursor, + page_size=page_size, + ascending=ascending, + store_v=store_v, + **kwargs, + ) + store_response = StoreResponse(store_response, node) + assert store_response.request_id is not None, "Request id is missing" + assert store_response.status_code, "Status code is missing" + assert store_response.status_desc, "Status desc is missing" + return store_response + + @allure.step + def check_published_message_is_stored( + self, + store_node=None, + peer_addr=None, + include_data=None, + pubsub_topic=None, + content_topics=None, + start_time=None, + end_time=None, + hashes=None, + cursor=None, + page_size=None, + ascending=None, + store_v="v3", + messages_to_check=None, + **kwargs, + ): + if pubsub_topic is None: + pubsub_topic = self.test_pubsub_topic + if messages_to_check is None: + messages_to_check = [self.message] + if store_node is None: + store_node = self.store_nodes + elif not isinstance(store_node, list): + store_node = [store_node] + for node in store_node: + logger.debug(f"Checking that peer {node.image} can find the stored messages") + self.store_response = self.get_messages_from_store( + node=node, + peer_addr=peer_addr, + include_data=include_data, + pubsub_topic=pubsub_topic, + content_topics=content_topics, + start_time=start_time, + end_time=end_time, + hashes=hashes, + cursor=cursor, + page_size=page_size, + ascending=ascending, + store_v=store_v, + **kwargs, + ) + + logger.debug(f"messages length is {len(self.store_response.messages)}") + assert self.store_response.messages, f"Peer {node.image} couldn't find any messages. Actual response: {self.store_response.resp_json}" + assert len(self.store_response.messages) >= len( + messages_to_check + ), f"Expected at least {len(messages_to_check)} messages but got {len(self.store_response.messages)}" + + # Determine the range of indices for message comparison + if len(messages_to_check) == 1: + indices = [-1] # Use the last message in the store response for a single message + else: + indices = range(len(messages_to_check)) # Use corresponding indices for multiple messages + + # Iterate through messages_to_check and their respective indices + for idx, message_to_check in zip(indices, messages_to_check): + if store_v == "v1": + waku_message = WakuMessage([self.store_response.messages[idx]]) + waku_message.assert_received_message(message_to_check) + else: + hash_type = "hex" if node.is_nwaku() else "base64" + expected_hash = self.compute_message_hash(pubsub_topic, message_to_check, hash_type=hash_type) + actual_hash = self.store_response.message_hash(idx) + assert ( + expected_hash == actual_hash + ), f"Message hash at index {idx} returned by store doesn't match the computed message hash {expected_hash}. Actual hash: {actual_hash}" + + @allure.step + def check_sent_message_is_stored( + self, + expected_hashes, + store_node=None, + peer_addr=None, + include_data=None, + pubsub_topic=None, + content_topics=None, + start_time=None, + end_time=None, + hashes=None, + cursor=None, + page_size=None, + ascending=None, + store_v="v3", + **kwargs, + ): + """Verify that messages with the given hashes are present in the store.""" + if pubsub_topic is None: + pubsub_topic = self.test_pubsub_topic + if isinstance(expected_hashes, str): + expected_hashes = [expected_hashes] + if store_node is None: + store_node = self.store_nodes + elif not isinstance(store_node, list): + store_node = [store_node] + + for node in store_node: + logger.debug(f"Checking that peer {node.image} can find the stored messages by hash") + self.store_response = self.get_messages_from_store( + node=node, + peer_addr=peer_addr, + include_data=include_data, + pubsub_topic=pubsub_topic, + content_topics=content_topics, + start_time=start_time, + end_time=end_time, + hashes=hashes, + cursor=cursor, + page_size=page_size, + ascending=ascending, + store_v=store_v, + **kwargs, + ) + + logger.debug(f"messages length is {len(self.store_response.messages)}") + assert self.store_response.messages, f"Peer {node.image} couldn't find any messages. " f"Actual response: {self.store_response.resp_json}" + assert len(self.store_response.messages) >= len(expected_hashes), ( + f"Expected at least {len(expected_hashes)} messages " f"but got {len(self.store_response.messages)}" + ) + + actual_hashes = [self.store_response.message_hash(i) for i in range(len(self.store_response.messages))] + for expected_hash in expected_hashes: + assert expected_hash in actual_hashes, f"Expected hash {expected_hash} not found in store. " f"Actual hashes: {actual_hashes}" + + @allure.step + def check_store_returns_empty_response(self, pubsub_topic=None): + if not pubsub_topic: + pubsub_topic = self.test_pubsub_topic + try: + self.check_published_message_is_stored(pubsubTopic=pubsub_topic, page_size=5, ascending="true") + except Exception as ex: + assert "couldn't find any messages" in str(ex) + + @allure.step + def create_payload(self, pubsub_topic=None, message=None, **kwargs): + if message is None: + message = self.create_message() + if pubsub_topic is None: + pubsub_topic = self.test_pubsub_topic + payload = {"pubsubTopic": pubsub_topic, "message": message} + payload.update(kwargs) + return payload + + @allure.step + def get_store_messages_with_errors( + self, + node=None, + peer_addr=None, + include_data=None, + pubsub_topic=None, + content_topics=None, + start_time=None, + end_time=None, + hashes=None, + cursor=None, + page_size=None, + ascending="true", + store_v="v3", + **kwargs, + ): + """ + This method calls the original get_store_messages and returns the actual + error response from the service, if present. + """ + try: + # Call the original get_store_messages method + store_response = node.get_store_messages( + peer_addr=peer_addr, + include_data=include_data, + pubsub_topic=pubsub_topic, + content_topics=content_topics, + start_time=start_time, + end_time=end_time, + hashes=hashes, + cursor=cursor, + page_size=page_size, + ascending=ascending, + store_v=store_v, + **kwargs, + ) + + # Check if the response has a status code >= 400, indicating an error + if store_response.status_code >= 400: + # Return the status code and the plain text error message directly + return {"status_code": store_response.status_code, "error_message": store_response.text} # Handling plain text response + + # Otherwise, return the successful response as JSON + response_json = store_response.json() + response_json["status_code"] = store_response.status_code + return response_json + + except requests.exceptions.HTTPError as http_err: + # Handle HTTP errors separately + return {"status_code": http_err.response.status_code, "error_message": http_err.response.text} + + except Exception as e: + # Handle unexpected errors and return as 500 + return {"status_code": 500, "error_message": str(e)} diff --git a/tests-e2e/src/test_data.py b/tests-e2e/src/test_data.py new file mode 100644 index 000000000..659dd39ae --- /dev/null +++ b/tests-e2e/src/test_data.py @@ -0,0 +1,356 @@ +from time import time +from datetime import datetime, timedelta + +NOW = datetime.now() + +SAMPLE_INPUTS = [ + {"description": "A simple string", "value": "Hello World!"}, + {"description": "An integer", "value": "1234567890"}, + {"description": "A dictionary", "value": '{"key": "value"}'}, + {"description": "Chinese characters", "value": "这是一些中文"}, + {"description": "Emojis", "value": "🚀🌟✨"}, + {"description": "Lorem ipsum text", "value": "Lorem ipsum dolor sit amet"}, + {"description": "HTML content", "value": "Hello"}, + {"description": "Cyrillic characters", "value": "\u041f\u0440\u0438\u0432\u0435\u0442"}, + {"description": "Base64 encoded string", "value": "Base64==dGVzdA=="}, + {"description": "Binary data", "value": "d29ya2luZyB3aXRoIGJpbmFyeSBkYXRh: \x50\x51"}, + {"description": "Special characters with whitespace", "value": "\t\nSpecial\tCharacters\n"}, + {"description": "Boolean false as a string", "value": "False"}, + {"description": "A float number", "value": "3.1415926535"}, + {"description": "A list", "value": "[1, 2, 3, 4, 5]"}, + {"description": "Hexadecimal number as a string", "value": "0xDEADBEEF"}, + {"description": "Email format", "value": "user@example.com"}, + {"description": "URL format", "value": "http://example.com"}, + {"description": "Date and time in ISO format", "value": "2023-11-01T12:00:00Z"}, + {"description": "String with escaped quotes", "value": '"Escaped" \\"quotes\\"'}, + {"description": "A regular expression", "value": "Regular expression: ^[a-z0-9_-]{3,16}$"}, + {"description": "A very long string", "value": "x" * 1000}, + {"description": "A JSON string", "value": '{"name": "John", "age": 30, "city": "New York"}'}, + {"description": "A Unix path", "value": "/usr/local/bin"}, + {"description": "A Windows path", "value": "C:\\Windows\\System32"}, + {"description": "An SQL query", "value": "SELECT * FROM users WHERE id = 1;"}, + {"description": "JavaScript code snippet", "value": "function test() { console.log('Hello World'); }"}, + {"description": "A CSS snippet", "value": "body { background-color: #fff; }"}, + {"description": "A Python one-liner", "value": "print('Hello World')"}, + {"description": "An IP address", "value": "192.168.1.1"}, + {"description": "A domain name", "value": "www.example.com"}, + {"description": "A user agent string", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}, + {"description": "A credit card number", "value": "1234-5678-9012-3456"}, + {"description": "A phone number", "value": "+1234567890"}, + {"description": "A UUID", "value": "123e4567-e89b-12d3-a456-426614174000"}, + {"description": "A hashtag", "value": "#helloWorld"}, + {"description": "A Twitter handle", "value": "@username"}, + {"description": "A password", "value": "P@ssw0rd!"}, + {"description": "A date in common format", "value": "01/11/2023"}, + {"description": "A time string", "value": "12:00:00"}, + {"description": "A mathematical equation", "value": "E = mc^2"}, +] + +INVALID_PAYLOADS = [ + {"description": "Empty string", "value": ""}, + {"description": "Unecoded text", "value": "Hello World!"}, + {"description": "A dictionary", "value": {"key": "YWFh"}}, + {"description": "An integer", "value": 1234567890}, + {"description": "A list", "value": ["YWFh"]}, + {"description": "A bool", "value": True}, +] + +INVALID_CONTENT_TOPICS = [ + {"description": "Empty string", "value": ""}, + {"description": "A dictionary", "value": {"key": "YWFh"}}, + {"description": "An integer", "value": 1234567890}, + {"description": "A list", "value": ["YWFh"]}, + {"description": "A bool", "value": True}, +] + +CONTENT_TOPICS_DIFFERENT_SHARDS = [ + "/myapp/1/latest/proto", # resolves to shard 0 + "/waku/2/content/test.js", # resolves to shard 1 + "/app/22/sometopic/someencoding", # resolves to shard 2 + "/toychat/2/huilong/proto", # resolves to shard 3 + "/statusim/1/community/cbor", # resolves to shard 4 + "/app/27/sometopic/someencoding", # resolves to shard 5 + "/app/29/sometopic/someencoding", # resolves to shard 6 + "/app/20/sometopic/someencoding", # resolves to shard 7 +] + +CONTENT_TOPICS_SHARD_0 = [ + "/newsService/1.0/weekly/protobuf", + "/newsService/1.0/alerts/xml", + "/newsService/1.0/updates/json", + "/newsService/2.0/alerts/json", + "/newsService/2.0/summaries/xml", + "/newsService/2.0/highlights/yaml", + "/newsService/3.0/weekly/json", + "/newsService/3.0/summaries/xml", +] + +CONTENT_TOPICS_SHARD_7 = [ + "/newsService/2.0/alerts/yaml", + "/newsService/2.0/highlights/xml", + "/newsService/3.0/daily/protobuf", + "/newsService/3.0/alerts/xml", + "/newsService/3.0/updates/protobuf", + "/newsService/3.0/reviews/xml", + "/newsService/4.0/alerts/yaml", + "/newsService/4.0/updates/yaml", +] + +DEFAULT_CLUSTER_ID = "198" +VALID_PUBSUB_TOPICS = [ + f"/waku/2/rs/{DEFAULT_CLUSTER_ID}/0", + f"/waku/2/rs/{DEFAULT_CLUSTER_ID}/1", + f"/waku/2/rs/{DEFAULT_CLUSTER_ID}/9", + f"/waku/2/rs/{DEFAULT_CLUSTER_ID}/25", + f"/waku/2/rs/{DEFAULT_CLUSTER_ID}/1000", +] + +PUBSUB_TOPICS_STORE = [ + f"/waku/2/rs/{DEFAULT_CLUSTER_ID}/0", + f"/waku/2/rs/{DEFAULT_CLUSTER_ID}/1", + f"/waku/2/rs/{DEFAULT_CLUSTER_ID}/2", + f"/waku/2/rs/{DEFAULT_CLUSTER_ID}/3", + f"/waku/2/rs/{DEFAULT_CLUSTER_ID}/4", + f"/waku/2/rs/{DEFAULT_CLUSTER_ID}/5", + f"/waku/2/rs/{DEFAULT_CLUSTER_ID}/6", + f"/waku/2/rs/{DEFAULT_CLUSTER_ID}/7", + f"/waku/2/rs/{DEFAULT_CLUSTER_ID}/8", +] + +INVALID_PUBSUB_TOPICS = ["/test/2/rs/0/1", "/waku/3/rs/0/1", "/waku/2/test/0/1", "/waku/2/rs/3/b", "/waku/2/rs/0"] + +PUBSUB_TOPICS_DIFFERENT_CLUSTERS = [ + "/waku/2/rs/2/0", + "/waku/2/rs/2/1", + "/waku/2/rs/5/0", + "/waku/2/rs/5/1", + "/waku/2/rs/5/999", + "/waku/2/rs/8/0", + "/waku/2/rs/999/999", +] + +PUBSUB_TOPICS_SAME_CLUSTER = [ + "/waku/2/rs/199/0", + "/waku/2/rs/199/1", + "/waku/2/rs/199/2", + "/waku/2/rs/199/3", + "/waku/2/rs/199/4", + "/waku/2/rs/199/5", + "/waku/2/rs/199/6", + "/waku/2/rs/199/7", +] + +PUBSUB_TOPICS_WRONG_FORMAT = [ + {"description": "A dictionary", "value": {"key": "YWFh"}}, + {"description": "An integer", "value": 1234567890}, + {"description": "A list", "value": ["YWFh"]}, + {"description": "A bool", "value": True}, +] + +SAMPLE_TIMESTAMPS = [ + {"description": "Now", "value": int(time() * 1e9), "valid_for": ["nwaku"]}, + { + "description": "Far future", + "value": int((NOW + timedelta(days=365 * 10)).timestamp() * 1e9), + "valid_for": ["nwaku"], + }, # 10 years from now + {"description": "Recent past", "value": int((NOW - timedelta(hours=1)).timestamp() * 1e9), "valid_for": ["nwaku"]}, # 1 hour ago + {"description": "Near future", "value": int((NOW + timedelta(hours=1)).timestamp() * 1e9), "valid_for": ["nwaku"]}, # 1 hour ahead + {"description": "Positive number", "value": 1, "valid_for": ["nwaku"]}, + {"description": "Negative number", "value": -1, "valid_for": ["nwaku"]}, + {"description": "DST change", "value": int(datetime(2020, 3, 8, 2, 0, 0).timestamp() * 1e9), "valid_for": ["nwaku"]}, # DST starts + {"description": "Timestamp as string number", "value": str(int(time() * 1e9)), "valid_for": []}, + {"description": "Invalid large number", "value": 2**63, "valid_for": []}, + {"description": "Float number", "value": float(time() * 1e9), "valid_for": []}, + {"description": "Array instead of timestamp", "value": [int(time() * 1e9)], "valid_for": []}, + {"description": "Object instead of timestamp", "value": {"time": int(time() * 1e9)}, "valid_for": []}, + {"description": "ISO 8601 timestamp", "value": "2023-12-26T10:58:51", "valid_for": []}, + {"description": "Missing", "value": None, "valid_for": []}, +] + +PUBSUB_TOPICS_RLN = [f"/waku/2/rs/{DEFAULT_CLUSTER_ID}/0"] + +LOG_ERROR_KEYWORDS = [ + "crash", + "fatal", + "panic", + "abort", + "segfault", + "corrupt", + "terminated", + "unhandled", + "stacktrace", + "deadlock", + "SIGSEGV", + "SIGABRT", + "stack overflow", + "index out of bounds", + "nil pointer dereference", + "goroutine exit", + "nil pointer", + "runtime error", + "goexit", + "race condition", + "double free", +] + +METRICS_WITH_INITIAL_VALUE_ZERO = [ + "libp2p_peers", + "libp2p_failed_upgrades_incoming_total", + "libp2p_failed_upgrades_outgoing_total", + "libp2p_total_dial_attempts_total", + "libp2p_successful_dials_total", + "libp2p_failed_dials_total", + "waku_rln_messages_total_total", + "waku_rln_spam_messages_total_total", + "waku_rln_proof_verification_total_total", + "waku_rln_number_registered_memberships", + "waku_rln_proof_verification_duration_seconds", + "waku_rln_proof_generation_duration_seconds", + "waku_rln_instance_creation_duration_seconds", + "waku_rln_membership_insertion_duration_seconds", + "waku_rln_membership_credentials_import_duration_seconds", + "waku_rln_remaining_proofs_per_epoch", + "waku_rln_total_generated_proofs", + "libp2p_pubsub_sig_verify_success_total", + "libp2p_pubsub_sig_verify_failure_total", + "libp2p_pubsub_disconnects_over_non_priority_queue_limit_total", + "libp2p_pubsub_peers", + "libp2p_pubsub_unsubscriptions_total", + "libp2p_pubsub_validation_success_total", + "libp2p_pubsub_validation_failure_total", + "libp2p_pubsub_validation_ignore_total", + "libp2p_pubsub_broadcast_iwant_total", + "libp2p_pubsub_received_iwant_total", + "libp2p_gossipsub_cache_window_size", + 'libp2p_gossipsub_peers_per_topic_mesh{topic="other"}', + 'libp2p_gossipsub_peers_per_topic_fanout{topic="other"}', + 'libp2p_gossipsub_peers_per_topic_gossipsub{topic="other"}', + "libp2p_gossipsub_low_peers_topics", + "libp2p_gossipsub_healthy_peers_topics", + "libp2p_gossipsub_failed_publish_total", + "libp2p_gossipsub_invalid_topic_subscription_total", + "libp2p_gossipsub_duplicate_during_validation_total", + "libp2p_gossipsub_idontwant_saved_messages_total", + "libp2p_gossipsub_duplicate_total", + "libp2p_gossipsub_received_total", + "libp2p_rendezvous_register_total", + "libp2p_rendezvous_discover_total", + "libp2p_rendezvous_registered", + "libp2p_rendezvous_namespaces", + "waku_peer_store_size", + "waku_total_unique_peers", + "presto_server_missing_requests_count", + "presto_server_invalid_requests_count", + 'waku_archive_messages{type="stored"}', + "waku_archive_insert_duration_seconds_sum", + "waku_archive_insert_duration_seconds_count", + 'waku_archive_insert_duration_seconds_bucket{le="0.005"}', + 'waku_archive_insert_duration_seconds_bucket{le="0.01"}', + 'waku_archive_insert_duration_seconds_bucket{le="0.025"}', + 'waku_archive_insert_duration_seconds_bucket{le="0.05"}', + 'waku_archive_insert_duration_seconds_bucket{le="0.075"}', + 'waku_archive_insert_duration_seconds_bucket{le="0.1"}', + 'waku_archive_insert_duration_seconds_bucket{le="0.25"}', + 'waku_archive_insert_duration_seconds_bucket{le="0.5"}', + 'waku_archive_insert_duration_seconds_bucket{le="0.75"}', + 'waku_archive_insert_duration_seconds_bucket{le="1.0"}', + 'waku_archive_insert_duration_seconds_bucket{le="2.5"}', + 'waku_archive_insert_duration_seconds_bucket{le="5.0"}', + 'waku_archive_insert_duration_seconds_bucket{le="7.5"}', + 'waku_archive_insert_duration_seconds_bucket{le="10.0"}', + 'waku_archive_insert_duration_seconds_bucket{le="+Inf"}', + "waku_archive_query_duration_seconds_sum", + "waku_archive_query_duration_seconds_count", + 'waku_archive_query_duration_seconds_bucket{le="0.005"}', + 'waku_archive_query_duration_seconds_bucket{le="0.01"}', + 'waku_archive_query_duration_seconds_bucket{le="0.025"}', + 'waku_archive_query_duration_seconds_bucket{le="0.05"}', + 'waku_archive_query_duration_seconds_bucket{le="0.075"}', + 'waku_archive_query_duration_seconds_bucket{le="0.1"}', + 'waku_archive_query_duration_seconds_bucket{le="0.25"}', + 'waku_archive_query_duration_seconds_bucket{le="0.5"}', + 'waku_archive_query_duration_seconds_bucket{le="0.75"}', + 'waku_archive_query_duration_seconds_bucket{le="1.0"}', + 'waku_archive_query_duration_seconds_bucket{le="2.5"}', + 'waku_archive_query_duration_seconds_bucket{le="5.0"}', + 'waku_archive_query_duration_seconds_bucket{le="7.5"}', + 'waku_archive_query_duration_seconds_bucket{le="10.0"}', + 'waku_archive_query_duration_seconds_bucket{le="+Inf"}', + "waku_filter_subscriptions", + "waku_filter_handle_message_duration_seconds_sum", + "waku_filter_handle_message_duration_seconds_count", + 'waku_filter_handle_message_duration_seconds_bucket{le="0.005"}', + 'waku_filter_handle_message_duration_seconds_bucket{le="0.01"}', + 'waku_filter_handle_message_duration_seconds_bucket{le="0.025"}', + 'waku_filter_handle_message_duration_seconds_bucket{le="0.05"}', + 'waku_filter_handle_message_duration_seconds_bucket{le="0.075"}', + 'waku_filter_handle_message_duration_seconds_bucket{le="0.1"}', + 'waku_filter_handle_message_duration_seconds_bucket{le="0.25"}', + 'waku_filter_handle_message_duration_seconds_bucket{le="0.5"}', + 'waku_filter_handle_message_duration_seconds_bucket{le="0.75"}', + 'waku_filter_handle_message_duration_seconds_bucket{le="1.0"}', + 'waku_filter_handle_message_duration_seconds_bucket{le="2.5"}', + 'waku_filter_handle_message_duration_seconds_bucket{le="5.0"}', + 'waku_filter_handle_message_duration_seconds_bucket{le="7.5"}', + 'waku_filter_handle_message_duration_seconds_bucket{le="10.0"}', + 'waku_filter_handle_message_duration_seconds_bucket{le="+Inf"}', + "discovery_session_lru_cache_hits_total", + "discovery_session_lru_cache_misses_total", + "discovery_session_decrypt_failures_total", + "discovery_unsolicited_messages_total", + "discovery_enr_auto_update_total", + "waku_px_peers_received_total", + "waku_px_peers_received_unknown", + "waku_px_peers_sent_total", + "waku_px_peers", + "waku_histogram_message_size_sum", + "waku_histogram_message_size_count", + 'waku_histogram_message_size_bucket{le="0.0"}', + 'waku_histogram_message_size_bucket{le="1.0"}', + 'waku_histogram_message_size_bucket{le="3.0"}', + 'waku_histogram_message_size_bucket{le="5.0"}', + 'waku_histogram_message_size_bucket{le="15.0"}', + 'waku_histogram_message_size_bucket{le="50.0"}', + 'waku_histogram_message_size_bucket{le="75.0"}', + 'waku_histogram_message_size_bucket{le="100.0"}', + 'waku_histogram_message_size_bucket{le="125.0"}', + 'waku_histogram_message_size_bucket{le="150.0"}', + 'waku_histogram_message_size_bucket{le="500.0"}', + 'waku_histogram_message_size_bucket{le="700.0"}', + 'waku_histogram_message_size_bucket{le="1000.0"}', + 'waku_histogram_message_size_bucket{le="+Inf"}', + "waku_lightpush_peers", + "waku_filter_peers", + "waku_store_peers", + "waku_px_peers", + "waku_dnsdisc_discovered", + "rendezvousPeerFoundTotal_total", + "reconciliation_roundtrips_sum", + "reconciliation_roundtrips_count", + "reconciliation_differences_sum", + "reconciliation_differences_count", + 'reconciliation_roundtrips_bucket{le="1.0"}', + 'reconciliation_roundtrips_bucket{le="2.0"}', + 'reconciliation_roundtrips_bucket{le="3.0"}', + 'reconciliation_roundtrips_bucket{le="5.0"}', + 'reconciliation_roundtrips_bucket{le="8.0"}', + 'reconciliation_roundtrips_bucket{le="13.0"}', + 'reconciliation_roundtrips_bucket{le="+Inf"}', + 'reconciliation_differences_bucket{le="0.0"}', + 'reconciliation_differences_bucket{le="10.0"}', + 'reconciliation_differences_bucket{le="50.0"}', + 'reconciliation_differences_bucket{le="100.0"}', + 'reconciliation_differences_bucket{le="500.0"}', + 'reconciliation_differences_bucket{le="1000.0"}', + 'reconciliation_differences_bucket{le="5000.0"}', + 'reconciliation_differences_bucket{le="+Inf"}', + 'waku_filter_handle_message_duration_seconds_bucket{le="15.0"}', + 'waku_filter_handle_message_duration_seconds_bucket{le="20.0"}', + 'waku_filter_handle_message_duration_seconds_bucket{le="30.0"}', + "total_messages_cached", + "waku_store_queries_total", + "mix_pool_size", + "libp2p_gossipsub_imreceiving_saved_messages_total", + "postgres_payload_size_bytes", +] diff --git a/tests-e2e/tests/__init__.py b/tests-e2e/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests-e2e/tests/conftest.py b/tests-e2e/tests/conftest.py new file mode 100644 index 000000000..5c42669dd --- /dev/null +++ b/tests-e2e/tests/conftest.py @@ -0,0 +1,100 @@ +# -*- coding: utf-8 -*- +import inspect +import glob +from src.libs.custom_logger import get_custom_logger +import os +import pytest +from datetime import datetime +from time import time +from uuid import uuid4 +from src.libs.common import attach_allure_file +import src.env_vars as env_vars +from src.data_storage import DS +from src.postgres_setup import start_postgres, stop_postgres + +logger = get_custom_logger(__name__) + + +# See https://docs.pytest.org/en/latest/example/simple.html#making-test-result-information-available-in-fixtures +@pytest.hookimpl(hookwrapper=True, tryfirst=True) +def pytest_runtest_makereport(item): + outcome = yield + rep = outcome.get_result() + if rep.when == "call": + setattr(item, "rep_call", rep) + return rep + return None + + +@pytest.fixture(scope="session", autouse=True) +def set_allure_env_variables(): + yield + if os.path.isdir("allure-results") and not os.path.isfile(os.path.join("allure-results", "environment.properties")): + logger.debug(f"Running fixture teardown: {inspect.currentframe().f_code.co_name}") + with open(os.path.join("allure-results", "environment.properties"), "w") as outfile: + for attribute_name in dir(env_vars): + if attribute_name.isupper(): + attribute_value = getattr(env_vars, attribute_name) + outfile.write(f"{attribute_name}={attribute_value}\n") + + +@pytest.fixture(scope="function", autouse=False) +def start_postgres_container(): + pg_container = start_postgres() + yield + stop_postgres(pg_container) + + +@pytest.fixture(scope="function", autouse=True) +def test_id(request): + # setting up an unique test id to be used where needed + logger.debug(f"Running fixture setup: {inspect.currentframe().f_code.co_name}") + request.cls.test_id = f"{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}__{str(uuid4())}" + + +@pytest.fixture(scope="function", autouse=True) +def test_setup(request, test_id): + logger.debug(f"Running test: {request.node.name} with id: {request.cls.test_id}") + yield + logger.debug(f"Running fixture teardown: {inspect.currentframe().f_code.co_name}") + for file in glob.glob(os.path.join(env_vars.DOCKER_LOG_DIR, "*")): + if os.path.getmtime(file) < time() - 3600: + logger.debug(f"Deleting old log file: {file}") + try: + os.remove(file) + except: + logger.error("Could not delete file") + + +@pytest.fixture(scope="function", autouse=True) +def attach_logs_on_fail(request): + yield + if env_vars.RUNNING_IN_CI and hasattr(request.node, "rep_call") and request.node.rep_call.failed: + logger.debug(f"Running fixture teardown: {inspect.currentframe().f_code.co_name}") + logger.debug("Test failed, attempting to attach logs to the allure reports") + for file in glob.glob(os.path.join(env_vars.DOCKER_LOG_DIR, "*" + request.cls.test_id + "*")): + attach_allure_file(file) + + +@pytest.fixture(scope="function", autouse=True) +def close_open_nodes(attach_logs_on_fail): + DS.waku_nodes = [] + yield + logger.debug(f"Running fixture teardown: {inspect.currentframe().f_code.co_name}") + crashed_containers = [] + for node in DS.waku_nodes: + try: + node.stop() + except Exception as ex: + if "No such container" in str(ex): + crashed_containers.append(node.image) + logger.error(f"Failed to stop container because of error {ex}") + assert not crashed_containers, f"Containers {crashed_containers} crashed during the test!!!" + + +@pytest.fixture(scope="function", autouse=True) +def check_waku_log_errors(): + yield + logger.debug(f"Running fixture teardown: {inspect.currentframe().f_code.co_name}") + for node in DS.waku_nodes: + node.check_waku_log_errors() diff --git a/tests-e2e/tests/wrappers_tests/conftest.py b/tests-e2e/tests/wrappers_tests/conftest.py new file mode 100644 index 000000000..3d2e19e38 --- /dev/null +++ b/tests-e2e/tests/wrappers_tests/conftest.py @@ -0,0 +1,35 @@ +import socket +import pytest +from src.test_data import DEFAULT_CLUSTER_ID + + +def free_port(): + """Return a currently-unbound TCP/UDP port from the OS.""" + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.bind(("", 0)) + return s.getsockname()[1] + + +def build_node_config(**overrides): + config = { + "logLevel": "DEBUG", + "listenAddress": "0.0.0.0", + "tcpPort": free_port(), + "discv5UdpPort": free_port(), + "restPort": free_port(), + "restAddress": "0.0.0.0", + "clusterId": DEFAULT_CLUSTER_ID, + "relay": True, + "store": True, + "filter": False, + "lightpush": False, + "peerExchange": False, + "discv5Discovery": False, + } + config.update(overrides) + return config + + +@pytest.fixture +def node_config(): + return build_node_config() diff --git a/tests-e2e/tests/wrappers_tests/test_basic_life_cycle.py b/tests-e2e/tests/wrappers_tests/test_basic_life_cycle.py new file mode 100644 index 000000000..eb2026438 --- /dev/null +++ b/tests-e2e/tests/wrappers_tests/test_basic_life_cycle.py @@ -0,0 +1,26 @@ +import pytest +from src.node.wrappers_manager import WrapperManager + + +@pytest.mark.smoke +class TestLogosDeliveryLifecycle: + def _create_start_node(self, node_config): + result = WrapperManager.create_and_start(config=node_config) + assert result.is_ok(), f"Failed to create and start node: {result.err()}" + return result.ok_value + + def test_create_start_and_stop_node(self, node_config): + node = self._create_start_node(node_config) + + stop_result = node.stop_and_destroy() + assert stop_result.is_ok(), f"Failed to stop and destroy node: {stop_result.err()}" + + def test_stop_node_without_destroy(self, node_config): + node = self._create_start_node(node_config) + + try: + stop_result = node.stop_node() + assert stop_result.is_ok(), f"Failed to stop node: {stop_result.err()}" + finally: + destroy_result = node.destroy() + assert destroy_result.is_ok(), f"Failed to destroy node: {destroy_result.err()}" diff --git a/tests-e2e/tests/wrappers_tests/test_send_e2e_part1.py b/tests-e2e/tests/wrappers_tests/test_send_e2e_part1.py new file mode 100644 index 000000000..c998c73df --- /dev/null +++ b/tests-e2e/tests/wrappers_tests/test_send_e2e_part1.py @@ -0,0 +1,1018 @@ +from concurrent.futures import ThreadPoolExecutor + +import pytest +from src.env_vars import NODE_2 +from src.steps.common import StepsCommon +from src.libs.common import delay, to_base64 +from src.libs.custom_logger import get_custom_logger +from src.node.waku_node import WakuNode +from src.node.wrappers_manager import WrapperManager +from src.node.wrapper_helpers import ( + EventCollector, + assert_event_invariants, + create_message_bindings, + get_node_multiaddr, + wait_for_connected, + wait_for_propagated, + wait_for_sent, + wait_for_error, +) +from src.steps.store import StepsStore +from tests.wrappers_tests.conftest import free_port + +logger = get_custom_logger(__name__) + +## max time to wait after sending the message +PROPAGATED_TIMEOUT_S = 30.0 +SENT_TIMEOUT_S = 10.0 +NO_SENT_OBSERVATION_S = 5.0 +SENT_AFTER_STORE_TIMEOUT_S = 60.0 +NO_STORE_OBSERVATION_S = 60.0 +RECOVERY_TIMEOUT_S = 45.0 + +# S20 stabilization delays for gossipsub mesh formation. +MESH_STABILIZATION_S = 10 +STORE_JOIN_STABILIZATION_S = 10 + +# MaxTimeInCache from send_service.nim. +MAX_TIME_IN_CACHE_S = 60.0 +# Extra slack to cover the background retry loop tick after the window expires. +CACHE_EXPIRY_SLACK_S = 10.0 +ERROR_AFTER_CACHE_EXPIRY_TIMEOUT_S = MAX_TIME_IN_CACHE_S + CACHE_EXPIRY_SLACK_S +RETRY_WINDOW_EXPIRED_MSG = "Unable to send within retry time window" + +# S30: concurrent sends on the same content topic during initial auto-subscribe. +S30_CONCURRENT_SENDS = 5 +S30_CONTENT_TOPIC = "/test/1/s30-concurrent/proto" + +# S31: concurrent sends across mixed topics during peer churn. +S31_BURST_SIZE = 8 +S31_CONTENT_TOPICS = [ + "/test/1/s31-topic-a/proto", + "/test/1/s31-topic-b/proto", + "/test/1/s31-topic-c/proto", + "/test/1/s31-topic-d/proto", + "/test/1/s31-topic-e/proto", + "/test/1/s31-topic-f/proto", + "/test/1/s31-topic-g/proto", + "/test/1/s31-topic-h/proto", +] + + +class TestSendBeforeRelay(StepsStore): + def test_s17_send_before_relay_peers_joins(self, node_config): + """ + S17: sender starts isolated, calls send() + - send() returns Ok(RequestId) immediately + - Propagated event eventually arrives + """ + sender_collector = EventCollector() + + node_config.update( + { + "relay": True, + "store": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + } + ) + + sender_result = WrapperManager.create_and_start( + config=node_config, + event_cb=sender_collector.event_callback, + ) + assert sender_result.is_ok(), f"Failed to start sender: {sender_result.err()}" + + with sender_result.ok_value as sender_node: + message = create_message_bindings() + send_result = sender_node.send_message(message=message) + assert send_result.is_ok(), f"send() must return Ok(RequestId) even with no peers, got: {send_result.err()}" + + request_id = send_result.ok_value + assert request_id, "send() returned an empty RequestId" + + # Step 2: start a relay peer with store enabled. + relay_config = { + **node_config, + "staticnodes": [get_node_multiaddr(sender_node)], + "portsShift": 1, + "store": True, + } + + relay_result = WrapperManager.create_and_start(config=relay_config) + assert relay_result.is_ok(), f"Failed to start relay peer: {relay_result.err()}" + + with relay_result.ok_value: + # Match the gating part2's tests use: wait until the sender + # actually reports Connected/PartiallyConnected before asserting + # on propagation. Without this, the wait_for_propagated poll can + # miss the event because the sender's mesh hasn't formed yet. + assert wait_for_connected(sender_collector) is not None, ( + f"Sender did not reach Connected/PartiallyConnected after " f"relay peer joined. Collected events: {sender_collector.events}" + ) + + propagated_event = wait_for_propagated( + collector=sender_collector, + request_id=request_id, + timeout_s=PROPAGATED_TIMEOUT_S, + ) + assert propagated_event is not None, ( + f"No MessagePropagatedEvent received within {PROPAGATED_TIMEOUT_S}s " + f"after relay peer joined. Collected events: {sender_collector.events}" + ) + sent_event = wait_for_sent( + collector=sender_collector, + request_id=request_id, + timeout_s=SENT_TIMEOUT_S, + ) + assert sent_event is not None, ( + f"No MessageSentEvent received within {SENT_TIMEOUT_S}s " + f"from a store-enabled relay peer. Collected events: {sender_collector.events}" + ) + + assert_event_invariants(sender_collector, request_id) + + @pytest.mark.docker_required + @pytest.mark.xfail(reason="fails to republish after store peer joins mesh see https://github.com/logos-messaging/logos-delivery/issues/3848") + def test_s19_store_peer_appears_after_propagation(self, node_config): + """ + S19: a store peer comes online later. + - send() returns Ok(RequestId) immediately + - Propagated --- relay peer + - Sent when store peer is reachable + """ + sender_collector = EventCollector() + + node_config.update({"relay": True, "store": False, "discv5Discovery": False, "numShardsInNetwork": 1, "reliabilityEnabled": True}) + + sender_result = WrapperManager.create_and_start( + config=node_config, + event_cb=sender_collector.event_callback, + ) + assert sender_result.is_ok(), f"Failed to start sender: {sender_result.err()}" + + with sender_result.ok_value as sender_node: + # relay peer + relay_config = { + **node_config, + "tcpPort": free_port(), + "discv5UdpPort": free_port(), + "restPort": free_port(), + "staticnodes": [get_node_multiaddr(sender_node)], + "store": False, + "reliabilityEnabled": True, + } + + relay_result = WrapperManager.create_and_start(config=relay_config) + assert relay_result.is_ok(), f"Failed to start relay peer: {relay_result.err()}" + + with relay_result.ok_value as relay_peer: + # Wait until the sender actually reports a connection before + # sending. Without this, send() can race the static-peer + # dial on slower runners (same gate S17 uses). + assert wait_for_connected(sender_collector) is not None, ( + f"Sender did not reach Connected/PartiallyConnected after " f"relay peer joined. Collected events: {sender_collector.events}" + ) + message = create_message_bindings() + send_result = sender_node.send_message(message=message) + assert send_result.is_ok(), f"send() must return Ok(RequestId), got: {send_result.err()}" + + request_id = send_result.ok_value + assert request_id, "send() returned an empty RequestId" + + # Propagated should arrive via the relay peer. + propagated_event = wait_for_propagated( + collector=sender_collector, + request_id=request_id, + timeout_s=PROPAGATED_TIMEOUT_S, + ) + assert propagated_event is not None, ( + f"No MessagePropagatedEvent received within {PROPAGATED_TIMEOUT_S}s. " f"Collected events: {sender_collector.events}" + ) + + early_sent_event = wait_for_sent( + collector=sender_collector, + request_id=request_id, + timeout_s=NO_SENT_OBSERVATION_S, + ) + assert early_sent_event is None, f"MessageSentEvent arrived before any store peer was reachable. " f"Event: {early_sent_event}" + + # Store peer + store_node = WakuNode(NODE_2, f"store_node") + store_node.start(relay="true", store="true", discv5_discovery="false", cluster_id=node_config["clusterId"], shard=0) + store_node.set_relay_subscriptions([self.test_pubsub_topic]) + relay_multiaddr = get_node_multiaddr(relay_peer) + sender_multiaddr = get_node_multiaddr(sender_node) + store_node.add_peers([relay_multiaddr, sender_multiaddr]) + self.wait_for_autoconnection([store_node], hard_wait=40) + delay(3) + + sent_event = wait_for_sent( + collector=sender_collector, + request_id=request_id, + timeout_s=SENT_AFTER_STORE_TIMEOUT_S, + ) + + assert sent_event is not None, ( + f"No MessageSentEvent received within {SENT_AFTER_STORE_TIMEOUT_S}s " + f"after store peer joined. Collected events: {sender_collector.events}" + ) + + self.check_published_message_is_stored( + store_node=store_node, + pubsub_topic=self.test_pubsub_topic, + messages_to_check=[message], + page_size=5, + ascending="true", + ) + + assert_event_invariants(sender_collector, request_id) + + @pytest.mark.docker_required + @pytest.mark.skip(reason="Forcing the miss store round not possible") + def test_s20_store_misses_initially_then_retry_succeeds(self, node_config): + """ + S20: relay propagation succeeds, the first store query misses + (the store peer is reachable but does not yet have the message), + a later retry republishes through the relay mesh, and the store + peer then archives it. + + Covers state flow: + SuccessfullyPropagated -> NextRoundRetry + -> SuccessfullyPropagated -> SuccessfullyValidated + + """ + sender_collector = EventCollector() + store_node = WakuNode(NODE_2, f"s20_store_node_{self.test_id}") + store_node.start( + relay="true", + store="true", + discv5_discovery="false", + cluster_id=node_config["clusterId"], + shard=0, + ) + store_multiaddr = store_node.get_multiaddr_with_id() + + node_config.update( + { + "relay": True, + "store": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + "reliabilityEnabled": True, + "storenode": store_multiaddr, + } + ) + + sender_result = WrapperManager.create_and_start( + config=node_config, + event_cb=sender_collector.event_callback, + ) + assert sender_result.is_ok(), f"Failed to start sender: {sender_result.err()}" + + with sender_result.ok_value as sender_node: + relay_config = { + **node_config, + "staticnodes": [get_node_multiaddr(sender_node)], + "portsShift": 1, + "store": False, + } + relay_result = WrapperManager.create_and_start(config=relay_config) + assert relay_result.is_ok(), f"Failed to start relay peer: {relay_result.err()}" + + with relay_result.ok_value as relay_peer: + # Wait for the sender to see the relay peer before publishing. + assert wait_for_connected(sender_collector) is not None, ( + f"Sender did not reach Connected/PartiallyConnected. " f"Collected events: {sender_collector.events}" + ) + + # Let the gossipsub mesh form between sender and relay peer. + delay(MESH_STABILIZATION_S) + + message = create_message_bindings(ephemeral=False) + send_result = sender_node.send_message(message=message) + assert send_result.is_ok(), f"send() must return Ok(RequestId), got: {send_result.err()}" + + request_id = send_result.ok_value + assert request_id, "send() returned an empty RequestId" + + # Round 1: propagation succeeds via the relay peer. + propagated_event = wait_for_propagated( + collector=sender_collector, + request_id=request_id, + timeout_s=PROPAGATED_TIMEOUT_S, + ) + assert propagated_event is not None, ( + f"No MessagePropagatedEvent within {PROPAGATED_TIMEOUT_S}s. " f"Collected events: {sender_collector.events}" + ) + + # The store peer is reachable for queries but never received + # the message via gossipsub, so the first store query must + # miss and Sent must NOT arrive yet. + early_sent_event = wait_for_sent( + collector=sender_collector, + request_id=request_id, + timeout_s=NO_SENT_OBSERVATION_S, + ) + assert early_sent_event is None, ( + f"MessageSentEvent arrived before the store could have the message. " + f"Initial store query should have missed. Event: {early_sent_event}" + ) + + # Now subscribe the store to the test topic and wire it into + # the relay mesh so the next retry round's republish reaches + # the store via gossipsub. + store_node.set_relay_subscriptions([self.test_pubsub_topic]) + store_node.add_peers([get_node_multiaddr(sender_node), get_node_multiaddr(relay_peer)]) + self.wait_for_autoconnection([store_node], hard_wait=10) + delay(STORE_JOIN_STABILIZATION_S) + + # Round 2: retry republishes, store archives, next query hits. + sent_event = wait_for_sent( + collector=sender_collector, + request_id=request_id, + timeout_s=SENT_AFTER_STORE_TIMEOUT_S, + ) + assert sent_event is not None, ( + f"No MessageSentEvent within {SENT_AFTER_STORE_TIMEOUT_S}s " + f"after the store joined the relay mesh. The retry round " + f"should have republished and the store should have archived. " + f"Collected events: {sender_collector.events}" + ) + + self.check_published_message_is_stored( + store_node=store_node, + pubsub_topic=self.test_pubsub_topic, + messages_to_check=[message], + page_size=5, + ascending="true", + ) + + assert_event_invariants(sender_collector, request_id) + + def test_s21_error_when_retry_window_expires(self, node_config): + """ + S21: delivery retry window expires before any valid path recovers. + """ + sender_collector = EventCollector() + + node_config.update( + { + "relay": True, + "store": False, + "lightpush": False, + "filter": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + } + ) + + sender_result = WrapperManager.create_and_start( + config=node_config, + event_cb=sender_collector.event_callback, + ) + assert sender_result.is_ok(), f"Failed to start sender: {sender_result.err()}" + + with sender_result.ok_value as sender_node: + message = create_message_bindings() + send_result = sender_node.send_message(message=message) + assert send_result.is_ok(), f"send() must return Ok(RequestId) even with no peers, got: {send_result.err()}" + + request_id = send_result.ok_value + assert request_id, "send() returned an empty RequestId" + + # No peer + error_event = wait_for_error( + collector=sender_collector, + request_id=request_id, + timeout_s=ERROR_AFTER_CACHE_EXPIRY_TIMEOUT_S, + ) + assert error_event is not None, ( + f"No MessageErrorEvent received within {ERROR_AFTER_CACHE_EXPIRY_TIMEOUT_S}s " + f"(MaxTimeInCache={MAX_TIME_IN_CACHE_S}s + slack). " + f"Collected events: {sender_collector.events}" + ) + logger.info(f"S21 received error event: {error_event}") + + assert error_event.get("error") == RETRY_WINDOW_EXPIRED_MSG, ( + f"Unexpected error message in message_error event.\n" + f"Expected: {RETRY_WINDOW_EXPIRED_MSG!r}\n" + f"Got: {error_event.get('error')!r}\n" + f"Full event: {error_event}" + ) + + assert_event_invariants(sender_collector, request_id) + + def test_s22_non_ephemeral_message_with_reliability_disabled(self, node_config): + """ + S22: non-ephemeral message with reliabilityEnabled disabled. + - propagation path exists ,reliabilityEnabled = false. + - Expected: Ok(RequestId), Propagated event only, no Sent event. + Note: S17 already covers the positive path of this test with reliabilityEnabled=True. + """ + sender_collector = EventCollector() + + node_config.update( + { + "relay": True, + "store": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + "reliabilityEnabled": False, + } + ) + + sender_result = WrapperManager.create_and_start( + config=node_config, + event_cb=sender_collector.event_callback, + ) + assert sender_result.is_ok(), f"Failed to start sender: {sender_result.err()}" + + with sender_result.ok_value as sender_node: + relay_config = { + **node_config, + "staticnodes": [get_node_multiaddr(sender_node)], + "portsShift": 1, + "store": True, + } + + relay_result = WrapperManager.create_and_start(config=relay_config) + assert relay_result.is_ok(), f"Failed to start relay peer: {relay_result.err()}" + + with relay_result.ok_value: + # Wait for the sender to actually establish the mesh before + # publishing, matching part2's pattern. Otherwise the publish + # races with mesh formation and message_propagated may not fire. + assert wait_for_connected(sender_collector) is not None, ( + f"Sender did not reach Connected/PartiallyConnected. " f"Collected events: {sender_collector.events}" + ) + + message = create_message_bindings(ephemeral=False) + send_result = sender_node.send_message(message=message) + assert send_result.is_ok(), f"send() must return Ok(RequestId), got: {send_result.err()}" + + request_id = send_result.ok_value + assert request_id, "send() returned an empty RequestId" + + propagated_event = wait_for_propagated( + collector=sender_collector, + request_id=request_id, + timeout_s=PROPAGATED_TIMEOUT_S, + ) + assert propagated_event is not None, ( + f"No MessagePropagatedEvent received within {PROPAGATED_TIMEOUT_S}s. " f"Collected events: {sender_collector.events}" + ) + + sent_event = wait_for_sent( + collector=sender_collector, + request_id=request_id, + timeout_s=NO_SENT_OBSERVATION_S, + ) + assert sent_event is None, ( + f"Unexpected MessageSentEvent received when reliabilityEnabled is disabled.\n" + f"Sent event: {sent_event}\n" + f"Collected events: {sender_collector.events}" + ) + + assert_event_invariants(sender_collector, request_id) + + def test_s23_no_sent_event_when_relay_has_no_store(self, node_config): + """ + S23: non-ephemeral message, reliability enabled, no store peer ever reachable. + - Expected: Ok(RequestId), Propagated event only, no Sent and no terminal error. + """ + sender_collector = EventCollector() + + node_config.update( + { + "relay": True, + "store": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + "reliabilityEnabled": True, + } + ) + + sender_result = WrapperManager.create_and_start( + config=node_config, + event_cb=sender_collector.event_callback, + ) + assert sender_result.is_ok(), f"Failed to start sender: {sender_result.err()}" + + with sender_result.ok_value as sender_node: + message = create_message_bindings(ephemeral=False) + send_result = sender_node.send_message(message=message) + assert send_result.is_ok(), f"send() must return Ok(RequestId) even with no peers, got: {send_result.err()}" + + request_id = send_result.ok_value + assert request_id, "send() returned an empty RequestId" + + relay_config = { + **node_config, + "staticnodes": [get_node_multiaddr(sender_node)], + "portsShift": 1, + "store": False, + } + + relay_result = WrapperManager.create_and_start(config=relay_config) + assert relay_result.is_ok(), f"Failed to start relay peer: {relay_result.err()}" + + with relay_result.ok_value: + propagated_event = wait_for_propagated( + collector=sender_collector, + request_id=request_id, + timeout_s=PROPAGATED_TIMEOUT_S, + ) + assert propagated_event is not None, ( + f"No MessagePropagatedEvent received within {PROPAGATED_TIMEOUT_S}s " + f"after relay peer joined. Collected events: {sender_collector.events}" + ) + + sent_event = wait_for_sent( + collector=sender_collector, + request_id=request_id, + timeout_s=NO_STORE_OBSERVATION_S, + ) + assert sent_event is None, ( + f"Unexpected MessageSentEvent within {NO_STORE_OBSERVATION_S}s " + f"when relay peer has store=false.\n" + f"Sent event: {sent_event}\n" + f"Collected events: {sender_collector.events}" + ) + + # Regression guard: current behavior must NOT convert "no store + # reachable" into an immediate terminal error. If a future change + # starts emitting one, this assertion will catch it. + error_event = wait_for_error( + collector=sender_collector, + request_id=request_id, + timeout_s=0, + ) + assert error_event is None, ( + f"Unexpected terminal error event when no store peer is reachable. " + f"S23 expects silent behavior (Propagated only).\n" + f"Error event: {error_event}\n" + f"Collected events: {sender_collector.events}" + ) + + assert_event_invariants(sender_collector, request_id) + + def test_s24_ephemeral_message_with_reachable_store(self, node_config): + """ + S24: ephemeral message, reliability enabled, reachable store peer. + - Setup: propagation path exists, relay peer has store=True (reachable), + - Expected: Ok(RequestId), Propagated event only, no Sent event. + """ + + sender_collector = EventCollector() + + node_config.update( + { + "relay": True, + "store": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + "reliabilityEnabled": True, + } + ) + + sender_result = WrapperManager.create_and_start( + config=node_config, + event_cb=sender_collector.event_callback, + ) + assert sender_result.is_ok(), f"Failed to start sender: {sender_result.err()}" + + with sender_result.ok_value as sender_node: + relay_config = { + **node_config, + "staticnodes": [get_node_multiaddr(sender_node)], + "portsShift": 1, + "store": True, + } + + relay_result = WrapperManager.create_and_start(config=relay_config) + assert relay_result.is_ok(), f"Failed to start relay peer: {relay_result.err()}" + + with relay_result.ok_value: + message = create_message_bindings(ephemeral=True) + send_result = sender_node.send_message(message=message) + assert send_result.is_ok(), f"send() must return Ok(RequestId), got: {send_result.err()}" + + request_id = send_result.ok_value + assert request_id, "send() returned an empty RequestId" + + propagated_event = wait_for_propagated( + collector=sender_collector, + request_id=request_id, + timeout_s=PROPAGATED_TIMEOUT_S, + ) + assert propagated_event is not None, ( + f"No MessagePropagatedEvent received within {PROPAGATED_TIMEOUT_S}s. " f"Collected events: {sender_collector.events}" + ) + + sent_event = wait_for_sent( + collector=sender_collector, + request_id=request_id, + timeout_s=NO_STORE_OBSERVATION_S, + ) + assert sent_event is None, ( + f"Unexpected MessageSentEvent for an ephemeral message. " + f"Ephemeral messages must never be store-validated.\n" + f"Sent event: {sent_event}\n" + f"Collected events: {sender_collector.events}" + ) + + assert_event_invariants(sender_collector, request_id) + + def test_s26_lightpush_peer_churn_alternate_remains(self, node_config): + """ + S26: multiple lightpush peers, the selected one disappears, + an alternate remains. + + Topology (3 peers + sender): + - peer1: relay + lightpush. The lightpush server initially selected + by the sender. Stopped mid-test to simulate churn. + - relay_peer: relay-only. Kept alive throughout the test as a + stable gossipsub mesh neighbour, so that after peer1 disappears + peer2 still has a relay path to propagate the message. + - peer2: relay + lightpush. The surviving lightpush server that + must take over once peer1 is gone. + - sender: edge node with peer1 and peer2 as static lightpush peers. + """ + sender_collector = EventCollector() + peer1_config = { + **node_config, + "relay": True, + "lightpush": True, + "store": False, + "filter": False, + "discv5Discovery": True, + "numShardsInNetwork": 1, + "portsShift": 1, + "discv5UdpPort": free_port(), + } + peer1_result = WrapperManager.create_and_start(config=peer1_config) + assert peer1_result.is_ok(), f"Failed to start lightpush peer1: {peer1_result.err()}" + peer1 = peer1_result.ok_value + + relay_config = { + **node_config, + "relay": True, + "lightpush": False, + "store": False, + "filter": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + "portsShift": 4, + } + + relay_result = WrapperManager.create_and_start(config=relay_config) + assert relay_result.is_ok(), f"Failed to start relay peer: {relay_result.err()}" + + with relay_result.ok_value as relay_peer: + peer2_config = { + **peer1_config, + "staticnodes": [ + get_node_multiaddr(peer1), + get_node_multiaddr(relay_peer), + ], + "portsShift": 2, + "discv5UdpPort": free_port(), + } + + peer2_result = WrapperManager.create_and_start(config=peer2_config) + assert peer2_result.is_ok(), f"Failed to start lightpush peer2: {peer2_result.err()}" + + with peer2_result.ok_value as peer2: + sender_config = { + **node_config, + "mode": "Edge", + "relay": False, + "store": False, + "filter": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + "portsShift": 3, + "staticnodes": [ + get_node_multiaddr(peer1), + get_node_multiaddr(peer2), + ], + } + + sender_result = WrapperManager.create_and_start( + config=sender_config, + event_cb=sender_collector.event_callback, + ) + assert sender_result.is_ok(), f"Failed to start sender: {sender_result.err()}" + + with sender_result.ok_value as sender_node: + delay(2) + stop_result = peer1.stop_and_destroy() + assert stop_result.is_ok(), f"Failed to stop peer1: {stop_result.err()}" + delay(2) + + message = create_message_bindings() + send_result = sender_node.send_message(message=message) + assert send_result.is_ok(), f"send() must return Ok(RequestId) during peer churn, got: {send_result.err()}" + + request_id = send_result.ok_value + assert request_id, "send() returned an empty RequestId" + + # Expect Propagated via the surviving lightpush peer (peer2). + propagated_event = wait_for_propagated( + collector=sender_collector, + request_id=request_id, + timeout_s=PROPAGATED_TIMEOUT_S, + ) + assert propagated_event is not None, ( + f"No MessagePropagatedEvent within {PROPAGATED_TIMEOUT_S}s " + f"after the selected lightpush peer disappeared. " + f"Collected events: {sender_collector.events}" + ) + + error_event = wait_for_error( + collector=sender_collector, + request_id=request_id, + timeout_s=0, + ) + assert error_event is None, f"Unexpected message_error event during peer churn: {error_event}" + + assert_event_invariants(sender_collector, request_id) + + def test_s30_concurrent_sends_during_auto_subscribe(self, node_config): + """ + S30: concurrent sends on the same content topic during initial auto-subscribe. + - Sender starts unsubscribed to the target topic. + - Several send() calls are issued at nearly the same time. + - Each call must return Ok(RequestId) with a unique id. + - Each request id must get its own propagated event, + with no dropped or cross-associated events. + """ + sender_collector = EventCollector() + + node_config.update( + { + "relay": True, + "store": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + } + ) + + sender_result = WrapperManager.create_and_start( + config=node_config, + event_cb=sender_collector.event_callback, + ) + assert sender_result.is_ok(), f"Failed to start sender: {sender_result.err()}" + + with sender_result.ok_value as sender_node: + # Relay peer so the sender has a propagation path. + relay_config = { + **node_config, + "staticnodes": [get_node_multiaddr(sender_node)], + "portsShift": 1, + } + + relay_result = WrapperManager.create_and_start(config=relay_config) + assert relay_result.is_ok(), f"Failed to start relay peer: {relay_result.err()}" + + with relay_result.ok_value: + # Build one message per send, with distinct payloads so we can + # detect any cross-association between request ids and events. + messages = [ + create_message_bindings( + contentTopic=S30_CONTENT_TOPIC, + payload=to_base64(f"s30-concurrent-{i}"), + ) + for i in range(S30_CONCURRENT_SENDS) + ] + + # Fire all sends concurrently. The sender is not yet subscribed + # to S30_CONTENT_TOPIC, so this exercises the auto-subscribe path + # under contention. + with ThreadPoolExecutor(max_workers=S30_CONCURRENT_SENDS) as pool: + send_results = list(pool.map(sender_node.send_message, messages)) + + # Every send must return Ok(RequestId). + request_ids = [] + for i, send_result in enumerate(send_results): + assert send_result.is_ok(), f"Concurrent send #{i} failed: {send_result.err()}" + request_id = send_result.ok_value + assert request_id, f"Concurrent send #{i} returned an empty RequestId" + request_ids.append(request_id) + + # Request ids must be unique across concurrent sends. + assert len(set(request_ids)) == len(request_ids), f"Duplicate RequestIds returned by concurrent sends: {request_ids}" + + # Each request id must get its own propagated event and no error. + for request_id in request_ids: + propagated_event = wait_for_propagated( + collector=sender_collector, + request_id=request_id, + timeout_s=PROPAGATED_TIMEOUT_S, + ) + assert propagated_event is not None, ( + f"No MessagePropagatedEvent for request_id={request_id} " + f"within {PROPAGATED_TIMEOUT_S}s. " + f"Collected events: {sender_collector.events}" + ) + + error_event = wait_for_error( + collector=sender_collector, + request_id=request_id, + timeout_s=0, + ) + assert error_event is None, f"Unexpected message_error for request_id={request_id}: {error_event}" + + # Cross-association guard: every event with a requestId must + # belong to exactly one of the request ids we issued. + issued = set(request_ids) + for event in sender_collector.snapshot(): + event_request_id = event.get("requestId") + if event_request_id is None: + continue + assert event_request_id in issued, ( + f"Event carries an unknown requestId={event_request_id!r}, " f"not in issued set {issued}. Event: {event}" + ) + + # Per-request invariants apply to every concurrent send + # (correct requestId, no duplicate terminal events, + # Sent never before Propagated). + for request_id in request_ids: + assert_event_invariants(sender_collector, request_id) + + @pytest.mark.docker_required + def test_s31_concurrent_sends_mixed_topics_during_churn(self, node_config): + """ + S31: concurrent sends across mixed content topics during peer churn. + """ + sender_collector = EventCollector() + + relay_peer = WakuNode(NODE_2, f"s31_relay_peer_{self.test_id}") + relay_peer.start(relay="true", discv5_discovery="false") + relay_peer.set_relay_subscriptions([self.test_pubsub_topic]) + + lightpush_peer = WakuNode(NODE_2, f"s31_lightpush_peer_{self.test_id}") + lightpush_peer.start(relay="true", lightpush="true", discv5_discovery="false") + lightpush_peer.set_relay_subscriptions([self.test_pubsub_topic]) + + store_peer = WakuNode(NODE_2, f"s31_store_peer_{self.test_id}") + store_peer.start(relay="true", store="true", discv5_discovery="false") + store_peer.set_relay_subscriptions([self.test_pubsub_topic]) + + churn_peers = [relay_peer, lightpush_peer, store_peer] + + # Mesh docker peers so a lightpushed message can fan out to the store peer. + peer_multiaddrs = [p.get_multiaddr_with_id() for p in churn_peers] + for peer in churn_peers: + others = [a for a in peer_multiaddrs if a != peer.get_multiaddr_with_id()] + peer.add_peers(others) + + node_config.update( + { + "mode": "Edge", + "relay": False, + "store": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + "lightpushnode": lightpush_peer.get_multiaddr_with_id(), + } + ) + + sender_result = WrapperManager.create_and_start( + config=node_config, + event_cb=sender_collector.event_callback, + ) + assert sender_result.is_ok(), f"Failed to start sender: {sender_result.err()}" + + with sender_result.ok_value as sender_node: + sender_multiaddr = get_node_multiaddr(sender_node) + for peer in churn_peers: + peer.add_peers([sender_multiaddr]) + delay(3) # let docker peers connect to the sender + + all_request_ids: list[str] = [] + phase1_ids = self._s31_fire_burst(sender_node, phase_label="phase1") + all_request_ids.extend(phase1_ids) + + for peer in churn_peers: + peer.restart() + delay(1) # small window so the restart is actually in-flight + phase2_ids = self._s31_fire_burst(sender_node, phase_label="phase2") + all_request_ids.extend(phase2_ids) + + # Wait for all peers to be ready again and re-attach the sender. + for peer in churn_peers: + peer.ensure_ready(timeout_duration=20) + peer.add_peers([sender_multiaddr]) + + peer_multiaddrs = [p.get_multiaddr_with_id() for p in churn_peers] + for peer in churn_peers: + others = [a for a in peer_multiaddrs if a != peer.get_multiaddr_with_id()] + peer.add_peers(others) + delay(3) + + phase3_ids = self._s31_fire_burst(sender_node, phase_label="phase3") + all_request_ids.extend(phase3_ids) + + assert len(set(all_request_ids)) == len(all_request_ids), f"Duplicate RequestIds across bursts: {all_request_ids}" + + # Phase 1 ran before any churn, so the mesh was stable — standard timeout. + # Phase 3 ran right after restart + re-attach, so the mesh needed to + # re-stabilize — use the recovery timeout to avoid CI flakiness. + phase_timeouts = [ + (phase1_ids, PROPAGATED_TIMEOUT_S), + (phase3_ids, RECOVERY_TIMEOUT_S), + ] + for request_ids, timeout_s in phase_timeouts: + for request_id in request_ids: + propagated_event = wait_for_propagated( + collector=sender_collector, + request_id=request_id, + timeout_s=timeout_s, + ) + assert propagated_event is not None, ( + f"No MessagePropagatedEvent for stable-phase " + f"request_id={request_id} within {timeout_s}s. " + f"Collected events: {sender_collector.events}" + ) + + error_event = wait_for_error( + collector=sender_collector, + request_id=request_id, + timeout_s=0, + ) + assert error_event is None, f"Unexpected message_error event for stable-phase " f"request_id={request_id}: {error_event}" + + for request_id in phase2_ids: + error_event = wait_for_error( + collector=sender_collector, + request_id=request_id, + timeout_s=0, + ) + assert error_event is None, f"Unexpected terminal message_error for phase-2 " f"request_id={request_id} after recovery: {error_event}" + + issued = set(all_request_ids) + for event in sender_collector.snapshot(): + event_request_id = event.get("requestId") + if event_request_id is None: + continue + assert event_request_id in issued, ( + f"Event carries an unknown requestId={event_request_id!r}, " f"not in issued set {issued}. Event: {event}" + ) + + # Use the hash the wrapper emitted on message_sent so the store + # lookup matches the exact bytes that were actually published. + phase3_hashes = [] + for request_id in phase3_ids: + sent_event = wait_for_sent( + collector=sender_collector, + request_id=request_id, + timeout_s=RECOVERY_TIMEOUT_S, + ) + assert sent_event is not None, ( + f"No message_sent event for phase-3 request_id={request_id} " + f"within {RECOVERY_TIMEOUT_S}s. Collected events: {sender_collector.events}" + ) + msg_hash = sent_event.get("messageHash") + assert msg_hash, f"message_sent event missing messageHash: {sent_event}" + phase3_hashes.append(msg_hash) + + # 3 phases × S31_BURST_SIZE messages, so the page must fit them all, + # otherwise phase-3 hashes (which sort last in ascending order) get cut off. + self.check_sent_message_is_stored( + expected_hashes=phase3_hashes, + store_node=store_peer, + pubsub_topic=self.test_pubsub_topic, + page_size=S31_BURST_SIZE * 3, + ascending="true", + ) + + # Per-request invariants apply across all phases, including the + # retry-path bursts (phase 2). If retries ever emit duplicate + # Propagated events or reorder Sent before Propagated, this catches it. + for request_id in all_request_ids: + assert_event_invariants(sender_collector, request_id) + + def _s31_fire_burst(self, sender_node, *, phase_label: str) -> list[str]: + """Fire S31_BURST_SIZE concurrent sends, one per topic in S31_CONTENT_TOPICS. + Returns the list of RequestIds. Asserts every send returned Ok.""" + messages = [ + self.create_message( + contentTopic=S31_CONTENT_TOPICS[i], + payload=to_base64(f"s31-{phase_label}-{i}"), + ) + for i in range(S31_BURST_SIZE) + ] + + with ThreadPoolExecutor(max_workers=S31_BURST_SIZE) as pool: + send_results = list(pool.map(sender_node.send_message, messages)) + + request_ids = [] + for i, send_result in enumerate(send_results): + assert send_result.is_ok(), f"{phase_label}: concurrent send #{i} failed: {send_result.err()}" + request_id = send_result.ok_value + assert request_id, f"{phase_label}: concurrent send #{i} returned an empty RequestId" + request_ids.append(request_id) + + return request_ids diff --git a/tests-e2e/tests/wrappers_tests/test_send_e2e_part2.py b/tests-e2e/tests/wrappers_tests/test_send_e2e_part2.py new file mode 100644 index 000000000..d7e3f088c --- /dev/null +++ b/tests-e2e/tests/wrappers_tests/test_send_e2e_part2.py @@ -0,0 +1,699 @@ +import base64 +import pytest +from src.steps.common import StepsCommon +from src.libs.common import delay, to_base64 +from src.libs.custom_logger import get_custom_logger +from src.node.wrappers_manager import WrapperManager +from src.node.wrapper_helpers import ( + EventCollector, + assert_event_invariants, + create_message_bindings, + get_node_multiaddr, + wait_for_connected, + wait_for_propagated, + wait_for_sent, + wait_for_error, +) +from tests.wrappers_tests.conftest import build_node_config + +logger = get_custom_logger(__name__) + +PROPAGATED_TIMEOUT_S = 30.0 +SENT_TIMEOUT_S = 10.0 +NO_SENT_OBSERVATION_S = 5.0 +SENT_AFTER_STORE_TIMEOUT_S = 60.0 +OVERSIZED_PAYLOAD_BYTES = 200 * 1024 +RECOVERY_TIMEOUT_S = 45.0 +SERVICE_DOWN_SETTLE_S = 3.0 + +# MaxTimeInCache from send_service.nim. +MAX_TIME_IN_CACHE_S = 60.0 +# Extra slack to cover the background retry loop tick after the window expires. +CACHE_EXPIRY_SLACK_S = 10.0 +ERROR_AFTER_CACHE_EXPIRY_TIMEOUT_S = MAX_TIME_IN_CACHE_S + CACHE_EXPIRY_SLACK_S +RETRY_WINDOW_EXPIRED_MSG = "Unable to send within retry time window" + + +class TestS02AutoSubscribeOnFirstSend(StepsCommon): + """ + S02 — Auto-subscribe on first send. + Sender never calls subscribe_content_topic() before send(). + The send API must auto-subscribe to the content topic used in the message. + Expected: send() returns Ok(RequestId), message_propagated arrives. + """ + + def test_s02_send_without_explicit_subscribe(self, node_config): + sender_collector = EventCollector() + + node_config.update( + { + "relay": True, + "store": False, + "lightpush": False, + "filter": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + } + ) + + sender_result = WrapperManager.create_and_start( + config=node_config, + event_cb=sender_collector.event_callback, + ) + assert sender_result.is_ok(), f"Failed to start sender: {sender_result.err()}" + + with sender_result.ok_value as sender: + peer_config = { + **node_config, + "staticnodes": [get_node_multiaddr(sender)], + "portsShift": 1, + } + + peer_result = WrapperManager.create_and_start(config=peer_config) + assert peer_result.is_ok(), f"Failed to start relay peer: {peer_result.err()}" + + with peer_result.ok_value: + assert wait_for_connected(sender_collector) is not None, "Sender did not reach Connected/PartiallyConnected state" + + message = create_message_bindings( + payload=to_base64("S02 auto-subscribe test payload"), + contentTopic="/test/1/s02-auto-subscribe/proto", + ) + + send_result = sender.send_message(message=message) + assert send_result.is_ok(), f"send() failed: {send_result.err()}" + + request_id = send_result.ok_value + assert request_id, "send() returned an empty RequestId" + + propagated = wait_for_propagated( + collector=sender_collector, + request_id=request_id, + timeout_s=PROPAGATED_TIMEOUT_S, + ) + assert propagated is not None, ( + f"No message_propagated event within {PROPAGATED_TIMEOUT_S}s. " f"Collected events: {sender_collector.events}" + ) + assert propagated["requestId"] == request_id + + error = wait_for_error(sender_collector, request_id, timeout_s=0) + assert error is None, f"Unexpected message_error event: {error}" + + +class TestS06CoreSenderRelayOnly(StepsCommon): + """ + S06 — Core sender with relay peers only, no store. + Sender has local relay enabled and is connected to one relay peer. + Expected: send() returns Ok(RequestId), message_propagated event arrives, + no message_sent (store disabled), no message_error. + """ + + def test_s06_relay_propagation_without_store(self, node_config): + sender_collector = EventCollector() + + node_config.update( + { + "relay": True, + "store": False, + "lightpush": False, + "filter": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + "reliabilityEnabled": True, + } + ) + + sender_result = WrapperManager.create_and_start( + config=node_config, + event_cb=sender_collector.event_callback, + ) + assert sender_result.is_ok(), f"Failed to start sender: {sender_result.err()}" + + with sender_result.ok_value as sender: + peer_config = { + **node_config, + "staticnodes": [get_node_multiaddr(sender)], + "portsShift": 1, + } + + peer_result = WrapperManager.create_and_start(config=peer_config) + assert peer_result.is_ok(), f"Failed to start relay peer: {peer_result.err()}" + + with peer_result.ok_value: + assert wait_for_connected(sender_collector) is not None, "Sender did not reach Connected/PartiallyConnected state" + + message = create_message_bindings( + payload=to_base64("S06 relay-only test payload"), + contentTopic="/test/1/s06-relay-only/proto", + ) + + send_result = sender.send_message(message=message) + assert send_result.is_ok(), f"send() failed: {send_result.err()}" + + request_id = send_result.ok_value + assert request_id, "send() returned an empty RequestId" + + propagated = wait_for_propagated( + collector=sender_collector, + request_id=request_id, + timeout_s=PROPAGATED_TIMEOUT_S, + ) + assert propagated is not None, ( + f"No message_propagated event within {PROPAGATED_TIMEOUT_S}s. " f"Collected events: {sender_collector.events}" + ) + assert propagated["requestId"] == request_id + + error = wait_for_error(sender_collector, request_id, timeout_s=0) + assert error is None, f"Unexpected message_error event: {error}" + + sent = wait_for_sent(sender_collector, request_id, timeout_s=0) + assert sent is None, f"Unexpected message_sent event (store is disabled): {sent}" + + assert_event_invariants(sender_collector, request_id) + + +class TestS07CoreSenderRelayAndStore(StepsCommon): + """ + S07 — Core sender with relay peers and store peer, reliability enabled. + Sender relays message to a store-capable peer; delivery service validates + the message reached the store via p2p reliability check. + Expected: Propagated, then Sent. + """ + + def test_s07_relay_propagation_with_store_validation(self, node_config): + sender_collector = EventCollector() + + node_config.update( + { + "relay": True, + "store": False, + "lightpush": False, + "filter": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + "reliabilityEnabled": True, + } + ) + + sender_result = WrapperManager.create_and_start( + config=node_config, + event_cb=sender_collector.event_callback, + ) + assert sender_result.is_ok(), f"Failed to start sender: {sender_result.err()}" + + with sender_result.ok_value as sender: + peer_config = { + **node_config, + "staticnodes": [get_node_multiaddr(sender)], + "portsShift": 1, + "store": True, + } + + peer_result = WrapperManager.create_and_start(config=peer_config) + assert peer_result.is_ok(), f"Failed to start store peer: {peer_result.err()}" + + with peer_result.ok_value: + message = create_message_bindings( + payload=to_base64("S07 relay+store test payload"), + contentTopic="/test/1/s07-relay-store/proto", + ) + + send_result = sender.send_message(message=message) + assert send_result.is_ok(), f"send() failed: {send_result.err()}" + + request_id = send_result.ok_value + assert request_id, "send() returned an empty RequestId" + + propagated = wait_for_propagated( + collector=sender_collector, + request_id=request_id, + timeout_s=PROPAGATED_TIMEOUT_S, + ) + assert propagated is not None, ( + f"No message_propagated event within {PROPAGATED_TIMEOUT_S}s. " f"Collected events: {sender_collector.events}" + ) + assert propagated["requestId"] == request_id + + sent = wait_for_sent( + collector=sender_collector, + request_id=request_id, + timeout_s=SENT_TIMEOUT_S, + ) + assert sent is not None, ( + f"No message_sent event within {SENT_TIMEOUT_S}s after propagation. " f"Collected events: {sender_collector.events}" + ) + assert sent["requestId"] == request_id + + error = wait_for_error(sender_collector, request_id, timeout_s=0) + assert error is None, f"Unexpected message_error event: {error}" + + assert_event_invariants(sender_collector, request_id) + + +class TestRelayToLightpushFallback(StepsCommon): + """S08/S09 — Relay-to-lightpush fallback. + + Sender has relay enabled but zero gossipsub relay peers. + A lightpush peer is reachable via lightpushnode (no staticnodes). + Relay fails with NO_PEERS_TO_RELAY, lightpush fallback succeeds + in the same processing pass. + + Topology: + [Service] relay=True, lightpush=True + [RelayPeer] relay=True, staticnodes=[service] (gives service gossipsub mesh) + [Sender] relay=True, lightpush=True, lightpushnode=service + (no staticnodes → zero gossipsub relay peers → fallback) + """ + + def test_s08_relay_fallback_to_lightpush(self, node_config): + """S08: no store peer → Propagated only.""" + sender_collector = EventCollector() + + node_config.update( + { + "relay": True, + "lightpush": True, + "store": False, + "filter": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + } + ) + + service_result = WrapperManager.create_and_start(config=node_config) + assert service_result.is_ok(), f"Failed to start service: {service_result.err()}" + + with service_result.ok_value as service: + service_addr = get_node_multiaddr(service) + + relay_config = { + **node_config, + "lightpush": False, + "staticnodes": [service_addr], + "portsShift": 1, + } + relay_result = WrapperManager.create_and_start(config=relay_config) + assert relay_result.is_ok(), f"Failed to start relay peer: {relay_result.err()}" + + with relay_result.ok_value: + sender_config = { + **node_config, + "lightpushnode": service_addr, + "portsShift": 2, + } + sender_result = WrapperManager.create_and_start( + config=sender_config, + event_cb=sender_collector.event_callback, + ) + assert sender_result.is_ok(), f"Failed to start sender: {sender_result.err()}" + + with sender_result.ok_value as sender: + message = create_message_bindings() + send_result = sender.send_message(message=message) + assert send_result.is_ok(), f"send() failed: {send_result.err()}" + + request_id = send_result.ok_value + assert request_id, "send() returned an empty RequestId" + + propagated = wait_for_propagated( + collector=sender_collector, + request_id=request_id, + timeout_s=PROPAGATED_TIMEOUT_S, + ) + assert propagated is not None, ( + f"No message_propagated event within {PROPAGATED_TIMEOUT_S}s. " f"Collected events: {sender_collector.events}" + ) + assert propagated["requestId"] == request_id + + error = wait_for_error(sender_collector, request_id, timeout_s=0) + assert error is None, f"Unexpected message_error event: {error}" + + sent = wait_for_sent(sender_collector, request_id, timeout_s=0) + assert sent is None, f"Unexpected message_sent event (no store peer): {sent}" + + assert_event_invariants(sender_collector, request_id) + + def test_s09_relay_fallback_to_lightpush_with_store_validation(self, node_config): + """S09: S08 + store peer + reliability → Propagated, then Sent.""" + sender_collector = EventCollector() + + node_config.update( + { + "relay": True, + "lightpush": True, + "store": True, + "filter": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + } + ) + + service_result = WrapperManager.create_and_start(config=node_config) + assert service_result.is_ok(), f"Failed to start service: {service_result.err()}" + + with service_result.ok_value as service: + service_addr = get_node_multiaddr(service) + + relay_config = { + **node_config, + "lightpush": False, + "store": False, + "staticnodes": [service_addr], + "portsShift": 1, + } + relay_result = WrapperManager.create_and_start(config=relay_config) + assert relay_result.is_ok(), f"Failed to start relay peer: {relay_result.err()}" + + with relay_result.ok_value: + sender_config = {**node_config, "reliabilityEnabled": True, "storenode": service_addr, "portsShift": 2, "store": False} + sender_result = WrapperManager.create_and_start( + config=sender_config, + event_cb=sender_collector.event_callback, + ) + assert sender_result.is_ok(), f"Failed to start sender: {sender_result.err()}" + + with sender_result.ok_value as sender: + message = create_message_bindings() + send_result = sender.send_message(message=message) + assert send_result.is_ok(), f"send() failed: {send_result.err()}" + + request_id = send_result.ok_value + assert request_id, "send() returned an empty RequestId" + + propagated = wait_for_propagated( + collector=sender_collector, + request_id=request_id, + timeout_s=PROPAGATED_TIMEOUT_S, + ) + assert propagated is not None, ( + f"No message_propagated event within {PROPAGATED_TIMEOUT_S}s. " f"Collected events: {sender_collector.events}" + ) + assert propagated["requestId"] == request_id + + sent = wait_for_sent( + collector=sender_collector, + request_id=request_id, + timeout_s=SENT_AFTER_STORE_TIMEOUT_S, + ) + assert sent is not None, ( + f"No message_sent event within {SENT_AFTER_STORE_TIMEOUT_S}s " + f"after propagation. Collected events: {sender_collector.events}" + ) + assert sent["requestId"] == request_id + + error = wait_for_error(sender_collector, request_id, timeout_s=0) + assert error is None, f"Unexpected message_error event: {error}" + + assert_event_invariants(sender_collector, request_id) + + +class TestS10EdgeSenderLightpushOnly(StepsCommon): + """ + S10 — Edge sender with lightpush path only, no store peer. + Edge sender has no local relay; it publishes via a lightpush service node. + Expected: Propagated only (no Sent, no Error). + """ + + def test_s10_edge_lightpush_propagation(self, node_config): + sender_collector = EventCollector() + + common = { + "store": False, + "filter": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + } + + service_config = build_node_config(relay=True, lightpush=True, **common) + + service_result = WrapperManager.create_and_start(config=service_config) + assert service_result.is_ok(), f"Failed to start service node: {service_result.err()}" + + with service_result.ok_value as service_node: + service_multiaddr = get_node_multiaddr(service_node) + + relay_config = build_node_config( + relay=True, + staticnodes=[service_multiaddr], + **common, + ) + + relay_result = WrapperManager.create_and_start(config=relay_config) + assert relay_result.is_ok(), f"Failed to start relay peer: {relay_result.err()}" + + with relay_result.ok_value: + edge_config = build_node_config( + mode="Edge", + relay=False, + staticnodes=[service_multiaddr], + **common, + ) + + edge_result = WrapperManager.create_and_start( + config=edge_config, + event_cb=sender_collector.event_callback, + ) + assert edge_result.is_ok(), f"Failed to start edge sender: {edge_result.err()}" + + with edge_result.ok_value as edge_sender: + message = create_message_bindings( + payload=to_base64("S10 edge lightpush test payload"), + contentTopic="/test/1/s10-edge-lightpush/proto", + ) + + send_result = edge_sender.send_message(message=message) + assert send_result.is_ok(), f"send() failed: {send_result.err()}" + + request_id = send_result.ok_value + assert request_id, "send() returned an empty RequestId" + + propagated = wait_for_propagated( + collector=sender_collector, + request_id=request_id, + timeout_s=PROPAGATED_TIMEOUT_S, + ) + assert propagated is not None, ( + f"No message_propagated event within {PROPAGATED_TIMEOUT_S}s. " f"Collected events: {sender_collector.events}" + ) + assert propagated["requestId"] == request_id + + sent = wait_for_sent(sender_collector, request_id, timeout_s=NO_SENT_OBSERVATION_S) + assert sent is None, f"Unexpected message_sent event (no store peer): {sent}" + + error = wait_for_error(sender_collector, request_id, timeout_s=0) + assert error is None, f"Unexpected message_error event: {error}" + + assert_event_invariants(sender_collector, request_id) + + +class TestS12IsolatedSenderNoPeers(StepsCommon): + """ + S12 — Isolated sender, no peers. + Sender has relay enabled but zero relay peers and zero lightpush peers. + Expected: send() returns Ok(RequestId), but eventually a message_error + event arrives (no route to propagate). + """ + + def test_s12_send_with_no_peers_produces_error(self, node_config): + sender_collector = EventCollector() + + node_config.update( + { + "relay": True, + "store": False, + "lightpush": False, + "filter": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + } + ) + + sender_result = WrapperManager.create_and_start( + config=node_config, + event_cb=sender_collector.event_callback, + ) + assert sender_result.is_ok(), f"Failed to start sender: {sender_result.err()}" + + with sender_result.ok_value as sender: + message = create_message_bindings( + payload=to_base64("S12 isolated sender payload"), + contentTopic="/test/1/s12-isolated/proto", + ) + + send_result = sender.send_message(message=message) + assert send_result.is_ok(), f"send() must return Ok(RequestId) even with no peers, got: {send_result.err()}" + + request_id = send_result.ok_value + assert request_id, "send() returned an empty RequestId" + + error = wait_for_error( + collector=sender_collector, + request_id=request_id, + timeout_s=ERROR_AFTER_CACHE_EXPIRY_TIMEOUT_S, + ) + assert error is not None, ( + f"No message_error event within {ERROR_AFTER_CACHE_EXPIRY_TIMEOUT_S}s " + f"(MaxTimeInCache={MAX_TIME_IN_CACHE_S}s + slack) for isolated sender. " + f"Collected events: {sender_collector.events}" + ) + assert error["requestId"] == request_id + + propagated = wait_for_propagated(sender_collector, request_id, timeout_s=0) + assert propagated is None, f"Unexpected message_propagated event for isolated sender: {propagated}" + + +class TestS14LightpushNonRetryableError(StepsCommon): + """ + S14 — Lightpush non-retryable error via oversized message. + Edge sender publishes a message exceeding DefaultMaxWakuMessageSize (150KiB) + through a lightpush service node. The server validates message size and + returns INVALID_MESSAGE (420), a non-retryable error. + Expected: send() returns Ok(RequestId), then message_error event. + """ + + def test_s14_oversized_message_triggers_error(self): + sender_collector = EventCollector() + + common = { + "store": False, + "filter": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + } + + service_config = build_node_config(relay=True, lightpush=True, **common) + service_result = WrapperManager.create_and_start(config=service_config) + assert service_result.is_ok(), f"Failed to start service: {service_result.err()}" + + with service_result.ok_value as service: + service_multiaddr = get_node_multiaddr(service) + + edge_config = build_node_config( + mode="Edge", + relay=False, + staticnodes=[service_multiaddr], + **common, + ) + edge_result = WrapperManager.create_and_start( + config=edge_config, + event_cb=sender_collector.event_callback, + ) + assert edge_result.is_ok(), f"Failed to start edge sender: {edge_result.err()}" + + with edge_result.ok_value as edge_sender: + oversized_payload = base64.b64encode(b"x" * OVERSIZED_PAYLOAD_BYTES).decode() + message = create_message_bindings( + payload=oversized_payload, + contentTopic="/test/1/s14-oversized/proto", + ) + + send_result = edge_sender.send_message(message=message) + assert send_result.is_ok(), f"send() failed: {send_result.err()}" + + request_id = send_result.ok_value + assert request_id, "send() returned an empty RequestId" + + error = wait_for_error( + collector=sender_collector, + request_id=request_id, + timeout_s=PROPAGATED_TIMEOUT_S, + ) + assert error is not None, ( + f"No message_error event within {PROPAGATED_TIMEOUT_S}s " + f"after sending oversized message. " + f"Collected events: {sender_collector.events}" + ) + assert error["requestId"] == request_id + logger.info(f"S14 received error event: {error}") + + error_msg = error.get("error", "").lower() + assert "size exceeded" in error_msg, f"Error message doesn't indicate size violation: {error}" + + propagated = wait_for_propagated(sender_collector, request_id, timeout_s=0) + assert propagated is None, f"Unexpected message_propagated for an invalid message: {propagated}" + + assert_event_invariants(sender_collector, request_id) + + +class TestS15LightpushRetryableErrorRecovery(StepsCommon): + """ + S15 — Lightpush retryable error + recovery. + Edge sender publishes via a lightpush service node that has NO relay peers. + The service accepts the lightpush request but returns NO_PEERS_TO_RELAY — + a retryable error (explicitly listed in the S15 spec). The message enters + the retry loop. A relay peer then joins the service node, and the next + retry succeeds. + Expected: send() returns Ok(RequestId), then eventually Propagated. + """ + + def test_s15_lightpush_retryable_error_then_recovery(self): + sender_collector = EventCollector() + + common = { + "store": False, + "filter": False, + "discv5Discovery": False, + "numShardsInNetwork": 1, + } + + service_config = build_node_config(relay=True, lightpush=True, **common) + service_result = WrapperManager.create_and_start(config=service_config) + assert service_result.is_ok(), f"Failed to start service: {service_result.err()}" + + with service_result.ok_value as service: + service_multiaddr = get_node_multiaddr(service) + + edge_config = build_node_config( + mode="Edge", + relay=False, + staticnodes=[service_multiaddr], + **common, + ) + edge_result = WrapperManager.create_and_start( + config=edge_config, + event_cb=sender_collector.event_callback, + ) + assert edge_result.is_ok(), f"Failed to start edge sender: {edge_result.err()}" + + with edge_result.ok_value as edge_sender: + msg = create_message_bindings( + payload=to_base64("S15 retryable error recovery"), + contentTopic="/test/1/s15-recovery/proto", + ) + send_result = edge_sender.send_message(message=msg) + assert send_result.is_ok(), f"send() failed: {send_result.err()}" + request_id = send_result.ok_value + assert request_id, "send() returned an empty RequestId" + + delay(SERVICE_DOWN_SETTLE_S) + + early_propagated = wait_for_propagated(sender_collector, request_id, timeout_s=0) + assert early_propagated is None, ( + f"message_propagated arrived before relay peer joined — " f"retryable error path was not exercised: {early_propagated}" + ) + + relay_config = build_node_config( + relay=True, + staticnodes=[service_multiaddr], + **common, + ) + relay_result = WrapperManager.create_and_start(config=relay_config) + assert relay_result.is_ok(), f"Failed to start relay peer: {relay_result.err()}" + + with relay_result.ok_value: + propagated = wait_for_propagated( + collector=sender_collector, + request_id=request_id, + timeout_s=RECOVERY_TIMEOUT_S, + ) + assert propagated is not None, ( + f"No message_propagated within {RECOVERY_TIMEOUT_S}s " + f"after relay peer joined. " + f"Collected events: {sender_collector.events}" + ) + assert propagated["requestId"] == request_id + + error = wait_for_error(sender_collector, request_id, timeout_s=0) + assert error is None, f"Unexpected message_error after recovery: {error}" + + assert_event_invariants(sender_collector, request_id) diff --git a/tests-e2e/vendor/logos-delivery-python-bindings/lib/.gitkeep b/tests-e2e/vendor/logos-delivery-python-bindings/lib/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/tests-e2e/vendor/logos-delivery-python-bindings/waku/wrapper.py b/tests-e2e/vendor/logos-delivery-python-bindings/waku/wrapper.py new file mode 100644 index 000000000..d23238833 --- /dev/null +++ b/tests-e2e/vendor/logos-delivery-python-bindings/waku/wrapper.py @@ -0,0 +1,392 @@ +import json +import threading + +from cffi import FFI +from pathlib import Path +from result import Result, Ok, Err + +ffi = FFI() + +ffi.cdef( + """ +typedef void (*FFICallBack)(int callerRet, const char *msg, size_t len, void *userData); + +void *logosdelivery_create_node( + const char *configJson, + FFICallBack callback, + void *userData +); + +int logosdelivery_start_node( + void *ctx, + FFICallBack callback, + void *userData +); + +int logosdelivery_stop_node( + void *ctx, + FFICallBack callback, + void *userData +); + +void logosdelivery_set_event_callback( + void *ctx, + FFICallBack callback, + void *userData +); + +int logosdelivery_destroy( + void *ctx, + FFICallBack callback, + void *userData +); + +int logosdelivery_subscribe( + void *ctx, + FFICallBack callback, + void *userData, + const char *contentTopic +); + +int logosdelivery_unsubscribe( + void *ctx, + FFICallBack callback, + void *userData, + const char *contentTopic +); + +int logosdelivery_send( + void *ctx, + FFICallBack callback, + void *userData, + const char *messageJson +); + +int logosdelivery_get_available_node_info_ids( + void *ctx, + FFICallBack callback, + void *userData +); + +int logosdelivery_get_node_info( + void *ctx, + FFICallBack callback, + void *userData, + const char *nodeInfoId +); + +int logosdelivery_get_available_configs( + void *ctx, + FFICallBack callback, + void *userData +); +""" +) + +_repo_root = Path(__file__).resolve().parents[1] +lib = ffi.dlopen(str(_repo_root / "lib" / "liblogosdelivery.so")) + +CallbackType = ffi.callback("void(int, const char*, size_t, void*)") + + +def _new_cb_state(): + return { + "done": threading.Event(), + "ret": None, + "msg": b"", + } + + +def _wait_cb_raw( + state, + op_name: str, + timeout_s: float = 20.0, +) -> Result[tuple[int, bytes], str]: + ok = state["done"].wait(timeout_s) + if not ok: + return Err(f"{op_name}: timeout after {timeout_s}s") + + if state["ret"] is None: + return Err(f"{op_name}: callback ret is None") + + return Ok((state["ret"], state["msg"])) + + +def _wait_cb_ok(state, op_name: str, timeout_s: float = 20.0) -> Result[int, str]: + wait_result = _wait_cb_raw(state, op_name, timeout_s) + if wait_result.is_err(): + return Err(wait_result.err()) + + cb_ret, cb_msg = wait_result.ok_value + if cb_ret != 0: + return Err(f"callback failed in _wait_cb_ok: {op_name} (ret={cb_ret}) msg={cb_msg!r}") + + return Ok(cb_ret) + + +class NodeWrapper: + def __init__(self, ctx, config_buffer, event_cb_handler): + self.ctx = ctx + self._config_buffer = config_buffer + self._event_cb_handler = event_cb_handler + + @staticmethod + def _make_waiting_cb(state): + def c_cb(ret, char_p, length, userData): + msg = ffi.buffer(char_p, length)[:] if char_p != ffi.NULL else b"" + + if not state["done"].is_set(): + state["ret"] = int(ret) + state["msg"] = msg + state["done"].set() + + return CallbackType(c_cb) + + @staticmethod + def _make_event_cb(py_callback): + def c_cb(ret, char_p, length, userData): + msg = ffi.buffer(char_p, length)[:] if char_p != ffi.NULL else b"" + py_callback(int(ret), msg) + + return CallbackType(c_cb) + + @classmethod + def create_node( + cls, + config: dict, + event_cb=None, + *, + timeout_s: float = 20.0, + ) -> Result["NodeWrapper", str]: + config_json = json.dumps(config, separators=(",", ":"), ensure_ascii=False) + config_buffer = ffi.new("char[]", config_json.encode("utf-8")) + + state = _new_cb_state() + cb = cls._make_waiting_cb(state) + + ctx = lib.logosdelivery_create_node( + config_buffer, + cb, + ffi.NULL, + ) + + if ctx == ffi.NULL: + return Err("create_node: ctx is NULL") + + wait_result = _wait_cb_ok(state, "create_node", timeout_s) + if wait_result.is_err(): + return Err(wait_result.err()) + + event_cb_handler = None + if event_cb is not None: + event_cb_handler = cls._make_event_cb(event_cb) + lib.logosdelivery_set_event_callback( + ctx, + event_cb_handler, + ffi.NULL, + ) + + return Ok(cls(ctx, config_buffer, event_cb_handler)) + + @classmethod + def create_and_start( + cls, + config: dict, + event_cb=None, + *, + timeout_s: float = 20.0, + ) -> Result["NodeWrapper", str]: + node_result = cls.create_node( + config=config, + event_cb=event_cb, + timeout_s=timeout_s, + ) + if node_result.is_err(): + return Err(node_result.err()) + + node = node_result.ok_value + + start_result = node.start_node(timeout_s=timeout_s) + if start_result.is_err(): + return Err(start_result.err()) + + return Ok(node) + + def start_node(self, *, timeout_s: float = 20.0) -> Result[int, str]: + state = _new_cb_state() + cb = self._make_waiting_cb(state) + + rc = lib.logosdelivery_start_node(self.ctx, cb, ffi.NULL) + if rc != 0: + return Err(f"start_node: immediate call failed (ret={rc})") + + return _wait_cb_ok(state, "start_node", timeout_s) + + def stop_node(self, *, timeout_s: float = 20.0) -> Result[int, str]: + state = _new_cb_state() + cb = self._make_waiting_cb(state) + + rc = lib.logosdelivery_stop_node(self.ctx, cb, ffi.NULL) + if rc != 0: + return Err(f"stop_node: immediate call failed (ret={rc})") + + return _wait_cb_ok(state, "stop_node", timeout_s) + + def destroy(self, *, timeout_s: float = 20.0) -> Result[int, str]: + state = _new_cb_state() + cb = self._make_waiting_cb(state) + + rc = lib.logosdelivery_destroy(self.ctx, cb, ffi.NULL) + if rc != 0: + return Err(f"destroy: immediate call failed (ret={rc})") + + wait_result = _wait_cb_ok(state, "destroy", timeout_s) + if wait_result.is_err(): + return Err(wait_result.err()) + + self.ctx = ffi.NULL + return wait_result + + def stop_and_destroy(self, *, timeout_s: float = 20.0) -> Result[int, str]: + stop_result = self.stop_node(timeout_s=timeout_s) + if stop_result.is_err(): + return Err(stop_result.err()) + + return self.destroy(timeout_s=timeout_s) + + def subscribe_content_topic(self, content_topic: str, *, timeout_s: float = 20.0) -> Result[int, str]: + state = _new_cb_state() + cb = self._make_waiting_cb(state) + + rc = lib.logosdelivery_subscribe( + self.ctx, + cb, + ffi.NULL, + content_topic.encode("utf-8"), + ) + if rc != 0: + return Err(f"subscribe_content_topic: immediate call failed (ret={rc})") + + return _wait_cb_ok(state, f"subscribe({content_topic})", timeout_s) + + def unsubscribe_content_topic(self, content_topic: str, *, timeout_s: float = 20.0) -> Result[int, str]: + state = _new_cb_state() + cb = self._make_waiting_cb(state) + + rc = lib.logosdelivery_unsubscribe( + self.ctx, + cb, + ffi.NULL, + content_topic.encode("utf-8"), + ) + if rc != 0: + return Err(f"unsubscribe_content_topic: immediate call failed (ret={rc})") + + return _wait_cb_ok(state, f"unsubscribe({content_topic})", timeout_s) + + def send_message(self, message: dict, *, timeout_s: float = 20.0) -> Result[str, str]: + state = _new_cb_state() + cb = self._make_waiting_cb(state) + + message_json = json.dumps(message, separators=(",", ":"), ensure_ascii=False) + + rc = lib.logosdelivery_send( + self.ctx, + cb, + ffi.NULL, + message_json.encode("utf-8"), + ) + if rc != 0: + return Err(f"send_message: immediate call failed (ret={rc})") + + wait_result = _wait_cb_raw(state, "send_message", timeout_s) + if wait_result.is_err(): + return Err(wait_result.err()) + + cb_ret, cb_msg = wait_result.ok_value + if cb_ret != 0: + return Err(f"send_message: callback failed (ret={cb_ret}) msg={cb_msg!r}") + + request_id = cb_msg.decode("utf-8") if cb_msg else "" + return Ok(request_id) + + def get_available_node_info_ids(self, *, timeout_s: float = 20.0) -> Result[list[str], str]: + state = _new_cb_state() + cb = self._make_waiting_cb(state) + + rc = lib.logosdelivery_get_available_node_info_ids(self.ctx, cb, ffi.NULL) + if rc != 0: + return Err(f"get_available_node_info_ids: immediate call failed (ret={rc})") + + wait_result = _wait_cb_raw(state, "get_available_node_info_ids", timeout_s) + if wait_result.is_err(): + return Err(wait_result.err()) + + cb_ret, cb_msg = wait_result.ok_value + if cb_ret != 0: + return Err(f"get_available_node_info_ids: callback failed (ret={cb_ret})") + if not cb_msg: + return Err("get_available_node_info_ids: empty response") + + try: + return Ok(json.loads(cb_msg.decode("utf-8").strip().lstrip("@"))) + except Exception as e: + return Err(f"get_available_node_info_ids: invalid response: {e}") + + def get_node_info(self, node_info_id: str, *, timeout_s: float = 20.0) -> Result[dict, str]: + state = _new_cb_state() + cb = self._make_waiting_cb(state) + + rc = lib.logosdelivery_get_node_info( + self.ctx, + cb, + ffi.NULL, + node_info_id.encode("utf-8"), + ) + if rc != 0: + return Err(f"get_node_info: immediate call failed (ret={rc})") + + wait_result = _wait_cb_raw(state, "get_node_info", timeout_s) + if wait_result.is_err(): + return Err(wait_result.err()) + + cb_ret, cb_msg = wait_result.ok_value + if cb_ret != 0: + return Err(f"get_node_info: callback failed (ret={cb_ret}) msg={cb_msg!r}") + + if not cb_msg: + return Err("get_node_info: empty response") + + try: + result = json.loads(cb_msg.decode("utf-8")) + except Exception as e: + return Err(f"get_node_info: invalid json: {e}") + + return Ok(result) + + def get_available_configs(self, *, timeout_s: float = 20.0) -> Result[dict, str]: + state = _new_cb_state() + cb = self._make_waiting_cb(state) + + rc = lib.logosdelivery_get_available_configs(self.ctx, cb, ffi.NULL) + if rc != 0: + return Err(f"get_available_configs: immediate call failed (ret={rc})") + + wait_result = _wait_cb_raw(state, "get_available_configs", timeout_s) + if wait_result.is_err(): + return Err(wait_result.err()) + + cb_ret, cb_msg = wait_result.ok_value + if cb_ret != 0: + return Err(f"get_available_configs: callback failed (ret={cb_ret}) msg={cb_msg!r}") + + if not cb_msg: + return Err("get_available_configs: empty response") + + try: + result = json.loads(cb_msg.decode("utf-8")) + except Exception as e: + return Err(f"get_available_configs: invalid json: {e}") + + return Ok(result) + From 29861bc28652ade8c866a4d39601b7366caaa586 Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Fri, 24 Jul 2026 07:22:22 +0200 Subject: [PATCH 8/9] chore: bump nim-brokers to 3.3.0 and add nim-brokers skill (#4058) * chore: bump nim-brokers to 3.3.0 and add nim-brokers skill Bump brokers requirement v3.1.4 -> v3.3.0 (nimble, lock, nix/deps.nix) and add the nim-brokers Claude skill copied from nim-brokers master (doc/CLAUDE_brokers_skill.md) at .claude/skills/nim-brokers/SKILL.md. * ci(container-image): serialize wakunode2 and logosdeliverynode builds --- .claude/skills/nim-brokers/SKILL.md | 551 ++++++++++++++++++++++++++ .github/workflows/container-image.yml | 10 +- logos_delivery.nimble | 2 +- nimble.lock | 6 +- nix/deps.nix | 4 +- 5 files changed, 566 insertions(+), 7 deletions(-) create mode 100644 .claude/skills/nim-brokers/SKILL.md diff --git a/.claude/skills/nim-brokers/SKILL.md b/.claude/skills/nim-brokers/SKILL.md new file mode 100644 index 000000000..c066ec493 --- /dev/null +++ b/.claude/skills/nim-brokers/SKILL.md @@ -0,0 +1,551 @@ +--- +name: nim-brokers +description: Reference for writing code against the nim-brokers (`brokers`) nimble package — EventBroker, RequestBroker, MultiRequestBroker, SignalBroker, body sugars (listenIt, provideIt, reprovideIt, onSignalIt), bind* sugar, BrokerContext scoping, (mt) multi-thread variants, the (API) FFI shared-library surface, and BrokerInterface/BrokerImplement. Use when declaring brokers, registering listeners/providers/handlers, emitting or requesting, or exposing brokers to C/C++/Python/Rust/Go. +--- + +# Working with `nim-brokers` + +> Agent skill for any project that depends on the `brokers` nimble package. +> For auto-discovery, copy this file into the consuming project as +> `.claude/skills/nim-brokers/SKILL.md` (or reference it from CLAUDE.md/AGENTS.md). +> Type-safe, decoupled messaging on top of **chronos** + **results**. +> All public APIs are exception-free: errors ride `Result[T, string]`, never raises. + +## Mental model + +Four macros, each declares a **broker type** and generates its full API. The +type *is* the channel — you call class-method-style on the typedesc: `T.emit`, +`T.request`, `T.listen`, `T.setProvider`. No instances, no singletons to wire. + +| Macro | Pattern | Producer side | Consumer side | +|-------|---------|---------------|---------------| +| `EventBroker` | pub/sub, many→many, fire-and-forget | `T.emit(...)` | `T.listen(handler)` | +| `RequestBroker` | request/response, **single** provider | `T.setProvider(handler)` | `T.request(...)` | +| `MultiRequestBroker` | request/response, **many** providers, fan-out | `T.setProvider(handler)` (N×) | `T.request(...)` | +| `SignalBroker` | one-way notification, **single** handler, no reply | `T.signal(...)` | `T.onSignal(handler)` | + +`(mt)` suffix → multi-thread variant (cross-thread dispatch). `(sync)` on +RequestBroker → blocking, non-async. `(API)` → FFI shared-library surface. + +Any provider/handler that is a **class method** (`self.foo`) can be installed +with the `bind*` / `rebind*` sugar instead of a hand-written forwarding closure — +see "Binding class-method providers" below. For inline bodies, each registration +verb also has a **body-sugar form** (`listenIt`, `provideIt` / `reprovideIt`, +`onSignalIt`) that takes a block instead of a lambda — see the per-broker sections. + +Import only what you use: +```nim +import brokers/event_broker +import brokers/request_broker +import brokers/multi_request_broker +import brokers/signal_broker +import brokers/broker_context # only if you need explicit contexts +``` + +--- + +## EventBroker — pub/sub + +```nim +import chronos, brokers/event_broker + +EventBroker: + type UserLoggedIn = object + userId*: int + name*: string + +# listen returns Result[ListenerHandle, string]; keep the handle to drop later +let h = UserLoggedIn.listen( + proc(evt: UserLoggedIn): Future[void] {.async: (raises: []).} = + info "login", id = evt.userId +) + +UserLoggedIn.emit(UserLoggedIn(userId: 7, name: "zoli")) # by value +UserLoggedIn.emit(userId = 7, name = "zoli") # by fields (inline-object only) + +await UserLoggedIn.dropListener(h.get()) # drop one — cancels its in-flight work +await UserLoggedIn.dropAllListeners() # drop all for this context +``` + +- `emit` is **sync `void`** in *every* lane (single-thread, `(mt)`, `(API)`): + snapshots listeners, `asyncSpawn`s each. It does not await delivery — + `await sleepAsync(0)` or yield to flush in tests. Never `await`/`waitFor` an emit. +- Handlers MUST be `{.async: (raises: []).}`. Swallow your own exceptions. +- `dropListener`/`dropAllListeners` are **`async` (`Future[void]`) in every lane** + — `await` them (or `discard`/`waitFor` in sync/`{.thread.}` contexts). Single-thread + cancels in-flight handlers before returning; MT/API bodies are suspension-free. + +### `listenIt` — listener body sugar (all lanes) +```nim +# The block IS the listener body; the event value is injected as `it`. +# Returns listen's Result[Listener, string] — keep it to drop later. +let h2 = UserLoggedIn.listenIt: + echo "login: ", it.name, " (#", it.userId, ")" + +let h3 = UserLoggedIn.listenIt(myCtx): # ctx-scoped form; body may await + await sleepAsync(chronos.milliseconds(1)) + echo "scoped: ", it.name +``` +- `raises: []` is enforced as for a hand-written listener; `void` event types + inject nothing (the block is just the body). + +### Payload variants +```nim +EventBroker: + type Tick = void # payload-less signal: Tick.emit() / listen(proc(): Future[void]...) +EventBroker: + type Score = int # native/alias/external types auto-wrapped in distinct +EventBroker: + type Blob = ref object # ref payloads fine + data*: seq[byte] +``` + +--- + +## RequestBroker — single provider request/response + +Two declaration styles. **Coupled** (named `type` + `proc`) and **proc-sugar** +(payload decoupled, broker named after the Capitalized verb). + +```nim +import chronos, brokers/request_broker + +# Coupled: broker name == type name == request() return payload +RequestBroker: + type FetchUser = object + name*: string + proc signature*(id: int): Future[Result[FetchUser, string]] {.async.} + +FetchUser.setProvider( + proc(id: int): Future[Result[FetchUser, string]] {.async.} = + ok(FetchUser(name: "u" & $id)) +).isOk() + +let r = await FetchUser.request(42) # Result[FetchUser, string] +FetchUser.clearProvider() +``` + +```nim +# Proc-sugar: broker = Capitalized verb, request() returns the RAW payload +RequestBroker: + proc getVersion(): Future[Result[string, string]] {.async.} # -> broker `GetVersion` + +GetVersion.setProvider( + proc(): Future[Result[string, string]] {.async.} = ok("1.2.3")).get() +let v = await GetVersion.request() # r.value is plain string, no unwrap +``` + +Rules & behaviors: +- **One provider per signature.** A second `setProvider` returns `err(...)` (no + silent override). `clearProvider()` first to swap. +- Two signature slots coexist: zero-arg and arg-based (overload by arity). +- Provider exceptions are caught → `err()`. Unset provider → `err(...)`. +- `isProvided()` checks registration. `T.request` is `async` here. + +### `provideIt` / `reprovideIt` — provider body sugar (all lanes) +```nim +# The block is the provider's REAL proc body — the declared signature arg +# names (`id` here) are injected; return / result= / trailing expression work. +discard FetchUser.provideIt: # -> setProvider (keeps "already set" guard) + if id < 0: + return err("bad id: " & $id) + return ok(FetchUser(name: "u" & $id)) + +discard FetchUser.reprovideIt: # -> replaceProvider (swap, no guard) + ok(FetchUser(name: "v2-u" & $id)) # trailing expression works too +``` +- A body that could fall through without producing a value is a **compile + error** (it would silently answer `err("")`) — e.g. a bare `echo` body, or an + `if` without `else` where only one branch returns. +- Dual-slot brokers name the slots explicitly: `provideIt` / `reprovideIt` for + the args slot, `provideItNoArgs` / `reprovideItNoArgs` for the zero-arg slot. +- Sync mode: same sugar, body cannot `await`. Ctx-form: `T.provideIt(ctx): body`. + +### Sync mode — no event loop needed +```nim +RequestBroker(sync): + proc getId(): Result[int, string] # note: no Future, no {.async.} +GetId.setProvider(proc(): Result[int, string] = ok(42)).isOk() +let id = GetId.request() # blocking, returns Result directly +``` + +### void payload (action with no return value) +```nim +RequestBroker: + proc doReset(force: bool): Future[Result[void, string]] {.async.} +DoReset.setProvider(proc(force: bool): Future[Result[void, string]] {.async.} = + if force: ok() else: err("need force")).isOk() +``` + +--- + +## MultiRequestBroker — fan-out to many providers + +Async only. `request()` calls **all** providers via `allFinished`, returns +`Result[seq[Payload], string]`. Any provider failing fails the whole request. + +```nim +import chronos, brokers/multi_request_broker + +MultiRequestBroker: + type Quote = object + price*: int + proc signature*(sym: string): Future[Result[Quote, string]] {.async.} + +discard Quote.setProvider(proc(sym: string): Future[Result[Quote, string]] {.async.} = + ok(Quote(price: 100))) +discard Quote.setProvider(proc(sym: string): Future[Result[Quote, string]] {.async.} = + ok(Quote(price: 101))) + +let all = await Quote.request("BTC") # all.get() is seq[Quote], len == 2 +Quote.removeProvider(handle.get()) # remove one (handle from setProvider) +Quote.clearProviders() # remove all +``` + +- No providers registered → `ok(@[])` (empty, not error). +- Identical handler refs deduplicated on registration. +- `setProvider` returns `Result[ProviderHandle, string]`; capture it for `removeProvider`. + +### `provideIt` — provider body sugar (adds, not replaces) +```nim +# Same body sugar as RequestBroker, but every provideIt ADDS a provider — +# there is NO reprovideIt (no replace verb), and the generated closure is a +# fresh reference, so it never dedups. Returns setProvider's handle. +let h1 = Quote.provideIt: + ok(Quote(price: 100)) +let h2 = Quote.provideIt: # a second provider — NOT a replacement + if sym.len == 0: + return err("empty symbol") + return ok(Quote(price: 101)) + +Quote.removeProvider(h1.get()) # drop just one by its handle +``` +- Dual-slot brokers: `provideIt` = args slot, `provideItNoArgs` = zero-arg slot. +- Same fall-through compile check as RequestBroker's `provideIt`. + +--- + +## SignalBroker — one-way notification, single handler + +Fire-and-forget into a module: an **inverted EventBroker** (single handler, no +reply path). `signal()` is a **plain (non-async) proc** returning +`Result[void, string]`; it does not tell you whether the handler *succeeded* — +only whether it was **accepted**. Handler exceptions are swallowed (chronicles +`warn`). For delivery confirmation, use `RequestBroker` with a `void` response. + +```nim +import chronos, brokers/signal_broker + +SignalBroker: + type IngestSample = object + deviceId*: string + value*: float64 + +# ONE handler (a second onSignal returns err). Handler is async, raises: []. +discard IngestSample.onSignal( + proc(s: IngestSample) {.async: (raises: []).} = + info "sample", dev = s.deviceId, v = s.value) + +let r = IngestSample.signal(IngestSample(deviceId: "d1", value: 0.5)) # by value +discard IngestSample.signal(deviceId = "d2", value = 1.25) # by fields +# r: Result[void, string] +# ok() = ACCEPTED (a handler exists + queue had room) — NOT "handled" +# err() = "no signal handler installed" | "queue full" + +await IngestSample.dropSignalHandler() # async Future[void] — await it +``` + +### `onSignalIt` — handler body sugar (all lanes) +```nim +# Same as listenIt, for the single signal handler: the block is the handler +# body, the signal value is injected as `it`. onSignal's duplicate guard and +# Result return are unchanged. +discard IngestSample.onSignalIt: + echo it.deviceId, " = ", it.value + +discard Wakeup.onSignalIt: echo "tick" # void payload: nothing injected +``` + +- `signal()` is **sync**, never `await` it. `dropSignalHandler()` is **async**. +- `type Foo = void` → payload-less pulse: `Foo.signal()` / `onSignal(proc() ...)`. +- Mock/replace trio (owning-thread only on `(mt)`): `replaceSignalHandler`, + `getCurrentSignalHandler`, `withMockSignalHandler(ctx, mock): body`. +- `(mt)` and `(API)` variants mirror the other brokers (one handler per context). + +--- + +## Binding class-method providers — `bind*` / `rebind*` (v3.1) + +Nim has no bound-method values (`self.send` is not a closure), so installing a +class method as a provider/handler normally needs a hand-written trampoline. The +`bind*` sugar synthesises it — **identical codegen, identical `self` capture**. +Passing a plain closure works too, so it is a strict superset of the typed verbs +(`setProvider` / `listen` / `onSignal` stay untouched). + +```nim +# before — hand-written forwarding closure +MessagingSend.setProvider(self.brokerCtx, + proc(e: MessageEnvelope): Future[Result[RequestId, string]] {.async.} = + await self.send(e)) + +# after — the sugar generates exactly that trampoline +MessagingSend.bindProvider(self.brokerCtx, self.send) +``` + +| Broker | install sugar | replace sugar | +|--------|---------------|---------------| +| `RequestBroker` / `(mt)` | `bindProvider` | `rebindProvider` | +| `MultiRequestBroker` | `bindProvider` (additive) | — | +| `EventBroker` / `(mt)` | `bindListener` (returns the listen handle) | — | +| `SignalBroker` / `(mt)` | `bindSignalHandler` | `rebindSignalHandler` | + +- Each verb has a **ctx-form** (`bindProvider(ctx, m)`) and a **no-ctx-form** + (`bindProvider(m)` → thread-global context). +- Dual-slot RequestBrokers (zero-arg **and** arg signatures) disambiguate by + arity automatically. +- Works on the `(API)` lane too — usable inside `setupProviders(ctx)`. + +--- + +## BrokerContext — scoping / multi-instance + +Every API takes an **optional first `BrokerContext` arg**. Omit it → the +thread-global context (`DefaultBrokerContext`). Use contexts to run independent +broker instances (per component, per test, per thread). + +```nim +import brokers/broker_context + +let ctx = NewBrokerContext() # globally-unique id (atomic) + +discard MyEvent.listen(ctx, handler) +MyEvent.emit(ctx, payload) +FetchUser.setProvider(ctx, provider) +let r = await FetchUser.request(ctx, 42) +await MyEvent.dropAllListeners(ctx) +``` + +Thread setup helpers (callable before the event loop starts): +| Call | Use | +|------|-----| +| `setThreadBrokerContext(ctx)` | adopt a context created elsewhere as this thread's global | +| `initThreadBrokerContext(): BrokerContext` | create + set as thread-global in one call | +| `threadGlobalBrokerContext()` | read current thread global (lock-free) | + +Async scoped swap (needs chronos loop): `lockGlobalBrokerContext` / +`lockNewGlobalBrokerContext` templates. + +--- + +## Multi-thread variants `(mt)` + +Add `(mt)`. **Identical call surface** — `emit` stays sync `void` and `drop*` +stay async (`Future[void]`), so the same source compiles with or without the +tag. Cross-thread dispatch is handled under the hood. Build with `--threads:on`. + +```nim +EventBroker(mt): + type Job = object + id*: int + +# from any thread: +proc worker() {.thread.} = + Job.emit(Job(id: 1)) # emit is sync void — same as single-thread +``` + +- Same-thread calls take a direct fast path; cross-thread go through a per-bucket + channel drained by one dispatch coroutine. fd cost is **O(threads)**, not per-broker. +- A thread that listens must keep its event loop alive (the broker dispatches on it). +- MT brokers accept capacity kwargs: `EventBroker(mt, queueDepth = ..., slabCapacity = ..., + maxPayloadBytes = ..., preset = "...")`. Omit for defaults. + +--- + +## Decision guide + +| You want… | Use | +|-----------|-----| +| Notify N listeners, don't care about replies | `EventBroker` | +| Ask one authority for an answer | `RequestBroker` | +| Blocking call, no async context | `RequestBroker(sync)` | +| Ask everyone, aggregate replies | `MultiRequestBroker` | +| One-way notify a single handler, no reply | `SignalBroker` | +| Same pattern across OS threads | add `(mt)`, `--threads:on` (call surface unchanged) | +| Multiple isolated instances | pass a `BrokerContext` first arg | +| Install a class method (`self.foo`) as provider/handler | `bind*` / `rebind*` sugar | +| Register an inline body without lambda boilerplate | `listenIt` / `provideIt` / `reprovideIt` / `onSignalIt` | +| Expose to C/C++/Python/Rust/Go | `(API)` + `registerBrokerLibrary` (see AGENTS.md) | + +## Gotchas + +- Handlers/providers are `raises: []` — never let an exception escape; return `err()`. +- `setProvider` on a RequestBroker that already has one **fails** — clear first. +- Single-thread `emit` returns immediately; await a yield before asserting in tests. +- A non-`object`/`ref object` broker type is auto-wrapped in `distinct`; construct + with `T(value)` and read with the base-type conversion. +- Keep all interaction with one context on one thread (single-thread brokers are + thread-local); cross-thread requires the `(mt)` variant. + +--- + +## FFI API `(API)` — expose brokers as a C/C++/Python/Rust/Go shared library + +Add `(API)` to `RequestBroker` / `EventBroker` / `SignalBroker`. Same declaration +syntax — it additionally generates a fixed C ABI and typed foreign wrappers. Wire +format is CBOR; wrappers carry the typed surface. Build with `-d:BrokerFfiApi +--threads:on --app:lib`. (`SignalBroker(API)` rides `_call` one-way — enqueue +only, no response slot; `_callAsync` rejects it with `ApiStatusOneWay`.) + +```nim +{.push raises: [].} +import brokers/[event_broker, request_broker, broker_context, api_library] + +# Plain Nim object types used in signatures are AUTO-registered — no annotation. +type DeviceInfo* = object + deviceId*: int64 + name*: string + online*: bool + +RequestBroker(API): + type GetDevice = object # broker name == type name == response payload + deviceId*: int64 + name*: string + proc signature*(deviceId: int64): Future[Result[GetDevice, string]] {.async.} + +EventBroker(API): + type DeviceStatusChanged = object + deviceId*: int64 + online*: bool + timestampMs*: int64 +``` + +Providers + event emission live in one proc named **`setupProviders`** (the +generated runtime calls it on the processing thread during `createContext`): + +```nim +proc setupProviders(ctx: BrokerContext): Result[void, string] = + let r = GetDevice.setProvider(ctx, # always pass the ctx the runtime gives you + proc(deviceId: int64): Future[Result[GetDevice, string]] {.closure, async.} = + DeviceStatusChanged.emit(ctx, # emit is sync void (all lanes) + DeviceStatusChanged(deviceId: deviceId, online: true, timestampMs: 0)) + ok(GetDevice(deviceId: deviceId, name: "u"))) + if r.isErr(): return err("register GetDevice: " & r.error()) + ok() + +# MUST be the last declaration in the module: +registerBrokerLibrary: + name: "mylib" # MUST match --nimMainPrefix and the .so basename + version: "1.0.0" # baked into _version() static string + initializeRequest: InitializeRequest # post-create config broker (optional) + shutdownRequest: ShutdownRequest # orderly teardown broker (optional) +{.pop.} +``` + +Build (name / `--nimMainPrefix` / `registerBrokerLibrary name` must all match): +``` +nim c -d:BrokerFfiApi --threads:on --app:lib --path:. \ + --outdir:build --nimMainPrefix:mylib mylib.nim +``` + +What you get — a fixed **12-function C ABI** per library: `_version`, +`_initialize` (once per process), `_createContext` (per instance), `_shutdown(ctx)`, +`_allocBuffer`, `_freeBuffer`, `_call` (sync round-trip), `_callAsync` +(non-blocking, callback-completed), `_subscribe`, `_unsubscribe`, `_listApis`, +`_getSchema`. `.h` (C) and `.hpp` (C++) are always emitted. Wire format +is CBOR (the historical native C-ABI codegen was retired in 3.0.0). + +| Flag | Emits | Notes | +|------|-------|-------| +| *(default)* | `.h`, `.hpp` | C + C++ always | +| `-d:BrokerFfiApiGenPy` | `.py` (cbor2) | next to the `.so` | +| `-d:BrokerFfiApiGenRust` | `_rs/` Cargo crate | ciborium + serde | +| `-d:BrokerFfiApiGenGo` | `_go/` Go module | fxamacker/cbor | + +FFI rules: +- `registerBrokerLibrary` is a **no-op without `-d:BrokerFfiApi`** — no `when defined` + guard needed; the normal in-process broker API still works. +- `(API)` brokers ride the MT lane, so they accept the same capacity kwargs as + `(mt)`: `RequestBroker(API, queueDepth = .., slabCapacity = .., maxPayloadBytes = .., + preset = "..")`. +- `_createContext()` is readiness-synchronous: returns only after providers + + listeners are installed and the event courier is live. +- Inspect generated Nim with `-d:brokerDebug` → `build/broker_debug/*.gen.nim`. + +--- + +## BrokerInterface / BrokerImplement — hierarchical / OOP layer + +An object-oriented facade over the brokers: an **interface** groups several +brokers behind one abstract type; an **implementation** provides per-instance +methods. Each instance gets its own `BrokerContext`, so two instances of the same +impl are fully isolated. Direct `instance.method()` calls **tunnel through broker +dispatch** (so provider mocks are honored — not a plain vtable call). + +```nim +import brokers/broker_interface +import brokers/broker_implement + +BrokerInterface(IGreeter): + EventBroker: + type Greeted = object + who: string + RequestBroker: + proc greet(name: string): Future[Result[string, string]] {.async.} + RequestBroker: + proc version(): Future[Result[string, string]] {.async.} + +type GreeterImpl = ref object of IGreeter # MUST be `ref object of ` + prefix: string + +BrokerImplement GreeterImpl of IGreeter: + proc new(T: typedesc[GreeterImpl], prefix: string): GreeterImpl = + GreeterImpl(prefix: prefix) # optional ctor; create() calls it + method greet(self: GreeterImpl, name: string): Future[Result[string, string]] {.async.} = + ok(self.prefix & name) + method version(self: GreeterImpl): Future[Result[string, string]] {.async.} = + ok("v2") +``` + +Use it: +```nim +let g = GreeterImpl.create(prefix = "hi ") # new() + wires providers under g.brokerCtx +echo (waitFor g.greet("sue")).value # "hi sue" — tunnels through Greet broker + +let base: IGreeter = g # virtual dispatch via the interface type +echo (waitFor base.greet("x")).value # resolves to the override + +# Each instance is isolated by its own context: +let a = GreeterImpl.create(prefix = "a:") +let b = GreeterImpl.create(prefix = "b:") +# a.brokerCtx != b.brokerCtx + +g.close() # clears THIS instance's providers + listeners; idempotent +``` + +Event facade (instance-scoped listen/emit — context is injected for you): +```nim +discard g.listen(Greeted, + proc(ev: Greeted): Future[void] {.async: (raises: []), gcsafe.} = …) +g.emit(Greeted, Greeted(who: "bob")) +``` + +Factory / dependency injection (resolve an impl behind the interface): +```nim +IGreeter.provideFactory( + proc(cfg: string): Result[IGreeter, string] = + ok(GreeterImpl.create(prefix = cfg))) +let d = IGreeter.create("cfg:") # Result[IGreeter, string]; last factory wins +``` + +Key points: +- The broker for `proc greet` is named **`Greet`** (Capitalized verb). Address it + directly with the instance context: `Greet.request(g.brokerCtx, "bob")`, + `Greet.clearProvider(g.brokerCtx)` (e.g. to install a mock). +- `Impl.create(args…)` = fresh context + `new` + provider wiring. + `Impl.createUnderContext(ctx, args…)` wires under an externally-supplied context + (the path the FFI runtime drives). +- `BrokerInterface(API, IName)` lowers the sub-brokers onto the MT/FFI lane so the + whole interface can be exposed as a shared library; `BrokerImplement` is unchanged. +- Sub-instances returned from a method (factory pattern) share the parent's + `classCtx` (routing) but get a distinct `instanceCtx` — see `classCtx()` / + `instanceCtx()` accessors. diff --git a/.github/workflows/container-image.yml b/.github/workflows/container-image.yml index 432858cf5..0c1f37682 100644 --- a/.github/workflows/container-image.yml +++ b/.github/workflows/container-image.yml @@ -86,8 +86,16 @@ jobs: - name: Build binaries id: build if: ${{ steps.secrets.outcome == 'success' }} + # Sequential make invocations: wakunode2 and logosdeliverynode each run + # via `nimble `. Under a single `make -j` the two nimble + # invocations re-resolve git deps concurrently and clobber each other + # in the shared ~/.nimble/pkgcache (e.g. "destination already exists", + # "fetch-pack: invalid index-pack output"), failing the build. + # Serializing the targets removes the race; Nim's own --parallelBuild + # still parallelizes compilation. Mirrors the -j1 fix in ci.yml. run: | - make -j${NPROC} V=1 POSTGRES=1 NIMFLAGS="-d:disableMarchNative -d:chronicles_colors:none" wakunode2 logosdeliverynode + make -j${NPROC} V=1 POSTGRES=1 NIMFLAGS="-d:disableMarchNative -d:chronicles_colors:none" wakunode2 + make -j${NPROC} V=1 POSTGRES=1 NIMFLAGS="-d:disableMarchNative -d:chronicles_colors:none" logosdeliverynode SHORT_REF=$(git rev-parse --short HEAD) diff --git a/logos_delivery.nimble b/logos_delivery.nimble index 275bd1a89..01ca35c94 100644 --- a/logos_delivery.nimble +++ b/logos_delivery.nimble @@ -65,7 +65,7 @@ requires "https://github.com/logos-messaging/nim-ffi#v0.1.3" requires "https://github.com/logos-messaging/nim-sds.git#b12f5ee07c5b764303b51fb948b32a4ade1de3b5" -requires "https://github.com/NagyZoltanPeter/nim-brokers.git#v3.1.4" +requires "https://github.com/NagyZoltanPeter/nim-brokers.git#v3.3.0" requires "https://github.com/vacp2p/nim-lsquic.git#v0.5.1" requires "https://github.com/vacp2p/nim-jwt.git#057ec95eb5af0eea9c49bfe9025b3312c95dc5f2" diff --git a/nimble.lock b/nimble.lock index 03bb7a434..229a705c7 100644 --- a/nimble.lock +++ b/nimble.lock @@ -328,8 +328,8 @@ } }, "brokers": { - "version": "#v3.1.4", - "vcsRevision": "8ae9e963b0b4478c93e6f888be6a46654da787de", + "version": "#v3.3.0", + "vcsRevision": "19565dd80621e33f6da396ef3fb07c379d55c324", "url": "https://github.com/NagyZoltanPeter/nim-brokers.git", "downloadMethod": "git", "dependencies": [ @@ -341,7 +341,7 @@ "cbor_serialization" ], "checksums": { - "sha1": "2949398033c1b3a2586f0afd7e92f46b9a0a412e" + "sha1": "2a17814c257c3182ea24726d4be0c46c3d48bbaa" } }, "stint": { diff --git a/nix/deps.nix b/nix/deps.nix index 63b01f8af..ba4d567fa 100644 --- a/nix/deps.nix +++ b/nix/deps.nix @@ -159,8 +159,8 @@ brokers = pkgs.fetchgit { url = "https://github.com/NagyZoltanPeter/nim-brokers.git"; - rev = "8ae9e963b0b4478c93e6f888be6a46654da787de"; - sha256 = "0r3vrc6h9jiwhd3p4sy3j8gx3k5174s77qcp2wrswclvfvbskw5y"; + rev = "19565dd80621e33f6da396ef3fb07c379d55c324"; + sha256 = "0jnn44pk587ck1l3ghjgy93d32fpxf0bjshri5ksnqjif2b7pdm9"; fetchSubmodules = true; }; From 296460a407cecaa743787173ddd2abc2d7b8ad9e Mon Sep 17 00:00:00 2001 From: Fabiana Cecin Date: Fri, 24 Jul 2026 09:41:35 -0300 Subject: [PATCH 9/9] fix: dial QUIC before TCP regardless of address list order (#4061) --- logos_delivery/waku/node/delivery_dialer.nim | 63 ++++++++++ logos_delivery/waku/node/waku_switch.nim | 5 +- logos_delivery/waku/waku_core/peers.nim | 10 +- tests/test_peer_manager.nim | 114 ++++++++++++++++++- tests/test_wakunode.nim | 18 --- 5 files changed, 182 insertions(+), 28 deletions(-) create mode 100644 logos_delivery/waku/node/delivery_dialer.nim diff --git a/logos_delivery/waku/node/delivery_dialer.nim b/logos_delivery/waku/node/delivery_dialer.nim new file mode 100644 index 000000000..5d34a33c5 --- /dev/null +++ b/logos_delivery/waku/node/delivery_dialer.nim @@ -0,0 +1,63 @@ +{.push raises: [].} + +import std/[sequtils, strutils] +import chronos, results +import + libp2p/dial, + libp2p/dialer, + libp2p/switch, + libp2p/peerid, + libp2p/multiaddress, + libp2p/stream/connection, + libp2p/muxers/muxer + +export dialer + +proc sortQuicFirst(addrs: seq[MultiAddress]): seq[MultiAddress] = + addrs.filterIt("/quic-v1" in $it) & addrs.filterIt("/quic-v1" notin $it) + +type DeliveryDialer* = ref object of Dialer + ## Logos Delivery dial policy layer. Replaces the switch dialer; every + ## dial in the process goes through here. Dials quic addresses before tcp. + +proc install*(T: typedesc[DeliveryDialer], switch: Switch) = + switch.dialer = DeliveryDialer.new( + switch.peerInfo.peerId, switch.connManager, switch.peerStore, switch.transports, + switch.ms, switch.nameResolver, + ) + +method connect*( + self: DeliveryDialer, + peerId: PeerId, + addrs: seq[MultiAddress], + forceDial = false, + reuseConnection = true, + dir = Direction.Out, +) {.async: (raises: [DialFailedError, CancelledError]).} = + await procCall Dialer(self).connect( + peerId, sortQuicFirst(addrs), forceDial, reuseConnection, dir + ) + +method dial*( + self: DeliveryDialer, + peerId: PeerId, + addrs: seq[MultiAddress], + protos: seq[string], + forceDial = false, +): Future[Stream] {.async: (raises: [DialFailedError, CancelledError]).} = + await procCall Dialer(self).dial(peerId, sortQuicFirst(addrs), protos, forceDial) + +method dialAndUpgrade*( + self: DeliveryDialer, + peerId: Opt[PeerId], + addrs: seq[MultiAddress], + dir = Direction.Out, +): Future[Muxer] {. + async: (raises: [CancelledError, MaError, TransportAddressError, LPError]) +.} = + await procCall Dialer(self).dialAndUpgrade(peerId, sortQuicFirst(addrs), dir) + +method tryDial*( + self: DeliveryDialer, peerId: PeerId, addrs: seq[MultiAddress] +): Future[Opt[MultiAddress]] {.async: (raises: [DialFailedError, CancelledError]).} = + await procCall Dialer(self).tryDial(peerId, sortQuicFirst(addrs)) diff --git a/logos_delivery/waku/node/waku_switch.nim b/logos_delivery/waku/node/waku_switch.nim index e0983cbee..37e2b99af 100644 --- a/logos_delivery/waku/node/waku_switch.nim +++ b/logos_delivery/waku/node/waku_switch.nim @@ -14,6 +14,7 @@ import libp2p/builders, libp2p/switch, libp2p/transports/[transport, tcptransport, wstransport] +import ./delivery_dialer # override nim-libp2p default value (which is also 1) const MaxConnectionsPerPeer* = 1 @@ -132,4 +133,6 @@ proc newWakuSwitch*( if not rendezvous.isNil(): b = b.withRendezVous() - b.build() + let switch = b.build() + DeliveryDialer.install(switch) + switch diff --git a/logos_delivery/waku/waku_core/peers.nim b/logos_delivery/waku/waku_core/peers.nim index 5fca2a649..f88840afa 100644 --- a/logos_delivery/waku/waku_core/peers.nim +++ b/logos_delivery/waku/waku_core/peers.nim @@ -251,13 +251,9 @@ proc parseUrlPeerAddr*(peerAddr: Opt[string]): Result[Opt[RemotePeerInfo], strin return ok(Opt.some(parsedPeerInfo)) -proc sortQuicFirst(addrs: seq[MultiAddress]): seq[MultiAddress] = - ## QUIC addresses first, so they are dialed ahead of TCP. - addrs.filterIt("/quic-v1" in $it) & addrs.filterIt("/quic-v1" notin $it) - proc toRemotePeerInfo*(enrRec: enr.Record): Result[RemotePeerInfo, cstring] = ## enr to dialable RemotePeerInfo. tcp from tcp/tcp6 fields, quic from the - ## multiaddrs ext (udp field is discv5, not quic). quic sorted first. + ## multiaddrs ext (udp field is discv5, not quic). let typedR = enrRec.toTyped().valueOr: return err(cstring("enr: failed to construct typed record: " & $error)) if not typedR.secp256k1.isSome(): @@ -296,8 +292,6 @@ proc toRemotePeerInfo*(enrRec: enr.Record): Result[RemotePeerInfo, cstring] = if addrs.len == 0: return err("enr: no dialable addresses in record") - addrs = sortQuicFirst(addrs) - let protocolsRes = catch: enrRec.getCapabilitiesCodecs() @@ -320,7 +314,7 @@ converter toRemotePeerInfo*(peerInfo: PeerInfo): RemotePeerInfo = ## Useful for testing or internal connections RemotePeerInfo( peerId: peerInfo.peerId, - addrs: sortQuicFirst(peerInfo.listenAddrs), + addrs: peerInfo.listenAddrs, enr: Opt.none(enr.Record), protocols: peerInfo.protocols, shards: @[], diff --git a/tests/test_peer_manager.nim b/tests/test_peer_manager.nim index e2f5a5a26..bd747299a 100644 --- a/tests/test_peer_manager.nim +++ b/tests/test_peer_manager.nim @@ -1,7 +1,7 @@ {.used.} import - std/[sequtils, times, sugar, net], + std/[sequtils, strutils, times, sugar, net], results, testutils/unittests, chronos, @@ -61,6 +61,118 @@ procSuite "Peer Manager": nodes[0].peerManager.switch.peerStore.connectedness(nodes[1].peerInfo.peerId) == Connectedness.Connected + asyncTest "connectPeer() prefers quic even when tcp is listed first": + ## Announced address lists are tcp-first and identify rewrites the + ## address book with that order after every connection, so dial paths + ## must reorder quic ahead of tcp themselves. + let nodes = toSeq(0 ..< 2).mapIt(newTestWakuNode(generateSecp256k1Key())) + await allFutures(nodes.mapIt(it.start())) + + let announced = nodes[1].peerInfo.toRemotePeerInfo().addrs + let tcpFirst = + announced.filterIt("/quic-v1" notin $it) & announced.filterIt("/quic-v1" in $it) + require tcpFirst.anyIt("/quic-v1" in $it) + require "/quic-v1" notin $tcpFirst[0] + + let peer = RemotePeerInfo.init(nodes[1].peerInfo.peerId, tcpFirst) + require await nodes[0].peerManager.connectPeer(peer) + await sleepAsync(chronos.milliseconds(200)) + + let conns = nodes[0].peerManager.switch.connManager.getConnections().getOrDefault( + nodes[1].peerInfo.peerId + ) + require conns.len >= 1 + let obsAddr = conns[0].connection.observedAddr + check: + obsAddr.isSome() + "/quic-v1" in $obsAddr.get() + + await allFutures(nodes.mapIt(it.stop())) + + asyncTest "reconnect after identify address book refresh still dials quic": + ## The original quic-to-tcp drift: identify rewrites the address book + ## with the peer's announced tcp-first order after every connection, so + ## reconnects from the book must still come out quic. + let nodes = toSeq(0 ..< 2).mapIt(newTestWakuNode(generateSecp256k1Key())) + await allFutures(nodes.mapIt(it.start())) + let peerId = nodes[1].peerInfo.peerId + + require await nodes[0].peerManager.connectPeer(nodes[1].peerInfo.toRemotePeerInfo()) + await sleepAsync(chronos.milliseconds(500)) + + # identify must have populated the book with a dual-stack address set + let bookAddrs = nodes[0].peerManager.switch.peerStore[AddressBook][peerId] + require bookAddrs.anyIt("/quic-v1" in $it) + require bookAddrs.anyIt("/quic-v1" notin $it) + + # pin the book to tcp-first, as identify writes it today + let tcpFirst = + bookAddrs.filterIt("/quic-v1" notin $it) & bookAddrs.filterIt("/quic-v1" in $it) + nodes[0].peerManager.switch.peerStore[AddressBook][peerId] = tcpFirst + + await nodes[0].peerManager.disconnectNode(peerId) + await sleepAsync(chronos.milliseconds(500)) + + require await nodes[0].peerManager.connectPeer( + RemotePeerInfo.init(peerId, tcpFirst) + ) + let conns = + nodes[0].peerManager.switch.connManager.getConnections().getOrDefault(peerId) + require conns.len >= 1 + let obsAddr = conns[0].connection.observedAddr + check: + obsAddr.isSome() + "/quic-v1" in $obsAddr.get() + + await allFutures(nodes.mapIt(it.stop())) + + asyncTest "protocol stream dial from tcp-first address book uses quic": + ## dialPeer(peerId, proto) resolves addresses from the address book and + ## must also come out quic when the book is tcp-first. + let nodes = toSeq(0 ..< 2).mapIt(newTestWakuNode(generateSecp256k1Key())) + await allFutures(nodes.mapIt(it.start())) + let peerId = nodes[1].peerInfo.peerId + + let announced = nodes[1].peerInfo.toRemotePeerInfo().addrs + let tcpFirst = + announced.filterIt("/quic-v1" notin $it) & announced.filterIt("/quic-v1" in $it) + require "/quic-v1" notin $tcpFirst[0] + nodes[0].peerManager.addPeer(RemotePeerInfo.init(peerId, tcpFirst)) + + let connOpt = await nodes[0].peerManager.dialPeer(peerId, "/ipfs/id/1.0.0") + require connOpt.isSome() + let obsAddr = connOpt.get().observedAddr + check: + obsAddr.isSome() + "/quic-v1" in $obsAddr.get() + + await allFutures(nodes.mapIt(it.stop())) + + asyncTest "tcp-only dialer connects to a quic-first address list": + ## A node without quic support must skip quic addresses at no cost and + ## connect over tcp. + let dialer = newTestWakuNode(generateSecp256k1Key(), quicEnabled = false) + let server = newTestWakuNode(generateSecp256k1Key()) + await allFutures(dialer.start(), server.start()) + + let announced = server.peerInfo.toRemotePeerInfo().addrs + let quicFirst = + announced.filterIt("/quic-v1" in $it) & announced.filterIt("/quic-v1" notin $it) + require "/quic-v1" in $quicFirst[0] + + let peer = RemotePeerInfo.init(server.peerInfo.peerId, quicFirst) + require await dialer.peerManager.connectPeer(peer) + let conns = dialer.peerManager.switch.connManager.getConnections().getOrDefault( + server.peerInfo.peerId + ) + require conns.len >= 1 + let obsAddr = conns[0].connection.observedAddr + check: + obsAddr.isSome() + "/quic-v1" notin $obsAddr.get() + + await allFutures(dialer.stop(), server.stop()) + asyncTest "Peer manager tracks active store request state": let nodes = toSeq(0 ..< 2).mapIt(newTestWakuNode(generateSecp256k1Key())) diff --git a/tests/test_wakunode.nim b/tests/test_wakunode.nim index a607c9f2c..d6c6f8cd4 100644 --- a/tests/test_wakunode.nim +++ b/tests/test_wakunode.nim @@ -242,24 +242,6 @@ suite "WakuNode": await node.stop() - test "toRemotePeerInfo sorts quic-v1 addresses first": - let - nodeKey = generateSecp256k1Key() - node = newTestWakuNode(nodeKey, quicEnabled = true) - - # peerinfo path - let fromPeerInfo = node.switch.peerInfo.toRemotePeerInfo() - check: - fromPeerInfo.addrs.anyIt("/quic-v1" in $it) - "/quic-v1" in $fromPeerInfo.addrs[0] - - # enr path - let fromEnr = toRemotePeerInfo(node.enr).valueOr: - raiseAssert "toRemotePeerInfo(enr) failed: " & $error - check: - fromEnr.addrs.anyIt("/quic-v1" in $it) - "/quic-v1" in $fromEnr.addrs[0] - asyncTest "Dual-stack nodes connect over QUIC": let nodeKey1 = generateSecp256k1Key()