From 2f6de9187f2962e717ef9edcc4ae549461dd515f Mon Sep 17 00:00:00 2001 From: Ivan Folgueira Bande Date: Thu, 2 Oct 2025 11:52:12 +0200 Subject: [PATCH] Squashed 'third-party/nwaku/' content from commit d94cb7c7 git-subtree-dir: third-party/nwaku git-subtree-split: d94cb7c73631ffd4b934839ba58bc622d331a135 --- .dockerignore | 9 + .editorconfig | 18 + .github/ISSUE_TEMPLATE/bug_report.md | 34 + .github/ISSUE_TEMPLATE/bump_dependencies.md | 48 + .github/ISSUE_TEMPLATE/feature_request.md | 26 + .github/ISSUE_TEMPLATE/improvement.md | 17 + .github/ISSUE_TEMPLATE/milestone.md | 41 + .github/ISSUE_TEMPLATE/prepare_release.md | 72 + .../ISSUE_TEMPLATE/research-related-issue.md | 19 + .github/pull_request_template.md | 8 + .github/workflows/auto_assign_pr.yml | 12 + .github/workflows/ci.yml | 191 + .github/workflows/container-image.yml | 99 + .github/workflows/pr-lint.yml | 54 + .github/workflows/pre-release.yml | 163 + .github/workflows/release-assets.yml | 65 + .github/workflows/sync-labels.yml | 17 + .github/workflows/windows-build.yml | 104 + .gitignore | 81 + .gitmodules | 190 + .sv4git.yml | 22 + .sv4git/templates/releasenotes-md.tpl | 8 + .sv4git/templates/rn-md-section-commits.tpl | 7 + CHANGELOG.md | 2495 +++++ Dockerfile | 93 + Dockerfile.lightpushWithMix.compile | 58 + LICENSE-APACHEv2 | 205 + LICENSE-MIT | 25 + Makefile | 546 + README.md | 186 + apps/benchmarks/benchmarks.nim | 74 + apps/chat2/chat2.nim | 626 ++ apps/chat2/config_chat2.nim | 351 + apps/chat2/nim.cfg | 4 + apps/chat2bridge/chat2bridge.nim | 328 + apps/chat2bridge/config_chat2bridge.nim | 148 + apps/chat2bridge/nim.cfg | 4 + apps/chat2mix/chat2mix.nim | 703 ++ apps/chat2mix/config_chat2mix.nim | 293 + apps/chat2mix/nim.cfg | 4 + apps/liteprotocoltester/.env | 27 + .../Dockerfile.liteprotocoltester | 37 + .../Dockerfile.liteprotocoltester.compile | 76 + apps/liteprotocoltester/README.md | 329 + .../diagnose_connections.nim | 65 + .../docker-compose-on-simularor.yml | 227 + apps/liteprotocoltester/docker-compose.yml | 172 + apps/liteprotocoltester/infra.env | 11 + apps/liteprotocoltester/legacy_publisher.nim | 24 + .../liteprotocoltester/liteprotocoltester.nim | 217 + apps/liteprotocoltester/lpt_metrics.nim | 56 + apps/liteprotocoltester/lpt_supervisor.py | 54 + .../customizations/custom-logo.png | Bin 0 -> 10938 bytes .../customizations/custom-logo.svg | 3 + .../monitoring/configuration/dashboards.yaml | 9 + .../liter-protocol-test-monitoring.json | 1949 ++++ .../monitoring/configuration/datasources.yaml | 11 + .../configuration/grafana-plugins.env | 2 + .../monitoring/configuration/grafana.ini | 53 + .../monitoring/prometheus-config.yml | 35 + apps/liteprotocoltester/nim.cfg | 4 + apps/liteprotocoltester/publisher.nim | 272 + apps/liteprotocoltester/publisher_base.nim | 14 + apps/liteprotocoltester/receiver.nim | 182 + apps/liteprotocoltester/run_service_node.sh | 63 + apps/liteprotocoltester/run_tester_node.sh | 161 + .../run_tester_node_at_infra.sh | 119 + .../run_tester_node_on_fleet.sh | 118 + .../service_peer_management.nim | 223 + apps/liteprotocoltester/statistics.nim | 336 + apps/liteprotocoltester/tester_config.nim | 208 + apps/liteprotocoltester/tester_message.nim | 121 + apps/liteprotocoltester/v3_publisher.nim | 29 + apps/networkmonitor/README.md | 84 + apps/networkmonitor/docker-compose.yml | 34 + apps/networkmonitor/networkmonitor.nim | 668 ++ apps/networkmonitor/networkmonitor_config.nim | 190 + .../networkmonitor/networkmonitor_metrics.nim | 107 + apps/networkmonitor/networkmonitor_utils.nim | 53 + apps/networkmonitor/nim.cfg | 4 + apps/networkmonitor/prometheus.yaml | 9 + apps/sonda/.env.example | 44 + apps/sonda/.gitignore | 4 + apps/sonda/Dockerfile.sonda | 23 + apps/sonda/README.md | 52 + apps/sonda/docker-compose.yml | 114 + .../customizations/custom-logo.png | Bin 0 -> 10938 bytes .../customizations/custom-logo.svg | 3 + .../monitoring/configuration/dashboards.yaml | 9 + .../dashboards/nwaku-monitoring.json | 5303 ++++++++++ .../dashboards/sonda-monitoring.json | 1571 +++ .../monitoring/configuration/datasources.yaml | 11 + .../configuration/grafana-plugins.env | 2 + .../monitoring/configuration/grafana.ini | 51 + apps/sonda/monitoring/prometheus-config.yml | 10 + apps/sonda/register_rln.sh | 31 + apps/sonda/run_node.sh | 110 + apps/sonda/sonda.py | 207 + apps/wakucanary/README.md | 58 + apps/wakucanary/certsgenerator.nim | 37 + apps/wakucanary/nim.cfg | 4 + apps/wakucanary/wakucanary.nim | 300 + apps/wakunode2/nim.cfg | 10 + apps/wakunode2/wakunode2.nim | 102 + ci/Jenkinsfile.lpt | 95 + ci/Jenkinsfile.prs | 137 + ci/Jenkinsfile.release | 146 + config.nims | 127 + docker/binaries/Dockerfile.bn.amd64 | 31 + docker/binaries/Dockerfile.bn.local | 63 + docs/api/node.md | 94 + docs/api/rest-api.md | 43 + docs/benchmarks/cspell.json | 20 + .../digram_multiple_nodes_one_database.png | Bin 0 -> 206077 bytes docs/benchmarks/imgs/insert-time-dist-2.png | Bin 0 -> 24921 bytes docs/benchmarks/imgs/insert-time-dist-3.png | Bin 0 -> 24443 bytes docs/benchmarks/imgs/insert-time-dist-4.png | Bin 0 -> 23470 bytes docs/benchmarks/imgs/insert-time-dist-5.png | Bin 0 -> 25031 bytes docs/benchmarks/imgs/insert-time-dist-6.png | Bin 0 -> 23649 bytes .../imgs/insert-time-dist-postgres-2.png | Bin 0 -> 20367 bytes .../imgs/insert-time-dist-postgres-3.png | Bin 0 -> 19415 bytes .../imgs/insert-time-dist-postgres.png | Bin 0 -> 17796 bytes docs/benchmarks/imgs/insert-time-dist.png | Bin 0 -> 22870 bytes docs/benchmarks/imgs/jmeter-results.png | Bin 0 -> 16031 bytes .../imgs/num-queries-per-minute.png | Bin 0 -> 133042 bytes docs/benchmarks/imgs/query-time-dist-2.png | Bin 0 -> 130720 bytes docs/benchmarks/imgs/query-time-dist-3.png | Bin 0 -> 59575 bytes docs/benchmarks/imgs/query-time-dist-4.png | Bin 0 -> 103766 bytes docs/benchmarks/imgs/query-time-dist-5.png | Bin 0 -> 99981 bytes docs/benchmarks/imgs/query-time-dist-6.png | Bin 0 -> 58551 bytes .../imgs/query-time-dist-postgres-2.png | Bin 0 -> 20119 bytes .../imgs/query-time-dist-postgres-3.png | Bin 0 -> 17039 bytes .../imgs/query-time-dist-postgres.png | Bin 0 -> 15791 bytes docs/benchmarks/imgs/query-time-dist.png | Bin 0 -> 24124 bytes .../imgs/topology-only-store-protocol.png | Bin 0 -> 116756 bytes docs/benchmarks/imgs/using-jmeter.png | Bin 0 -> 73641 bytes docs/benchmarks/postgres-adoption.md | 239 + docs/benchmarks/test-results-summary.md | 90 + docs/contributors/README.md | 11 + docs/contributors/cluster-logs.md | 11 + docs/contributors/continuous-integration.md | 32 + docs/contributors/git-submodules.md | 10 + docs/contributors/nph.md | 34 + docs/contributors/release-process.md | 119 + docs/contributors/waku-fleets.md | 107 + docs/faq.md | 34 + docs/operators/README.md | 35 + docs/operators/docker-quickstart.md | 79 + docs/operators/droplet-quickstart.md | 305 + docs/operators/how-to/build.md | 59 + docs/operators/how-to/configure-dns-disc.md | 27 + docs/operators/how-to/configure-domain.md | 16 + docs/operators/how-to/configure-key.md | 54 + docs/operators/how-to/configure-rest-api.md | 23 + .../how-to/configure-store-v0.12.0.md | 56 + docs/operators/how-to/configure-store.md | 58 + docs/operators/how-to/configure-websocket.md | 35 + docs/operators/how-to/configure.md | 136 + docs/operators/how-to/connect.md | 60 + docs/operators/how-to/monitor.md | 111 + docs/operators/how-to/run-with-rln.md | 89 + docs/operators/how-to/run.md | 196 + docs/operators/overview.md | 39 + docs/operators/quickstart.md | 61 + docs/tutorial/chat2.md | 212 + docs/tutorial/db-migration.md | 61 + docs/tutorial/dingpu.md | 44 + docs/tutorial/dns-disc.md | 69 + docs/tutorial/filter.md | 35 + docs/tutorial/heaptrack.md | 114 + .../imgs/good_heaptrack_report_example.png | Bin 0 -> 353365 bytes .../imgs/infura-dashboard-mainnet.png | Bin 0 -> 279597 bytes docs/tutorial/imgs/infura-dashboard.png | Bin 0 -> 261477 bytes docs/tutorial/imgs/infura-endpoints.png | Bin 0 -> 220283 bytes docs/tutorial/imgs/infura-key.png | Bin 0 -> 77900 bytes .../imgs/rln-relay-chat2-overview.png | Bin 0 -> 69040 bytes docs/tutorial/nangang.md | 42 + .../nim.2.2.4_heaptracker_addon.patch | 44 + docs/tutorial/onchain-rln-relay-chat2.md | 232 + ...f-running-on-chain-spam-protected-chat2.md | 104 + docs/tutorial/rln-chat-cross-client.md | 33 + docs/tutorial/rln-chat2-live-testnet.md | 125 + docs/tutorial/rln-chat2-local-test.md | 147 + docs/tutorial/rln-keystore-generator.md | 73 + docs/tutorial/store.md | 42 + docs/tutorial/websocket.md | 69 + env.sh | 8 + examples/README.md | 75 + examples/cbindings/README.md | 18 + examples/cbindings/base64.c | 58 + examples/cbindings/base64.h | 11 + examples/cbindings/waku_example.c | 366 + examples/cpp/README.md | 18 + examples/cpp/base64.cpp | 53 + examples/cpp/base64.h | 11 + examples/cpp/waku.cpp | 331 + examples/filter_subscriber.nim | 117 + examples/golang/README.md | 44 + examples/golang/waku.go | 652 ++ .../lightpush_mix/lightpush_publisher_mix.nim | 196 + .../lightpush_publisher_mix_config.nim | 28 + .../lightpush_publisher_mix_metrics.nim | 8 + examples/lightpush_publisher.nim | 109 + examples/mobile/.bundle/config | 2 + examples/mobile/.eslintrc.js | 4 + examples/mobile/.gitignore | 74 + examples/mobile/.prettierrc.js | 7 + examples/mobile/.watchmanconfig | 1 + examples/mobile/.yarnrc | 5 + examples/mobile/App.tsx | 327 + examples/mobile/Gemfile | 9 + examples/mobile/README.md | 79 + examples/mobile/__tests__/App.test.tsx | 17 + examples/mobile/android/app/build.gradle | 141 + examples/mobile/android/app/debug.keystore | Bin 0 -> 2257 bytes .../mobile/android/app/proguard-rules.pro | 10 + .../android/app/src/debug/AndroidManifest.xml | 9 + .../android/app/src/main/AndroidManifest.xml | 25 + .../src/main/java/com/mobile/MainActivity.kt | 29 + .../main/java/com/mobile/MainApplication.kt | 43 + .../java/com/mobile/ReactNativePackage.kt | 19 + .../src/main/java/com/mobile/WakuModule.kt | 247 + .../android/app/src/main/jni/.gitignore | 1 + .../android/app/src/main/jni/Android.mk | 17 + .../android/app/src/main/jni/Application.mk | 1 + .../android/app/src/main/jni/waku_ffi.c | 325 + .../app/src/main/jniLibs/arm64-v8a/.gitkeep | 0 .../app/src/main/jniLibs/armeabi-v7a/.gitkeep | 0 .../android/app/src/main/jniLibs/x86/.gitkeep | 0 .../app/src/main/jniLibs/x86_64/.gitkeep | 0 .../res/drawable/rn_edit_text_material.xml | 37 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3056 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5024 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2096 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2858 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4569 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7098 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6464 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10676 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9250 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15523 bytes .../app/src/main/res/values/strings.xml | 3 + .../app/src/main/res/values/styles.xml | 9 + examples/mobile/android/build.gradle | 21 + examples/mobile/android/gradle.properties | 41 + .../android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 63721 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + examples/mobile/android/gradlew | 249 + examples/mobile/android/gradlew.bat | 92 + examples/mobile/android/settings.gradle | 4 + examples/mobile/app.json | 4 + examples/mobile/babel.config.js | 3 + examples/mobile/build-nwaku.js | 64 + examples/mobile/index.js | 9 + examples/mobile/ios/.xcode.env | 11 + examples/mobile/ios/Podfile | 40 + .../ios/mobile.xcodeproj/project.pbxproj | 688 ++ .../xcshareddata/xcschemes/mobile.xcscheme | 88 + examples/mobile/ios/mobile/AppDelegate.h | 6 + examples/mobile/ios/mobile/AppDelegate.mm | 31 + .../AppIcon.appiconset/Contents.json | 53 + .../ios/mobile/Images.xcassets/Contents.json | 6 + examples/mobile/ios/mobile/Info.plist | 52 + .../mobile/ios/mobile/LaunchScreen.storyboard | 47 + .../mobile/ios/mobile/PrivacyInfo.xcprivacy | 38 + examples/mobile/ios/mobile/main.m | 10 + examples/mobile/ios/mobileTests/Info.plist | 24 + examples/mobile/ios/mobileTests/mobileTests.m | 66 + examples/mobile/jest.config.js | 3 + examples/mobile/metro.config.js | 11 + examples/mobile/package.json | 38 + examples/mobile/tsconfig.json | 3 + examples/mobile/yarn.lock | 6747 ++++++++++++ examples/nim.cfg | 5 + examples/nodejs/binding.gyp | 9 + examples/nodejs/waku.js | 78 + examples/nodejs/waku_addon.c | 586 ++ examples/publisher.nim | 142 + examples/python/requirements.txt | 7 + examples/python/waku.py | 154 + examples/qt/Makefile | 26 + examples/qt/main.qml | 64 + examples/qt/main_qt.cpp | 46 + examples/qt/qt.pro | 18 + examples/qt/waku_handler.h | 56 + examples/rust/Cargo.lock | 25 + examples/rust/Cargo.toml | 9 + examples/rust/README.md | 6 + examples/rust/build.rs | 5 + examples/rust/src/main.rs | 111 + examples/subscriber.nim | 129 + examples/waku_example.nim | 38 + examples/wakustealthcommitments/README.md | 38 + .../erc_5564_interface.nim | 167 + examples/wakustealthcommitments/nim.cfg | 11 + examples/wakustealthcommitments/node_spec.nim | 62 + .../stealth_commitment_protocol.nim | 193 + .../wakustealthcommitments.nim | 27 + examples/wakustealthcommitments/wire_spec.nim | 133 + flake.lock | 49 + flake.nix | 64 + library/alloc.nim | 42 + library/events/json_base_event.nim | 6 + .../events/json_connection_change_event.nim | 17 + library/events/json_message_event.nim | 106 + .../events/json_topic_health_change_event.nim | 20 + .../events/json_waku_not_responding_event.nim | 9 + library/ffi_types.nim | 30 + library/libwaku.h | 253 + library/libwaku.nim | 853 ++ library/nim.cfg | 1 + library/utils.nim | 20 + library/waku_context.nim | 226 + .../requests/debug_node_request.nim | 63 + .../requests/discovery_request.nim | 150 + .../requests/node_lifecycle_request.nim | 110 + .../requests/peer_manager_request.nim | 135 + .../requests/ping_request.nim | 56 + .../requests/protocols/filter_request.nim | 105 + .../requests/protocols/lightpush_request.nim | 109 + .../requests/protocols/relay_request.nim | 166 + .../requests/protocols/store_request.nim | 131 + .../waku_thread_request.nim | 104 + metrics/waku-fleet-dashboard.json | 9099 +++++++++++++++++ metrics/waku-network-monitor-dashboard.json | 7419 ++++++++++++++ metrics/waku-network-monitor-discovery.json | 789 ++ metrics/waku-rln-relay-fleet-dashboard.json | 1151 +++ .../waku-rln-relay-single-node-dashboard.json | 983 ++ metrics/waku-single-node-dashboard.json | 5754 +++++++++++ .../00001_addMessageTable.up.sql | 8 + .../00002_addSenderTimeStamp.up.sql | 29 + .../00003_convertTimestampsToInt64.up.sql | 29 + .../00004_extendPrimaryKey.up.sql | 18 + .../message_store/00005_updateIndex.up.sql | 1 + .../message_store/00006_renameColumn.up.sql | 11 + .../00007_updatePrimaryKey.up.sql | 18 + .../00008_updatePrimaryKey_add_col.up.sql | 28 + .../message_store/00009_addMetaColumn.up.sql | 1 + .../message_store/00010_dropStoredAt.up.sql | 3 + .../content_script_version_1.nim | 21 + .../content_script_version_2.nim | 70 + .../content_script_version_3.nim | 8 + .../content_script_version_4.nim | 9 + .../content_script_version_5.nim | 6 + .../content_script_version_6.nim | 12 + .../content_script_version_7.nim | 30 + .../pg_migration_manager.nim | 30 + .../peer_store/00001_addPeerTable.up.sql | 6 + .../00001_addNotDeliveredMessagesTable.up.sql | 9 + nix/README.md | 35 + nix/atlas.nix | 12 + nix/checksums.nix | 12 + nix/csources.nix | 12 + nix/default.nix | 116 + nix/nimble.nix | 12 + nix/pkgs/android-sdk/compose.nix | 26 + nix/pkgs/android-sdk/default.nix | 14 + nix/pkgs/android-sdk/pkgs.nix | 17 + nix/pkgs/android-sdk/shell.nix | 19 + nix/sat.nix | 12 + nix/shell.nix | 23 + nix/tools.nix | 15 + scripts/build_rln.sh | 60 + scripts/build_rln_android.sh | 28 + scripts/build_windows.sh | 60 + scripts/chkhealth.sh | 61 + scripts/generate_nimble_links.sh | 29 + scripts/git_pre_commit_format.sh | 16 + scripts/install_anvil.sh | 15 + scripts/install_pnpm.sh | 8 + scripts/install_rln_tests_dependencies.sh | 7 + scripts/run_cov.sh | 52 + simulations/README.md | 4 + simulations/mixnet/README.md | 70 + simulations/mixnet/config.toml | 25 + simulations/mixnet/config1.toml | 27 + simulations/mixnet/config2.toml | 27 + simulations/mixnet/config3.toml | 27 + simulations/mixnet/config4.toml | 27 + simulations/mixnet/run_chat_mix.sh | 1 + simulations/mixnet/run_chat_mix1.sh | 1 + simulations/mixnet/run_lp_service_node.sh | 1 + simulations/mixnet/run_mix_node1.sh | 1 + simulations/mixnet/run_mix_node2.sh | 1 + simulations/mixnet/run_mix_node3.sh | 1 + simulations/mixnet/run_mix_node4.sh | 1 + tests/all_tests_common.nim | 3 + tests/all_tests_waku.nim | 106 + tests/all_tests_wakunode2.nim | 3 + tests/api/test_all.nim | 3 + tests/api/test_entry_nodes.nim | 264 + tests/api/test_node_conf.nim | 277 + tests/common/test_all.nim | 12 + tests/common/test_base64_codec.nim | 50 + tests/common/test_enr_builder.nim | 126 + tests/common/test_parse_size.nim | 104 + tests/common/test_protobuf_validation.nim | 96 + tests/common/test_ratelimit_setting.nim | 165 + tests/common/test_requestratelimiter.nim | 98 + tests/common/test_sqlite_migrations.nim | 117 + tests/common/test_timed_map.nim | 60 + tests/common/test_tokenbucket.nim | 69 + tests/factory/test_all.nim | 3 + tests/factory/test_node_factory.nim | 72 + tests/factory/test_waku_conf.nim | 296 + tests/incentivization/test_all.nim | 3 + .../incentivization/test_poc_eligibility.nim | 207 + tests/incentivization/test_poc_reputation.nim | 43 + tests/incentivization/test_rpc_codec.nim | 22 + tests/nim.cfg | 3 + .../peer_store/test_migrations.nim | 56 + .../peer_store/test_peer_storage.nim | 21 + .../peer_store/test_waku_peer_storage.nim | 108 + tests/node/peer_manager/peer_store/utils.nim | 9 + tests/node/peer_manager/test_peer_manager.nim | 137 + tests/node/test_all.nim | 10 + tests/node/test_wakunode_filter.nim | 838 ++ tests/node/test_wakunode_legacy_lightpush.nim | 250 + tests/node/test_wakunode_legacy_store.nim | 1069 ++ tests/node/test_wakunode_lightpush.nim | 246 + tests/node/test_wakunode_peer_exchange.nim | 293 + tests/node/test_wakunode_peer_manager.nim | 958 ++ tests/node/test_wakunode_relay_rln.nim | 757 ++ tests/node/test_wakunode_sharding.nim | 1027 ++ tests/node/test_wakunode_store.nim | 1338 +++ tests/node/utils.nim | 7 + tests/postgres-docker-compose.yml | 10 + tests/resources/content_topics.nim | 12 + tests/resources/payloads.nim | 57 + tests/resources/pubsub_topics.nim | 13 + tests/test_all.nim | 3 + tests/test_helpers.nim | 46 + tests/test_message_cache.nim | 249 + tests/test_peer_manager.nim | 1204 +++ tests/test_peer_storage.nim | 97 + tests/test_peer_store_extended.nim | 355 + tests/test_relay_peer_exchange.nim | 111 + tests/test_utils_compat.nim | 48 + tests/test_waku.nim | 91 + tests/test_waku_dnsdisc.nim | 117 + tests/test_waku_enr.nim | 448 + tests/test_waku_keepalive.nim | 56 + tests/test_waku_keystore.nim | 305 + tests/test_waku_keystore_keyfile.nim | 366 + tests/test_waku_metadata.nim | 66 + tests/test_waku_netconfig.nim | 428 + tests/test_waku_noise.nim | 902 ++ tests/test_waku_noise_sessions.nim | 421 + tests/test_waku_protobufs.nim | 30 + tests/test_waku_rendezvous.nim | 67 + tests/test_waku_switch.nim | 114 + tests/test_wakunode.nim | 372 + tests/testlib/assertions.nim | 14 + tests/testlib/common.nim | 32 + tests/testlib/comparisons.nim | 2 + tests/testlib/futures.nim | 49 + tests/testlib/postgres.nim | 27 + tests/testlib/postgres_legacy.nim | 27 + tests/testlib/sequtils.nim | 2 + tests/testlib/simple_mock.nim | 47 + tests/testlib/tables.nim | 21 + tests/testlib/testasync.nim | 20 + tests/testlib/testutils.nim | 37 + tests/testlib/wakucore.nim | 76 + tests/testlib/wakunode.nim | 154 + tests/tools/test_all.nim | 3 + tests/tools/test_confutils_envvar.nim | 73 + .../test_confutils_envvar_serialization.nim | 17 + tests/waku_archive/archive_utils.nim | 39 + tests/waku_archive/test_all.nim | 14 + tests/waku_archive/test_driver_postgres.nim | 170 + .../test_driver_postgres_query.nim | 1819 ++++ tests/waku_archive/test_driver_queue.nim | 182 + .../waku_archive/test_driver_queue_index.nim | 47 + .../test_driver_queue_pagination.nim | 396 + .../waku_archive/test_driver_queue_query.nim | 1696 +++ tests/waku_archive/test_driver_sqlite.nim | 54 + .../waku_archive/test_driver_sqlite_query.nim | 1754 ++++ tests/waku_archive/test_partition_manager.nim | 14 + tests/waku_archive/test_retention_policy.nim | 153 + tests/waku_archive/test_waku_archive.nim | 544 + tests/waku_archive_legacy/archive_utils.nim | 55 + tests/waku_archive_legacy/test_all.nim | 13 + .../test_driver_postgres.nim | 220 + .../test_driver_postgres_query.nim | 1987 ++++ .../waku_archive_legacy/test_driver_queue.nim | 182 + .../test_driver_queue_index.nim | 219 + .../test_driver_queue_pagination.nim | 405 + .../test_driver_queue_query.nim | 1795 ++++ .../test_driver_sqlite.nim | 58 + .../test_driver_sqlite_query.nim | 1873 ++++ .../waku_archive_legacy/test_waku_archive.nim | 535 + tests/waku_core/test_all.nim | 9 + tests/waku_core/test_message_digest.nim | 151 + tests/waku_core/test_namespaced_topics.nim | 214 + tests/waku_core/test_peers.nim | 179 + tests/waku_core/test_published_address.nim | 19 + tests/waku_core/test_time.nim | 30 + tests/waku_core/topics/test_pubsub_topic.nim | 20 + tests/waku_core/topics/test_sharding.nim | 209 + tests/waku_discv5/test_waku_discv5.nim | 542 + tests/waku_discv5/utils.nim | 33 + tests/waku_enr/test_all.nim | 1 + tests/waku_enr/test_sharding.nim | 167 + tests/waku_enr/utils.nim | 35 + tests/waku_filter_v2/test_all.nim | 3 + tests/waku_filter_v2/test_waku_client.nim | 2556 +++++ .../test_waku_filter_dos_protection.nim | 176 + tests/waku_filter_v2/waku_filter_utils.nim | 66 + tests/waku_keystore/utils.nim | 29 + tests/waku_lightpush/lightpush_utils.nim | 33 + tests/waku_lightpush/test_all.nim | 3 + tests/waku_lightpush/test_client.nim | 373 + tests/waku_lightpush/test_ratelimit.nim | 137 + .../waku_lightpush_legacy/lightpush_utils.nim | 28 + tests/waku_lightpush_legacy/test_all.nim | 3 + tests/waku_lightpush_legacy/test_client.nim | 333 + .../waku_lightpush_legacy/test_ratelimit.nim | 143 + tests/waku_peer_exchange/test_all.nim | 3 + tests/waku_peer_exchange/test_protocol.nim | 456 + tests/waku_peer_exchange/test_rpc_codec.nim | 73 + tests/waku_peer_exchange/utils.nim | 53 + tests/waku_relay/crypto_utils.nim | 44 + tests/waku_relay/resources/test_cert.pem | 22 + tests/waku_relay/resources/test_key.pem | 28 + tests/waku_relay/test_all.nim | 3 + tests/waku_relay/test_message_id.nim | 39 + tests/waku_relay/test_protocol.nim | 1364 +++ tests/waku_relay/test_wakunode_relay.nim | 704 ++ tests/waku_relay/utils.nim | 110 + tests/waku_rln_relay/rln/buffer_utils.nim | 11 + .../waku_rln_relay/rln/test_rln_interface.nim | 17 + tests/waku_rln_relay/rln/test_wrappers.nim | 136 + .../rln/waku_rln_relay_utils.nim | 57 + tests/waku_rln_relay/test_all.nim | 7 + .../test_rln_group_manager_onchain.nim | 486 + .../waku_rln_relay/test_rln_nonce_manager.nim | 43 + tests/waku_rln_relay/test_waku_rln_relay.nim | 640 ++ .../test_wakunode_rln_relay.nim | 742 ++ tests/waku_rln_relay/utils.nim | 32 + tests/waku_rln_relay/utils_offchain.nim | 84 + tests/waku_rln_relay/utils_onchain.nim | 610 ++ tests/waku_store/store_utils.nim | 22 + tests/waku_store/test_all.nim | 8 + tests/waku_store/test_client.nim | 226 + tests/waku_store/test_resume.nim | 113 + tests/waku_store/test_rpc_codec.nim | 95 + tests/waku_store/test_waku_store.nim | 119 + tests/waku_store/test_wakunode_store.nim | 427 + tests/waku_store_legacy/store_utils.nim | 33 + tests/waku_store_legacy/test_all.nim | 8 + tests/waku_store_legacy/test_client.nim | 214 + tests/waku_store_legacy/test_resume.nim | 342 + tests/waku_store_legacy/test_rpc_codec.nim | 185 + tests/waku_store_legacy/test_waku_store.nim | 113 + .../waku_store_legacy/test_wakunode_store.nim | 316 + tests/waku_store_sync/sync_utils.nim | 72 + tests/waku_store_sync/test_all.nim | 3 + tests/waku_store_sync/test_codec.nim | 214 + tests/waku_store_sync/test_protocol.nim | 935 ++ tests/waku_store_sync/test_range_split.nim | 297 + .../waku_store_sync/test_state_transition.nim | 291 + tests/waku_store_sync/test_storage.nim | 278 + tests/wakunode2/test_all.nim | 3 + tests/wakunode2/test_app.nim | 99 + tests/wakunode2/test_cli_args.nim | 402 + tests/wakunode2/test_validators.nim | 413 + tests/wakunode_rest/test_all.nim | 15 + tests/wakunode_rest/test_rest_admin.nim | 323 + tests/wakunode_rest/test_rest_cors.nim | 290 + tests/wakunode_rest/test_rest_debug.nim | 92 + .../wakunode_rest/test_rest_debug_serdes.nim | 34 + tests/wakunode_rest/test_rest_filter.nim | 490 + tests/wakunode_rest/test_rest_health.nim | 134 + tests/wakunode_rest/test_rest_lightpush.nim | 303 + .../test_rest_lightpush_legacy.nim | 296 + tests/wakunode_rest/test_rest_relay.nim | 787 ++ .../wakunode_rest/test_rest_relay_serdes.nim | 47 + tests/wakunode_rest/test_rest_serdes.nim | 63 + tests/wakunode_rest/test_rest_store.nim | 874 ++ tools/confutils/cli_args.nim | 1025 ++ tools/confutils/envvar.nim | 16 + tools/confutils/envvar_net.nim | 22 + tools/confutils/envvar_serialization.nim | 49 + .../confutils/envvar_serialization/reader.nim | 108 + .../confutils/envvar_serialization/utils.nim | 89 + .../confutils/envvar_serialization/writer.nim | 44 + tools/rln_keystore_generator/README.md | 3 + .../rln_keystore_generator.nim | 124 + vendor/db_connector | 1 + vendor/dnsclient.nim | 1 + vendor/mix | 1 + vendor/nim-bearssl | 1 + vendor/nim-chronicles | 1 + vendor/nim-chronos | 1 + vendor/nim-confutils | 1 + vendor/nim-dnsdisc | 1 + vendor/nim-eth | 1 + vendor/nim-faststreams | 1 + vendor/nim-http-utils | 1 + vendor/nim-json-rpc | 1 + vendor/nim-json-serialization | 1 + vendor/nim-libbacktrace | 1 + vendor/nim-libp2p | 1 + vendor/nim-metrics | 1 + vendor/nim-minilru | 1 + vendor/nim-nat-traversal | 1 + vendor/nim-presto | 1 + vendor/nim-regex | 1 + vendor/nim-results | 1 + vendor/nim-secp256k1 | 1 + vendor/nim-serialization | 1 + vendor/nim-sqlite3-abi | 1 + vendor/nim-stew | 1 + vendor/nim-stint | 1 + vendor/nim-taskpools | 1 + vendor/nim-testutils | 1 + vendor/nim-toml-serialization | 1 + vendor/nim-unicodedb | 1 + vendor/nim-unittest2 | 1 + vendor/nim-web3 | 1 + vendor/nim-websock | 1 + vendor/nim-zlib | 1 + vendor/nimbus-build-system | 1 + vendor/nimcrypto | 1 + vendor/nph | 1 + vendor/waku-rlnv2-contract | 1 + vendor/zerokit | 1 + waku.nim | 10 + waku.nimble | 221 + waku/README.md | 237 + waku/api/api.nim | 17 + waku/api/api_conf.nim | 203 + waku/api/entry_nodes.nim | 77 + waku/common/base64.nim | 36 + waku/common/callbacks.nim | 5 + waku/common/databases/common.nim | 3 + waku/common/databases/db_postgres.nim | 3 + waku/common/databases/db_postgres/dbconn.nim | 331 + .../databases/db_postgres/pgasyncpool.nim | 189 + .../databases/db_postgres/query_metrics.nim | 33 + waku/common/databases/db_sqlite.nim | 505 + waku/common/databases/dburl.nim | 29 + waku/common/enr.nim | 19 + waku/common/enr/builder.nim | 85 + waku/common/enr/typed_record.nim | 99 + waku/common/error_handling.nim | 1 + waku/common/hexstrings.nim | 61 + waku/common/logging.nim | 105 + waku/common/nimchronos.nim | 31 + waku/common/paging.nim | 28 + waku/common/protobuf.nim | 64 + waku/common/rate_limit/per_peer_limiter.nim | 38 + waku/common/rate_limit/request_limiter.nim | 143 + waku/common/rate_limit/service_metrics.nim | 30 + waku/common/rate_limit/setting.nim | 135 + .../rate_limit/single_token_limiter.nim | 59 + waku/common/rate_limit/timed_map.nim | 162 + waku/common/rate_limit/token_bucket.nim | 182 + waku/common/utils/DEPRECATION_NOTICE.md | 6 + waku/common/utils/matterbridge_client.nim | 74 + waku/common/utils/nat.nim | 80 + waku/common/utils/parse_size_units.nim | 74 + waku/common/utils/sequence.nim | 7 + waku/discovery/autonat_service.nim | 35 + waku/discovery/waku_discv5.nim | 484 + waku/discovery/waku_dnsdisc.nim | 130 + waku/factory/app_callbacks.nim | 6 + waku/factory/builder.nim | 227 + waku/factory/conf_builder/conf_builder.nim | 19 + .../conf_builder/discv5_conf_builder.nim | 63 + .../dns_discovery_conf_builder.nim | 34 + .../filter_service_conf_builder.nim | 45 + .../metrics_server_conf_builder.nim | 47 + .../factory/conf_builder/mix_conf_builder.nim | 35 + .../conf_builder/rate_limit_conf_builder.nim | 29 + .../conf_builder/rest_server_conf_builder.nim | 64 + .../conf_builder/rln_relay_conf_builder.nim | 99 + .../store_service_conf_builder.nim | 74 + .../conf_builder/store_sync_conf_builder.nim | 51 + .../conf_builder/waku_conf_builder.nim | 677 ++ .../conf_builder/web_socket_conf_builder.nim | 70 + waku/factory/internal_config.nim | 144 + waku/factory/networks_config.nim | 73 + waku/factory/node_factory.nim | 537 + waku/factory/validator_signed.nim | 83 + waku/factory/waku.nim | 469 + waku/factory/waku_conf.nim | 235 + waku/incentivization/common.nim | 9 + waku/incentivization/eligibility_manager.nim | 98 + waku/incentivization/reputation_manager.nim | 48 + waku/incentivization/rpc.nim | 12 + waku/incentivization/rpc_codec.nim | 51 + .../delivery_monitor/delivery_callback.nim | 17 + .../delivery_monitor/delivery_monitor.nim | 43 + .../not_delivered_storage/migrations.nim | 26 + .../not_delivered_storage.nim | 38 + .../delivery_monitor/publish_observer.nim | 9 + waku/node/delivery_monitor/recv_monitor.nim | 196 + waku/node/delivery_monitor/send_monitor.nim | 212 + .../subscriptions_observer.nim | 13 + waku/node/health_monitor.nim | 4 + waku/node/health_monitor/health_status.nim | 16 + .../health_monitor/node_health_monitor.nim | 425 + waku/node/health_monitor/online_monitor.nim | 77 + waku/node/health_monitor/protocol_health.nim | 46 + waku/node/net_config.nim | 189 + waku/node/peer_manager.nim | 3 + waku/node/peer_manager/peer_manager.nim | 1127 ++ .../peer_manager/peer_store/migrations.nim | 33 + .../peer_manager/peer_store/peer_storage.nim | 25 + .../peer_store/waku_peer_storage.nim | 172 + waku/node/peer_manager/waku_peer_store.nim | 204 + waku/node/waku_metrics.nim | 90 + waku/node/waku_node.nim | 1675 +++ waku/node/waku_switch.nim | 117 + waku/utils/DEPRECATION_NOTICE.md | 6 + waku/utils/collector.nim | 40 + waku/utils/noise.nim | 40 + waku/utils/requests.nim | 10 + waku/utils/tableutils.nim | 33 + waku/waku_api.nim | 3 + waku/waku_api/handlers.nim | 37 + waku/waku_api/message_cache.nim | 278 + waku/waku_api/rest/admin/client.nim | 75 + waku/waku_api/rest/admin/handlers.nim | 474 + waku/waku_api/rest/admin/types.nim | 324 + waku/waku_api/rest/builder.nim | 219 + waku/waku_api/rest/client.nim | 6 + waku/waku_api/rest/debug/client.nim | 20 + waku/waku_api/rest/debug/handlers.nim | 44 + waku/waku_api/rest/debug/types.nim | 56 + waku/waku_api/rest/filter/client.nim | 71 + waku/waku_api/rest/filter/handlers.nim | 432 + waku/waku_api/rest/filter/types.nim | 426 + waku/waku_api/rest/health/client.nim | 11 + waku/waku_api/rest/health/handlers.nim | 39 + waku/waku_api/rest/health/types.nim | 83 + .../waku_api/rest/legacy_lightpush/client.nim | 15 + .../rest/legacy_lightpush/handlers.nim | 91 + waku/waku_api/rest/legacy_lightpush/types.nim | 67 + waku/waku_api/rest/legacy_store/client.nim | 75 + waku/waku_api/rest/legacy_store/handlers.nim | 256 + waku/waku_api/rest/legacy_store/types.nim | 379 + waku/waku_api/rest/lightpush/client.nim | 23 + waku/waku_api/rest/lightpush/handlers.nim | 104 + waku/waku_api/rest/lightpush/types.nim | 114 + waku/waku_api/rest/origin_handler.nim | 125 + waku/waku_api/rest/relay/client.nim | 69 + waku/waku_api/rest/relay/handlers.nim | 326 + waku/waku_api/rest/relay/types.nim | 145 + waku/waku_api/rest/responses.nim | 45 + waku/waku_api/rest/rest_serdes.nim | 84 + waku/waku_api/rest/serdes.nim | 124 + waku/waku_api/rest/server.nim | 206 + waku/waku_api/rest/store/client.nim | 63 + waku/waku_api/rest/store/handlers.nim | 240 + waku/waku_api/rest/store/types.nim | 321 + waku/waku_archive.nim | 7 + waku/waku_archive/archive.nim | 296 + waku/waku_archive/archive_metrics.nim | 18 + waku/waku_archive/common.nim | 54 + waku/waku_archive/driver.nim | 102 + waku/waku_archive/driver/builder.nim | 124 + waku/waku_archive/driver/postgres_driver.nim | 8 + .../driver/postgres_driver/migrations.nim | 99 + .../postgres_driver/partitions_manager.nim | 139 + .../postgres_driver/postgres_driver.nim | 1556 +++ .../postgres_driver/postgres_healthcheck.nim | 38 + waku/waku_archive/driver/queue_driver.nim | 5 + .../driver/queue_driver/index.nim | 28 + .../driver/queue_driver/queue_driver.nim | 358 + waku/waku_archive/driver/sqlite_driver.nim | 5 + .../driver/sqlite_driver/migrations.nim | 74 + .../driver/sqlite_driver/queries.nim | 590 ++ .../driver/sqlite_driver/sqlite_driver.nim | 192 + waku/waku_archive/retention_policy.nim | 13 + .../waku_archive/retention_policy/builder.nim | 85 + .../retention_policy_capacity.nim | 69 + .../retention_policy_size.nim | 27 + .../retention_policy_time.nim | 39 + waku/waku_archive_legacy.nim | 6 + waku/waku_archive_legacy/archive.nim | 285 + waku/waku_archive_legacy/archive_metrics.nim | 22 + waku/waku_archive_legacy/common.nim | 88 + waku/waku_archive_legacy/driver.nim | 121 + waku/waku_archive_legacy/driver/builder.nim | 104 + .../driver/postgres_driver.nim | 8 + .../postgres_driver/postgres_driver.nim | 978 ++ .../postgres_driver/postgres_healthcheck.nim | 38 + .../driver/queue_driver.nim | 8 + .../driver/queue_driver/index.nim | 91 + .../driver/queue_driver/queue_driver.nim | 364 + .../driver/sqlite_driver.nim | 8 + .../driver/sqlite_driver/cursor.nim | 11 + .../driver/sqlite_driver/migrations.nim | 74 + .../driver/sqlite_driver/queries.nim | 739 ++ .../driver/sqlite_driver/sqlite_driver.nim | 225 + waku/waku_core.nim | 10 + waku/waku_core/codecs.nim | 12 + waku/waku_core/message.nim | 3 + waku/waku_core/message/codec.nim | 73 + waku/waku_core/message/default_values.nim | 8 + waku/waku_core/message/digest.nim | 68 + waku/waku_core/message/message.nim | 29 + waku/waku_core/multiaddrstr.nim | 21 + waku/waku_core/peers.nim | 378 + waku/waku_core/subscription.nim | 3 + waku/waku_core/subscription/push_handler.nim | 8 + .../subscription/subscription_manager.nim | 52 + waku/waku_core/time.nim | 37 + waku/waku_core/topics.nim | 12 + waku/waku_core/topics/content_topic.nim | 140 + waku/waku_core/topics/parsing.nim | 30 + waku/waku_core/topics/pubsub_topic.nim | 91 + waku/waku_core/topics/sharding.nim | 141 + waku/waku_enr.nim | 8 + waku/waku_enr/capabilities.nim | 122 + waku/waku_enr/mix.nim | 20 + waku/waku_enr/multiaddr.nim | 95 + waku/waku_enr/sharding.nim | 255 + waku/waku_filter_v2.nim | 4 + waku/waku_filter_v2/client.nim | 215 + waku/waku_filter_v2/common.nim | 94 + waku/waku_filter_v2/protocol.nim | 405 + waku/waku_filter_v2/protocol_metrics.nim | 26 + waku/waku_filter_v2/rpc.nim | 96 + waku/waku_filter_v2/rpc_codec.nim | 98 + waku/waku_filter_v2/subscriptions.nim | 195 + waku/waku_keystore.nim | 13 + waku/waku_keystore/conversion_utils.nim | 33 + waku/waku_keystore/keyfile.nim | 602 ++ waku/waku_keystore/keystore.nim | 269 + waku/waku_keystore/protocol_types.nim | 165 + waku/waku_keystore/utils.nim | 81 + waku/waku_lightpush.nim | 3 + waku/waku_lightpush/callbacks.nim | 60 + waku/waku_lightpush/client.nim | 158 + waku/waku_lightpush/common.nim | 87 + waku/waku_lightpush/protocol.nim | 169 + waku/waku_lightpush/protocol_metrics.nim | 19 + waku/waku_lightpush/rpc.nim | 20 + waku/waku_lightpush/rpc_codec.nim | 81 + waku/waku_lightpush/self_req_handler.nim | 36 + waku/waku_lightpush_legacy.nim | 5 + waku/waku_lightpush_legacy/README.md | 1 + waku/waku_lightpush_legacy/callbacks.nim | 62 + waku/waku_lightpush_legacy/client.nim | 116 + waku/waku_lightpush_legacy/common.nim | 15 + waku/waku_lightpush_legacy/protocol.nim | 127 + .../protocol_metrics.nim | 19 + waku/waku_lightpush_legacy/rpc.nim | 18 + waku/waku_lightpush_legacy/rpc_codec.nim | 96 + .../self_req_handler.nim | 59 + waku/waku_metadata.nim | 5 + waku/waku_metadata/protocol.nim | 119 + waku/waku_metadata/rpc.nim | 82 + waku/waku_mix.nim | 3 + waku/waku_mix/protocol.nim | 177 + waku/waku_node.nim | 7 + waku/waku_noise/noise.nim | 364 + .../waku_noise/noise_handshake_processing.nim | 669 ++ waku/waku_noise/noise_types.nim | 290 + waku/waku_noise/noise_utils.nim | 588 ++ waku/waku_peer_exchange.nim | 5 + waku/waku_peer_exchange/README.md | 3 + waku/waku_peer_exchange/client.nim | 102 + waku/waku_peer_exchange/common.nim | 21 + waku/waku_peer_exchange/protocol.nim | 219 + waku/waku_peer_exchange/rpc.nim | 61 + waku/waku_peer_exchange/rpc_codec.nim | 115 + waku/waku_relay.nim | 3 + waku/waku_relay/message_id.nim | 30 + waku/waku_relay/protocol.nim | 695 ++ waku/waku_relay/topic_health.nim | 19 + waku/waku_rendezvous.nim | 3 + waku/waku_rendezvous/common.nim | 38 + waku/waku_rendezvous/protocol.nim | 311 + waku/waku_rln_relay.nim | 7 + waku/waku_rln_relay/constants.nim | 43 + waku/waku_rln_relay/contract.nim | 14 + waku/waku_rln_relay/conversion_utils.nim | 179 + waku/waku_rln_relay/group_manager.nim | 3 + .../group_manager/group_manager_base.nim | 153 + .../waku_rln_relay/group_manager/on_chain.nim | 3 + .../group_manager/on_chain/group_manager.nim | 649 ++ .../group_manager/on_chain/retry_wrapper.nim | 36 + .../group_manager/on_chain/rpc_wrapper.nim | 101 + waku/waku_rln_relay/nonce_manager.nim | 59 + waku/waku_rln_relay/protocol_metrics.nim | 126 + waku/waku_rln_relay/protocol_types.nim | 145 + waku/waku_rln_relay/rln.nim | 3 + waku/waku_rln_relay/rln/rln_interface.nim | 196 + waku/waku_rln_relay/rln/wrappers.nim | 305 + waku/waku_rln_relay/rln_relay.nim | 480 + waku/waku_store.nim | 3 + waku/waku_store/client.nim | 93 + waku/waku_store/common.nim | 156 + waku/waku_store/protocol.nim | 169 + waku/waku_store/protocol_metrics.nim | 32 + waku/waku_store/resume.nim | 220 + waku/waku_store/rpc_codec.nim | 213 + waku/waku_store/self_req_handler.nim | 37 + waku/waku_store_legacy.nim | 3 + waku/waku_store_legacy/README.md | 3 + waku/waku_store_legacy/client.nim | 245 + waku/waku_store_legacy/common.nim | 108 + waku/waku_store_legacy/protocol.nim | 187 + waku/waku_store_legacy/protocol_metrics.nim | 21 + waku/waku_store_legacy/rpc.nim | 223 + waku/waku_store_legacy/rpc_codec.nim | 255 + waku/waku_store_legacy/self_req_handler.nim | 31 + waku/waku_store_sync.nim | 6 + waku/waku_store_sync/codec.nim | 351 + waku/waku_store_sync/common.nim | 84 + waku/waku_store_sync/protocols_metrics.nim | 24 + waku/waku_store_sync/reconciliation.nim | 496 + .../storage/range_processing.nim | 55 + waku/waku_store_sync/storage/seq_storage.nim | 519 + waku/waku_store_sync/storage/storage.nim | 52 + waku/waku_store_sync/transfer.nim | 238 + 921 files changed, 161565 insertions(+) create mode 100644 .dockerignore create mode 100644 .editorconfig create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/bump_dependencies.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/improvement.md create mode 100644 .github/ISSUE_TEMPLATE/milestone.md create mode 100644 .github/ISSUE_TEMPLATE/prepare_release.md create mode 100644 .github/ISSUE_TEMPLATE/research-related-issue.md create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/auto_assign_pr.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/container-image.yml create mode 100644 .github/workflows/pr-lint.yml create mode 100644 .github/workflows/pre-release.yml create mode 100644 .github/workflows/release-assets.yml create mode 100644 .github/workflows/sync-labels.yml create mode 100644 .github/workflows/windows-build.yml create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 .sv4git.yml create mode 100644 .sv4git/templates/releasenotes-md.tpl create mode 100644 .sv4git/templates/rn-md-section-commits.tpl create mode 100644 CHANGELOG.md create mode 100644 Dockerfile create mode 100644 Dockerfile.lightpushWithMix.compile create mode 100644 LICENSE-APACHEv2 create mode 100644 LICENSE-MIT create mode 100644 Makefile create mode 100644 README.md create mode 100644 apps/benchmarks/benchmarks.nim create mode 100644 apps/chat2/chat2.nim create mode 100644 apps/chat2/config_chat2.nim create mode 100644 apps/chat2/nim.cfg create mode 100644 apps/chat2bridge/chat2bridge.nim create mode 100644 apps/chat2bridge/config_chat2bridge.nim create mode 100644 apps/chat2bridge/nim.cfg create mode 100644 apps/chat2mix/chat2mix.nim create mode 100644 apps/chat2mix/config_chat2mix.nim create mode 100644 apps/chat2mix/nim.cfg create mode 100644 apps/liteprotocoltester/.env create mode 100644 apps/liteprotocoltester/Dockerfile.liteprotocoltester create mode 100644 apps/liteprotocoltester/Dockerfile.liteprotocoltester.compile create mode 100644 apps/liteprotocoltester/README.md create mode 100644 apps/liteprotocoltester/diagnose_connections.nim create mode 100644 apps/liteprotocoltester/docker-compose-on-simularor.yml create mode 100644 apps/liteprotocoltester/docker-compose.yml create mode 100644 apps/liteprotocoltester/infra.env create mode 100644 apps/liteprotocoltester/legacy_publisher.nim create mode 100644 apps/liteprotocoltester/liteprotocoltester.nim create mode 100644 apps/liteprotocoltester/lpt_metrics.nim create mode 100755 apps/liteprotocoltester/lpt_supervisor.py create mode 100644 apps/liteprotocoltester/monitoring/configuration/customizations/custom-logo.png create mode 100644 apps/liteprotocoltester/monitoring/configuration/customizations/custom-logo.svg create mode 100644 apps/liteprotocoltester/monitoring/configuration/dashboards.yaml create mode 100644 apps/liteprotocoltester/monitoring/configuration/dashboards/liter-protocol-test-monitoring.json create mode 100644 apps/liteprotocoltester/monitoring/configuration/datasources.yaml create mode 100644 apps/liteprotocoltester/monitoring/configuration/grafana-plugins.env create mode 100644 apps/liteprotocoltester/monitoring/configuration/grafana.ini create mode 100644 apps/liteprotocoltester/monitoring/prometheus-config.yml create mode 100644 apps/liteprotocoltester/nim.cfg create mode 100644 apps/liteprotocoltester/publisher.nim create mode 100644 apps/liteprotocoltester/publisher_base.nim create mode 100644 apps/liteprotocoltester/receiver.nim create mode 100755 apps/liteprotocoltester/run_service_node.sh create mode 100755 apps/liteprotocoltester/run_tester_node.sh create mode 100644 apps/liteprotocoltester/run_tester_node_at_infra.sh create mode 100644 apps/liteprotocoltester/run_tester_node_on_fleet.sh create mode 100644 apps/liteprotocoltester/service_peer_management.nim create mode 100644 apps/liteprotocoltester/statistics.nim create mode 100644 apps/liteprotocoltester/tester_config.nim create mode 100644 apps/liteprotocoltester/tester_message.nim create mode 100644 apps/liteprotocoltester/v3_publisher.nim create mode 100644 apps/networkmonitor/README.md create mode 100644 apps/networkmonitor/docker-compose.yml create mode 100644 apps/networkmonitor/networkmonitor.nim create mode 100644 apps/networkmonitor/networkmonitor_config.nim create mode 100644 apps/networkmonitor/networkmonitor_metrics.nim create mode 100644 apps/networkmonitor/networkmonitor_utils.nim create mode 100644 apps/networkmonitor/nim.cfg create mode 100644 apps/networkmonitor/prometheus.yaml create mode 100644 apps/sonda/.env.example create mode 100644 apps/sonda/.gitignore create mode 100644 apps/sonda/Dockerfile.sonda create mode 100644 apps/sonda/README.md create mode 100644 apps/sonda/docker-compose.yml create mode 100644 apps/sonda/monitoring/configuration/customizations/custom-logo.png create mode 100644 apps/sonda/monitoring/configuration/customizations/custom-logo.svg create mode 100644 apps/sonda/monitoring/configuration/dashboards.yaml create mode 100644 apps/sonda/monitoring/configuration/dashboards/nwaku-monitoring.json create mode 100644 apps/sonda/monitoring/configuration/dashboards/sonda-monitoring.json create mode 100644 apps/sonda/monitoring/configuration/datasources.yaml create mode 100644 apps/sonda/monitoring/configuration/grafana-plugins.env create mode 100644 apps/sonda/monitoring/configuration/grafana.ini create mode 100644 apps/sonda/monitoring/prometheus-config.yml create mode 100755 apps/sonda/register_rln.sh create mode 100644 apps/sonda/run_node.sh create mode 100644 apps/sonda/sonda.py create mode 100644 apps/wakucanary/README.md create mode 100644 apps/wakucanary/certsgenerator.nim create mode 100644 apps/wakucanary/nim.cfg create mode 100644 apps/wakucanary/wakucanary.nim create mode 100644 apps/wakunode2/nim.cfg create mode 100644 apps/wakunode2/wakunode2.nim create mode 100644 ci/Jenkinsfile.lpt create mode 100644 ci/Jenkinsfile.prs create mode 100644 ci/Jenkinsfile.release create mode 100644 config.nims create mode 100644 docker/binaries/Dockerfile.bn.amd64 create mode 100644 docker/binaries/Dockerfile.bn.local create mode 100644 docs/api/node.md create mode 100644 docs/api/rest-api.md create mode 100644 docs/benchmarks/cspell.json create mode 100644 docs/benchmarks/imgs/digram_multiple_nodes_one_database.png create mode 100644 docs/benchmarks/imgs/insert-time-dist-2.png create mode 100644 docs/benchmarks/imgs/insert-time-dist-3.png create mode 100644 docs/benchmarks/imgs/insert-time-dist-4.png create mode 100644 docs/benchmarks/imgs/insert-time-dist-5.png create mode 100644 docs/benchmarks/imgs/insert-time-dist-6.png create mode 100644 docs/benchmarks/imgs/insert-time-dist-postgres-2.png create mode 100644 docs/benchmarks/imgs/insert-time-dist-postgres-3.png create mode 100644 docs/benchmarks/imgs/insert-time-dist-postgres.png create mode 100644 docs/benchmarks/imgs/insert-time-dist.png create mode 100644 docs/benchmarks/imgs/jmeter-results.png create mode 100644 docs/benchmarks/imgs/num-queries-per-minute.png create mode 100644 docs/benchmarks/imgs/query-time-dist-2.png create mode 100644 docs/benchmarks/imgs/query-time-dist-3.png create mode 100644 docs/benchmarks/imgs/query-time-dist-4.png create mode 100644 docs/benchmarks/imgs/query-time-dist-5.png create mode 100644 docs/benchmarks/imgs/query-time-dist-6.png create mode 100644 docs/benchmarks/imgs/query-time-dist-postgres-2.png create mode 100644 docs/benchmarks/imgs/query-time-dist-postgres-3.png create mode 100644 docs/benchmarks/imgs/query-time-dist-postgres.png create mode 100644 docs/benchmarks/imgs/query-time-dist.png create mode 100644 docs/benchmarks/imgs/topology-only-store-protocol.png create mode 100644 docs/benchmarks/imgs/using-jmeter.png create mode 100644 docs/benchmarks/postgres-adoption.md create mode 100644 docs/benchmarks/test-results-summary.md create mode 100644 docs/contributors/README.md create mode 100644 docs/contributors/cluster-logs.md create mode 100644 docs/contributors/continuous-integration.md create mode 100644 docs/contributors/git-submodules.md create mode 100644 docs/contributors/nph.md create mode 100644 docs/contributors/release-process.md create mode 100644 docs/contributors/waku-fleets.md create mode 100644 docs/faq.md create mode 100644 docs/operators/README.md create mode 100644 docs/operators/docker-quickstart.md create mode 100644 docs/operators/droplet-quickstart.md create mode 100644 docs/operators/how-to/build.md create mode 100644 docs/operators/how-to/configure-dns-disc.md create mode 100644 docs/operators/how-to/configure-domain.md create mode 100644 docs/operators/how-to/configure-key.md create mode 100644 docs/operators/how-to/configure-rest-api.md create mode 100644 docs/operators/how-to/configure-store-v0.12.0.md create mode 100644 docs/operators/how-to/configure-store.md create mode 100644 docs/operators/how-to/configure-websocket.md create mode 100644 docs/operators/how-to/configure.md create mode 100644 docs/operators/how-to/connect.md create mode 100644 docs/operators/how-to/monitor.md create mode 100644 docs/operators/how-to/run-with-rln.md create mode 100644 docs/operators/how-to/run.md create mode 100644 docs/operators/overview.md create mode 100644 docs/operators/quickstart.md create mode 100644 docs/tutorial/chat2.md create mode 100644 docs/tutorial/db-migration.md create mode 100644 docs/tutorial/dingpu.md create mode 100644 docs/tutorial/dns-disc.md create mode 100644 docs/tutorial/filter.md create mode 100644 docs/tutorial/heaptrack.md create mode 100644 docs/tutorial/imgs/good_heaptrack_report_example.png create mode 100644 docs/tutorial/imgs/infura-dashboard-mainnet.png create mode 100644 docs/tutorial/imgs/infura-dashboard.png create mode 100644 docs/tutorial/imgs/infura-endpoints.png create mode 100644 docs/tutorial/imgs/infura-key.png create mode 100644 docs/tutorial/imgs/rln-relay-chat2-overview.png create mode 100644 docs/tutorial/nangang.md create mode 100644 docs/tutorial/nim.2.2.4_heaptracker_addon.patch create mode 100644 docs/tutorial/onchain-rln-relay-chat2.md create mode 100644 docs/tutorial/pre-requisites-of-running-on-chain-spam-protected-chat2.md create mode 100644 docs/tutorial/rln-chat-cross-client.md create mode 100644 docs/tutorial/rln-chat2-live-testnet.md create mode 100644 docs/tutorial/rln-chat2-local-test.md create mode 100644 docs/tutorial/rln-keystore-generator.md create mode 100644 docs/tutorial/store.md create mode 100644 docs/tutorial/websocket.md create mode 100755 env.sh create mode 100644 examples/README.md create mode 100644 examples/cbindings/README.md create mode 100644 examples/cbindings/base64.c create mode 100644 examples/cbindings/base64.h create mode 100644 examples/cbindings/waku_example.c create mode 100644 examples/cpp/README.md create mode 100644 examples/cpp/base64.cpp create mode 100644 examples/cpp/base64.h create mode 100644 examples/cpp/waku.cpp create mode 100644 examples/filter_subscriber.nim create mode 100644 examples/golang/README.md create mode 100644 examples/golang/waku.go create mode 100644 examples/lightpush_mix/lightpush_publisher_mix.nim create mode 100644 examples/lightpush_mix/lightpush_publisher_mix_config.nim create mode 100644 examples/lightpush_mix/lightpush_publisher_mix_metrics.nim create mode 100644 examples/lightpush_publisher.nim create mode 100644 examples/mobile/.bundle/config create mode 100644 examples/mobile/.eslintrc.js create mode 100644 examples/mobile/.gitignore create mode 100644 examples/mobile/.prettierrc.js create mode 100644 examples/mobile/.watchmanconfig create mode 100644 examples/mobile/.yarnrc create mode 100644 examples/mobile/App.tsx create mode 100644 examples/mobile/Gemfile create mode 100644 examples/mobile/README.md create mode 100644 examples/mobile/__tests__/App.test.tsx create mode 100644 examples/mobile/android/app/build.gradle create mode 100644 examples/mobile/android/app/debug.keystore create mode 100644 examples/mobile/android/app/proguard-rules.pro create mode 100644 examples/mobile/android/app/src/debug/AndroidManifest.xml create mode 100644 examples/mobile/android/app/src/main/AndroidManifest.xml create mode 100644 examples/mobile/android/app/src/main/java/com/mobile/MainActivity.kt create mode 100644 examples/mobile/android/app/src/main/java/com/mobile/MainApplication.kt create mode 100644 examples/mobile/android/app/src/main/java/com/mobile/ReactNativePackage.kt create mode 100644 examples/mobile/android/app/src/main/java/com/mobile/WakuModule.kt create mode 100644 examples/mobile/android/app/src/main/jni/.gitignore create mode 100644 examples/mobile/android/app/src/main/jni/Android.mk create mode 100644 examples/mobile/android/app/src/main/jni/Application.mk create mode 100644 examples/mobile/android/app/src/main/jni/waku_ffi.c create mode 100644 examples/mobile/android/app/src/main/jniLibs/arm64-v8a/.gitkeep create mode 100644 examples/mobile/android/app/src/main/jniLibs/armeabi-v7a/.gitkeep create mode 100644 examples/mobile/android/app/src/main/jniLibs/x86/.gitkeep create mode 100644 examples/mobile/android/app/src/main/jniLibs/x86_64/.gitkeep create mode 100644 examples/mobile/android/app/src/main/res/drawable/rn_edit_text_material.xml create mode 100644 examples/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 examples/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 examples/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 examples/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 examples/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 examples/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 examples/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 examples/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 examples/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 examples/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 examples/mobile/android/app/src/main/res/values/strings.xml create mode 100644 examples/mobile/android/app/src/main/res/values/styles.xml create mode 100644 examples/mobile/android/build.gradle create mode 100644 examples/mobile/android/gradle.properties create mode 100644 examples/mobile/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 examples/mobile/android/gradle/wrapper/gradle-wrapper.properties create mode 100755 examples/mobile/android/gradlew create mode 100644 examples/mobile/android/gradlew.bat create mode 100644 examples/mobile/android/settings.gradle create mode 100644 examples/mobile/app.json create mode 100644 examples/mobile/babel.config.js create mode 100644 examples/mobile/build-nwaku.js create mode 100644 examples/mobile/index.js create mode 100644 examples/mobile/ios/.xcode.env create mode 100644 examples/mobile/ios/Podfile create mode 100644 examples/mobile/ios/mobile.xcodeproj/project.pbxproj create mode 100644 examples/mobile/ios/mobile.xcodeproj/xcshareddata/xcschemes/mobile.xcscheme create mode 100644 examples/mobile/ios/mobile/AppDelegate.h create mode 100644 examples/mobile/ios/mobile/AppDelegate.mm create mode 100644 examples/mobile/ios/mobile/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 examples/mobile/ios/mobile/Images.xcassets/Contents.json create mode 100644 examples/mobile/ios/mobile/Info.plist create mode 100644 examples/mobile/ios/mobile/LaunchScreen.storyboard create mode 100644 examples/mobile/ios/mobile/PrivacyInfo.xcprivacy create mode 100644 examples/mobile/ios/mobile/main.m create mode 100644 examples/mobile/ios/mobileTests/Info.plist create mode 100644 examples/mobile/ios/mobileTests/mobileTests.m create mode 100644 examples/mobile/jest.config.js create mode 100644 examples/mobile/metro.config.js create mode 100644 examples/mobile/package.json create mode 100644 examples/mobile/tsconfig.json create mode 100644 examples/mobile/yarn.lock create mode 100644 examples/nim.cfg create mode 100644 examples/nodejs/binding.gyp create mode 100644 examples/nodejs/waku.js create mode 100644 examples/nodejs/waku_addon.c create mode 100644 examples/publisher.nim create mode 100644 examples/python/requirements.txt create mode 100644 examples/python/waku.py create mode 100644 examples/qt/Makefile create mode 100644 examples/qt/main.qml create mode 100644 examples/qt/main_qt.cpp create mode 100644 examples/qt/qt.pro create mode 100644 examples/qt/waku_handler.h create mode 100644 examples/rust/Cargo.lock create mode 100644 examples/rust/Cargo.toml create mode 100644 examples/rust/README.md create mode 100644 examples/rust/build.rs create mode 100644 examples/rust/src/main.rs create mode 100644 examples/subscriber.nim create mode 100644 examples/waku_example.nim create mode 100644 examples/wakustealthcommitments/README.md create mode 100644 examples/wakustealthcommitments/erc_5564_interface.nim create mode 100644 examples/wakustealthcommitments/nim.cfg create mode 100644 examples/wakustealthcommitments/node_spec.nim create mode 100644 examples/wakustealthcommitments/stealth_commitment_protocol.nim create mode 100644 examples/wakustealthcommitments/wakustealthcommitments.nim create mode 100644 examples/wakustealthcommitments/wire_spec.nim create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 library/alloc.nim create mode 100644 library/events/json_base_event.nim create mode 100644 library/events/json_connection_change_event.nim create mode 100644 library/events/json_message_event.nim create mode 100644 library/events/json_topic_health_change_event.nim create mode 100644 library/events/json_waku_not_responding_event.nim create mode 100644 library/ffi_types.nim create mode 100644 library/libwaku.h create mode 100644 library/libwaku.nim create mode 100644 library/nim.cfg create mode 100644 library/utils.nim create mode 100644 library/waku_context.nim create mode 100644 library/waku_thread_requests/requests/debug_node_request.nim create mode 100644 library/waku_thread_requests/requests/discovery_request.nim create mode 100644 library/waku_thread_requests/requests/node_lifecycle_request.nim create mode 100644 library/waku_thread_requests/requests/peer_manager_request.nim create mode 100644 library/waku_thread_requests/requests/ping_request.nim create mode 100644 library/waku_thread_requests/requests/protocols/filter_request.nim create mode 100644 library/waku_thread_requests/requests/protocols/lightpush_request.nim create mode 100644 library/waku_thread_requests/requests/protocols/relay_request.nim create mode 100644 library/waku_thread_requests/requests/protocols/store_request.nim create mode 100644 library/waku_thread_requests/waku_thread_request.nim create mode 100644 metrics/waku-fleet-dashboard.json create mode 100644 metrics/waku-network-monitor-dashboard.json create mode 100644 metrics/waku-network-monitor-discovery.json create mode 100644 metrics/waku-rln-relay-fleet-dashboard.json create mode 100644 metrics/waku-rln-relay-single-node-dashboard.json create mode 100644 metrics/waku-single-node-dashboard.json create mode 100644 migrations/message_store/00001_addMessageTable.up.sql create mode 100644 migrations/message_store/00002_addSenderTimeStamp.up.sql create mode 100644 migrations/message_store/00003_convertTimestampsToInt64.up.sql create mode 100644 migrations/message_store/00004_extendPrimaryKey.up.sql create mode 100644 migrations/message_store/00005_updateIndex.up.sql create mode 100644 migrations/message_store/00006_renameColumn.up.sql create mode 100644 migrations/message_store/00007_updatePrimaryKey.up.sql create mode 100644 migrations/message_store/00008_updatePrimaryKey_add_col.up.sql create mode 100644 migrations/message_store/00009_addMetaColumn.up.sql create mode 100644 migrations/message_store/00010_dropStoredAt.up.sql create mode 100644 migrations/message_store_postgres/content_script_version_1.nim create mode 100644 migrations/message_store_postgres/content_script_version_2.nim create mode 100644 migrations/message_store_postgres/content_script_version_3.nim create mode 100644 migrations/message_store_postgres/content_script_version_4.nim create mode 100644 migrations/message_store_postgres/content_script_version_5.nim create mode 100644 migrations/message_store_postgres/content_script_version_6.nim create mode 100644 migrations/message_store_postgres/content_script_version_7.nim create mode 100644 migrations/message_store_postgres/pg_migration_manager.nim create mode 100644 migrations/peer_store/00001_addPeerTable.up.sql create mode 100644 migrations/sent_msgs/00001_addNotDeliveredMessagesTable.up.sql create mode 100644 nix/README.md create mode 100644 nix/atlas.nix create mode 100644 nix/checksums.nix create mode 100644 nix/csources.nix create mode 100644 nix/default.nix create mode 100644 nix/nimble.nix create mode 100644 nix/pkgs/android-sdk/compose.nix create mode 100644 nix/pkgs/android-sdk/default.nix create mode 100644 nix/pkgs/android-sdk/pkgs.nix create mode 100644 nix/pkgs/android-sdk/shell.nix create mode 100644 nix/sat.nix create mode 100644 nix/shell.nix create mode 100644 nix/tools.nix create mode 100755 scripts/build_rln.sh create mode 100755 scripts/build_rln_android.sh create mode 100755 scripts/build_windows.sh create mode 100755 scripts/chkhealth.sh create mode 100755 scripts/generate_nimble_links.sh create mode 100644 scripts/git_pre_commit_format.sh create mode 100755 scripts/install_anvil.sh create mode 100755 scripts/install_pnpm.sh create mode 100755 scripts/install_rln_tests_dependencies.sh create mode 100755 scripts/run_cov.sh create mode 100644 simulations/README.md create mode 100644 simulations/mixnet/README.md create mode 100644 simulations/mixnet/config.toml create mode 100644 simulations/mixnet/config1.toml create mode 100644 simulations/mixnet/config2.toml create mode 100644 simulations/mixnet/config3.toml create mode 100644 simulations/mixnet/config4.toml create mode 100755 simulations/mixnet/run_chat_mix.sh create mode 100755 simulations/mixnet/run_chat_mix1.sh create mode 100755 simulations/mixnet/run_lp_service_node.sh create mode 100755 simulations/mixnet/run_mix_node1.sh create mode 100755 simulations/mixnet/run_mix_node2.sh create mode 100755 simulations/mixnet/run_mix_node3.sh create mode 100755 simulations/mixnet/run_mix_node4.sh create mode 100644 tests/all_tests_common.nim create mode 100644 tests/all_tests_waku.nim create mode 100644 tests/all_tests_wakunode2.nim create mode 100644 tests/api/test_all.nim create mode 100644 tests/api/test_entry_nodes.nim create mode 100644 tests/api/test_node_conf.nim create mode 100644 tests/common/test_all.nim create mode 100644 tests/common/test_base64_codec.nim create mode 100644 tests/common/test_enr_builder.nim create mode 100644 tests/common/test_parse_size.nim create mode 100644 tests/common/test_protobuf_validation.nim create mode 100644 tests/common/test_ratelimit_setting.nim create mode 100644 tests/common/test_requestratelimiter.nim create mode 100644 tests/common/test_sqlite_migrations.nim create mode 100644 tests/common/test_timed_map.nim create mode 100644 tests/common/test_tokenbucket.nim create mode 100644 tests/factory/test_all.nim create mode 100644 tests/factory/test_node_factory.nim create mode 100644 tests/factory/test_waku_conf.nim create mode 100644 tests/incentivization/test_all.nim create mode 100644 tests/incentivization/test_poc_eligibility.nim create mode 100644 tests/incentivization/test_poc_reputation.nim create mode 100644 tests/incentivization/test_rpc_codec.nim create mode 100644 tests/nim.cfg create mode 100644 tests/node/peer_manager/peer_store/test_migrations.nim create mode 100644 tests/node/peer_manager/peer_store/test_peer_storage.nim create mode 100644 tests/node/peer_manager/peer_store/test_waku_peer_storage.nim create mode 100644 tests/node/peer_manager/peer_store/utils.nim create mode 100644 tests/node/peer_manager/test_peer_manager.nim create mode 100644 tests/node/test_all.nim create mode 100644 tests/node/test_wakunode_filter.nim create mode 100644 tests/node/test_wakunode_legacy_lightpush.nim create mode 100644 tests/node/test_wakunode_legacy_store.nim create mode 100644 tests/node/test_wakunode_lightpush.nim create mode 100644 tests/node/test_wakunode_peer_exchange.nim create mode 100644 tests/node/test_wakunode_peer_manager.nim create mode 100644 tests/node/test_wakunode_relay_rln.nim create mode 100644 tests/node/test_wakunode_sharding.nim create mode 100644 tests/node/test_wakunode_store.nim create mode 100644 tests/node/utils.nim create mode 100644 tests/postgres-docker-compose.yml create mode 100644 tests/resources/content_topics.nim create mode 100644 tests/resources/payloads.nim create mode 100644 tests/resources/pubsub_topics.nim create mode 100644 tests/test_all.nim create mode 100644 tests/test_helpers.nim create mode 100644 tests/test_message_cache.nim create mode 100644 tests/test_peer_manager.nim create mode 100644 tests/test_peer_storage.nim create mode 100644 tests/test_peer_store_extended.nim create mode 100644 tests/test_relay_peer_exchange.nim create mode 100644 tests/test_utils_compat.nim create mode 100644 tests/test_waku.nim create mode 100644 tests/test_waku_dnsdisc.nim create mode 100644 tests/test_waku_enr.nim create mode 100644 tests/test_waku_keepalive.nim create mode 100644 tests/test_waku_keystore.nim create mode 100644 tests/test_waku_keystore_keyfile.nim create mode 100644 tests/test_waku_metadata.nim create mode 100644 tests/test_waku_netconfig.nim create mode 100644 tests/test_waku_noise.nim create mode 100644 tests/test_waku_noise_sessions.nim create mode 100644 tests/test_waku_protobufs.nim create mode 100644 tests/test_waku_rendezvous.nim create mode 100644 tests/test_waku_switch.nim create mode 100644 tests/test_wakunode.nim create mode 100644 tests/testlib/assertions.nim create mode 100644 tests/testlib/common.nim create mode 100644 tests/testlib/comparisons.nim create mode 100644 tests/testlib/futures.nim create mode 100644 tests/testlib/postgres.nim create mode 100644 tests/testlib/postgres_legacy.nim create mode 100644 tests/testlib/sequtils.nim create mode 100644 tests/testlib/simple_mock.nim create mode 100644 tests/testlib/tables.nim create mode 100644 tests/testlib/testasync.nim create mode 100644 tests/testlib/testutils.nim create mode 100644 tests/testlib/wakucore.nim create mode 100644 tests/testlib/wakunode.nim create mode 100644 tests/tools/test_all.nim create mode 100644 tests/tools/test_confutils_envvar.nim create mode 100644 tests/tools/test_confutils_envvar_serialization.nim create mode 100644 tests/waku_archive/archive_utils.nim create mode 100644 tests/waku_archive/test_all.nim create mode 100644 tests/waku_archive/test_driver_postgres.nim create mode 100644 tests/waku_archive/test_driver_postgres_query.nim create mode 100644 tests/waku_archive/test_driver_queue.nim create mode 100644 tests/waku_archive/test_driver_queue_index.nim create mode 100644 tests/waku_archive/test_driver_queue_pagination.nim create mode 100644 tests/waku_archive/test_driver_queue_query.nim create mode 100644 tests/waku_archive/test_driver_sqlite.nim create mode 100644 tests/waku_archive/test_driver_sqlite_query.nim create mode 100644 tests/waku_archive/test_partition_manager.nim create mode 100644 tests/waku_archive/test_retention_policy.nim create mode 100644 tests/waku_archive/test_waku_archive.nim create mode 100644 tests/waku_archive_legacy/archive_utils.nim create mode 100644 tests/waku_archive_legacy/test_all.nim create mode 100644 tests/waku_archive_legacy/test_driver_postgres.nim create mode 100644 tests/waku_archive_legacy/test_driver_postgres_query.nim create mode 100644 tests/waku_archive_legacy/test_driver_queue.nim create mode 100644 tests/waku_archive_legacy/test_driver_queue_index.nim create mode 100644 tests/waku_archive_legacy/test_driver_queue_pagination.nim create mode 100644 tests/waku_archive_legacy/test_driver_queue_query.nim create mode 100644 tests/waku_archive_legacy/test_driver_sqlite.nim create mode 100644 tests/waku_archive_legacy/test_driver_sqlite_query.nim create mode 100644 tests/waku_archive_legacy/test_waku_archive.nim create mode 100644 tests/waku_core/test_all.nim create mode 100644 tests/waku_core/test_message_digest.nim create mode 100644 tests/waku_core/test_namespaced_topics.nim create mode 100644 tests/waku_core/test_peers.nim create mode 100644 tests/waku_core/test_published_address.nim create mode 100644 tests/waku_core/test_time.nim create mode 100644 tests/waku_core/topics/test_pubsub_topic.nim create mode 100644 tests/waku_core/topics/test_sharding.nim create mode 100644 tests/waku_discv5/test_waku_discv5.nim create mode 100644 tests/waku_discv5/utils.nim create mode 100644 tests/waku_enr/test_all.nim create mode 100644 tests/waku_enr/test_sharding.nim create mode 100644 tests/waku_enr/utils.nim create mode 100644 tests/waku_filter_v2/test_all.nim create mode 100644 tests/waku_filter_v2/test_waku_client.nim create mode 100644 tests/waku_filter_v2/test_waku_filter_dos_protection.nim create mode 100644 tests/waku_filter_v2/waku_filter_utils.nim create mode 100644 tests/waku_keystore/utils.nim create mode 100644 tests/waku_lightpush/lightpush_utils.nim create mode 100644 tests/waku_lightpush/test_all.nim create mode 100644 tests/waku_lightpush/test_client.nim create mode 100644 tests/waku_lightpush/test_ratelimit.nim create mode 100644 tests/waku_lightpush_legacy/lightpush_utils.nim create mode 100644 tests/waku_lightpush_legacy/test_all.nim create mode 100644 tests/waku_lightpush_legacy/test_client.nim create mode 100644 tests/waku_lightpush_legacy/test_ratelimit.nim create mode 100644 tests/waku_peer_exchange/test_all.nim create mode 100644 tests/waku_peer_exchange/test_protocol.nim create mode 100644 tests/waku_peer_exchange/test_rpc_codec.nim create mode 100644 tests/waku_peer_exchange/utils.nim create mode 100644 tests/waku_relay/crypto_utils.nim create mode 100644 tests/waku_relay/resources/test_cert.pem create mode 100644 tests/waku_relay/resources/test_key.pem create mode 100644 tests/waku_relay/test_all.nim create mode 100644 tests/waku_relay/test_message_id.nim create mode 100644 tests/waku_relay/test_protocol.nim create mode 100644 tests/waku_relay/test_wakunode_relay.nim create mode 100644 tests/waku_relay/utils.nim create mode 100644 tests/waku_rln_relay/rln/buffer_utils.nim create mode 100644 tests/waku_rln_relay/rln/test_rln_interface.nim create mode 100644 tests/waku_rln_relay/rln/test_wrappers.nim create mode 100644 tests/waku_rln_relay/rln/waku_rln_relay_utils.nim create mode 100644 tests/waku_rln_relay/test_all.nim create mode 100644 tests/waku_rln_relay/test_rln_group_manager_onchain.nim create mode 100644 tests/waku_rln_relay/test_rln_nonce_manager.nim create mode 100644 tests/waku_rln_relay/test_waku_rln_relay.nim create mode 100644 tests/waku_rln_relay/test_wakunode_rln_relay.nim create mode 100644 tests/waku_rln_relay/utils.nim create mode 100644 tests/waku_rln_relay/utils_offchain.nim create mode 100644 tests/waku_rln_relay/utils_onchain.nim create mode 100644 tests/waku_store/store_utils.nim create mode 100644 tests/waku_store/test_all.nim create mode 100644 tests/waku_store/test_client.nim create mode 100644 tests/waku_store/test_resume.nim create mode 100644 tests/waku_store/test_rpc_codec.nim create mode 100644 tests/waku_store/test_waku_store.nim create mode 100644 tests/waku_store/test_wakunode_store.nim create mode 100644 tests/waku_store_legacy/store_utils.nim create mode 100644 tests/waku_store_legacy/test_all.nim create mode 100644 tests/waku_store_legacy/test_client.nim create mode 100644 tests/waku_store_legacy/test_resume.nim create mode 100644 tests/waku_store_legacy/test_rpc_codec.nim create mode 100644 tests/waku_store_legacy/test_waku_store.nim create mode 100644 tests/waku_store_legacy/test_wakunode_store.nim create mode 100644 tests/waku_store_sync/sync_utils.nim create mode 100644 tests/waku_store_sync/test_all.nim create mode 100644 tests/waku_store_sync/test_codec.nim create mode 100644 tests/waku_store_sync/test_protocol.nim create mode 100644 tests/waku_store_sync/test_range_split.nim create mode 100644 tests/waku_store_sync/test_state_transition.nim create mode 100644 tests/waku_store_sync/test_storage.nim create mode 100644 tests/wakunode2/test_all.nim create mode 100644 tests/wakunode2/test_app.nim create mode 100644 tests/wakunode2/test_cli_args.nim create mode 100644 tests/wakunode2/test_validators.nim create mode 100644 tests/wakunode_rest/test_all.nim create mode 100644 tests/wakunode_rest/test_rest_admin.nim create mode 100644 tests/wakunode_rest/test_rest_cors.nim create mode 100644 tests/wakunode_rest/test_rest_debug.nim create mode 100644 tests/wakunode_rest/test_rest_debug_serdes.nim create mode 100644 tests/wakunode_rest/test_rest_filter.nim create mode 100644 tests/wakunode_rest/test_rest_health.nim create mode 100644 tests/wakunode_rest/test_rest_lightpush.nim create mode 100644 tests/wakunode_rest/test_rest_lightpush_legacy.nim create mode 100644 tests/wakunode_rest/test_rest_relay.nim create mode 100644 tests/wakunode_rest/test_rest_relay_serdes.nim create mode 100644 tests/wakunode_rest/test_rest_serdes.nim create mode 100644 tests/wakunode_rest/test_rest_store.nim create mode 100644 tools/confutils/cli_args.nim create mode 100644 tools/confutils/envvar.nim create mode 100644 tools/confutils/envvar_net.nim create mode 100644 tools/confutils/envvar_serialization.nim create mode 100644 tools/confutils/envvar_serialization/reader.nim create mode 100644 tools/confutils/envvar_serialization/utils.nim create mode 100644 tools/confutils/envvar_serialization/writer.nim create mode 100644 tools/rln_keystore_generator/README.md create mode 100644 tools/rln_keystore_generator/rln_keystore_generator.nim create mode 160000 vendor/db_connector create mode 160000 vendor/dnsclient.nim create mode 160000 vendor/mix create mode 160000 vendor/nim-bearssl create mode 160000 vendor/nim-chronicles create mode 160000 vendor/nim-chronos create mode 160000 vendor/nim-confutils create mode 160000 vendor/nim-dnsdisc create mode 160000 vendor/nim-eth create mode 160000 vendor/nim-faststreams create mode 160000 vendor/nim-http-utils create mode 160000 vendor/nim-json-rpc create mode 160000 vendor/nim-json-serialization create mode 160000 vendor/nim-libbacktrace create mode 160000 vendor/nim-libp2p create mode 160000 vendor/nim-metrics create mode 160000 vendor/nim-minilru create mode 160000 vendor/nim-nat-traversal create mode 160000 vendor/nim-presto create mode 160000 vendor/nim-regex create mode 160000 vendor/nim-results create mode 160000 vendor/nim-secp256k1 create mode 160000 vendor/nim-serialization create mode 160000 vendor/nim-sqlite3-abi create mode 160000 vendor/nim-stew create mode 160000 vendor/nim-stint create mode 160000 vendor/nim-taskpools create mode 160000 vendor/nim-testutils create mode 160000 vendor/nim-toml-serialization create mode 160000 vendor/nim-unicodedb create mode 160000 vendor/nim-unittest2 create mode 160000 vendor/nim-web3 create mode 160000 vendor/nim-websock create mode 160000 vendor/nim-zlib create mode 160000 vendor/nimbus-build-system create mode 160000 vendor/nimcrypto create mode 160000 vendor/nph create mode 160000 vendor/waku-rlnv2-contract create mode 160000 vendor/zerokit create mode 100644 waku.nim create mode 100644 waku.nimble create mode 100644 waku/README.md create mode 100644 waku/api/api.nim create mode 100644 waku/api/api_conf.nim create mode 100644 waku/api/entry_nodes.nim create mode 100644 waku/common/base64.nim create mode 100644 waku/common/callbacks.nim create mode 100644 waku/common/databases/common.nim create mode 100644 waku/common/databases/db_postgres.nim create mode 100644 waku/common/databases/db_postgres/dbconn.nim create mode 100644 waku/common/databases/db_postgres/pgasyncpool.nim create mode 100644 waku/common/databases/db_postgres/query_metrics.nim create mode 100644 waku/common/databases/db_sqlite.nim create mode 100644 waku/common/databases/dburl.nim create mode 100644 waku/common/enr.nim create mode 100644 waku/common/enr/builder.nim create mode 100644 waku/common/enr/typed_record.nim create mode 100644 waku/common/error_handling.nim create mode 100644 waku/common/hexstrings.nim create mode 100644 waku/common/logging.nim create mode 100644 waku/common/nimchronos.nim create mode 100644 waku/common/paging.nim create mode 100644 waku/common/protobuf.nim create mode 100644 waku/common/rate_limit/per_peer_limiter.nim create mode 100644 waku/common/rate_limit/request_limiter.nim create mode 100644 waku/common/rate_limit/service_metrics.nim create mode 100644 waku/common/rate_limit/setting.nim create mode 100644 waku/common/rate_limit/single_token_limiter.nim create mode 100644 waku/common/rate_limit/timed_map.nim create mode 100644 waku/common/rate_limit/token_bucket.nim create mode 100644 waku/common/utils/DEPRECATION_NOTICE.md create mode 100644 waku/common/utils/matterbridge_client.nim create mode 100644 waku/common/utils/nat.nim create mode 100644 waku/common/utils/parse_size_units.nim create mode 100644 waku/common/utils/sequence.nim create mode 100644 waku/discovery/autonat_service.nim create mode 100644 waku/discovery/waku_discv5.nim create mode 100644 waku/discovery/waku_dnsdisc.nim create mode 100644 waku/factory/app_callbacks.nim create mode 100644 waku/factory/builder.nim create mode 100644 waku/factory/conf_builder/conf_builder.nim create mode 100644 waku/factory/conf_builder/discv5_conf_builder.nim create mode 100644 waku/factory/conf_builder/dns_discovery_conf_builder.nim create mode 100644 waku/factory/conf_builder/filter_service_conf_builder.nim create mode 100644 waku/factory/conf_builder/metrics_server_conf_builder.nim create mode 100644 waku/factory/conf_builder/mix_conf_builder.nim create mode 100644 waku/factory/conf_builder/rate_limit_conf_builder.nim create mode 100644 waku/factory/conf_builder/rest_server_conf_builder.nim create mode 100644 waku/factory/conf_builder/rln_relay_conf_builder.nim create mode 100644 waku/factory/conf_builder/store_service_conf_builder.nim create mode 100644 waku/factory/conf_builder/store_sync_conf_builder.nim create mode 100644 waku/factory/conf_builder/waku_conf_builder.nim create mode 100644 waku/factory/conf_builder/web_socket_conf_builder.nim create mode 100644 waku/factory/internal_config.nim create mode 100644 waku/factory/networks_config.nim create mode 100644 waku/factory/node_factory.nim create mode 100644 waku/factory/validator_signed.nim create mode 100644 waku/factory/waku.nim create mode 100644 waku/factory/waku_conf.nim create mode 100644 waku/incentivization/common.nim create mode 100644 waku/incentivization/eligibility_manager.nim create mode 100644 waku/incentivization/reputation_manager.nim create mode 100644 waku/incentivization/rpc.nim create mode 100644 waku/incentivization/rpc_codec.nim create mode 100644 waku/node/delivery_monitor/delivery_callback.nim create mode 100644 waku/node/delivery_monitor/delivery_monitor.nim create mode 100644 waku/node/delivery_monitor/not_delivered_storage/migrations.nim create mode 100644 waku/node/delivery_monitor/not_delivered_storage/not_delivered_storage.nim create mode 100644 waku/node/delivery_monitor/publish_observer.nim create mode 100644 waku/node/delivery_monitor/recv_monitor.nim create mode 100644 waku/node/delivery_monitor/send_monitor.nim create mode 100644 waku/node/delivery_monitor/subscriptions_observer.nim create mode 100644 waku/node/health_monitor.nim create mode 100644 waku/node/health_monitor/health_status.nim create mode 100644 waku/node/health_monitor/node_health_monitor.nim create mode 100644 waku/node/health_monitor/online_monitor.nim create mode 100644 waku/node/health_monitor/protocol_health.nim create mode 100644 waku/node/net_config.nim create mode 100644 waku/node/peer_manager.nim create mode 100644 waku/node/peer_manager/peer_manager.nim create mode 100644 waku/node/peer_manager/peer_store/migrations.nim create mode 100644 waku/node/peer_manager/peer_store/peer_storage.nim create mode 100644 waku/node/peer_manager/peer_store/waku_peer_storage.nim create mode 100644 waku/node/peer_manager/waku_peer_store.nim create mode 100644 waku/node/waku_metrics.nim create mode 100644 waku/node/waku_node.nim create mode 100644 waku/node/waku_switch.nim create mode 100644 waku/utils/DEPRECATION_NOTICE.md create mode 100644 waku/utils/collector.nim create mode 100644 waku/utils/noise.nim create mode 100644 waku/utils/requests.nim create mode 100644 waku/utils/tableutils.nim create mode 100644 waku/waku_api.nim create mode 100644 waku/waku_api/handlers.nim create mode 100644 waku/waku_api/message_cache.nim create mode 100644 waku/waku_api/rest/admin/client.nim create mode 100644 waku/waku_api/rest/admin/handlers.nim create mode 100644 waku/waku_api/rest/admin/types.nim create mode 100644 waku/waku_api/rest/builder.nim create mode 100644 waku/waku_api/rest/client.nim create mode 100644 waku/waku_api/rest/debug/client.nim create mode 100644 waku/waku_api/rest/debug/handlers.nim create mode 100644 waku/waku_api/rest/debug/types.nim create mode 100644 waku/waku_api/rest/filter/client.nim create mode 100644 waku/waku_api/rest/filter/handlers.nim create mode 100644 waku/waku_api/rest/filter/types.nim create mode 100644 waku/waku_api/rest/health/client.nim create mode 100644 waku/waku_api/rest/health/handlers.nim create mode 100644 waku/waku_api/rest/health/types.nim create mode 100644 waku/waku_api/rest/legacy_lightpush/client.nim create mode 100644 waku/waku_api/rest/legacy_lightpush/handlers.nim create mode 100644 waku/waku_api/rest/legacy_lightpush/types.nim create mode 100644 waku/waku_api/rest/legacy_store/client.nim create mode 100644 waku/waku_api/rest/legacy_store/handlers.nim create mode 100644 waku/waku_api/rest/legacy_store/types.nim create mode 100644 waku/waku_api/rest/lightpush/client.nim create mode 100644 waku/waku_api/rest/lightpush/handlers.nim create mode 100644 waku/waku_api/rest/lightpush/types.nim create mode 100644 waku/waku_api/rest/origin_handler.nim create mode 100644 waku/waku_api/rest/relay/client.nim create mode 100644 waku/waku_api/rest/relay/handlers.nim create mode 100644 waku/waku_api/rest/relay/types.nim create mode 100644 waku/waku_api/rest/responses.nim create mode 100644 waku/waku_api/rest/rest_serdes.nim create mode 100644 waku/waku_api/rest/serdes.nim create mode 100644 waku/waku_api/rest/server.nim create mode 100644 waku/waku_api/rest/store/client.nim create mode 100644 waku/waku_api/rest/store/handlers.nim create mode 100644 waku/waku_api/rest/store/types.nim create mode 100644 waku/waku_archive.nim create mode 100644 waku/waku_archive/archive.nim create mode 100644 waku/waku_archive/archive_metrics.nim create mode 100644 waku/waku_archive/common.nim create mode 100644 waku/waku_archive/driver.nim create mode 100644 waku/waku_archive/driver/builder.nim create mode 100644 waku/waku_archive/driver/postgres_driver.nim create mode 100644 waku/waku_archive/driver/postgres_driver/migrations.nim create mode 100644 waku/waku_archive/driver/postgres_driver/partitions_manager.nim create mode 100644 waku/waku_archive/driver/postgres_driver/postgres_driver.nim create mode 100644 waku/waku_archive/driver/postgres_driver/postgres_healthcheck.nim create mode 100644 waku/waku_archive/driver/queue_driver.nim create mode 100644 waku/waku_archive/driver/queue_driver/index.nim create mode 100644 waku/waku_archive/driver/queue_driver/queue_driver.nim create mode 100644 waku/waku_archive/driver/sqlite_driver.nim create mode 100644 waku/waku_archive/driver/sqlite_driver/migrations.nim create mode 100644 waku/waku_archive/driver/sqlite_driver/queries.nim create mode 100644 waku/waku_archive/driver/sqlite_driver/sqlite_driver.nim create mode 100644 waku/waku_archive/retention_policy.nim create mode 100644 waku/waku_archive/retention_policy/builder.nim create mode 100644 waku/waku_archive/retention_policy/retention_policy_capacity.nim create mode 100644 waku/waku_archive/retention_policy/retention_policy_size.nim create mode 100644 waku/waku_archive/retention_policy/retention_policy_time.nim create mode 100644 waku/waku_archive_legacy.nim create mode 100644 waku/waku_archive_legacy/archive.nim create mode 100644 waku/waku_archive_legacy/archive_metrics.nim create mode 100644 waku/waku_archive_legacy/common.nim create mode 100644 waku/waku_archive_legacy/driver.nim create mode 100644 waku/waku_archive_legacy/driver/builder.nim create mode 100644 waku/waku_archive_legacy/driver/postgres_driver.nim create mode 100644 waku/waku_archive_legacy/driver/postgres_driver/postgres_driver.nim create mode 100644 waku/waku_archive_legacy/driver/postgres_driver/postgres_healthcheck.nim create mode 100644 waku/waku_archive_legacy/driver/queue_driver.nim create mode 100644 waku/waku_archive_legacy/driver/queue_driver/index.nim create mode 100644 waku/waku_archive_legacy/driver/queue_driver/queue_driver.nim create mode 100644 waku/waku_archive_legacy/driver/sqlite_driver.nim create mode 100644 waku/waku_archive_legacy/driver/sqlite_driver/cursor.nim create mode 100644 waku/waku_archive_legacy/driver/sqlite_driver/migrations.nim create mode 100644 waku/waku_archive_legacy/driver/sqlite_driver/queries.nim create mode 100644 waku/waku_archive_legacy/driver/sqlite_driver/sqlite_driver.nim create mode 100644 waku/waku_core.nim create mode 100644 waku/waku_core/codecs.nim create mode 100644 waku/waku_core/message.nim create mode 100644 waku/waku_core/message/codec.nim create mode 100644 waku/waku_core/message/default_values.nim create mode 100644 waku/waku_core/message/digest.nim create mode 100644 waku/waku_core/message/message.nim create mode 100644 waku/waku_core/multiaddrstr.nim create mode 100644 waku/waku_core/peers.nim create mode 100644 waku/waku_core/subscription.nim create mode 100644 waku/waku_core/subscription/push_handler.nim create mode 100644 waku/waku_core/subscription/subscription_manager.nim create mode 100644 waku/waku_core/time.nim create mode 100644 waku/waku_core/topics.nim create mode 100644 waku/waku_core/topics/content_topic.nim create mode 100644 waku/waku_core/topics/parsing.nim create mode 100644 waku/waku_core/topics/pubsub_topic.nim create mode 100644 waku/waku_core/topics/sharding.nim create mode 100644 waku/waku_enr.nim create mode 100644 waku/waku_enr/capabilities.nim create mode 100644 waku/waku_enr/mix.nim create mode 100644 waku/waku_enr/multiaddr.nim create mode 100644 waku/waku_enr/sharding.nim create mode 100644 waku/waku_filter_v2.nim create mode 100644 waku/waku_filter_v2/client.nim create mode 100644 waku/waku_filter_v2/common.nim create mode 100644 waku/waku_filter_v2/protocol.nim create mode 100644 waku/waku_filter_v2/protocol_metrics.nim create mode 100644 waku/waku_filter_v2/rpc.nim create mode 100644 waku/waku_filter_v2/rpc_codec.nim create mode 100644 waku/waku_filter_v2/subscriptions.nim create mode 100644 waku/waku_keystore.nim create mode 100644 waku/waku_keystore/conversion_utils.nim create mode 100644 waku/waku_keystore/keyfile.nim create mode 100644 waku/waku_keystore/keystore.nim create mode 100644 waku/waku_keystore/protocol_types.nim create mode 100644 waku/waku_keystore/utils.nim create mode 100644 waku/waku_lightpush.nim create mode 100644 waku/waku_lightpush/callbacks.nim create mode 100644 waku/waku_lightpush/client.nim create mode 100644 waku/waku_lightpush/common.nim create mode 100644 waku/waku_lightpush/protocol.nim create mode 100644 waku/waku_lightpush/protocol_metrics.nim create mode 100644 waku/waku_lightpush/rpc.nim create mode 100644 waku/waku_lightpush/rpc_codec.nim create mode 100644 waku/waku_lightpush/self_req_handler.nim create mode 100644 waku/waku_lightpush_legacy.nim create mode 100644 waku/waku_lightpush_legacy/README.md create mode 100644 waku/waku_lightpush_legacy/callbacks.nim create mode 100644 waku/waku_lightpush_legacy/client.nim create mode 100644 waku/waku_lightpush_legacy/common.nim create mode 100644 waku/waku_lightpush_legacy/protocol.nim create mode 100644 waku/waku_lightpush_legacy/protocol_metrics.nim create mode 100644 waku/waku_lightpush_legacy/rpc.nim create mode 100644 waku/waku_lightpush_legacy/rpc_codec.nim create mode 100644 waku/waku_lightpush_legacy/self_req_handler.nim create mode 100644 waku/waku_metadata.nim create mode 100644 waku/waku_metadata/protocol.nim create mode 100644 waku/waku_metadata/rpc.nim create mode 100644 waku/waku_mix.nim create mode 100644 waku/waku_mix/protocol.nim create mode 100644 waku/waku_node.nim create mode 100644 waku/waku_noise/noise.nim create mode 100644 waku/waku_noise/noise_handshake_processing.nim create mode 100644 waku/waku_noise/noise_types.nim create mode 100644 waku/waku_noise/noise_utils.nim create mode 100644 waku/waku_peer_exchange.nim create mode 100644 waku/waku_peer_exchange/README.md create mode 100644 waku/waku_peer_exchange/client.nim create mode 100644 waku/waku_peer_exchange/common.nim create mode 100644 waku/waku_peer_exchange/protocol.nim create mode 100644 waku/waku_peer_exchange/rpc.nim create mode 100644 waku/waku_peer_exchange/rpc_codec.nim create mode 100644 waku/waku_relay.nim create mode 100644 waku/waku_relay/message_id.nim create mode 100644 waku/waku_relay/protocol.nim create mode 100644 waku/waku_relay/topic_health.nim create mode 100644 waku/waku_rendezvous.nim create mode 100644 waku/waku_rendezvous/common.nim create mode 100644 waku/waku_rendezvous/protocol.nim create mode 100644 waku/waku_rln_relay.nim create mode 100644 waku/waku_rln_relay/constants.nim create mode 100644 waku/waku_rln_relay/contract.nim create mode 100644 waku/waku_rln_relay/conversion_utils.nim create mode 100644 waku/waku_rln_relay/group_manager.nim create mode 100644 waku/waku_rln_relay/group_manager/group_manager_base.nim create mode 100644 waku/waku_rln_relay/group_manager/on_chain.nim create mode 100644 waku/waku_rln_relay/group_manager/on_chain/group_manager.nim create mode 100644 waku/waku_rln_relay/group_manager/on_chain/retry_wrapper.nim create mode 100644 waku/waku_rln_relay/group_manager/on_chain/rpc_wrapper.nim create mode 100644 waku/waku_rln_relay/nonce_manager.nim create mode 100644 waku/waku_rln_relay/protocol_metrics.nim create mode 100644 waku/waku_rln_relay/protocol_types.nim create mode 100644 waku/waku_rln_relay/rln.nim create mode 100644 waku/waku_rln_relay/rln/rln_interface.nim create mode 100644 waku/waku_rln_relay/rln/wrappers.nim create mode 100644 waku/waku_rln_relay/rln_relay.nim create mode 100644 waku/waku_store.nim create mode 100644 waku/waku_store/client.nim create mode 100644 waku/waku_store/common.nim create mode 100644 waku/waku_store/protocol.nim create mode 100644 waku/waku_store/protocol_metrics.nim create mode 100644 waku/waku_store/resume.nim create mode 100644 waku/waku_store/rpc_codec.nim create mode 100644 waku/waku_store/self_req_handler.nim create mode 100644 waku/waku_store_legacy.nim create mode 100644 waku/waku_store_legacy/README.md create mode 100644 waku/waku_store_legacy/client.nim create mode 100644 waku/waku_store_legacy/common.nim create mode 100644 waku/waku_store_legacy/protocol.nim create mode 100644 waku/waku_store_legacy/protocol_metrics.nim create mode 100644 waku/waku_store_legacy/rpc.nim create mode 100644 waku/waku_store_legacy/rpc_codec.nim create mode 100644 waku/waku_store_legacy/self_req_handler.nim create mode 100644 waku/waku_store_sync.nim create mode 100644 waku/waku_store_sync/codec.nim create mode 100644 waku/waku_store_sync/common.nim create mode 100644 waku/waku_store_sync/protocols_metrics.nim create mode 100644 waku/waku_store_sync/reconciliation.nim create mode 100644 waku/waku_store_sync/storage/range_processing.nim create mode 100644 waku/waku_store_sync/storage/seq_storage.nim create mode 100644 waku/waku_store_sync/storage/storage.nim create mode 100644 waku/waku_store_sync/transfer.nim diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..247ac61 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +/README.md +/Dockerfile +/.*ignore +/LICENSE* +/tests +/metrics +/nimcache +librln* +**/vendor/* diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e7f569e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true + + +[{Makefile, *.sh}] +indent_style = tab + +# Trailing spaces in markdown indicate word wrap +[{*.markdown,*.md}] +trim_trailing_spaces = false +max_line_length = 80 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..8e54bbf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,34 @@ +--- +name: Bug report +about: Report any bugs or unexpected behavior +title: 'bug: ' +labels: bug, track:maintenance +assignees: '' + +--- + +### Problem +A clear and concise description of what the bug is. + +### Impact +Indicate how significant you believe the impact of the bug is. Bugs that lead to data loss or corruption would be considered `critical`. In such cases, please also add the `critical` label. + +### To reproduce +If you can reproduce the behavior, steps to reproduce: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +### Expected behavior +A clear and concise description of what you expected to happen. + +### Screenshots/logs +If applicable, add screenshots or logs to help explain your problem. + +### nwaku version/commit hash +State the version of `nwaku` where you've encountered the bug or, if built off a specific commit, the relevant commit hash. You can check the version by running `./wakunode2 --version`. +- e.g. `v0.9` or `ed53bcd` + +### Additional context +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/bump_dependencies.md b/.github/ISSUE_TEMPLATE/bump_dependencies.md new file mode 100644 index 0000000..0413cbf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bump_dependencies.md @@ -0,0 +1,48 @@ +--- +name: Bump dependencies +about: Bump vendor dependencies for release +title: 'Bump vendor dependencies for release 0.0.0' +labels: dependencies +assignees: '' + +--- + + + +Update `nwaku` "vendor" dependencies. + +### Items to bump +- [ ] dnsclient.nim ( update to the latest tag version ) +- [ ] nim-bearssl +- [ ] nimbus-build-system +- [ ] nim-chronicles +- [ ] nim-chronos +- [ ] nim-confutils +- [ ] nimcrypto +- [ ] nim-dnsdisc +- [ ] nim-eth +- [ ] nim-faststreams +- [ ] nim-http-utils +- [ ] nim-json-rpc +- [ ] nim-json-serialization +- [ ] nim-libbacktrace +- [ ] nim-libp2p ( update to the latest tag version ) +- [ ] nim-metrics +- [ ] nim-nat-traversal +- [ ] nim-presto +- [ ] nim-regex ( update to the latest tag version ) +- [ ] nim-results +- [ ] nim-secp256k1 +- [ ] nim-serialization +- [ ] nim-sqlite3-abi ( update to the latest tag version ) +- [ ] nim-stew +- [ ] nim-stint +- [ ] nim-taskpools ( update to the latest tag version ) +- [ ] nim-testutils ( update to the latest tag version ) +- [ ] nim-toml-serialization +- [ ] nim-unicodedb +- [ ] nim-unittest2 ( update to the latest tag version ) +- [ ] nim-web3 ( update to the latest tag version ) +- [ ] nim-websock ( update to the latest tag version ) +- [ ] nim-zlib +- [ ] zerokit ( this should be kept in version `v0.7.0` ) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..52e2164 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,26 @@ +--- +name: Feature request +about: Suggest an idea for the nwaku implementation +title: 'feat: ' +labels: track:production +assignees: '' + +--- + +### Problem +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +### Suggested solution +A clear and concise description of what you want to happen. + +### Alternatives considered +A clear and concise description of any alternative solutions or features you've considered. + +### Additional context +Add any other context or screenshots about the feature request here. + +### Acceptance criteria +A list of tasks that need to be done for the issue to be considered resolved. + +### Epic +Epic title and link the feature refers to. diff --git a/.github/ISSUE_TEMPLATE/improvement.md b/.github/ISSUE_TEMPLATE/improvement.md new file mode 100644 index 0000000..5dee34f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/improvement.md @@ -0,0 +1,17 @@ +--- +name: Improvement +about: Suggest improvements to the codebase or processes. This includes refactoring, + docs and any other chores. +title: 'chore:' +labels: track:maintenance +assignees: '' + +--- +### Background +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]; There is a spelling error in [...]; It's difficult to read the code in module [...] + +### Details +A clear and concise description of what you want to happen. + +### Acceptance criteria +A list of tasks that need to be done for the issue to be considered resolved. diff --git a/.github/ISSUE_TEMPLATE/milestone.md b/.github/ISSUE_TEMPLATE/milestone.md new file mode 100644 index 0000000..d167ce1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/milestone.md @@ -0,0 +1,41 @@ +--- +name: Milestone Issue Template +about: Track Milestones +title: "[Milestone] " +labels: milestone +assignees: '' + +--- + + + + +**Planned start date**: +**Due date**: + +# Summary + +# Acceptance Criteria + + + +## Tasks + + + +# RAID (Risks, Assumptions, Issues and Dependencies) + + + + + + + + diff --git a/.github/ISSUE_TEMPLATE/prepare_release.md b/.github/ISSUE_TEMPLATE/prepare_release.md new file mode 100644 index 0000000..9553d56 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/prepare_release.md @@ -0,0 +1,72 @@ +--- +name: Prepare release +about: Execute tasks for the creation and publishing of a new release +title: 'Prepare release 0.0.0' +labels: release +assignees: '' + +--- + + + +### Items to complete + +All items below are to be completed by the owner of the given release. + +- [ ] Create release branch +- [ ] Assign release candidate tag to the release branch HEAD. e.g. v0.30.0-rc.0 +- [ ] Generate and edit releases notes in CHANGELOG.md +- [ ] Review possible update of [config-options](https://github.com/waku-org/docs.waku.org/blob/develop/docs/guides/nwaku/config-options.md) +- [ ] _End user impact_: Summarize impact of changes on Status end users (can be a comment in this issue). +- [ ] **Validate release candidate** + - [ ] Bump nwaku dependency in [waku-rust-bindings](https://github.com/waku-org/waku-rust-bindings) and make sure all examples and tests work + +- [ ] Automated testing + - [ ] Ensures js-waku tests are green against release candidate + - [ ] Ask Vac-QA and Vac-DST to perform available tests against release candidate + - [ ] Vac-QA + - [ ] Vac-DST (we need additional report. see [this](https://www.notion.so/DST-Reports-1228f96fb65c80729cd1d98a7496fe6f)) + + - [ ] **On Waku fleets** + - [ ] Lock `waku.test` fleet to release candidate version + - [ ] Continuously stress `waku.test` fleet for a week (e.g. from `wakudev`) + - [ ] Search _Kibana_ logs from the previous month (since last release was deployed), for possible crashes or errors in `waku.test` and `waku.sandbox`. + - Most relevant logs are `(fleet: "waku.test" OR fleet: "waku.sandbox") AND message: "SIGSEGV"` + - [ ] Run release candidate with `waku-simulator`, ensure that nodes connected to each other + - [ ] Unlock `waku.test` to resume auto-deployment of latest `master` commit + + - [ ] **On Status fleet** + - [ ] Deploy release candidate to `status.staging` + - [ ] Perform [sanity check](https://www.notion.so/How-to-test-Nwaku-on-Status-12c6e4b9bf06420ca868bd199129b425) and log results as comments in this issue. + - [ ] Connect 2 instances to `status.staging` fleet, one in relay mode, the other one in light client. + - [ ] 1:1 Chats with each other + - [ ] Send and receive messages in a community + - [ ] Close one instance, send messages with second instance, reopen first instance and confirm messages sent while offline are retrieved from store + - [ ] Perform checks based _end user impact_ + - [ ] Inform other (Waku and Status) CCs to point their instance to `status.staging` for a few days. Ping Status colleagues from their Discord server or [Status community](https://status.app/c/G3kAAMSQtb05kog3aGbr3kiaxN4tF5xy4BAGEkkLwILk2z3GcoYlm5hSJXGn7J3laft-tnTwDWmYJ18dP_3bgX96dqr_8E3qKAvxDf3NrrCMUBp4R9EYkQez9XSM4486mXoC3mIln2zc-TNdvjdfL9eHVZ-mGgs=#zQ3shZeEJqTC1xhGUjxuS4rtHSrhJ8vUYp64v6qWkLpvdy9L9) (not blocking point.) + - [ ] Ask Status-QA to perform sanity checks (as described above) + checks based on _end user impact_; do specify the version being tested + - [ ] Ask Status-QA or infra to run the automated Status e2e tests against `status.staging` + - [ ] Get other CCs sign-off: they comment on this PR "used app for a week, no problem", or problem reported, resolved and new RC + - [ ] **Get Status-QA sign-off**. Ensuring that `status.test` update will not disturb ongoing activities. + +- [ ] **Proceed with release** + + - [ ] Assign a release tag to the same commit that contains the validated release-candidate tag + - [ ] Create GitHub release + - [ ] Deploy the release to DockerHub + - [ ] Announce the release + +- [ ] **Promote release to fleets**. + - [ ] Update infra config with any deprecated arguments or changed options + - [ ] [Deploy final release to `waku.sandbox` fleet](https://ci.infra.status.im/job/nim-waku/job/deploy-waku-sandbox) + - [ ] [Deploy final release to `status.staging` fleet](https://ci.infra.status.im/job/nim-waku/job/deploy-shards-staging/) + - [ ] [Deploy final release to `status.prod` fleet](https://ci.infra.status.im/job/nim-waku/job/deploy-shards-test/) + +- [ ] **Post release** + - [ ] Submit a PR from the release branch to master. Important to commit the PR with "create a merge commit" option. + - [ ] Update waku-org/nwaku-compose with the new release version. + - [ ] Update version in js-waku repo. [update only this](https://github.com/waku-org/js-waku/blob/7c0ce7b2eca31cab837da0251e1e4255151be2f7/.github/workflows/ci.yml#L135) by submitting a PR. diff --git a/.github/ISSUE_TEMPLATE/research-related-issue.md b/.github/ISSUE_TEMPLATE/research-related-issue.md new file mode 100644 index 0000000..b90b7d8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/research-related-issue.md @@ -0,0 +1,19 @@ +--- +name: Research-related issue +about: Use this template if your issue is related to any Vac research tracks +title: 'research:' +labels: '' +assignees: '' + +--- + +### Problem + +### Acceptance criteria + +### Details + +### Possible Solutions + +### Research track +Indicate the Vac research track that this issue relates to. Please also add the relevant track as a label. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..b5aba5c --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,8 @@ + +## Description + +## Changes + +## Issue + +closes # diff --git a/.github/workflows/auto_assign_pr.yml b/.github/workflows/auto_assign_pr.yml new file mode 100644 index 0000000..39847b0 --- /dev/null +++ b/.github/workflows/auto_assign_pr.yml @@ -0,0 +1,12 @@ +name: Auto Assign PR to Creator + +on: + pull_request: + types: + - opened + +jobs: + assign_creator: + runs-on: ubuntu-22.04 + steps: + - uses: toshimaru/auto-author-assign@v1.6.2 \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..5b32193 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,191 @@ +name: ci + +on: + pull_request: + push: + branches: + - master + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +env: + NPROC: 2 + MAKEFLAGS: "-j${NPROC}" + NIMFLAGS: "--parallelBuild:${NPROC} --colors:off -d:chronicles_colors:none" + +jobs: + changes: # changes detection + runs-on: ubuntu-22.04 + permissions: + pull-requests: read + steps: + - uses: actions/checkout@v4 + name: Checkout code + id: checkout + - uses: dorny/paths-filter@v2 + id: filter + with: + filters: | + common: + - '.github/workflows/**' + - 'vendor/**' + - 'Makefile' + - 'waku.nimble' + - 'library/**' + v2: + - 'waku/**' + - 'apps/**' + - 'tools/**' + - 'tests/all_tests_v2.nim' + - 'tests/**' + docker: + - 'docker/**' + + outputs: + common: ${{ steps.filter.outputs.common }} + v2: ${{ steps.filter.outputs.v2 }} + docker: ${{ steps.filter.outputs.docker }} + + build: + needs: changes + if: ${{ needs.changes.outputs.v2 == 'true' || needs.changes.outputs.common == 'true' }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-22.04, macos-13] + runs-on: ${{ matrix.os }} + timeout-minutes: 60 + + name: build-${{ matrix.os }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Get submodules hash + id: submodules + run: | + echo "hash=$(git submodule status | awk '{print $1}' | sort | shasum -a 256 | sed 's/[ -]*//g')" >> $GITHUB_OUTPUT + + - name: Cache submodules + uses: actions/cache@v3 + with: + path: | + vendor/ + .git/modules + key: ${{ runner.os }}-vendor-modules-${{ steps.submodules.outputs.hash }} + + - name: Build binaries + run: make V=1 QUICK_AND_DIRTY_COMPILER=1 all tools + + build-windows: + needs: changes + if: ${{ needs.changes.outputs.v2 == 'true' || needs.changes.outputs.common == 'true' }} + uses: ./.github/workflows/windows-build.yml + with: + branch: ${{ github.ref }} + + test: + needs: changes + if: ${{ needs.changes.outputs.v2 == 'true' || needs.changes.outputs.common == 'true' }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-22.04, macos-13] + runs-on: ${{ matrix.os }} + timeout-minutes: 60 + + name: test-${{ matrix.os }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Get submodules hash + id: submodules + run: | + echo "hash=$(git submodule status | awk '{print $1}' | sort | shasum -a 256 | sed 's/[ -]*//g')" >> $GITHUB_OUTPUT + + - name: Cache submodules + uses: actions/cache@v3 + with: + path: | + vendor/ + .git/modules + key: ${{ runner.os }}-vendor-modules-${{ steps.submodules.outputs.hash }} + + - name: Run tests + run: | + postgres_enabled=0 + if [ ${{ runner.os }} == "Linux" ]; then + sudo docker run --rm -d -e POSTGRES_PASSWORD=test123 -p 5432:5432 postgres:15.4-alpine3.18 + postgres_enabled=1 + fi + + export MAKEFLAGS="-j1" + export NIMFLAGS="--colors:off -d:chronicles_colors:none" + export USE_LIBBACKTRACE=0 + + make V=1 LOG_LEVEL=DEBUG QUICK_AND_DIRTY_COMPILER=1 POSTGRES=$postgres_enabled test + make V=1 LOG_LEVEL=DEBUG QUICK_AND_DIRTY_COMPILER=1 POSTGRES=$postgres_enabled testwakunode2 + + build-docker-image: + needs: changes + if: ${{ needs.changes.outputs.v2 == 'true' || needs.changes.outputs.common == 'true' || needs.changes.outputs.docker == 'true' }} + uses: waku-org/nwaku/.github/workflows/container-image.yml@master + secrets: inherit + + nwaku-nwaku-interop-tests: + needs: build-docker-image + uses: waku-org/waku-interop-tests/.github/workflows/nim_waku_PR.yml@SMOKE_TEST_0.0.1 + with: + node_nwaku: ${{ needs.build-docker-image.outputs.image }} + + secrets: inherit + + js-waku-node: + needs: build-docker-image + uses: waku-org/js-waku/.github/workflows/test-node.yml@master + with: + nim_wakunode_image: ${{ needs.build-docker-image.outputs.image }} + test_type: node + + js-waku-node-optional: + needs: build-docker-image + uses: waku-org/js-waku/.github/workflows/test-node.yml@master + with: + nim_wakunode_image: ${{ needs.build-docker-image.outputs.image }} + test_type: node-optional + + lint: + name: "Lint" + runs-on: ubuntu-22.04 + needs: build + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Get submodules hash + id: submodules + run: | + echo "hash=$(git submodule status | awk '{print $1}' | sort | shasum -a 256 | sed 's/[ -]*//g')" >> $GITHUB_OUTPUT + + - name: Cache submodules + uses: actions/cache@v3 + with: + path: | + vendor/ + .git/modules + key: ${{ runner.os }}-vendor-modules-${{ steps.submodules.outputs.hash }} + + - name: Build nph + run: | + make build-nph + + - name: Check nph formatting + run: | + shopt -s extglob # Enable extended globbing + NPH=$(make print-nph-path) + echo "using nph at ${NPH}" + "${NPH}" examples waku tests tools apps *.@(nim|nims|nimble) + git diff --exit-code diff --git a/.github/workflows/container-image.yml b/.github/workflows/container-image.yml new file mode 100644 index 0000000..cfa66d2 --- /dev/null +++ b/.github/workflows/container-image.yml @@ -0,0 +1,99 @@ +name: container-image-build + +on: + workflow_call: + inputs: + image_tag: + type: string + default: ${{ github.event.number }} + outputs: + image: + description: The resulting image link + value: ${{ jobs.build-docker-image.outputs.image }} + +env: + NPROC: 2 + MAKEFLAGS: "-j${NPROC}" + NIMFLAGS: "--parallelBuild:${NPROC}" + +# This workflow should not run for outside contributors +# If org secrets are not available, we'll avoid building and publishing the docker image and we'll pass the workflow +jobs: + build-docker-image: + strategy: + matrix: + os: [ubuntu-22.04] + runs-on: ${{ matrix.os }} + timeout-minutes: 60 + + name: docker-build-${{ matrix.os }} + outputs: + image: ${{ steps.build.outputs.image }} + steps: + - name: Check secrets + id: secrets + continue-on-error: true + run: | + if [[ -z "$QUAY_PASSWORD" || -z "$QUAY_USER" ]]; then + echo "User does not have access to secrets, skipping workflow" + exit 1 + fi + env: + QUAY_PASSWORD: ${{ secrets.QUAY_PASSWORD }} + QUAY_USER: ${{ secrets.QUAY_USER }} + + - name: Checkout code + if: ${{ steps.secrets.outcome == 'success' }} + uses: actions/checkout@v4 + + - name: Get submodules hash + id: submodules + if: ${{ steps.secrets.outcome == 'success' }} + run: | + echo "hash=$(git submodule status | awk '{print $1}' | sort | shasum -a 256 | sed 's/[ -]*//g')" >> $GITHUB_OUTPUT + + - name: Cache submodules + if: ${{ steps.secrets.outcome == 'success' }} + uses: actions/cache@v3 + with: + path: | + vendor/ + .git/modules + key: ${{ runner.os }}-vendor-modules-${{ steps.submodules.outputs.hash }} + + - name: Build binaries + id: build + if: ${{ steps.secrets.outcome == 'success' }} + run: | + + make -j${NPROC} V=1 QUICK_AND_DIRTY_COMPILER=1 NIMFLAGS="-d:disableMarchNative -d:postgres -d:chronicles_colors:none" wakunode2 + + SHORT_REF=$(git rev-parse --short HEAD) + + TAG=$([ "${PR_NUMBER}" == "" ] && echo "${SHORT_REF}" || echo "${PR_NUMBER}") + IMAGE=quay.io/wakuorg/nwaku-pr:${TAG} + + echo "image=${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} + env: + QUAY_PASSWORD: ${{ secrets.QUAY_PASSWORD }} + QUAY_USER: ${{ secrets.QUAY_USER }} + PR_NUMBER: ${{ inputs.image_tag}} + + - name: Comment PR + uses: thollander/actions-comment-pull-request@v2 + if: ${{ github.event_name == 'pull_request' && steps.secrets.outcome == 'success' }} + with: + message: | + You can find the image built from this PR at + + ``` + ${{steps.build.outputs.image}} + ``` + + Built from ${{ steps.build.outputs.commit_hash }} + comment_tag: execution-rln-v${{ matrix.rln_version }} diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml new file mode 100644 index 0000000..d3ac05f --- /dev/null +++ b/.github/workflows/pr-lint.yml @@ -0,0 +1,54 @@ +name: "Lint PR" + +on: + pull_request_target: + types: + - opened + - edited + - synchronize + +jobs: + labels: + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v4 + name: Checkout code + id: checkout + - uses: dorny/paths-filter@v2 + id: filter + with: + filters: | + config: + - 'apps/wakunode2/external_config.nim' + - 'apps/networkmonitor/networkmonitor_config.nim' + - 'apps/chat2/config_chat2.nim' + - 'apps/chat2bridge/config_chat2bridge.nim' + + db_schema: + - 'waku/waku_archive/driver/postgres_driver/postgres_driver.nim' + - 'waku/waku_archive/driver/sqlite_driver/queries.nim' + - name: Comment config change + uses: thollander/actions-comment-pull-request@v2 + if: ${{steps.filter.outputs.config == 'true'}} + with: + message: | + This PR may contain changes to **configuration options** of one of the apps. + + If you are introducing a breaking change (i.e. the set of options in latest release would no longer be applicable) make sure the original option is preserved with a *deprecation* note for 2 following releases before it is actually removed. + + Please also make sure the label `release-notes` is added to make sure any changes to the user interface are properly announced in changelog and release notes. + comment_tag: configs + + - name: Comment DB schema change + uses: thollander/actions-comment-pull-request@v2 + if: ${{steps.filter.outputs.db_schema == 'true'}} + with: + header: pr-title-lint-error + message: | + This PR may contain changes to **database schema** of one of the drivers. + + If you are introducing any changes to the schema, make sure the upgrade from the latest release to this change passes without any errors/issues. + + Please make sure the label `release-notes` is added to make sure upgrade instructions properly highlight this change. + comment_tag: db_schema diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml new file mode 100644 index 0000000..b138a22 --- /dev/null +++ b/.github/workflows/pre-release.yml @@ -0,0 +1,163 @@ +name: Pre-Release + +on: + push: + tags: + - 'v*-rc.*' + schedule: + - cron: 13 3 * * * + workflow_dispatch: + +env: + RELEASE_NAME: nightly + + NPROC: 2 + MAKEFLAGS: "-j${NPROC}" + NIMFLAGS: "--parallelBuild:${NPROC}" + +jobs: + tag-name: + runs-on: ubuntu-22.04 + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Vars + id: vars + run: | + TAG=$([[ "${{github.ref}}" == "refs/heads/master" ]] && echo "${{env.RELEASE_NAME}}" || echo ${{github.ref}} | sed 's#refs/tags/##') + echo "tag=${TAG}" >> $GITHUB_OUTPUT + outputs: + tag: ${{steps.vars.outputs.tag}} + + build-and-publish: + needs: tag-name + strategy: + matrix: + os: [ubuntu-22.04, macos-13] + arch: [amd64] + include: + - os: macos-13 + arch: arm64 + runs-on: ${{ matrix.os }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: prep variables + id: vars + run: | + ARCH=${{matrix.arch}} + + echo "arch=${ARCH}" >> $GITHUB_OUTPUT + + NWAKU_ARTIFACT_NAME=$(echo "nwaku-${ARCH}-${{runner.os}}-${{ needs.tag-name.outputs.tag }}.tar.gz" | tr "[:upper:]" "[:lower:]") + NWAKU_TOOLS_ARTIFACT_NAME=$(echo "nwaku-tools-${ARCH}-${{runner.os}}-${{ needs.tag-name.outputs.tag }}.tar.gz" | tr "[:upper:]" "[:lower:]") + + echo "nwaku=${NWAKU_ARTIFACT_NAME}" >> $GITHUB_OUTPUT + echo "nwakutools=${NWAKU_TOOLS_ARTIFACT_NAME}" >> $GITHUB_OUTPUT + + + - name: build artifacts + id: build + run: | + OS=$([[ "${{runner.os}}" == "macOS" ]] && echo "macosx" || echo "linux") + + make QUICK_AND_DIRTY_COMPILER=1 V=1 CI=false NIMFLAGS="-d:disableMarchNative --os:${OS} --cpu:${{matrix.arch}}" \ + update + + make QUICK_AND_DIRTY_COMPILER=1 V=1 CI=false\ + NIMFLAGS="-d:disableMarchNative --os:${OS} --cpu:${{matrix.arch}} -d:postgres" \ + wakunode2\ + chat2\ + tools + + tar -cvzf ${{steps.vars.outputs.nwaku}} ./build/wakunode2 ./build/chat2 + tar -cvzf ${{steps.vars.outputs.nwakutools}} ./build/wakucanary ./build/networkmonitor + + - name: upload artifacts + uses: actions/upload-artifact@v4 + with: + name: wakunode2 + path: ${{steps.vars.outputs.nwaku}} + retention-days: 2 + + - name: upload artifacts + uses: actions/upload-artifact@v4 + with: + name: wakutools + path: ${{steps.vars.outputs.nwakutools}} + retention-days: 2 + + build-docker-image: + needs: tag-name + uses: waku-org/nwaku/.github/workflows/container-image.yml@master + with: + image_tag: ${{ needs.tag-name.outputs.tag }} + secrets: inherit + + js-waku-node: + needs: build-docker-image + uses: waku-org/js-waku/.github/workflows/test-node.yml@master + with: + nim_wakunode_image: ${{ needs.build-docker-image.outputs.image }} + test_type: node + debug: waku* + + js-waku-node-optional: + needs: build-docker-image + uses: waku-org/js-waku/.github/workflows/test-node.yml@master + with: + nim_wakunode_image: ${{ needs.build-docker-image.outputs.image }} + test_type: node-optional + debug: waku* + + create-release-candidate: + runs-on: ubuntu-22.04 + needs: [ tag-name, build-and-publish ] + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: master + + - name: download artifacts + uses: actions/download-artifact@v4 + + - name: prep variables + id: vars + run: | + REF=$(echo ${{github.ref}} | sed 's#.*/##') + + echo "ref=${REF}" >> $GITHUB_OUTPUT + + - name: generate release notes + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -x + gh release view ${{ needs.tag-name.outputs.tag }} &>/dev/null &&\ + gh release delete -y ${{ needs.tag-name.outputs.tag }} &&\ + [[ "${{ needs.tag-name.outputs.tag }}" == "nightly" ]] && git tag -d ${{ needs.tag-name.outputs.tag }} + + RELEASE_NOTES_TAG=$([[ "${{ needs.tag-name.outputs.tag }}" != "nightly" ]] && echo "-t ${{steps.vars.outputs.ref}}" || echo "") + + docker run \ + -t \ + --rm \ + -v ${PWD}:/opt/sv4git/repo:z \ + -u $(id -u) \ + docker.io/wakuorg/sv4git:latest \ + release-notes ${RELEASE_NOTES_TAG} --previous $(git tag -l --sort -creatordate | grep -e "^v[0-9]*\.[0-9]*\.[0-9]*$") |\ + sed -E 's@#([0-9]+)@[#\1](https://github.com/waku-org/nwaku/issues/\1)@g' > release_notes.md + + sed -i "s/^## .*/Generated at $(date)/" release_notes.md + + cat release_notes.md + + TARGET=$([[ "${{ needs.tag-name.outputs.tag }}" == "nightly" ]] && echo "--target ${{steps.vars.outputs.ref}}" || echo "") + + gh release create ${{ needs.tag-name.outputs.tag }} --prerelease ${TARGET} \ + --title ${{ needs.tag-name.outputs.tag }} --notes-file release_notes.md \ + wakunode2/* wakutools/* diff --git a/.github/workflows/release-assets.yml b/.github/workflows/release-assets.yml new file mode 100644 index 0000000..2c7c260 --- /dev/null +++ b/.github/workflows/release-assets.yml @@ -0,0 +1,65 @@ +name: Upload Release Asset + +on: + push: + tags: + - 'v*' # "e.g. v0.4" + + workflow_dispatch: + +env: + NPROC: 2 + +jobs: + build-and-upload: + strategy: + matrix: + os: [ubuntu-22.04, macos-13] + arch: [amd64] + include: + - os: macos-13 + arch: arm64 + runs-on: ${{ matrix.os }} + timeout-minutes: 60 + + name: ${{ matrix.os }} - ${{ matrix.arch }} + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Get submodules hash + id: submodules + run: | + echo "hash=$(git submodule status | awk '{print $1}' | sort | shasum -a 256 | sed 's/[ -]*//g')" >> $GITHUB_OUTPUT + + - name: Cache submodules + uses: actions/cache@v3 + with: + path: | + vendor/ + .git/modules + key: ${{ runner.os }}-${{matrix.arch}}-submodules-${{ steps.submodules.outputs.hash }} + + - name: prep variables + id: vars + run: | + NWAKU_ARTIFACT_NAME=$(echo "nwaku-${{matrix.arch}}-${{runner.os}}.tar.gz" | tr "[:upper:]" "[:lower:]") + + echo "nwaku=${NWAKU_ARTIFACT_NAME}" >> $GITHUB_OUTPUT + + - name: Install dependencies + run: | + OS=$([[ "${{runner.os}}" == "macOS" ]] && echo "macosx" || echo "linux") + + make -j${NPROC} NIMFLAGS="--parallelBuild:${NPROC} -d:disableMarchNative --os:${OS} --cpu:${{matrix.arch}}" V=1 update + make -j${NPROC} NIMFLAGS="--parallelBuild:${NPROC} -d:disableMarchNative --os:${OS} --cpu:${{matrix.arch}} -d:postgres" CI=false wakunode2 + make -j${NPROC} NIMFLAGS="--parallelBuild:${NPROC} -d:disableMarchNative --os:${OS} --cpu:${{matrix.arch}}" CI=false chat2 + tar -cvzf ${{steps.vars.outputs.nwaku}} ./build/ + + - name: Upload asset + uses: actions/upload-artifact@v4.4.0 + with: + name: ${{steps.vars.outputs.nwaku}} + path: ${{steps.vars.outputs.nwaku}} + if-no-files-found: error diff --git a/.github/workflows/sync-labels.yml b/.github/workflows/sync-labels.yml new file mode 100644 index 0000000..e53797b --- /dev/null +++ b/.github/workflows/sync-labels.yml @@ -0,0 +1,17 @@ +name: Sync labels +on: + push: + branches: + - master + paths: + - .github/labels.yml +jobs: + build: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v2 + - uses: micnncim/action-label-syncer@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + manifest: .github/labels.yml diff --git a/.github/workflows/windows-build.yml b/.github/workflows/windows-build.yml new file mode 100644 index 0000000..ed6d2cb --- /dev/null +++ b/.github/workflows/windows-build.yml @@ -0,0 +1,104 @@ +name: ci / build-windows + +on: + workflow_call: + inputs: + branch: + required: true + type: string + +jobs: + build: + runs-on: windows-latest + + defaults: + run: + shell: msys2 {0} + + env: + MSYSTEM: MINGW64 + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + update: true + install: >- + git + base-devel + mingw-w64-x86_64-toolchain + make + cmake + upx + mingw-w64-x86_64-rust + mingw-w64-x86_64-postgresql + mingw-w64-x86_64-gcc + mingw-w64-x86_64-gcc-libs + mingw-w64-x86_64-libwinpthread-git + mingw-w64-x86_64-zlib + mingw-w64-x86_64-openssl + mingw-w64-x86_64-python + mingw-w64-x86_64-cmake + mingw-w64-x86_64-llvm + mingw-w64-x86_64-clang + + - name: Add UPX to PATH + run: | + echo "/usr/bin:$PATH" >> $GITHUB_PATH + echo "/mingw64/bin:$PATH" >> $GITHUB_PATH + echo "/usr/lib:$PATH" >> $GITHUB_PATH + echo "/mingw64/lib:$PATH" >> $GITHUB_PATH + + - name: Verify dependencies + run: | + which upx gcc g++ make cmake cargo rustc python + + - name: Updating submodules + run: git submodule update --init --recursive + + - name: Creating tmp directory + run: mkdir -p tmp + + - name: Building Nim + run: | + cd vendor/nimbus-build-system/vendor/Nim + ./build_all.bat + cd ../../../.. + + - name: Building miniupnpc + run: | + cd vendor/nim-nat-traversal/vendor/miniupnp/miniupnpc + make -f Makefile.mingw CC=gcc CXX=g++ libminiupnpc.a V=1 + cd ../../../../.. + + - name: Building libnatpmp + run: | + cd ./vendor/nim-nat-traversal/vendor/libnatpmp-upstream + make CC="gcc -fPIC -D_WIN32_WINNT=0x0600 -DNATPMP_STATICLIB" libnatpmp.a V=1 + cd ../../../../ + + - name: Building wakunode2.exe + run: | + make wakunode2 LOG_LEVEL=DEBUG V=3 -j8 + + - name: Building libwaku.dll + run: | + make libwaku STATIC=0 LOG_LEVEL=DEBUG V=1 -j + + - name: Check Executable + run: | + if [ -f "./build/wakunode2.exe" ]; then + echo "wakunode2.exe build successful" + else + echo "Build failed: wakunode2.exe not found" + exit 1 + fi + if [ -f "./build/libwaku.dll" ]; then + echo "libwaku.dll build successful" + else + echo "Build failed: libwaku.dll not found" + exit 1 + fi diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7430c3e --- /dev/null +++ b/.gitignore @@ -0,0 +1,81 @@ +/nimcache + +# Executables shall be put in an ignored build/ directory +/build + +# Nimble packages +/vendor/.nimble + +# Generated Files +*.generated.nim + +# ntags/ctags output +/tags + +# a symlink that can't be added to the repo because of Windows +/waku.nims + +# Ignore dynamic, static libs and libtool archive files +*.so +*.dylib +*.a +*.la +*.exe +*.dll + +.DS_Store + +# Ignore simulation generated metrics files +/metrics/prometheus +/metrics/waku-sim-all-nodes-grafana-dashboard.json + +*.log +/package-lock.json +/package.json +node_modules/ +/.update.timestamp + +# Ignore Jetbrains IDE files +.idea/ + +# ignore vscode files +.vscode/ + +# RLN / keystore +rlnKeystore.json +*.tar.gz + +# Nimbus Build System +nimbus-build-system.paths + +# sqlite db +*.db +*.db-shm +*.db-wal +*.sqlite3 +*.sqlite3-shm +*.sqlite3-wal + +/examples/nodejs/build/ +/examples/rust/target/ + + +# Coverage +coverage_html_report/ +*.info + +# Wildcard +*.ignore.* + +# Ignore all possible node runner directories +**/keystore/ +**/rln_tree/ +**/certs/ + +# simple qt example +.qmake.stash +main-qt +waku_handler.moc.cpp + +# Nix build result +result diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..408def1 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,190 @@ +[submodule "vendor/nim-eth"] + path = vendor/nim-eth + url = https://github.com/status-im/nim-eth.git + ignore = dirty + branch = master +[submodule "vendor/nim-secp256k1"] + path = vendor/nim-secp256k1 + url = https://github.com/status-im/nim-secp256k1.git + ignore = dirty + branch = master +[submodule "vendor/nim-libp2p"] + path = vendor/nim-libp2p + url = https://github.com/vacp2p/nim-libp2p.git + ignore = dirty + branch = master +[submodule "vendor/nim-stew"] + path = vendor/nim-stew + url = https://github.com/status-im/nim-stew.git + ignore = dirty + branch = master +[submodule "vendor/nimbus-build-system"] + path = vendor/nimbus-build-system + url = https://github.com/status-im/nimbus-build-system.git + ignore = dirty + branch = master +[submodule "vendor/nim-nat-traversal"] + path = vendor/nim-nat-traversal + url = https://github.com/status-im/nim-nat-traversal.git + ignore = dirty + branch = master +[submodule "vendor/nim-libbacktrace"] + path = vendor/nim-libbacktrace + url = https://github.com/status-im/nim-libbacktrace.git + ignore = dirty + branch = master +[submodule "vendor/nim-confutils"] + path = vendor/nim-confutils + url = https://github.com/status-im/nim-confutils.git + ignore = dirty + branch = master +[submodule "vendor/nim-chronicles"] + path = vendor/nim-chronicles + url = https://github.com/status-im/nim-chronicles.git + ignore = dirty + branch = master +[submodule "vendor/nim-faststreams"] + path = vendor/nim-faststreams + url = https://github.com/status-im/nim-faststreams.git + ignore = dirty + branch = master +[submodule "vendor/nim-chronos"] + path = vendor/nim-chronos + url = https://github.com/status-im/nim-chronos.git + ignore = dirty + branch = master +[submodule "vendor/nim-json-serialization"] + path = vendor/nim-json-serialization + url = https://github.com/status-im/nim-json-serialization.git + ignore = dirty + branch = master +[submodule "vendor/nim-serialization"] + path = vendor/nim-serialization + url = https://github.com/status-im/nim-serialization.git + ignore = dirty + branch = master +[submodule "vendor/nimcrypto"] + path = vendor/nimcrypto + url = https://github.com/cheatfate/nimcrypto.git + ignore = dirty + branch = master +[submodule "vendor/nim-metrics"] + path = vendor/nim-metrics + url = https://github.com/status-im/nim-metrics.git + ignore = dirty + branch = master +[submodule "vendor/nim-stint"] + path = vendor/nim-stint + url = https://github.com/status-im/nim-stint.git + ignore = dirty + branch = master +[submodule "vendor/nim-json-rpc"] + path = vendor/nim-json-rpc + url = https://github.com/status-im/nim-json-rpc.git + ignore = dirty + branch = master +[submodule "vendor/nim-http-utils"] + path = vendor/nim-http-utils + url = https://github.com/status-im/nim-http-utils.git + ignore = dirty + branch = master +[submodule "vendor/nim-bearssl"] + path = vendor/nim-bearssl + url = https://github.com/status-im/nim-bearssl.git + ignore = dirty + branch = master +[submodule "vendor/nim-sqlite3-abi"] + path = vendor/nim-sqlite3-abi + url = https://github.com/arnetheduck/nim-sqlite3-abi.git + ignore = dirty + branch = master +[submodule "vendor/nim-web3"] + path = vendor/nim-web3 + url = https://github.com/status-im/nim-web3.git +[submodule "vendor/nim-testutils"] + path = vendor/nim-testutils + url = https://github.com/status-im/nim-testutils.git + ignore = untracked + branch = master +[submodule "vendor/nim-unittest2"] + path = vendor/nim-unittest2 + url = https://github.com/status-im/nim-unittest2.git + ignore = untracked + branch = master +[submodule "vendor/nim-websock"] + path = vendor/nim-websock + url = https://github.com/status-im/nim-websock.git + ignore = untracked + branch = main +[submodule "vendor/nim-zlib"] + path = vendor/nim-zlib + url = https://github.com/status-im/nim-zlib.git + ignore = untracked + branch = master +[submodule "vendor/nim-dnsdisc"] + path = vendor/nim-dnsdisc + url = https://github.com/status-im/nim-dnsdisc.git + ignore = untracked + branch = main +[submodule "vendor/dnsclient.nim"] + path = vendor/dnsclient.nim + url = https://github.com/ba0f3/dnsclient.nim.git + ignore = untracked + branch = master +[submodule "vendor/nim-toml-serialization"] + path = vendor/nim-toml-serialization + url = https://github.com/status-im/nim-toml-serialization.git +[submodule "vendor/nim-presto"] + path = vendor/nim-presto + url = https://github.com/status-im/nim-presto.git + ignore = untracked + branch = master +[submodule "vendor/zerokit"] + path = vendor/zerokit + url = https://github.com/vacp2p/zerokit.git + ignore = dirty + branch = v0.5.1 +[submodule "vendor/nim-regex"] + path = vendor/nim-regex + url = https://github.com/nitely/nim-regex.git + ignore = untracked + branch = master +[submodule "vendor/nim-unicodedb"] + path = vendor/nim-unicodedb + url = https://github.com/nitely/nim-unicodedb.git + ignore = untracked + branch = master +[submodule "vendor/nim-taskpools"] + path = vendor/nim-taskpools + url = https://github.com/status-im/nim-taskpools.git + ignore = untracked + branch = stable +[submodule "vendor/nim-results"] + ignore = untracked + branch = master + path = vendor/nim-results + url = https://github.com/arnetheduck/nim-results.git +[submodule "vendor/db_connector"] + path = vendor/db_connector + url = https://github.com/nim-lang/db_connector.git + ignore = untracked + branch = devel +[submodule "vendor/nph"] + ignore = untracked + branch = master + path = vendor/nph + url = https://github.com/arnetheduck/nph.git +[submodule "vendor/nim-minilru"] + path = vendor/nim-minilru + url = https://github.com/status-im/nim-minilru.git + ignore = untracked + branch = master +[submodule "vendor/waku-rlnv2-contract"] + path = vendor/waku-rlnv2-contract + url = https://github.com/waku-org/waku-rlnv2-contract.git + ignore = untracked + branch = master +[submodule "vendor/mix"] + path = vendor/mix + url = https://github.com/vacp2p/mix/ + branch = main diff --git a/.sv4git.yml b/.sv4git.yml new file mode 100644 index 0000000..8975e69 --- /dev/null +++ b/.sv4git.yml @@ -0,0 +1,22 @@ +version: "1.1" #config version + +tag: + pattern: "v%d.%d.%d" + filter: "v*" + +release-notes: + sections: # Array with each section of release note. Check template section for more information. + - name: Features # Name used on section. + section-type: commits # Type of the section, supported types: commits, breaking-changes. + commit-types: [feat] # Commit types for commit section-type, one commit type cannot be in more than one section. + - name: Bug Fixes + section-type: commits + commit-types: [fix, bug] + - name: Changes + section-type: commits + commit-types: [chore, docs, build, refactor, docker] + +commit-message: + + issue: + regex: '#[0-9]+' # Regex for issue id. \ No newline at end of file diff --git a/.sv4git/templates/releasenotes-md.tpl b/.sv4git/templates/releasenotes-md.tpl new file mode 100644 index 0000000..a513e69 --- /dev/null +++ b/.sv4git/templates/releasenotes-md.tpl @@ -0,0 +1,8 @@ +## {{if .Release}}{{.Release}}{{end}}{{if and (not .Date.IsZero) .Release}} ({{end}}{{timefmt .Date "2006-01-02"}}{{if and (not .Date.IsZero) .Release}}){{end}} +{{- range $section := .Sections }} +{{- if (eq $section.SectionType "commits") }} +{{- template "rn-md-section-commits.tpl" $section }} +{{- else if (eq $section.SectionType "breaking-changes")}} +{{- template "rn-md-section-breaking-changes.tpl" $section }} +{{- end}} +{{- end}} diff --git a/.sv4git/templates/rn-md-section-commits.tpl b/.sv4git/templates/rn-md-section-commits.tpl new file mode 100644 index 0000000..2732fcd --- /dev/null +++ b/.sv4git/templates/rn-md-section-commits.tpl @@ -0,0 +1,7 @@ +{{- if .}}{{- if ne .SectionName ""}} + +### {{.SectionName}} +{{range $k,$v := .Items}} +- {{if $v.Message.Scope}}**{{$v.Message.Scope}}:** {{end}}{{$v.Message.Description}} ([{{$v.Hash}}](https://github.com/waku-org/nwaku/commit/{{$v.Hash}})){{if $v.Message.Metadata.issue}} ([https://github.com/waku-org/nwaku/issues/{{$v.Message.Metadata.issue}}]({{$v.Message.Metadata.issue}})){{end}} +{{- end}} +{{- end}}{{- end}} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..dc07379 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,2495 @@ +## v0.36.0 (2025-06-20) +### Notes + +- Extended REST API for better debugging + - Extended `/health` report + - Very detailed access to peers and actual status through [`/admin/v1/peers/...` endpoints](https://waku-org.github.io/waku-rest-api/#get-/admin/v1/peers/stats) + - Dynamic log level change with[ `/admin/v1/log-level`](https://waku-org.github.io/waku-rest-api/#post-/admin/v1/log-level/-logLevel-) + +- The `rln-relay-eth-client-address` parameter, from now on, should be passed as an array of RPC addresses. +- new `preset` parameter. `preset=twn` is the RLN-protected Waku Network (cluster 1). Overrides other values. +- Removed `dns-addrs` parameter as it was duplicated and unused. +- Removed `rln-relay-id-key`, `rln-relay-id-commitment-key`, `rln-relay-bandwidth-threshold` parameters. +- Effectively removed `pubsub-topic`, which was deprecated in `v0.33.0`. +- Removed `store-sync-max-payload-size` parameter. +- Removed `dns-discovery-name-server` and `discv5-only` parameters. + +### Features + +- Update implementation for new contract abi ([#3390](https://github.com/waku-org/nwaku/issues/3390)) ([ee4058b2d](https://github.com/waku-org/nwaku/commit/ee4058b2d)) +- Lighptush v3 for lite-protocol-tester ([#3455](https://github.com/waku-org/nwaku/issues/3455)) ([3f3c59488](https://github.com/waku-org/nwaku/commit/3f3c59488)) +- Retrieve metrics from libwaku ([#3452](https://github.com/waku-org/nwaku/issues/3452)) ([f016ede60](https://github.com/waku-org/nwaku/commit/f016ede60)) +- Dynamic logging via REST API ([#3451](https://github.com/waku-org/nwaku/issues/3451)) ([9fe8ef8d2](https://github.com/waku-org/nwaku/commit/9fe8ef8d2)) +- Add waku_disconnect_all_peers to libwaku ([#3438](https://github.com/waku-org/nwaku/issues/3438)) ([7f51d103b](https://github.com/waku-org/nwaku/commit/7f51d103b)) +- Extend node /health REST endpoint with all protocol's state ([#3419](https://github.com/waku-org/nwaku/issues/3419)) ([1632496a2](https://github.com/waku-org/nwaku/commit/1632496a2)) +- Deprecate sync / local merkle tree ([#3312](https://github.com/waku-org/nwaku/issues/3312)) ([50fe7d727](https://github.com/waku-org/nwaku/commit/50fe7d727)) +- Refactor waku sync DOS protection ([#3391](https://github.com/waku-org/nwaku/issues/3391)) ([a81f9498c](https://github.com/waku-org/nwaku/commit/a81f9498c)) +- Waku Sync dashboard new panel & update ([#3379](https://github.com/waku-org/nwaku/issues/3379)) ([5ed6aae10](https://github.com/waku-org/nwaku/commit/5ed6aae10)) +- Enhance Waku Sync logs and metrics ([#3370](https://github.com/waku-org/nwaku/issues/3370)) ([f6c680a46](https://github.com/waku-org/nwaku/commit/f6c680a46)) +- Add waku_get_connected_peers_info to libwaku ([#3356](https://github.com/waku-org/nwaku/issues/3356)) ([0eb9c6200](https://github.com/waku-org/nwaku/commit/0eb9c6200)) +- Add waku_relay_get_peers_in_mesh to libwaku ([#3352](https://github.com/waku-org/nwaku/issues/3352)) ([ef9074443](https://github.com/waku-org/nwaku/commit/ef9074443)) +- Add waku_relay_get_connected_peers to libwaku ([#3353](https://github.com/waku-org/nwaku/issues/3353)) ([7250d7392](https://github.com/waku-org/nwaku/commit/7250d7392)) +- Introduce `preset` option ([#3346](https://github.com/waku-org/nwaku/issues/3346)) ([0eaf90465](https://github.com/waku-org/nwaku/commit/0eaf90465)) +- Add store sync dashboard panel ([#3307](https://github.com/waku-org/nwaku/issues/3307)) ([ef8ee233f](https://github.com/waku-org/nwaku/commit/ef8ee233f)) + +### Bug Fixes + +- Fix typo from DIRVER to DRIVER ([#3442](https://github.com/waku-org/nwaku/issues/3442)) ([b9a4d7702](https://github.com/waku-org/nwaku/commit/b9a4d7702)) +- Fix discv5 protocol id in libwaku ([#3447](https://github.com/waku-org/nwaku/issues/3447)) ([f7be4c2f0](https://github.com/waku-org/nwaku/commit/f7be4c2f0)) +- Fix dnsresolver ([#3440](https://github.com/waku-org/nwaku/issues/3440)) ([e42e28cc6](https://github.com/waku-org/nwaku/commit/e42e28cc6)) +- Misc sync fixes, added debug logging ([#3411](https://github.com/waku-org/nwaku/issues/3411)) ([b9efa874d](https://github.com/waku-org/nwaku/commit/b9efa874d)) +- Relay unsubscribe ([#3422](https://github.com/waku-org/nwaku/issues/3422)) ([9fc631e10](https://github.com/waku-org/nwaku/commit/9fc631e10)) +- Fix build_rln.sh update version to download v0.7.0 ([#3425](https://github.com/waku-org/nwaku/issues/3425)) ([2678303bf](https://github.com/waku-org/nwaku/commit/2678303bf)) +- Timestamp based validation ([#3406](https://github.com/waku-org/nwaku/issues/3406)) ([1512bdaf0](https://github.com/waku-org/nwaku/commit/1512bdaf0)) +- Enable WebSocket connection also in case only websocket-secure-support enabled ([#3417](https://github.com/waku-org/nwaku/issues/3417)) ([698fe6525](https://github.com/waku-org/nwaku/commit/698fe6525)) +- Fix addPeer could unintentionally override metadata of previously stored peer with defaults and empty ([#3403](https://github.com/waku-org/nwaku/issues/3403)) ([5cccaaac6](https://github.com/waku-org/nwaku/commit/5cccaaac6)) +- Fix bad HttpCode conversion, add missing lightpush v3 rest api tests ([#3389](https://github.com/waku-org/nwaku/issues/3389)) ([7ff055e42](https://github.com/waku-org/nwaku/commit/7ff055e42)) +- Adjust mistaken comments and broken link ([#3381](https://github.com/waku-org/nwaku/issues/3381)) ([237f7abbb](https://github.com/waku-org/nwaku/commit/237f7abbb)) +- Avoid libwaku's redundant allocs ([#3380](https://github.com/waku-org/nwaku/issues/3380)) ([ac454a30b](https://github.com/waku-org/nwaku/commit/ac454a30b)) +- Avoid performing nil check for userData ([#3365](https://github.com/waku-org/nwaku/issues/3365)) ([b8707b6a5](https://github.com/waku-org/nwaku/commit/b8707b6a5)) +- Fix waku sync timing ([#3337](https://github.com/waku-org/nwaku/issues/3337)) ([b01b1837d](https://github.com/waku-org/nwaku/commit/b01b1837d)) +- Fix filter out ephemeral msg from waku sync ([#3332](https://github.com/waku-org/nwaku/issues/3332)) ([4b963d8f5](https://github.com/waku-org/nwaku/commit/4b963d8f5)) +- Apply latest nph formating ([#3334](https://github.com/waku-org/nwaku/issues/3334)) ([77105a6c2](https://github.com/waku-org/nwaku/commit/77105a6c2)) +- waku sync 2.0 codecs ENR support ([#3326](https://github.com/waku-org/nwaku/issues/3326)) ([bf735e777](https://github.com/waku-org/nwaku/commit/bf735e777)) +- waku sync mounting ([#3321](https://github.com/waku-org/nwaku/issues/3321)) ([380d2e338](https://github.com/waku-org/nwaku/commit/380d2e338)) +- Fix rest-relay-cache-capacity ([#3454](https://github.com/waku-org/nwaku/issues/3454)) ([fed4dc280](https://github.com/waku-org/nwaku/commit/fed4dc280)) + +### Changes + +- Lower waku sync log lvl ([#3461](https://github.com/waku-org/nwaku/issues/3461)) ([4277a5349](https://github.com/waku-org/nwaku/commit/4277a5349)) +- Refactor to unify online and health monitors ([#3456](https://github.com/waku-org/nwaku/issues/3456)) ([2e40f2971](https://github.com/waku-org/nwaku/commit/2e40f2971)) +- Refactor rm discv5-only ([#3453](https://github.com/waku-org/nwaku/issues/3453)) ([b998430d5](https://github.com/waku-org/nwaku/commit/b998430d5)) +- Add extra debug REST helper via getting peer statistics ([#3443](https://github.com/waku-org/nwaku/issues/3443)) ([f4ad7a332](https://github.com/waku-org/nwaku/commit/f4ad7a332)) +- Expose online state in libwaku ([#3433](https://github.com/waku-org/nwaku/issues/3433)) ([e7f5c8cb2](https://github.com/waku-org/nwaku/commit/e7f5c8cb2)) +- Add heaptrack support build for Nim v2.0.12 builds ([#3424](https://github.com/waku-org/nwaku/issues/3424)) ([91885fb9e](https://github.com/waku-org/nwaku/commit/91885fb9e)) +- Remove debug for js-waku ([#3423](https://github.com/waku-org/nwaku/issues/3423)) ([5628dc6ad](https://github.com/waku-org/nwaku/commit/5628dc6ad)) +- Bump dependencies for v0.36 ([#3410](https://github.com/waku-org/nwaku/issues/3410)) ([005815746](https://github.com/waku-org/nwaku/commit/005815746)) +- Enhance feedback on error CLI ([#3405](https://github.com/waku-org/nwaku/issues/3405)) ([3464d81a6](https://github.com/waku-org/nwaku/commit/3464d81a6)) +- Allow multiple rln eth clients ([#3402](https://github.com/waku-org/nwaku/issues/3402)) ([861710bc7](https://github.com/waku-org/nwaku/commit/861710bc7)) +- Separate internal and CLI configurations ([#3357](https://github.com/waku-org/nwaku/issues/3357)) ([dd8d66431](https://github.com/waku-org/nwaku/commit/dd8d66431)) +- Avoid double relay subscription ([#3396](https://github.com/waku-org/nwaku/issues/3396)) ([7d5eb9374](https://github.com/waku-org/nwaku/commit/7d5eb9374) [#3429](https://github.com/waku-org/nwaku/issues/3429)) ([ee5932ebc](https://github.com/waku-org/nwaku/commit/ee5932ebc)) +- Improve disconnection handling ([#3385](https://github.com/waku-org/nwaku/issues/3385)) ([1ec9b8d96](https://github.com/waku-org/nwaku/commit/1ec9b8d96)) +- Return all peers from REST admin ([#3395](https://github.com/waku-org/nwaku/issues/3395)) ([f6fdd960f](https://github.com/waku-org/nwaku/commit/f6fdd960f)) +- Simplify rln_relay code a little ([#3392](https://github.com/waku-org/nwaku/issues/3392)) ([7a6c00bd0](https://github.com/waku-org/nwaku/commit/7a6c00bd0)) +- Extended /admin/v1 RESP API with different option to look at current connected/relay/mesh state of the node ([#3382](https://github.com/waku-org/nwaku/issues/3382)) ([3db00f39e](https://github.com/waku-org/nwaku/commit/3db00f39e)) +- Timestamp set to now in publish if not provided ([#3373](https://github.com/waku-org/nwaku/issues/3373)) ([f7b424451](https://github.com/waku-org/nwaku/commit/f7b424451)) +- Update lite-protocol-tester for handling shard argument ([#3371](https://github.com/waku-org/nwaku/issues/3371)) ([5ab69edd7](https://github.com/waku-org/nwaku/commit/5ab69edd7)) +- Fix unused and deprecated imports ([#3368](https://github.com/waku-org/nwaku/issues/3368)) ([6ebb49a14](https://github.com/waku-org/nwaku/commit/6ebb49a14)) +- Expect camelCase JSON for libwaku store queries ([#3366](https://github.com/waku-org/nwaku/issues/3366)) ([ccb4ed51d](https://github.com/waku-org/nwaku/commit/ccb4ed51d)) +- Maintenance to c and c++ simple examples ([#3367](https://github.com/waku-org/nwaku/issues/3367)) ([25d30d44d](https://github.com/waku-org/nwaku/commit/25d30d44d)) +- Skip two flaky tests ([#3364](https://github.com/waku-org/nwaku/issues/3364)) ([b672617b2](https://github.com/waku-org/nwaku/commit/b672617b2)) +- Retrieve protocols in new added peer from discv5 ([#3354](https://github.com/waku-org/nwaku/issues/3354)) ([df58643ea](https://github.com/waku-org/nwaku/commit/df58643ea)) +- Better keystore management ([#3358](https://github.com/waku-org/nwaku/issues/3358)) ([a914fdccc](https://github.com/waku-org/nwaku/commit/a914fdccc)) +- Remove pubsub topics arguments ([#3350](https://github.com/waku-org/nwaku/issues/3350)) ([9778b45c6](https://github.com/waku-org/nwaku/commit/9778b45c6)) +- New performance measurement metrics for non-relay protocols ([#3299](https://github.com/waku-org/nwaku/issues/3299)) ([68c50a09a](https://github.com/waku-org/nwaku/commit/68c50a09a)) +- Start triggering CI for windows build ([#3316](https://github.com/waku-org/nwaku/issues/3316)) ([55ac6ba9f](https://github.com/waku-org/nwaku/commit/55ac6ba9f)) +- Less logs for rendezvous ([#3319](https://github.com/waku-org/nwaku/issues/3319)) ([6df05bae2](https://github.com/waku-org/nwaku/commit/6df05bae2)) +- Add test reporting doc to benchmarks dir ([#3238](https://github.com/waku-org/nwaku/issues/3238)) ([94554a6e0](https://github.com/waku-org/nwaku/commit/94554a6e0)) +- Improve epoch monitoring ([#3197](https://github.com/waku-org/nwaku/issues/3197)) ([b0c025f81](https://github.com/waku-org/nwaku/commit/b0c025f81)) + +### This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`WAKU2-LIGHTPUSH v3`](https://github.com/waku-org/specs/blob/master/standards/core/lightpush.md) | `draft` | `/vac/waku/lightpush/3.0.0` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | +| [`WAKU-SYNC`](https://github.com/waku-org/specs/blob/feat--waku-sync/standards/core/sync.md) | `draft` | `/vac/waku/sync/1.0.0` | + + +## v0.35.1 (2025-03-30) + +### Bug fixes + +* Update RLN references ([3287](https://github.com/waku-org/nwaku/pull/3287)) ([ea961fa](https://github.com/waku-org/nwaku/pull/3287/commits/ea961faf4ed4f8287a2043a6b5d84b660745072b)) + +**Info:** before upgrading to this version, make sure you delete the previous rln_tree folder, i.e., +the one that is passed through this CLI: `--rln-relay-tree-path`. + +### Features +* lightpush v3 ([#3279](https://github.com/waku-org/nwaku/pull/3279)) ([e0b563ff](https://github.com/waku-org/nwaku/commit/e0b563ffe5af20bd26d37cd9b4eb9ed9eb82ff80)) + Upgrade for Waku Llightpush protocol with enhanced error handling. Read specification [here](https://github.com/waku-org/specs/blob/master/standards/core/lightpush.md) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`WAKU2-LIGHTPUSH v3`](https://github.com/waku-org/specs/blob/master/standards/core/lightpush.md) | `draft` | `/vac/waku/lightpush/3.0.0` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | +| [`WAKU-SYNC`](https://github.com/waku-org/specs/blob/feat--waku-sync/standards/core/sync.md) | `draft` | `/vac/waku/sync/1.0.0` | + +## v0.35.0 (2025-03-03) + +### Notes + +- Deprecated parameter + - max-relay-peers + +- New parameters + - relay-service-ratio + + String value with peers distribution within max-connections parameter. + This percentage ratio represents the relay peers to service peers. + For example, 60:40, tells that 60% of the max-connections will be used for relay protocol + and the other 40% of max-connections will be reserved for other service protocols (e.g., + filter, lightpush, store, metadata, etc.) + + - rendezvous + + boolean attribute that optionally activates waku rendezvous discovery server. + True by default. + +### Release highlights + +- New filter approach to keep push stream opened within subscription period. +- Waku sync protocol. +- Libwaku async +- Lite-protocol-tester enhancements. +- New panels and metrics in RLN to control outstanding request quota. + +### Features + +- waku sync shard matching check ([#3259](https://github.com/waku-org/nwaku/issues/3259)) ([42fd6b827](https://github.com/waku-org/nwaku/commit/42fd6b827)) +- waku store sync 2.0 config & setup ([#3217](https://github.com/waku-org/nwaku/issues/3217)) ([7f64dc03a](https://github.com/waku-org/nwaku/commit/7f64dc03a)) +- waku store sync 2.0 protocols & tests ([#3216](https://github.com/waku-org/nwaku/issues/3216)) ([6ee494d90](https://github.com/waku-org/nwaku/commit/6ee494d90)) +- waku store sync 2.0 storage & tests ([#3215](https://github.com/waku-org/nwaku/issues/3215)) ([54a7a6875](https://github.com/waku-org/nwaku/commit/54a7a6875)) +- waku store sync 2.0 common types & codec ([#3213](https://github.com/waku-org/nwaku/issues/3213)) ([29fda2dab](https://github.com/waku-org/nwaku/commit/29fda2dab)) +- add txhash-based eligibility checks for incentivization PoC ([#3166](https://github.com/waku-org/nwaku/issues/3166)) ([505ec84ce](https://github.com/waku-org/nwaku/commit/505ec84ce)) +- connection change event ([#3225](https://github.com/waku-org/nwaku/issues/3225)) ([e81a5517b](https://github.com/waku-org/nwaku/commit/e81a5517b)) +- libwaku add protected topic ([#3211](https://github.com/waku-org/nwaku/issues/3211)) ([d932dd10c](https://github.com/waku-org/nwaku/commit/d932dd10c)) +- topic health tracking ([#3212](https://github.com/waku-org/nwaku/issues/3212)) ([6020a673b](https://github.com/waku-org/nwaku/commit/6020a673b)) +- allowing configuration of application level callbacks ([#3206](https://github.com/waku-org/nwaku/issues/3206)) ([049fbeabb](https://github.com/waku-org/nwaku/commit/049fbeabb)) +- waku rendezvous wrapper ([#2962](https://github.com/waku-org/nwaku/issues/2962)) ([650a9487e](https://github.com/waku-org/nwaku/commit/650a9487e)) +- making dns discovery async ([#3175](https://github.com/waku-org/nwaku/issues/3175)) ([d7d00bfd7](https://github.com/waku-org/nwaku/commit/d7d00bfd7)) +- remove Waku Sync 1.0 & Negentropy ([#3185](https://github.com/waku-org/nwaku/issues/3185)) ([2ab9c3d36](https://github.com/waku-org/nwaku/commit/2ab9c3d36)) +- add waku_dial_peer and get_connected_peers to libwaku ([#3149](https://github.com/waku-org/nwaku/issues/3149)) ([507b1fc4d](https://github.com/waku-org/nwaku/commit/507b1fc4d)) +- running periodicaly peer exchange if discv5 is disabled ([#3150](https://github.com/waku-org/nwaku/issues/3150)) ([400d7a54f](https://github.com/waku-org/nwaku/commit/400d7a54f)) + +### Bug Fixes + +- avoid double db migration for sqlite ([#3244](https://github.com/waku-org/nwaku/issues/3244)) ([2ce245354](https://github.com/waku-org/nwaku/commit/2ce245354)) +- libwaku waku_relay_unsubscribe ([#3207](https://github.com/waku-org/nwaku/issues/3207)) ([ab0c1d4aa](https://github.com/waku-org/nwaku/commit/ab0c1d4aa)) +- libwaku support string and int64 for timestamps ([#3205](https://github.com/waku-org/nwaku/issues/3205)) ([2022f54f5](https://github.com/waku-org/nwaku/commit/2022f54f5)) +- lite-protocol-tester receiver exit check ([#3187](https://github.com/waku-org/nwaku/issues/3187)) ([beb21c78f](https://github.com/waku-org/nwaku/commit/beb21c78f)) +- linting error ([#3156](https://github.com/waku-org/nwaku/issues/3156)) ([99ac68447](https://github.com/waku-org/nwaku/commit/99ac68447)) + +### Changes + +- more efficient metrics usage ([#3298](https://github.com/waku-org/nwaku/issues/3298)) ([6f004d5d4](https://github.com/waku-org/nwaku/commit/6f004d5d4))([c07e278d8](https://github.com/waku-org/nwaku/commit/c07e278d82c3aa771b9988e85bad7422890e4d74)) +- filter refactor subscription management and react when the remote peer closes the stream. See the following commits in chronological order: + - issue: [#3281](https://github.com/waku-org/nwaku/issues/3281) commit: [5392b8ea4](https://github.com/waku-org/nwaku/commit/5392b8ea4) + - issue: [#3198](https://github.com/waku-org/nwaku/issues/3198) commit: [287e9b12c](https://github.com/waku-org/nwaku/commit/287e9b12c) + - issue: [#3267](https://github.com/waku-org/nwaku/issues/3267) commit: [46747fd49](https://github.com/waku-org/nwaku/commit/46747fd49) +- send msg hash as string on libwaku message event ([#3234](https://github.com/waku-org/nwaku/issues/3234)) ([9c209b4c3](https://github.com/waku-org/nwaku/commit/9c209b4c3)) +- separate heaptrack from debug build ([#3249](https://github.com/waku-org/nwaku/issues/3249)) ([81f24cc25](https://github.com/waku-org/nwaku/commit/81f24cc25)) +- capping mechanism for relay and service connections ([#3184](https://github.com/waku-org/nwaku/issues/3184)) ([2942782f9](https://github.com/waku-org/nwaku/commit/2942782f9)) +- add extra migration to sqlite and improving error message ([#3240](https://github.com/waku-org/nwaku/issues/3240)) ([bfd60ceab](https://github.com/waku-org/nwaku/commit/bfd60ceab)) +- optimize libwaku size ([#3242](https://github.com/waku-org/nwaku/issues/3242)) ([9c0ad8517](https://github.com/waku-org/nwaku/commit/9c0ad8517)) +- golang example end using negentropy dependency plus simple readme.md ([#3235](https://github.com/waku-org/nwaku/issues/3235)) ([0e0fcfb1a](https://github.com/waku-org/nwaku/commit/0e0fcfb1a)) +- enhance libwaku store protocol and more ([#3223](https://github.com/waku-org/nwaku/issues/3223)) ([22ce9ee87](https://github.com/waku-org/nwaku/commit/22ce9ee87)) +- add two RLN metrics and panel ([#3181](https://github.com/waku-org/nwaku/issues/3181)) ([1b532e8ab](https://github.com/waku-org/nwaku/commit/1b532e8ab)) +- libwaku async ([#3180](https://github.com/waku-org/nwaku/issues/3180)) ([47a623541](https://github.com/waku-org/nwaku/commit/47a623541)) +- filter protocol in libwaku ([#3177](https://github.com/waku-org/nwaku/issues/3177)) ([f856298ca](https://github.com/waku-org/nwaku/commit/f856298ca)) +- add supervisor for lite-protocol-tester infra ([#3176](https://github.com/waku-org/nwaku/issues/3176)) ([a7264d68c](https://github.com/waku-org/nwaku/commit/a7264d68c)) +- libwaku better error handling and better waku thread destroy handling ([#3167](https://github.com/waku-org/nwaku/issues/3167)) ([294dd03c4](https://github.com/waku-org/nwaku/commit/294dd03c4)) +- libwaku allow several multiaddresses for a single peer in store queries ([#3171](https://github.com/waku-org/nwaku/issues/3171)) ([3cb8ebdd8](https://github.com/waku-org/nwaku/commit/3cb8ebdd8)) +- naming connectPeer procedure ([#3157](https://github.com/waku-org/nwaku/issues/3157)) ([b3656d6ee](https://github.com/waku-org/nwaku/commit/b3656d6ee)) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | +| [`WAKU-SYNC`](https://github.com/waku-org/specs/blob/master/standards/core/sync.md) | `draft` | `/vac/waku/reconciliation/1.0.0` & `/vac/waku/transfer/1.0.0` | + +## v0.34.0 (2024-10-29) + +### Notes: + +* The `--protected-topic` CLI configuration has been removed. Equivalent flag, `--protected-shard`, shall be used instead. + +### Features + +- change latency buckets ([#3153](https://github.com/waku-org/nwaku/issues/3153)) ([956fde6e](https://github.com/waku-org/nwaku/commit/956fde6e)) +- libwaku: ping peer ([#3144](https://github.com/waku-org/nwaku/issues/3144)) ([de11e576](https://github.com/waku-org/nwaku/commit/de11e576)) +- initial windows support ([#3107](https://github.com/waku-org/nwaku/issues/3107)) ([ff21c01e](https://github.com/waku-org/nwaku/commit/ff21c01e)) +- circuit relay support ([#3112](https://github.com/waku-org/nwaku/issues/3112)) ([cfde7eea](https://github.com/waku-org/nwaku/commit/cfde7eea)) + +### Bug Fixes + +- peer exchange libwaku response handling ([#3141](https://github.com/waku-org/nwaku/issues/3141)) ([76606421](https://github.com/waku-org/nwaku/commit/76606421)) +- add more logs, stagger intervals & set prune offset to 10% for waku sync ([#3142](https://github.com/waku-org/nwaku/issues/3142)) ([a386880b](https://github.com/waku-org/nwaku/commit/a386880b)) +- add log and archive message ingress for sync ([#3133](https://github.com/waku-org/nwaku/issues/3133)) ([80c7581a](https://github.com/waku-org/nwaku/commit/80c7581a)) +- add a limit of max 10 content topics per query ([#3117](https://github.com/waku-org/nwaku/issues/3117)) ([c35dc549](https://github.com/waku-org/nwaku/commit/c35dc549)) +- avoid segfault by setting a default num peers requested in Peer eXchange ([#3122](https://github.com/waku-org/nwaku/issues/3122)) ([82fd5dde](https://github.com/waku-org/nwaku/commit/82fd5dde)) +- returning peerIds in base 64 ([#3105](https://github.com/waku-org/nwaku/issues/3105)) ([37edaf62](https://github.com/waku-org/nwaku/commit/37edaf62)) +- changing libwaku's error handling format ([#3093](https://github.com/waku-org/nwaku/issues/3093)) ([2e6c299d](https://github.com/waku-org/nwaku/commit/2e6c299d)) +- remove spammy log ([#3091](https://github.com/waku-org/nwaku/issues/3091)) ([1d2b910f](https://github.com/waku-org/nwaku/commit/1d2b910f)) +- avoid out connections leak ([#3077](https://github.com/waku-org/nwaku/issues/3077)) ([eb2bbae6](https://github.com/waku-org/nwaku/commit/eb2bbae6)) +- rejecting excess relay connections ([#3065](https://github.com/waku-org/nwaku/issues/3065)) ([8b0884c7](https://github.com/waku-org/nwaku/commit/8b0884c7)) +- static linking negentropy in ARM based mac ([#3046](https://github.com/waku-org/nwaku/issues/3046)) ([256b7853](https://github.com/waku-org/nwaku/commit/256b7853)) + +### Changes + +- support ping with multiple multiaddresses and close stream ([#3154](https://github.com/waku-org/nwaku/issues/3154)) ([3665991a](https://github.com/waku-org/nwaku/commit/3665991a)) +- liteprotocoltester: easy setup fleets ([#3125](https://github.com/waku-org/nwaku/issues/3125)) ([268e7e66](https://github.com/waku-org/nwaku/commit/268e7e66)) +- saving peers enr capabilities ([#3127](https://github.com/waku-org/nwaku/issues/3127)) ([69d9524f](https://github.com/waku-org/nwaku/commit/69d9524f)) +- networkmonitor: add missing field on RlnRelay init, set default for num of shard ([#3136](https://github.com/waku-org/nwaku/issues/3136)) ([edcb0e15](https://github.com/waku-org/nwaku/commit/edcb0e15)) +- add to libwaku peer id retrieval proc ([#3124](https://github.com/waku-org/nwaku/issues/3124)) ([c5a825e2](https://github.com/waku-org/nwaku/commit/c5a825e2)) +- adding to libwaku dial and disconnect by peerIds ([#3111](https://github.com/waku-org/nwaku/issues/3111)) ([25da8102](https://github.com/waku-org/nwaku/commit/25da8102)) +- dbconn: add requestId info as a comment in the database logs ([#3110](https://github.com/waku-org/nwaku/issues/3110)) ([30c072a4](https://github.com/waku-org/nwaku/commit/30c072a4)) +- improving get_peer_ids_by_protocol by returning the available protocols of connected peers ([#3109](https://github.com/waku-org/nwaku/issues/3109)) ([ed0ee5be](https://github.com/waku-org/nwaku/commit/ed0ee5be)) +- remove warnings ([#3106](https://github.com/waku-org/nwaku/issues/3106)) ([c861fa9f](https://github.com/waku-org/nwaku/commit/c861fa9f)) +- better store logs ([#3103](https://github.com/waku-org/nwaku/issues/3103)) ([21b03551](https://github.com/waku-org/nwaku/commit/21b03551)) +- Improve binding for waku_sync ([#3102](https://github.com/waku-org/nwaku/issues/3102)) ([c3756e3a](https://github.com/waku-org/nwaku/commit/c3756e3a)) +- improving and temporarily skipping flaky rln test ([#3094](https://github.com/waku-org/nwaku/issues/3094)) ([a6ed80a5](https://github.com/waku-org/nwaku/commit/a6ed80a5)) +- update master after release v0.33.1 ([#3089](https://github.com/waku-org/nwaku/issues/3089)) ([54c3083d](https://github.com/waku-org/nwaku/commit/54c3083d)) +- re-arrange function based on responsibility of peer-manager ([#3086](https://github.com/waku-org/nwaku/issues/3086)) ([0f8e8740](https://github.com/waku-org/nwaku/commit/0f8e8740)) +- waku_keystore: give some more context in case of error ([#3064](https://github.com/waku-org/nwaku/issues/3064)) ([3ad613ca](https://github.com/waku-org/nwaku/commit/3ad613ca)) +- bump negentropy ([#3078](https://github.com/waku-org/nwaku/issues/3078)) ([643ab20f](https://github.com/waku-org/nwaku/commit/643ab20f)) +- Optimize store ([#3061](https://github.com/waku-org/nwaku/issues/3061)) ([5875ed63](https://github.com/waku-org/nwaku/commit/5875ed63)) +- wrap peer store ([#3051](https://github.com/waku-org/nwaku/issues/3051)) ([729e63f5](https://github.com/waku-org/nwaku/commit/729e63f5)) +- disabling metrics for libwaku ([#3058](https://github.com/waku-org/nwaku/issues/3058)) ([b358c90f](https://github.com/waku-org/nwaku/commit/b358c90f)) +- test peer connection management ([#3049](https://github.com/waku-org/nwaku/issues/3049)) ([711e7db1](https://github.com/waku-org/nwaku/commit/711e7db1)) +- updating upload and download artifact actions to v4 ([#3047](https://github.com/waku-org/nwaku/issues/3047)) ([7c4a9717](https://github.com/waku-org/nwaku/commit/7c4a9717)) +- Better database query logs and logarithmic scale in grafana store panels ([#3048](https://github.com/waku-org/nwaku/issues/3048)) ([d68b06f1](https://github.com/waku-org/nwaku/commit/d68b06f1)) +- extending store metrics ([#3042](https://github.com/waku-org/nwaku/issues/3042)) ([fd83b42f](https://github.com/waku-org/nwaku/commit/fd83b42f)) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | +| [`WAKU-SYNC`](https://github.com/waku-org/specs/blob/master/standards/core/sync.md) | `draft` | `/vac/waku/sync/1.0.0` | + +## v0.33.1 (2024-10-03) + +### Bug fixes + +* Fix out connections leak ([3077](https://github.com/waku-org/nwaku/pull/3077)) ([eb2bbae6](https://github.com/waku-org/nwaku/commit/eb2bbae6)) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | +| [`WAKU-SYNC`](https://github.com/waku-org/specs/blob/feat--waku-sync/standards/core/sync.md) | `draft` | `/vac/waku/sync/1.0.0` | + +## v0.33.0 (2024-09-30) + +#### Notes: + +* The `--pubsub-topic` CLI configuration has been deprecated and support for it will be removed on release v0.35.0. In order to migrate, please use the `--shard` configuration instead. For example, instead of `--pubsub-topic=/waku/2/rs//`, use `--cluster-id=` once and `--shard=` for each subscribed shard +* The `--rest-private` CLI configuration has been removed. Please delete any reference to it when running your nodes +* Introduced the `--reliability` CLI configuration, activating the new experimental StoreV3 message confirmation protocol +* DOS protection configurations of non-relay, req/resp protocols are changed + * `--request-rate-limit` and `--request-rate-period` options are no longer supported. + * `--rate-limit` CLI configuration is now available. + - The new flag can describe various rate-limit requirements for each protocol supported. The setting can be repeated, each instance can define exactly one rate-limit option. + - Format is `:volume/period` + - If protocol is not given, settings will be taken as default for un-set protocols. Ex: 80/2s + - Supported protocols are: lightpush|filter|px|store|storev2|storev3 + - `volume` must be an integer value, representing number of requests over the period of time allowed. + - `period ` must be an integer with defined unit as one of h|m|s|ms + - If not set, no rate limit will be applied to request/response protocols, except for the filter protocol. + + +### Release highlights + +* a new experimental reliability protocol has been implemented, leveraging StoreV3 to confirm message delivery +* Peer Exchange protocol can now be protected by rate-limit boundary checks. +* Fine-grained configuration of DOS protection is available with this release. See, "Notes" above. + +### Bug Fixes + +- rejecting excess relay connections ([#3063](https://github.com/waku-org/nwaku/issues/3063)) ([8b0884c7](https://github.com/waku-org/nwaku/commit/8b0884c7)) +- make Peer Exchange's rpc status_code optional for backward compatibility ([#3059](https://github.com/waku-org/nwaku/pull/3059)) ([5afa9b13](https://github.com/waku-org/nwaku/commit/5afa9b13)) +- px protocol decode - do not treat missing response field as error ([#3054](https://github.com/waku-org/nwaku/issues/3054)) ([9b445ac4](https://github.com/waku-org/nwaku/commit/9b445ac4)) +- setting up node with modified config ([#3036](https://github.com/waku-org/nwaku/issues/3036)) ([8f289925](https://github.com/waku-org/nwaku/commit/8f289925)) +- get back health check for postgres legacy ([#3010](https://github.com/waku-org/nwaku/issues/3010)) ([5a0edff7](https://github.com/waku-org/nwaku/commit/5a0edff7)) +- libnegentropy integration ([#2996](https://github.com/waku-org/nwaku/issues/2996)) ([c3cb06ac](https://github.com/waku-org/nwaku/commit/c3cb06ac)) +- peer-exchange issue ([#2889](https://github.com/waku-org/nwaku/issues/2889)) ([43157102](https://github.com/waku-org/nwaku/commit/43157102)) + +### Changes + +- append current version in agentString which is used by the identify protocol ([#3057](https://github.com/waku-org/nwaku/pull/3057)) ([368bb3c1](https://github.com/waku-org/nwaku/commit/368bb3c1)) +- rate limit peer exchange protocol, enhanced response status in RPC ([#3035](https://github.com/waku-org/nwaku/issues/3035)) ([0a7f16a3](https://github.com/waku-org/nwaku/commit/0a7f16a3)) +- Switch libnegentropy library build from shared to static linkage ([#3041](https://github.com/waku-org/nwaku/issues/3041)) ([83f25c3e](https://github.com/waku-org/nwaku/commit/83f25c3e)) +- libwaku reduce repetitive code by adding a template handling resp returns ([#3032](https://github.com/waku-org/nwaku/issues/3032)) ([1713f562](https://github.com/waku-org/nwaku/commit/1713f562)) +- libwaku - extending the library with peer_manager and peer_exchange features ([#3026](https://github.com/waku-org/nwaku/issues/3026)) ([5ea1cf0c](https://github.com/waku-org/nwaku/commit/5ea1cf0c)) +- use submodule nph in CI to check lint ([#3027](https://github.com/waku-org/nwaku/issues/3027)) ([ce9a8c46](https://github.com/waku-org/nwaku/commit/ce9a8c46)) +- deprecating pubsub topic ([#2997](https://github.com/waku-org/nwaku/issues/2997)) ([a3cd2a1a](https://github.com/waku-org/nwaku/commit/a3cd2a1a)) +- lightpush - error metric less variable by only setting a fixed string ([#3020](https://github.com/waku-org/nwaku/issues/3020)) ([d3e6717a](https://github.com/waku-org/nwaku/commit/d3e6717a)) +- enhance libpq management ([#3015](https://github.com/waku-org/nwaku/issues/3015)) ([45319f09](https://github.com/waku-org/nwaku/commit/45319f09)) +- per limit split of PostgreSQL queries ([#3008](https://github.com/waku-org/nwaku/issues/3008)) ([e1e05afb](https://github.com/waku-org/nwaku/commit/e1e05afb)) +- Added metrics to liteprotocoltester ([#3002](https://github.com/waku-org/nwaku/issues/3002)) ([8baf627f](https://github.com/waku-org/nwaku/commit/8baf627f)) +- extending store metrics ([#2995](https://github.com/waku-org/nwaku/issues/2995)) ([fd83b42f](https://github.com/waku-org/nwaku/commit/fd83b42f)) +- Better timing and requestId detail for slower store db queries ([#2994](https://github.com/waku-org/nwaku/issues/2994)) ([e8a49b76](https://github.com/waku-org/nwaku/commit/e8a49b76)) +- remove unused setting from external_config.nim ([#3004](https://github.com/waku-org/nwaku/issues/3004)) ([fd84363e](https://github.com/waku-org/nwaku/commit/fd84363e)) +- delivery monitor for store v3 reliability protocol ([#2977](https://github.com/waku-org/nwaku/issues/2977)) ([0f68274c](https://github.com/waku-org/nwaku/commit/0f68274c)) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | +| [`WAKU-SYNC`](https://github.com/waku-org/specs/blob/feat--waku-sync/standards/core/sync.md) | `draft` | `/vac/waku/sync/1.0.0` | + +## v0.32.0 (2024-08-30) + +#### Notes: + +* A new `discv5-only` CLI flag was introduced, which if set to true will perform optimizations for nodes that only run the DiscV5 service +* The `protected-topic` CLI config item has been deprecated in favor of the new `protected-shard` configuration. Protected topics are still supported and will be completely removed in two releases time for `v0.34.0` + +### Release highlights + +* Merged Nwaku Sync protocol for synchronizing store nodes +* Added Store Resume mechanism to retrieve messages sent when the node was offline + +### Features + +- Nwaku Sync ([#2403](https://github.com/waku-org/nwaku/issues/2403)) ([2cc86c51](https://github.com/waku-org/nwaku/commit/2cc86c51)) +- misc. updates for discovery network analysis ([#2930](https://github.com/waku-org/nwaku/issues/2930)) ([4340eb75](https://github.com/waku-org/nwaku/commit/4340eb75)) +- store resume ([#2919](https://github.com/waku-org/nwaku/issues/2919)) ([aed2a113](https://github.com/waku-org/nwaku/commit/aed2a113)) + +### Bug Fixes + +- return on insert error ([#2956](https://github.com/waku-org/nwaku/issues/2956)) ([5f0fbd78](https://github.com/waku-org/nwaku/commit/5f0fbd78)) +- network monitor improvements ([#2939](https://github.com/waku-org/nwaku/issues/2939)) ([80583237](https://github.com/waku-org/nwaku/commit/80583237)) +- add back waku discv5 metrics ([#2927](https://github.com/waku-org/nwaku/issues/2927)) ([e4e01fab](https://github.com/waku-org/nwaku/commit/e4e01fab)) +- update and shift unittest ([#2934](https://github.com/waku-org/nwaku/issues/2934)) ([08973add](https://github.com/waku-org/nwaku/commit/08973add)) +- handle rln-relay-message-limit ([#2867](https://github.com/waku-org/nwaku/issues/2867)) ([8d107b0d](https://github.com/waku-org/nwaku/commit/8d107b0d)) + +### Changes + +- libwaku retrieve my enr and adapt golang example ([#2987](https://github.com/waku-org/nwaku/issues/2987)) ([1ff9f1dd](https://github.com/waku-org/nwaku/commit/1ff9f1dd)) +- run `ANALYZE messages` regularly for better db performance ([#2986](https://github.com/waku-org/nwaku/issues/2986)) ([32f2d85d](https://github.com/waku-org/nwaku/commit/32f2d85d)) +- liteprotocoltester for simulation and for fleets ([#2813](https://github.com/waku-org/nwaku/issues/2813)) ([f4fa73e9](https://github.com/waku-org/nwaku/commit/f4fa73e9)) +- lock in nph version and add pre-commit hook ([#2938](https://github.com/waku-org/nwaku/issues/2938)) ([d63e3430](https://github.com/waku-org/nwaku/commit/d63e3430)) +- logging received message info via onValidated observer ([#2973](https://github.com/waku-org/nwaku/issues/2973)) ([e8bce67d](https://github.com/waku-org/nwaku/commit/e8bce67d)) +- deprecating protected topics in favor of protected shards ([#2983](https://github.com/waku-org/nwaku/issues/2983)) ([e51ffe07](https://github.com/waku-org/nwaku/commit/e51ffe07)) +- rename NsPubsubTopic ([#2974](https://github.com/waku-org/nwaku/issues/2974)) ([67439057](https://github.com/waku-org/nwaku/commit/67439057)) +- install dig ([#2975](https://github.com/waku-org/nwaku/issues/2975)) ([d24b56b9](https://github.com/waku-org/nwaku/commit/d24b56b9)) +- print WakuMessageHash as hex strings ([#2969](https://github.com/waku-org/nwaku/issues/2969)) ([2fd4eb62](https://github.com/waku-org/nwaku/commit/2fd4eb62)) +- updating dependencies for release 0.32.0 ([#2971](https://github.com/waku-org/nwaku/issues/2971)) ([dfd42a7c](https://github.com/waku-org/nwaku/commit/dfd42a7c)) +- bump negentropy to latest master ([#2968](https://github.com/waku-org/nwaku/issues/2968)) ([b36cb075](https://github.com/waku-org/nwaku/commit/b36cb075)) +- keystore: verbose error message when credential is not found ([#2943](https://github.com/waku-org/nwaku/issues/2943)) ([0f11ee14](https://github.com/waku-org/nwaku/commit/0f11ee14)) +- upgrade peer exchange mounting ([#2953](https://github.com/waku-org/nwaku/issues/2953)) ([42f1bed0](https://github.com/waku-org/nwaku/commit/42f1bed0)) +- replace statusim.net instances with status.im ([#2941](https://github.com/waku-org/nwaku/issues/2941)) ([f534549a](https://github.com/waku-org/nwaku/commit/f534549a)) +- updating doc reference to https rpc ([#2937](https://github.com/waku-org/nwaku/issues/2937)) ([bb7bba35](https://github.com/waku-org/nwaku/commit/bb7bba35)) +- Simplification of store legacy code ([#2931](https://github.com/waku-org/nwaku/issues/2931)) ([d4e8a0da](https://github.com/waku-org/nwaku/commit/d4e8a0da)) +- add peer filtering by cluster for waku peer exchange ([#2932](https://github.com/waku-org/nwaku/issues/2932)) ([b4618f98](https://github.com/waku-org/nwaku/commit/b4618f98)) +- return all connected peers from REST API ([#2923](https://github.com/waku-org/nwaku/issues/2923)) ([a29eca77](https://github.com/waku-org/nwaku/commit/a29eca77)) +- adding lint job to the CI ([#2925](https://github.com/waku-org/nwaku/issues/2925)) ([086cc8ed](https://github.com/waku-org/nwaku/commit/086cc8ed)) +- improve sonda dashboard ([#2918](https://github.com/waku-org/nwaku/issues/2918)) ([6d385cef](https://github.com/waku-org/nwaku/commit/6d385cef)) +- Add new custom built and test target to make in order to enable easy build or test single nim modules ([#2913](https://github.com/waku-org/nwaku/issues/2913)) ([ad25f437](https://github.com/waku-org/nwaku/commit/ad25f437)) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | +| [`WAKU-SYNC`](https://github.com/waku-org/specs/blob/feat--waku-sync/standards/core/sync.md) | `draft` | `/vac/waku/sync/1.0.0` | + +## v0.31.1 (2024-08-02) + +### Changes + +- Optimize hash queries with lookup table ([#2933](https://github.com/waku-org/nwaku/issues/2933)) ([6463885bf](https://github.com/waku-org/nwaku/commit/6463885bf)) + +### Bug fixes + +* Use of detach finalize when needed [2966](https://github.com/waku-org/nwaku/pull/2966) +* Prevent legacy store from creating new partitions as that approach blocked the database. +[2931](https://github.com/waku-org/nwaku/pull/2931) + +* lightpush better feedback in case the lightpush service node does not have peers [2951](https://github.com/waku-org/nwaku/pull/2951) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`WAKU2-STORE`](https://github.com/waku-org/specs/blob/master/standards/core/store.md) | `draft` | `/vac/waku/store-query/3.0.0` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | + +## v0.31.0 (2024-07-16) +### Notes + +* Named sharding has been deprecated in favor of static sharding. Topics in formats other than `/waku/2/rs//` are no longer supported + +### Features + +- DOS protection of non relay protocols - rate limit phase3 (#2897) ([ba418ab5b](https://github.com/waku-org/nwaku/commit/ba418ab5b)) +- sonda tool (#2893) ([e269dca9c](https://github.com/waku-org/nwaku/commit/e269dca9c)) +- add proper per shard bandwidth metric calculation (#2851) ([8f14c0473](https://github.com/waku-org/nwaku/commit/8f14c0473)) + +### Bug Fixes + +- bug(storev3): can't advance cursor [#2745](https://github.com/waku-org/nwaku/issues/2745) +- chore(storev3): only select the messageHash column when using a store query with include_data: false [#2637](https://github.com/waku-org/nwaku/issues/2637) +- rln_keystore_generator improve error handling for unrecoverable failure (#2881) ([1c9eb2741](https://github.com/waku-org/nwaku/commit/1c9eb2741)) +- duplicate message forwarding in filter service (#2842) ([99149ea9d](https://github.com/waku-org/nwaku/commit/99149ea9d)) +- only set disconnect time on left event (#2831) ([01050138c](https://github.com/waku-org/nwaku/commit/01050138c)) +- adding peer exchange peers to the peerStore (#2824) ([325e13169](https://github.com/waku-org/nwaku/commit/325e13169)) +- ci use --tags to match non-annotated tags (#2814) ([317c83dc1](https://github.com/waku-org/nwaku/commit/317c83dc1)) +- update peers ENRs in peer store in case they are updated (#2818) ([cda18f96c](https://github.com/waku-org/nwaku/commit/cda18f96c)) +- mount metadata in wakucanary (#2793) ([3b27aee82](https://github.com/waku-org/nwaku/commit/3b27aee82)) + +### Changes + +- setting filter handling logs to trace (#2914) ([5c539fe13](https://github.com/waku-org/nwaku/commit/5c539fe13)) +- enhance postgres and retention policy logs (#2884) ([71ee42de5](https://github.com/waku-org/nwaku/commit/71ee42de5)) +- improving logging under debugDiscv5 flag (#2899) ([8578fb0c3](https://github.com/waku-org/nwaku/commit/8578fb0c3)) +- archive and drivers refactor (#2761) ([f54ba10bc](https://github.com/waku-org/nwaku/commit/f54ba10bc)) +- new release process to include Status fleets (#2825) ([4264666a3](https://github.com/waku-org/nwaku/commit/4264666a3)) +- sqlite make sure code is always run (#2891) ([4ac4ab2a4](https://github.com/waku-org/nwaku/commit/4ac4ab2a4)) +- deprecating named sharding (#2723) ([e1518cf9f](https://github.com/waku-org/nwaku/commit/e1518cf9f)) +- bump dependencies for v0.31.0 (#2885) ([fd6a71cdd](https://github.com/waku-org/nwaku/commit/fd6a71cdd)) +- refactor relative path to better absolute (#2861) ([8bfad3ab4](https://github.com/waku-org/nwaku/commit/8bfad3ab4)) +- saving agent and protoVersion in peerStore (#2860) ([cae0c7e37](https://github.com/waku-org/nwaku/commit/cae0c7e37)) +- unit test for duplicate message push (#2852) ([31c632e42](https://github.com/waku-org/nwaku/commit/31c632e42)) +- remove all pre-nim-1.6 deadcode from codebase (#2857) ([9bd8c33ae](https://github.com/waku-org/nwaku/commit/9bd8c33ae)) +- nim-chronos bump submodule (#2850) ([092add1ca](https://github.com/waku-org/nwaku/commit/092add1ca)) +- ignore arbitrary data stored in `multiaddrs` enr key (#2853) ([76d5b2642](https://github.com/waku-org/nwaku/commit/76d5b2642)) +- add origin to peers admin endpoint (#2848) ([7205f95cf](https://github.com/waku-org/nwaku/commit/7205f95cf)) +- add discv5 logs (#2811) ([974b8a39a](https://github.com/waku-org/nwaku/commit/974b8a39a)) +- archive.nim - increase the max limit of content topics per query to 100 (#2846) ([a05fa0691](https://github.com/waku-org/nwaku/commit/a05fa0691)) +- update content-topic parsing for filter (#2835) ([733edae43](https://github.com/waku-org/nwaku/commit/733edae43)) +- better descriptive log (#2826) ([94947a850](https://github.com/waku-org/nwaku/commit/94947a850)) +- zerokit: bump submodule (#2830) ([c483acee3](https://github.com/waku-org/nwaku/commit/c483acee3)) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`WAKU2-STORE`](https://github.com/waku-org/specs/blob/master/standards/core/store.md) | `draft` | `/vac/waku/store-query/3.0.0` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | + + +## v0.30.2 (2024-07-12) + +### Release highlights + +* RLN message limit to 100 messages per epoch. +* Avoid exclusive access when creating new partitions in the PostgreSQL messages table. + +### Changes + +- chore(rln): rln message limit to 100 ([#2883](https://github.com/waku-org/nwaku/pull/2883)) +- fix: postgres_driver better partition creation without exclusive access [28bdb70b](https://github.com/waku-org/nwaku/commit/28bdb70be46d3fb3a6f992b3f9f2de1defd85a30) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | + +## v0.30.1 (2024-07-03) + +### Notes + +* Before upgrading to this version, if you are currently using RLN, make sure to remove your existing `keystore` folder and `rln_tree` +and start your installation from scratch, as +explained in [nwaku-compose](https://github.com/waku-org/nwaku-compose/blob/1b56575df9ddb904af0941a19ea1df3d36bfddfa/README.md). + +### Release highlights + +* RLN_v2 is used. The maximum rate can be set to `N` messages per epoch, instead of just one message per epoch. See [this](https://github.com/waku-org/nwaku/issues/2345) for more details. Notice that we established an epoch of 10 minutes. + + +### Changes + +- rln-relay: add chain-id flag to wakunode and restrict usage if mismatches rpc provider ([#2858](https://github.com/waku-org/nwaku/pull/2858)) +- rln: fix nullifierlog vulnerability ([#2855](https://github.com/waku-org/nwaku/pull/2855)) +- chore: add TWN parameters for RLNv2 ([#2843](https://github.com/waku-org/nwaku/pull/2843)) +- fix(rln-relay): clear nullifier log only if length is over max epoch gap ([#2836](https://github.com/waku-org/nwaku/pull/2836)) +- rlnv2: clean fork of rlnv2 ([#2828](https://github.com/waku-org/nwaku/issues/2828)) ([a02832fe](https://github.com/waku-org/nwaku/commit/a02832fe)) +- zerokit: bump submodule ([#2830](https://github.com/waku-org/nwaku/issues/2830)) ([bd064882](https://github.com/waku-org/nwaku/commit/bd064882)) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | + +## v0.29.0 (2024-06-19) + +## What's Changed + +Notes: + +* Named sharding will be deprecated in favor of static sharding. Topics in formats other than `/waku/2/rs//` will stop being supported starting from `v0.31.0` + +Release highlights: + +* Android support in libwaku +* Discovery is available in libwaku +* New LiteProcotolTester tool +* RLN proofs as a lightpush service + +### Features + +- RLN proofs as a lightpush service ([#2768](https://github.com/waku-org/nwaku/issues/2768)) ([0561e5bd](https://github.com/waku-org/nwaku/commit/0561e5bd)) +- Push newly released nwaku image with latest-release tag ([#2732](https://github.com/waku-org/nwaku/issues/2732)) ([736ce1cb](https://github.com/waku-org/nwaku/commit/736ce1cb)) +- Rln-relay: use arkzkey variant of zerokit ([#2681](https://github.com/waku-org/nwaku/issues/2681)) ([e7b0777d](https://github.com/waku-org/nwaku/commit/e7b0777d)) + +### Bug Fixes + +- Better sync lock in partition creation ([#2783](https://github.com/waku-org/nwaku/issues/2783)) ([8d3bbb1b](https://github.com/waku-org/nwaku/pull/2809/commits/8d3bbb1b4e79b15c8cf18bb91d366e9ec1153301)) +- Multi nat initialization causing dead lock in waku tests + serialize test runs to avoid timing and port occupied issues ([#2799](https://github.com/waku-org/nwaku/issues/2799)) ([5989de88](https://github.com/waku-org/nwaku/commit/5989de88)) +- Increase on chain group manager starting balance ([#2795](https://github.com/waku-org/nwaku/issues/2795)) ([e72bb7e7](https://github.com/waku-org/nwaku/commit/e72bb7e7)) +- More detailed logs to differentiate shards with peers ([#2794](https://github.com/waku-org/nwaku/issues/2794)) ([55a87d21](https://github.com/waku-org/nwaku/commit/55a87d21)) +- waku_archive: only allow a single instance to execute migrations ([#2736](https://github.com/waku-org/nwaku/issues/2736)) ([88b8e186](https://github.com/waku-org/nwaku/commit/88b8e186)) +- Move postgres related tests under linux conditional ([57ecb3e0](https://github.com/waku-org/nwaku/commit/57ecb3e0)) +- Invalid cursor returning messages ([#2724](https://github.com/waku-org/nwaku/issues/2724)) ([a65b13fc](https://github.com/waku-org/nwaku/commit/a65b13fc)) +- Do not print the db url on error ([#2725](https://github.com/waku-org/nwaku/issues/2725)) ([40296f9d](https://github.com/waku-org/nwaku/commit/40296f9d)) +- Use `when` instead of `if` for adding soname on linux ([#2721](https://github.com/waku-org/nwaku/issues/2721)) ([cbaefeb3](https://github.com/waku-org/nwaku/commit/cbaefeb3)) +- Store v3 bug fixes ([#2718](https://github.com/waku-org/nwaku/issues/2718)) ([4a6ec468](https://github.com/waku-org/nwaku/commit/4a6ec468)) + + +### Changes + +- Set msg_hash logs to notice level ([#2737](https://github.com/waku-org/nwaku/issues/2737)) ([f5d87c5b](https://github.com/waku-org/nwaku/commit/f5d87c5b)) +- Minor enhancements ([#2789](https://github.com/waku-org/nwaku/issues/2789)) ([31bd6d71](https://github.com/waku-org/nwaku/commit/31bd6d71)) +- postgres_driver - acquire/release advisory lock when creating partitions ([#2784](https://github.com/waku-org/nwaku/issues/2784)) ([c5d19c44](https://github.com/waku-org/nwaku/commit/c5d19c44)) +- Setting fail-fast to false in matrixed github actions ([#2787](https://github.com/waku-org/nwaku/issues/2787)) ([005349cc](https://github.com/waku-org/nwaku/commit/005349cc)) +- Simple link refactor ([#2781](https://github.com/waku-org/nwaku/issues/2781)) ([77adfccd](https://github.com/waku-org/nwaku/commit/77adfccd)) +- Improving liteprotocolteseter stats ([#2750](https://github.com/waku-org/nwaku/issues/2750)) ([4c7c8a15](https://github.com/waku-org/nwaku/commit/4c7c8a15)) +- Extract common prefixes into a constant for multiple query ([#2747](https://github.com/waku-org/nwaku/issues/2747)) ([dfc979a8](https://github.com/waku-org/nwaku/commit/dfc979a8)) +- wakucanary: fix fitler protocol, add storev3 ([#2735](https://github.com/waku-org/nwaku/issues/2735)) ([e0079cd0](https://github.com/waku-org/nwaku/commit/e0079cd0)) +- Bump nim-libp2p version ([#2661](https://github.com/waku-org/nwaku/issues/2661)) ([6fbab633](https://github.com/waku-org/nwaku/commit/6fbab633)) +- Link validation process docs to the release process file ([#2714](https://github.com/waku-org/nwaku/issues/2714)) ([ebe69be8](https://github.com/waku-org/nwaku/commit/ebe69be8)) +- Android support ([#2554](https://github.com/waku-org/nwaku/issues/2554)) ([1e2aa57a](https://github.com/waku-org/nwaku/commit/1e2aa57a)) +- Discovery in libwaku ([#2711](https://github.com/waku-org/nwaku/issues/2711)) ([74646848](https://github.com/waku-org/nwaku/commit/74646848)) +- libwaku - allow to properly set the log level in libwaku and unify a little ([#2708](https://github.com/waku-org/nwaku/issues/2708)) ([3faffdbc](https://github.com/waku-org/nwaku/commit/3faffdbc)) +- waku_discv5, peer_manager - add more logs help debug discovery issues ([#2705](https://github.com/waku-org/nwaku/issues/2705)) ([401630ee](https://github.com/waku-org/nwaku/commit/401630ee)) +- Generic change to reduce the number of compilation warnings ([#2696](https://github.com/waku-org/nwaku/issues/2696)) ([78132dc1](https://github.com/waku-org/nwaku/commit/78132dc1)) + + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | + +## v0.28.1 (2024-05-29) + +This patch release fixes the following bug: +- Store node does not retrieve messages because the meta field is missing in queries. + +### Bug Fix + +- Commit that fixes the bug [8b42f199](https://github.com/waku-org/nwaku/commit/8b42f199baf4e00794c4cec4d8601c3f6c330a20) + +This is a patch release that is fully backwards-compatible with release `v0.28.0`. + +It supports the same [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | + + +## v0.28.0 (2024-05-22) + +## What's Changed + +Release highlights: + +* Store V3 has been merged +* Implemented an enhanced and more robust node health check mechanism +* Introduced the Waku object to libwaku in order to setup a node and its protocols + +### Features + +- Added message size check before relay for lightpush ([#2695](https://github.com/waku-org/nwaku/issues/2695)) ([9dfdfa27](https://github.com/waku-org/nwaku/commit/9dfdfa27)) +- adding json string support to bindings config ([#2685](https://github.com/waku-org/nwaku/issues/2685)) ([be5471c6](https://github.com/waku-org/nwaku/commit/be5471c6)) +- Added flexible rate limit checks for store, legacy store and lightpush ([#2668](https://github.com/waku-org/nwaku/issues/2668)) ([026d804a](https://github.com/waku-org/nwaku/commit/026d804a)) +- store v3 return pubsub topics ([#2676](https://github.com/waku-org/nwaku/issues/2676)) ([d700006a](https://github.com/waku-org/nwaku/commit/d700006a)) +- supporting meta field in store ([#2609](https://github.com/waku-org/nwaku/issues/2609)) ([a46d4451](https://github.com/waku-org/nwaku/commit/a46d4451)) +- store v3 ([#2431](https://github.com/waku-org/nwaku/issues/2431)) ([0b0fbfad](https://github.com/waku-org/nwaku/commit/0b0fbfad)) + +### Bug Fixes + +- use await instead of waitFor in async tests ([#2690](https://github.com/waku-org/nwaku/issues/2690)) ([a37c9ba9](https://github.com/waku-org/nwaku/commit/a37c9ba9)) +- message cache removal crash ([#2682](https://github.com/waku-org/nwaku/issues/2682)) ([fa26d05f](https://github.com/waku-org/nwaku/commit/fa26d05f)) +- add `meta` to sqlite migration scripts ([#2675](https://github.com/waku-org/nwaku/issues/2675)) ([82f95999](https://github.com/waku-org/nwaku/commit/82f95999)) +- content_script_version_4.nim: migration failed when dropping unexisting constraing ([#2672](https://github.com/waku-org/nwaku/issues/2672)) ([38f8b08c](https://github.com/waku-org/nwaku/commit/38f8b08c)) +- **filter:** log is too large ([#2665](https://github.com/waku-org/nwaku/issues/2665)) ([cee020f2](https://github.com/waku-org/nwaku/commit/cee020f2)) +- issue [#2644](https://github.com/waku-org/nwaku/issues/2644) properly ([#2663](https://github.com/waku-org/nwaku/issues/2663)) ([853ec186](https://github.com/waku-org/nwaku/commit/853ec186)) +- store v3 validate cursor & remove messages ([#2636](https://github.com/waku-org/nwaku/issues/2636)) ([e03d1165](https://github.com/waku-org/nwaku/commit/e03d1165)) +- **waku_keystore:** sigsegv on different appInfo ([#2654](https://github.com/waku-org/nwaku/issues/2654)) ([5dd645cf](https://github.com/waku-org/nwaku/commit/5dd645cf)) +- **rln-relay:** persist metadata every batch during initial sync ([#2649](https://github.com/waku-org/nwaku/issues/2649)) ([a9e19efd](https://github.com/waku-org/nwaku/commit/a9e19efd)) +- handle named sharding in enr ([#2647](https://github.com/waku-org/nwaku/issues/2647)) ([8d1b0834](https://github.com/waku-org/nwaku/commit/8d1b0834)) +- parse shards properly in enr config for non twn ([#2633](https://github.com/waku-org/nwaku/issues/2633)) ([6e6cb298](https://github.com/waku-org/nwaku/commit/6e6cb298)) +- proto field numbers & status desc ([#2632](https://github.com/waku-org/nwaku/issues/2632)) ([843fe217](https://github.com/waku-org/nwaku/commit/843fe217)) +- missing rate limit setting for legacy store protocol ([#2631](https://github.com/waku-org/nwaku/issues/2631)) ([5f65565c](https://github.com/waku-org/nwaku/commit/5f65565c)) +- **rln-relay:** enforce error callback to remove exception raised from retryWrapper ([#2622](https://github.com/waku-org/nwaku/issues/2622)) ([9c9883a6](https://github.com/waku-org/nwaku/commit/9c9883a6)) +- **rln-relay:** increase retries for 1 minute recovery time ([#2614](https://github.com/waku-org/nwaku/issues/2614)) ([1a23700d](https://github.com/waku-org/nwaku/commit/1a23700d)) +- **ci:** unique comment_tag to reference rln version ([#2613](https://github.com/waku-org/nwaku/issues/2613)) ([2c01fa0f](https://github.com/waku-org/nwaku/commit/2c01fa0f)) +- don't use WakuMessageSize in req/resp protocols ([#2601](https://github.com/waku-org/nwaku/issues/2601)) ([e61e4ff9](https://github.com/waku-org/nwaku/commit/e61e4ff9)) +- create options api for cors preflight request ([#2598](https://github.com/waku-org/nwaku/issues/2598)) ([768c61b1](https://github.com/waku-org/nwaku/commit/768c61b1)) +- node restart test issue ([#2576](https://github.com/waku-org/nwaku/issues/2576)) ([4a8e62ac](https://github.com/waku-org/nwaku/commit/4a8e62ac)) +- **doc:** update REST API docs ([#2581](https://github.com/waku-org/nwaku/issues/2581)) ([006d43ae](https://github.com/waku-org/nwaku/commit/006d43ae)) + +### Changes + +- move code from wakunode2 to a more generic place, waku ([#2670](https://github.com/waku-org/nwaku/issues/2670)) ([840e0122](https://github.com/waku-org/nwaku/commit/840e0122)) +- closing ping streams ([#2692](https://github.com/waku-org/nwaku/issues/2692)) ([7d4857ea](https://github.com/waku-org/nwaku/commit/7d4857ea)) +- Postgres enhance get oldest timestamp ([#2687](https://github.com/waku-org/nwaku/issues/2687)) ([8451cf8e](https://github.com/waku-org/nwaku/commit/8451cf8e)) +- **rln-relay:** health check should account for window of roots ([#2664](https://github.com/waku-org/nwaku/issues/2664)) ([6a1af922](https://github.com/waku-org/nwaku/commit/6a1af922)) +- updating TWN bootstrap fleet to waku.sandbox ([#2638](https://github.com/waku-org/nwaku/issues/2638)) ([22f64bbd](https://github.com/waku-org/nwaku/commit/22f64bbd)) +- simplify migration script postgres version_4 ([#2674](https://github.com/waku-org/nwaku/issues/2674)) ([91c85738](https://github.com/waku-org/nwaku/commit/91c85738)) +- big refactor to add waku component in libwaku instead of only waku node ([#2658](https://github.com/waku-org/nwaku/issues/2658)) ([2463527b](https://github.com/waku-org/nwaku/commit/2463527b)) +- simplify app.nim and move discovery items to appropriate modules ([#2657](https://github.com/waku-org/nwaku/issues/2657)) ([404810aa](https://github.com/waku-org/nwaku/commit/404810aa)) +- log enhancement for message reliability analysis ([#2640](https://github.com/waku-org/nwaku/issues/2640)) ([d5e0e4a9](https://github.com/waku-org/nwaku/commit/d5e0e4a9)) +- metrics server. Simplify app.nim module ([#2650](https://github.com/waku-org/nwaku/issues/2650)) ([4a110f65](https://github.com/waku-org/nwaku/commit/4a110f65)) +- change nim-libp2p branch from unstable to master ([#2648](https://github.com/waku-org/nwaku/issues/2648)) ([d09c9c91](https://github.com/waku-org/nwaku/commit/d09c9c91)) +- Enabling to use a full node for lightpush via rest api without lightpush client configured ([#2626](https://github.com/waku-org/nwaku/issues/2626)) ([2a4c0f15](https://github.com/waku-org/nwaku/commit/2a4c0f15)) +- **rln-relay:** resultify rln-relay 1/n ([#2607](https://github.com/waku-org/nwaku/issues/2607)) ([1d7ff288](https://github.com/waku-org/nwaku/commit/1d7ff288)) +- ci.yml - avoid calling brew link libpq --force on macos ([#2627](https://github.com/waku-org/nwaku/issues/2627)) ([05f332ed](https://github.com/waku-org/nwaku/commit/05f332ed)) +- an enhanced version of convenient node health check script ([#2624](https://github.com/waku-org/nwaku/issues/2624)) ([7f8d8e80](https://github.com/waku-org/nwaku/commit/7f8d8e80)) +- **rln-db-inspector:** add more logging to find zero leaf indices ([#2617](https://github.com/waku-org/nwaku/issues/2617)) ([40752b1e](https://github.com/waku-org/nwaku/commit/40752b1e)) +- addition of waku_api/rest/builder.nim and reduce app.nim ([#2623](https://github.com/waku-org/nwaku/issues/2623)) ([b28207ab](https://github.com/waku-org/nwaku/commit/b28207ab)) +- Separation of node health and initialization state from rln_relay ([#2612](https://github.com/waku-org/nwaku/issues/2612)) ([6d135b0d](https://github.com/waku-org/nwaku/commit/6d135b0d)) +- enabling rest api as default ([#2600](https://github.com/waku-org/nwaku/issues/2600)) ([6bc79bc7](https://github.com/waku-org/nwaku/commit/6bc79bc7)) +- move app.nim and networks_config.nim to waku/factory ([#2608](https://github.com/waku-org/nwaku/issues/2608)) ([1ba9df4b](https://github.com/waku-org/nwaku/commit/1ba9df4b)) +- workflow to autoassign PR ([#2604](https://github.com/waku-org/nwaku/issues/2604)) ([10d36c39](https://github.com/waku-org/nwaku/commit/10d36c39)) +- start moving discovery modules to waku/discovery ([#2587](https://github.com/waku-org/nwaku/issues/2587)) ([828583ad](https://github.com/waku-org/nwaku/commit/828583ad)) +- don't create docker images for users without org's secrets ([#2585](https://github.com/waku-org/nwaku/issues/2585)) ([51ec12be](https://github.com/waku-org/nwaku/commit/51ec12be)) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | + +The Waku v1 implementation has been removed from this repository and can be found in a separate [Waku Legacy](https://github.com/waku-org/waku-legacy) repository. + +## v0.27.0 (2024-04-19) + +> **Note:** + +> - Filter v1 protocol and its REST-API access have been deprecated. +> - A new field of the `WakuMetadataRequest` protobuf for shards was introduced. The old shards field (2) will be deprecated in 2 releases time +> - CLI flags `--requestRateLimit` and `--requestRatePeriod` have been added for rate limiting configuration. Period is measured in seconds. Limits are measured per protocol per period of time. Over limit will result in TOO_MANY_REQUEST (429) response. + +## What's Changed + +Release highlights: + +* Introduced configurable rate limiting for lightpush and store requests +* Sync time has been considerably reduced for node initialization +* Significant refactors were made to node initialization and `WakuArchive` logic as work towards C-bindings and Store V3 features + +### Features + +- Added simple, configurable rate limit for lightpush and store-query ([#2390](https://github.com/waku-org/nwaku/issues/2390)) ([a00f350c](https://github.com/waku-org/nwaku/commit/a00f350c)) +- examples/golang/waku.go add new example ([#2559](https://github.com/waku-org/nwaku/issues/2559)) ([8d66a548](https://github.com/waku-org/nwaku/commit/8d66a548)) +- **c-bindings:** rln relay ([#2544](https://github.com/waku-org/nwaku/issues/2544)) ([2aa835e3](https://github.com/waku-org/nwaku/commit/2aa835e3)) +- **incentivization:** add codec for eligibility proof and status ([#2419](https://github.com/waku-org/nwaku/issues/2419)) ([65530264](https://github.com/waku-org/nwaku/commit/65530264)) +- **rest:** add support to ephemeral field ([#2525](https://github.com/waku-org/nwaku/issues/2525)) ([c734f60d](https://github.com/waku-org/nwaku/commit/c734f60d)) +- archive update for store v3 ([#2451](https://github.com/waku-org/nwaku/issues/2451)) ([505479b8](https://github.com/waku-org/nwaku/commit/505479b8)) +- **c-bindings:** add function to dealloc nodes ([#2499](https://github.com/waku-org/nwaku/issues/2499)) ([8341864d](https://github.com/waku-org/nwaku/commit/8341864d)) + +### Bug Fixes + +- **rln-relay:** reduce sync time ([#2577](https://github.com/waku-org/nwaku/issues/2577)) ([480a62fa](https://github.com/waku-org/nwaku/commit/480a62fa)) +- rest store: content_topic -> contentTopic in the response ([#2584](https://github.com/waku-org/nwaku/issues/2584)) ([d2578553](https://github.com/waku-org/nwaku/commit/d2578553)) +- **c-bindings:** rln credential path key ([#2564](https://github.com/waku-org/nwaku/issues/2564)) ([3d752b11](https://github.com/waku-org/nwaku/commit/3d752b11)) +- cluster-id 0 disc5 issue ([#2562](https://github.com/waku-org/nwaku/issues/2562)) ([a76c9587](https://github.com/waku-org/nwaku/commit/a76c9587)) +- regex for rpc endpoint ([#2563](https://github.com/waku-org/nwaku/issues/2563)) ([c87545d5](https://github.com/waku-org/nwaku/commit/c87545d5)) +- **rln:** set a minimum epoch gap ([#2555](https://github.com/waku-org/nwaku/issues/2555)) ([b5e4795f](https://github.com/waku-org/nwaku/commit/b5e4795f)) +- fix regresion + remove deprecated flag ([#2556](https://github.com/waku-org/nwaku/issues/2556)) ([47ad0fb0](https://github.com/waku-org/nwaku/commit/47ad0fb0)) +- **networkmanager:** regularly disconnect from random peers ([#2553](https://github.com/waku-org/nwaku/issues/2553)) ([70c53fc0](https://github.com/waku-org/nwaku/commit/70c53fc0)) +- remove subscription queue limit ([#2551](https://github.com/waku-org/nwaku/issues/2551)) ([94ff5eab](https://github.com/waku-org/nwaku/commit/94ff5eab)) +- peer_manager - extend the number of connection requests to known peers ([#2534](https://github.com/waku-org/nwaku/issues/2534)) ([2173fe22](https://github.com/waku-org/nwaku/commit/2173fe22)) +- **2491:** Fix metadata protocol disconnecting light nodes ([#2533](https://github.com/waku-org/nwaku/issues/2533)) ([33774fad](https://github.com/waku-org/nwaku/commit/33774fad)) +- **rest:** filter/v2/subscriptions response ([#2529](https://github.com/waku-org/nwaku/issues/2529)) ([7aea2d4f](https://github.com/waku-org/nwaku/commit/7aea2d4f)) +- **store:** retention policy regex ([#2532](https://github.com/waku-org/nwaku/issues/2532)) ([23a291b3](https://github.com/waku-org/nwaku/commit/23a291b3)) +- enable autosharding in any cluster ([#2505](https://github.com/waku-org/nwaku/issues/2505)) ([5a225809](https://github.com/waku-org/nwaku/commit/5a225809)) +- introduce new field for shards in metadata protocol ([#2511](https://github.com/waku-org/nwaku/issues/2511)) ([f9f92b7d](https://github.com/waku-org/nwaku/commit/f9f92b7d)) +- **rln-relay:** handle empty metadata returned by getMetadata proc ([#2516](https://github.com/waku-org/nwaku/issues/2516)) ([1274b15d](https://github.com/waku-org/nwaku/commit/1274b15d)) + +### Changes + +- adding migration script adding i_query index ([#2578](https://github.com/waku-org/nwaku/issues/2578)) ([4117fe65](https://github.com/waku-org/nwaku/commit/4117fe65)) +- bumping chronicles version ([#2583](https://github.com/waku-org/nwaku/issues/2583)) ([a04e0d99](https://github.com/waku-org/nwaku/commit/a04e0d99)) +- add ARM64 support for Linux/MacOS ([#2580](https://github.com/waku-org/nwaku/issues/2580)) ([269139cf](https://github.com/waku-org/nwaku/commit/269139cf)) +- **rln:** update submodule + rln patch version ([#2574](https://github.com/waku-org/nwaku/issues/2574)) ([24f6fed8](https://github.com/waku-org/nwaku/commit/24f6fed8)) +- bumping dependencies for 0.27.0 ([#2572](https://github.com/waku-org/nwaku/issues/2572)) ([f68ac792](https://github.com/waku-org/nwaku/commit/f68ac792)) +- **c-bindings:** node initialization ([#2547](https://github.com/waku-org/nwaku/issues/2547)) ([6d0f6d82](https://github.com/waku-org/nwaku/commit/6d0f6d82)) +- remove deprecated legacy filter protocol ([#2507](https://github.com/waku-org/nwaku/issues/2507)) ([e8613172](https://github.com/waku-org/nwaku/commit/e8613172)) +- switch wakuv2 to waku fleet ([#2519](https://github.com/waku-org/nwaku/issues/2519)) ([18a05359](https://github.com/waku-org/nwaku/commit/18a05359)) +- create nph.md ([#2536](https://github.com/waku-org/nwaku/issues/2536)) ([a576e624](https://github.com/waku-org/nwaku/commit/a576e624)) +- Better postgres duplicate insert ([#2535](https://github.com/waku-org/nwaku/issues/2535)) ([693a1778](https://github.com/waku-org/nwaku/commit/693a1778)) +- add 150 kB to msg size histogram metric ([#2430](https://github.com/waku-org/nwaku/issues/2430)) ([2c1391d3](https://github.com/waku-org/nwaku/commit/2c1391d3)) +- content_script_version_2: add simple protection and rename messages_backup if exists ([#2531](https://github.com/waku-org/nwaku/issues/2531)) ([c6c376b5](https://github.com/waku-org/nwaku/commit/c6c376b5)) +- **vendor:** update nim-libp2p path ([#2527](https://github.com/waku-org/nwaku/issues/2527)) ([3c823756](https://github.com/waku-org/nwaku/commit/3c823756)) +- adding node factory tests ([#2524](https://github.com/waku-org/nwaku/issues/2524)) ([a1b3e090](https://github.com/waku-org/nwaku/commit/a1b3e090)) +- factory cleanup ([#2523](https://github.com/waku-org/nwaku/issues/2523)) ([8d7eb3a6](https://github.com/waku-org/nwaku/commit/8d7eb3a6)) +- **rln-relay-v2:** wakunode testing + improvements ([#2501](https://github.com/waku-org/nwaku/issues/2501)) ([059cb975](https://github.com/waku-org/nwaku/commit/059cb975)) +- update CHANGELOG for v0.26.0 release ([#2518](https://github.com/waku-org/nwaku/issues/2518)) ([097cb362](https://github.com/waku-org/nwaku/commit/097cb362)) +- migrating logic from wakunode2.nim to node_factory.nim ([#2504](https://github.com/waku-org/nwaku/issues/2504)) ([dcc88ee0](https://github.com/waku-org/nwaku/commit/dcc88ee0)) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | + +The Waku v1 implementation has been removed from this repository and can be found in a separate [Waku Legacy](https://github.com/waku-org/waku-legacy) repository. + +## v0.26.0 (2024-03-07) + +> **Note:** +> - JSON-RPC API has been removed completely. Instead we recommend you to utilize REST API endpoints that have same and extended functionality. +> Please have a look at Waku's REST-API reference: https://waku-org.github.io/waku-rest-api +> - Support for Cross-Origin-Resource-Sharing (CORS headers) is added for our REST-API services. This allows you to access our REST-API from a browser. +> New repeatable CLI flag is added by this feature: +> `--rest-allow-origin="example.com"` or `--rest-allow-origin="127.0.0.0:*"` +> Flag allows using wildcards (`*` and `?`) in the origin string. +> - Store protocol now has a better support for controlling DB size of Postgres store. This feature needs no user action. + +> **Announcement:** +> +> Please notice that from the next release (0.27.0) we will deprecate features. +> +> - We will decomission the Filter v1 protocol and its REST-API access. + +### Features + +- Postgres partition implementation ([#2506](https://github.com/waku-org/nwaku/issues/2506)) ([161a10ec](https://github.com/waku-org/nwaku/commit/161a10ec)) +- **waku-stealth-commitments:** waku stealth commitment protocol ([#2490](https://github.com/waku-org/nwaku/issues/2490)) ([0def4904](https://github.com/waku-org/nwaku/commit/0def4904)) +- **bindings:** generate a random private key ([#2446](https://github.com/waku-org/nwaku/issues/2446)) ([56ff30ca](https://github.com/waku-org/nwaku/commit/56ff30ca)) +- prioritise yamux above mplex ([#2417](https://github.com/waku-org/nwaku/issues/2417)) ([ce151efc](https://github.com/waku-org/nwaku/commit/ce151efc)) +- supporting meta field in WakuMessage ([#2384](https://github.com/waku-org/nwaku/issues/2384)) ([3903f130](https://github.com/waku-org/nwaku/commit/3903f130)) +- `eventCallback` per wakunode and `userData` ([#2418](https://github.com/waku-org/nwaku/issues/2418)) ([707f3e8b](https://github.com/waku-org/nwaku/commit/707f3e8b)) +- **rln-relay-v2:** nonce/messageId manager ([#2413](https://github.com/waku-org/nwaku/issues/2413)) ([50308eda](https://github.com/waku-org/nwaku/commit/50308eda)) +- **networkmonitor:** add support for rln ([#2401](https://github.com/waku-org/nwaku/issues/2401)) ([9c0e9431](https://github.com/waku-org/nwaku/commit/9c0e9431)) +- **rln-relay-v2:** rln-keystore-generator updates ([#2392](https://github.com/waku-org/nwaku/issues/2392)) ([2d46c351](https://github.com/waku-org/nwaku/commit/2d46c351)) +- add yamux support ([#2397](https://github.com/waku-org/nwaku/issues/2397)) ([1b402667](https://github.com/waku-org/nwaku/commit/1b402667)) + +### Bug Fixes + +- **rln-relay:** make nullifier log abide by epoch ordering ([#2508](https://github.com/waku-org/nwaku/issues/2508)) ([beba14dc](https://github.com/waku-org/nwaku/commit/beba14dc)) +- **postgres:** import under feature flag ([#2500](https://github.com/waku-org/nwaku/issues/2500)) ([e692edf6](https://github.com/waku-org/nwaku/commit/e692edf6)) +- notify Waku Metadata when Waku Filter subscribe to a topic ([#2493](https://github.com/waku-org/nwaku/issues/2493)) ([91e3f8cd](https://github.com/waku-org/nwaku/commit/91e3f8cd)) +- time on 32 bits architecture ([#2492](https://github.com/waku-org/nwaku/issues/2492)) ([0a751228](https://github.com/waku-org/nwaku/commit/0a751228)) +- return message id on `waku_relay_publish` ([#2485](https://github.com/waku-org/nwaku/issues/2485)) ([045091a9](https://github.com/waku-org/nwaku/commit/045091a9)) +- **bindings:** base64 payload and key for content topic ([#2435](https://github.com/waku-org/nwaku/issues/2435)) ([d01585e9](https://github.com/waku-org/nwaku/commit/d01585e9)) +- **rln-relay:** regex pattern match for extended domains ([#2444](https://github.com/waku-org/nwaku/issues/2444)) ([29b0c0b8](https://github.com/waku-org/nwaku/commit/29b0c0b8)) +- checking for keystore file existence ([#2427](https://github.com/waku-org/nwaku/issues/2427)) ([8f487a21](https://github.com/waku-org/nwaku/commit/8f487a21)) +- **rln-relay:** graceful shutdown with non-zero exit code ([#2429](https://github.com/waku-org/nwaku/issues/2429)) ([22026b7e](https://github.com/waku-org/nwaku/commit/22026b7e)) +- check max message size in validator according to configured value ([#2424](https://github.com/waku-org/nwaku/issues/2424)) ([731dfcbd](https://github.com/waku-org/nwaku/commit/731dfcbd)) +- **wakunode2:** move node config inside app init branch ([#2423](https://github.com/waku-org/nwaku/issues/2423)) ([0dac9f9d](https://github.com/waku-org/nwaku/commit/0dac9f9d)) + +### Changes + +- **rln_db_inspector:** include in wakunode2 binary ([#2292](https://github.com/waku-org/nwaku/issues/2292)) ([a9d0e481](https://github.com/waku-org/nwaku/commit/a9d0e481)) +- Update link to DNS discovery tutorial ([#2496](https://github.com/waku-org/nwaku/issues/2496)) ([9ef2eccb](https://github.com/waku-org/nwaku/commit/9ef2eccb)) +- **rln-relay-v2:** added tests for static rln-relay-v2 ([#2484](https://github.com/waku-org/nwaku/issues/2484)) ([5b174fb3](https://github.com/waku-org/nwaku/commit/5b174fb3)) +- moving node initialization code to node_factory.nim ([#2479](https://github.com/waku-org/nwaku/issues/2479)) ([361fe2cd](https://github.com/waku-org/nwaku/commit/361fe2cd)) +- Postgres migrations ([#2477](https://github.com/waku-org/nwaku/issues/2477)) ([560f949a](https://github.com/waku-org/nwaku/commit/560f949a)) +- **rln-relay-v2:** added tests for onchain rln-relay-v2 ([#2482](https://github.com/waku-org/nwaku/issues/2482)) ([88ff9282](https://github.com/waku-org/nwaku/commit/88ff9282)) +- remove json rpc ([#2416](https://github.com/waku-org/nwaku/issues/2416)) ([c994ee04](https://github.com/waku-org/nwaku/commit/c994ee04)) +- **ci:** use git describe for image version ([55ff6674](https://github.com/waku-org/nwaku/commit/55ff6674)) +- Implemented CORS handling for nwaku REST server ([#2470](https://github.com/waku-org/nwaku/issues/2470)) ([d832f92a](https://github.com/waku-org/nwaku/commit/d832f92a)) +- remove rln epoch hardcoding ([#2483](https://github.com/waku-org/nwaku/issues/2483)) ([3f4f6d7e](https://github.com/waku-org/nwaku/commit/3f4f6d7e)) +- **cbindings:** cbindings rust simple libwaku integration example ([#2089](https://github.com/waku-org/nwaku/issues/2089)) ([a4993005](https://github.com/waku-org/nwaku/commit/a4993005)) +- adding NIMFLAGS usage to readme ([#2469](https://github.com/waku-org/nwaku/issues/2469)) ([a1d5cbd9](https://github.com/waku-org/nwaku/commit/a1d5cbd9)) +- bumping nim-libp2p after yamux timeout fix ([#2468](https://github.com/waku-org/nwaku/issues/2468)) ([216531b0](https://github.com/waku-org/nwaku/commit/216531b0)) +- new proc to foster different size retention policy implementations ([#2463](https://github.com/waku-org/nwaku/issues/2463)) ([d5305282](https://github.com/waku-org/nwaku/commit/d5305282)) +- **rln-relay:** use anvil instead of ganache in onchain tests ([#2449](https://github.com/waku-org/nwaku/issues/2449)) ([f6332ac6](https://github.com/waku-org/nwaku/commit/f6332ac6)) +- bindings return multiaddress array ([#2461](https://github.com/waku-org/nwaku/issues/2461)) ([7aea145e](https://github.com/waku-org/nwaku/commit/7aea145e)) +- **ci:** fix IMAGE_NAME to use harbor.status.im ([b700d046](https://github.com/waku-org/nwaku/commit/b700d046)) +- **rln-relay:** remove wss support from node config ([#2442](https://github.com/waku-org/nwaku/issues/2442)) ([2060cfab](https://github.com/waku-org/nwaku/commit/2060cfab)) +- **ci:** reuse discord send function from library ([1151d50f](https://github.com/waku-org/nwaku/commit/1151d50f)) +- **rln-relay-v2:** add tests for serde ([#2421](https://github.com/waku-org/nwaku/issues/2421)) ([d0377056](https://github.com/waku-org/nwaku/commit/d0377056)) +- add stdef.h to libwaku.h ([#2409](https://github.com/waku-org/nwaku/issues/2409)) ([d58aca01](https://github.com/waku-org/nwaku/commit/d58aca01)) +- automatically generating certs if not provided (Waku Canary) ([#2408](https://github.com/waku-org/nwaku/issues/2408)) ([849d76d6](https://github.com/waku-org/nwaku/commit/849d76d6)) +- Simplify configuration for the waku network ([#2404](https://github.com/waku-org/nwaku/issues/2404)) ([985d092f](https://github.com/waku-org/nwaku/commit/985d092f)) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | + +The Waku v1 implementation has been removed from this repository and can be found in a separate [Waku Legacy](https://github.com/waku-org/waku-legacy) repository. + +## v0.25.0 (2024-02-06) + +> **Note:** +> Waku Filter v2 now has three additional configuration options +> `--filter-max-peers-to-serve=1000` drives how many peers can subscribe at once and +> `--filter-max-criteria=1000` defines what is the maximum criterion stored per each peers +> +> This release introduces a major change in Filter v2 protocol subscription management. +> From now each subscribed peer needs to refresh its living subscriptions by sending a SUBSCRIBER_PING message every 5 minutes by default, otherwise the peer's subscription will be removed. +> `--filter-subscription-timeout=300` defines configurable timeout for the subscriptions (*in seconds*). +> +> New experimental feature, shard aware peer manager for relay protocol can be activated by the flag: +> `--relay-shard-manager=true|false` +> It is disabled by default. + +> **Announcement:** +> +> Please notice that from the next release (0.26.0) we will deprecate features. +> +> - JSON-RPC API will be removed completely. Instead we recommend you to utilize REST API endpoints that have same and extended functionality. +> - We will retire websockets support for RLN on-chain group management. You are expected to use HTTP version of ETH_CLIENT_ADDRESS + +### Features + +- running validators in /relay/v1/auto/messages/{topic} ([#2394](https://github.com/waku-org/nwaku/issues/2394)) ([e4e147bc](https://github.com/waku-org/nwaku/commit/e4e147bc)) +- **rln-relay-v2:** update C FFI api's and serde ([#2385](https://github.com/waku-org/nwaku/issues/2385)) ([b88facd0](https://github.com/waku-org/nwaku/commit/b88facd0)) +- running validators in /relay/v1/messages/{pubsubTopic} ([#2373](https://github.com/waku-org/nwaku/issues/2373)) ([59d8b620](https://github.com/waku-org/nwaku/commit/59d8b620)) +- shard aware relay peer management ([#2332](https://github.com/waku-org/nwaku/issues/2332)) ([edca1df1](https://github.com/waku-org/nwaku/commit/edca1df1)) + +### Bug Fixes + +- adding rln validator as default ([#2367](https://github.com/waku-org/nwaku/issues/2367)) ([bb58a63a](https://github.com/waku-org/nwaku/commit/bb58a63a)) +- Fix test for filter client receiving messages after restart ([#2360](https://github.com/waku-org/nwaku/issues/2360)) ([7de91d92](https://github.com/waku-org/nwaku/commit/7de91d92)) +- making filter admin data test order independent ([#2355](https://github.com/waku-org/nwaku/issues/2355)) ([8a9fad29](https://github.com/waku-org/nwaku/commit/8a9fad29)) + +### Changes + +- **rln-relay-v2:** use rln-v2 contract code ([#2381](https://github.com/waku-org/nwaku/issues/2381)) ([c55ca067](https://github.com/waku-org/nwaku/commit/c55ca067)) +- v0.25 vendor bump and associated fixes ([#2352](https://github.com/waku-org/nwaku/issues/2352)) ([761ce7b1](https://github.com/waku-org/nwaku/commit/761ce7b1)) +- handle errors w.r.t. configured cluster-id and pubsub topics ([#2368](https://github.com/waku-org/nwaku/issues/2368)) ([e04e35e2](https://github.com/waku-org/nwaku/commit/e04e35e2)) +- add coverage target to Makefile ([#2382](https://github.com/waku-org/nwaku/issues/2382)) ([57378873](https://github.com/waku-org/nwaku/commit/57378873)) +- Add check spell allowed words ([#2383](https://github.com/waku-org/nwaku/issues/2383)) ([c1121dd1](https://github.com/waku-org/nwaku/commit/c1121dd1)) +- adding nwaku compose image update to release process ([#2370](https://github.com/waku-org/nwaku/issues/2370)) ([4f06dcff](https://github.com/waku-org/nwaku/commit/4f06dcff)) +- changing digest and hash log format from bytes to hex ([#2363](https://github.com/waku-org/nwaku/issues/2363)) ([025c6ec9](https://github.com/waku-org/nwaku/commit/025c6ec9)) +- log messageHash for lightpush request that helps in debugging ([#2366](https://github.com/waku-org/nwaku/issues/2366)) ([42204115](https://github.com/waku-org/nwaku/commit/42204115)) +- **rln-relay:** enabled http based polling in OnchainGroupManager ([#2364](https://github.com/waku-org/nwaku/issues/2364)) ([efdc5244](https://github.com/waku-org/nwaku/commit/efdc5244)) +- improve POST /relay/v1/auto/messages/{topic} error handling ([#2339](https://github.com/waku-org/nwaku/issues/2339)) ([f841454e](https://github.com/waku-org/nwaku/commit/f841454e)) +- Refactor of FilterV2 subscription management with Time-to-live maintenance ([#2341](https://github.com/waku-org/nwaku/issues/2341)) ([c3358409](https://github.com/waku-org/nwaku/commit/c3358409)) +- Bump `nim-dnsdisc` ([#2354](https://github.com/waku-org/nwaku/issues/2354)) ([3d816c08](https://github.com/waku-org/nwaku/commit/3d816c08)) +- postgres-adoption.md add metadata title, description, and better first-readable-title ([#2346](https://github.com/waku-org/nwaku/issues/2346)) ([2f8e8bcb](https://github.com/waku-org/nwaku/commit/2f8e8bcb)) +- fix typo ([#2348](https://github.com/waku-org/nwaku/issues/2348)) ([a4a8dee3](https://github.com/waku-org/nwaku/commit/a4a8dee3)) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | + +The Waku v1 implementation has been removed from this repository and can be found in a separate [Waku Legacy](https://github.com/waku-org/waku-legacy) repository. + +## v0.24.0 (2024-01-10) + +> Note: The Waku message size limit (150 KiB) is now enforced according to the specifications. To change this limit please use `--max-msg-size="1MiB"` + +> Note: `--ip-colocation-limit=2` is the new parameter for limiting connections from the same IP + +## What's Changed + +Release highlights: +* IP colocation filter can now be changed via a configuration parameter. +* New filter admin endpoint can now be used to access subscription data. +* Waku message size limit can now be changed via a configuration parameter. + +### Features + +- feat: adding filter data admin endpoint (REST) [#2314](https://github.com/waku-org/nwaku/pull/2314) +- ip colocation is parameterizable. if set to 0, it is disabled [#2323](https://github.com/waku-org/nwaku/pull/2323) + +### Bug Fixes +- fix: revert "feat: shard aware peer management [#2151](https://github.com/waku-org/nwaku/pull/2151)" [#2312](https://github.com/waku-org/nwaku/pull/2312) +- fix: setting connectivity loop interval to 15 seconds [#2307](https://github.com/waku-org/nwaku/pull/2307) +- fix: set record to the Waku node builder in the examples as it is required [#2328](https://github.com/waku-org/nwaku/pull/2328) +- fix(discv5): add bootnode filter exception [#2267](https://github.com/waku-org/nwaku/pull/2267) + + +### Changes +- update CHANGELOG.md for 0.23.0 [#2309](https://github.com/waku-org/nwaku/pull/2309) +- test(store): Implement store tests [#2235](https://github.com/waku-org/nwaku/pull/2235), [#2240](https://github.com/waku-org/nwaku/commit/86353e22a871820c132deee077f65e7af4356671) +- refactor(store): HistoryQuery.direction [#2263](https://github.com/waku-org/nwaku/pull/2263) +- test_driver_postgres: enhance test coverage, multiple and single topic [#2301](https://github.com/waku-org/nwaku/pull/2301) +- chore: examples/nodejs - adapt code to latest callback and ctx/userData definitions [#2281](https://github.com/waku-org/nwaku/pull/2281) +- chore: update `CHANGELOG.md` to reflect bug fix for issue [#2317](https://github.com/waku-org/nwaku/issues/2317) [#2340](https://github.com/waku-org/nwaku/pull/2340) in v0.23.1 +- test(peer-connection-managenent): functional tests [#2321](https://github.com/waku-org/nwaku/pull/2321) +- docs: update post-release steps [#2336](https://github.com/waku-org/nwaku/pull/2336) +- docs: fix typos across various documentation files [#2310](https://github.com/waku-org/nwaku/pull/2310) +- test(peer-connection-managenent): functional tests [#2321](https://github.com/waku-org/nwaku/pull/2321) +- bump vendors for 0.24.0 [#2333](https://github.com/waku-org/nwaku/pull/2333) +- test(autosharding): functional tests [#2318](https://github.com/waku-org/nwaku/pull/2318) +- docs: add benchmark around postgres adoption [#2316](https://github.com/waku-org/nwaku/pull/2316) +- chore: set max Waku message size to 150KiB according to spec [#2298](https://github.com/waku-org/nwaku/pull/2298) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | + +The Waku v1 implementation has been removed from this repository and can be found in a separate [Waku Legacy](https://github.com/waku-org/waku-legacy) repository. + +## v0.23.1 (2023-01-09) + +This patch release fixes the following bug: +- Sort order ignored in store nodes. + +### Bug Fix + +- Bug definition: [#2317](https://github.com/waku-org/nwaku/issues/2317) +- Commit that fixes the bug [fae20bff](https://github.com/waku-org/nwaku/commit/fae20bff) + +This is a patch release that is fully backwards-compatible with release `v0.23.0`. + +It supports the same [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | + +The Waku v1 implementation has been removed from this repository and can be found in a separate [Waku Legacy](https://github.com/waku-org/waku-legacy) repository. + + +## v0.23.0 (2023-12-18) + +## What's Changed + +Release highlights: +* Bug fix in Postgres when querying more than one content topic. +* :warning: Add new DB column `messageHash`. This requires a manual database update in _Postgres_. +* Updated deterministic message hash algorithm. +* REST admin can inform whether a node supports lightpush and/or filter protocols. +* Improvements to cluster id and shards setup. +* Properly apply RLN when publishing from REST or jsonrpc API. +* Remove trailing commas from the RLN keystore json generated during credentials registration. +* General test cleanup, better relay tests and new filter unsubscribe tests. +* Rewrite docs for clarity and update screenshots. + +### Features + +- setting image deployment to harbor registry ([93dd5ae5](https://github.com/waku-org/nwaku/commit/93dd5ae5)) +- Add new DB column `messageHash` ([#2202](https://github.com/waku-org/nwaku/issues/2202)) ([aeb77a3e](https://github.com/waku-org/nwaku/commit/aeb77a3e)) + +### Bug Fixes + +- make rln rate limit spec compliant ([#2294](https://github.com/waku-org/nwaku/issues/2294)) ([5847f49d](https://github.com/waku-org/nwaku/commit/5847f49d)) +- update num-msgs archive metrics every minute and not only at the beginning ([#2287](https://github.com/waku-org/nwaku/issues/2287)) ([0fc617ff](https://github.com/waku-org/nwaku/commit/0fc617ff)) +- **rln-relay:** graceful retries on rpc calls ([#2250](https://github.com/waku-org/nwaku/issues/2250)) ([15c1f974](https://github.com/waku-org/nwaku/commit/15c1f974)) +- add protection in rest service to always publish with timestamp if user doesn't provide it ([#2261](https://github.com/waku-org/nwaku/issues/2261)) ([42f19579](https://github.com/waku-org/nwaku/commit/42f19579)) +- remove trailing commas from keystore json ([#2200](https://github.com/waku-org/nwaku/issues/2200)) ([103d3981](https://github.com/waku-org/nwaku/commit/103d3981)) +- **dockerfile:** update dockerignore and base image ([#2262](https://github.com/waku-org/nwaku/issues/2262)) ([c86dc442](https://github.com/waku-org/nwaku/commit/c86dc442)) +- waku_filter_v2/common: PEER_DIAL_FAILURE ret code change: 200 -> 504 ([#2236](https://github.com/waku-org/nwaku/issues/2236)) ([6301bec0](https://github.com/waku-org/nwaku/commit/6301bec0)) +- extended Postgres code to support retention policy + refactoring ([#2244](https://github.com/waku-org/nwaku/issues/2244)) ([a1ed517f](https://github.com/waku-org/nwaku/commit/a1ed517f)) +- admin REST API to be enabled only if config is set ([#2218](https://github.com/waku-org/nwaku/issues/2218)) ([110de90f](https://github.com/waku-org/nwaku/commit/110de90f)) +- **rln:** error in api when rate limit ([#2212](https://github.com/waku-org/nwaku/issues/2212)) ([51f36099](https://github.com/waku-org/nwaku/commit/51f36099)) +- **relay:** Failing protocol tests ([#2224](https://github.com/waku-org/nwaku/issues/2224)) ([c9e869fb](https://github.com/waku-org/nwaku/commit/c9e869fb)) +- **tests:** Compilation failure fix ([#2222](https://github.com/waku-org/nwaku/issues/2222)) ([a5da1fc4](https://github.com/waku-org/nwaku/commit/a5da1fc4)) +- **rest:** properly check if rln is used ([#2205](https://github.com/waku-org/nwaku/issues/2205)) ([2cb0989a](https://github.com/waku-org/nwaku/commit/2cb0989a)) + +### Changes + +- archive - move error to trace level when insert row fails ([#2283](https://github.com/waku-org/nwaku/issues/2283)) ([574cdf55](https://github.com/waku-org/nwaku/commit/574cdf55)) +- including content topics on FilterSubscribeRequest logs ([#2295](https://github.com/waku-org/nwaku/issues/2295)) ([306c8a62](https://github.com/waku-org/nwaku/commit/306c8a62)) +- vendor bump for 0.23.0 ([#2274](https://github.com/waku-org/nwaku/issues/2274)) ([385daf16](https://github.com/waku-org/nwaku/commit/385daf16)) +- peer_manager.nim - reduce logs from debug to trace ([#2279](https://github.com/waku-org/nwaku/issues/2279)) ([0cc0c805](https://github.com/waku-org/nwaku/commit/0cc0c805)) +- Cbindings allow mounting the Store protocol from libwaku ([#2276](https://github.com/waku-org/nwaku/issues/2276)) ([28142f40](https://github.com/waku-org/nwaku/commit/28142f40)) +- Better feedback invalid content topic ([#2254](https://github.com/waku-org/nwaku/issues/2254)) ([72a1f8c7](https://github.com/waku-org/nwaku/commit/72a1f8c7)) +- fix typos ([#2239](https://github.com/waku-org/nwaku/issues/2239)) ([958b9bd7](https://github.com/waku-org/nwaku/commit/958b9bd7)) +- creating prepare_release template ([#2225](https://github.com/waku-org/nwaku/issues/2225)) ([5883dbeb](https://github.com/waku-org/nwaku/commit/5883dbeb)) +- **rest:** refactor message cache ([#2221](https://github.com/waku-org/nwaku/issues/2221)) ([bebaa59c](https://github.com/waku-org/nwaku/commit/bebaa59c)) +- updating nim-json-serialization dependency ([#2248](https://github.com/waku-org/nwaku/issues/2248)) ([9f4e6f45](https://github.com/waku-org/nwaku/commit/9f4e6f45)) +- **store-archive:** Remove duplicated code ([#2234](https://github.com/waku-org/nwaku/issues/2234)) ([38e100e9](https://github.com/waku-org/nwaku/commit/38e100e9)) +- refactoring peer storage ([#2243](https://github.com/waku-org/nwaku/issues/2243)) ([c301e880](https://github.com/waku-org/nwaku/commit/c301e880)) +- postres driver allow setting the max number of connection from a parameter ([#2246](https://github.com/waku-org/nwaku/issues/2246)) ([b31c1823](https://github.com/waku-org/nwaku/commit/b31c1823)) +- deterministic message hash algorithm updated ([#2233](https://github.com/waku-org/nwaku/issues/2233)) ([a22ee604](https://github.com/waku-org/nwaku/commit/a22ee604)) +- **REST:** returning lightpush support and updated filter protocol ([#2219](https://github.com/waku-org/nwaku/issues/2219)) ([59ee3c69](https://github.com/waku-org/nwaku/commit/59ee3c69)) +- mics. improvements to cluster id and shards setup ([#2187](https://github.com/waku-org/nwaku/issues/2187)) ([897f4879](https://github.com/waku-org/nwaku/commit/897f4879)) +- update docs for rln-keystore-generator ([#2210](https://github.com/waku-org/nwaku/issues/2210)) ([8c5666d2](https://github.com/waku-org/nwaku/commit/8c5666d2)) +- removing automatic vacuuming from retention policy code ([#2228](https://github.com/waku-org/nwaku/issues/2228)) ([9ff441ab](https://github.com/waku-org/nwaku/commit/9ff441ab)) +- decoupling announced and listen addresses ([#2203](https://github.com/waku-org/nwaku/issues/2203)) ([ef8ffbdb](https://github.com/waku-org/nwaku/commit/ef8ffbdb)) +- **release:** update changelog for v0.22.0 release ([#2216](https://github.com/waku-org/nwaku/issues/2216)) ([9c4fdac6](https://github.com/waku-org/nwaku/commit/9c4fdac6)) +- Allow text/plain content type descriptor for json formatted content body ([#2209](https://github.com/waku-org/nwaku/issues/2209)) ([6d81e384](https://github.com/waku-org/nwaku/commit/6d81e384)) +- rewrite for clarity, update screenshots ([#2206](https://github.com/waku-org/nwaku/issues/2206)) ([a0ef3c2f](https://github.com/waku-org/nwaku/commit/a0ef3c2f)) +- **release:** update changelog for v0.21.3 release ([#2208](https://github.com/waku-org/nwaku/issues/2208)) ([f74474b4](https://github.com/waku-org/nwaku/commit/f74474b4)) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | + +The Waku v1 implementation has been removed from this repository and can be found in a separate [Waku Legacy](https://github.com/waku-org/waku-legacy) repository. + +## v0.22.0 (2023-11-15) + +> Note: The `--topic` option is now deprecated in favor of a more specific options `--pubsub-topic` & `--content-topic` + +> Note: The `--ext-multiaddr-only` CLI flag was introduced for cases in which the user wants to manually set their announced addresses + +## What's Changed + +Release highlights: +* simplified the process of generating RLN credentials through the new `generateRlnKeystore` subcommand +* added support for configuration of port 0 in order to bind to kernel selected ports +* shards are now automatically updated in metadata protocol when supported shards change on runtime +* introduced `messageHash` attribute to SQLite which will later replace the `id` attribute + +### Features + +- rln-keystore-generator is now a subcommand ([#2189](https://github.com/waku-org/nwaku/issues/2189)) ([3498a846](https://github.com/waku-org/nwaku/commit/3498a846)) +- amending computeDigest func. + related test cases ([#2132](https://github.com/waku-org/nwaku/issues/2132))" ([#2180](https://github.com/waku-org/nwaku/issues/2180)) ([d7ef3ca1](https://github.com/waku-org/nwaku/commit/d7ef3ca1)) +- **discv5:** filter out peers without any listed capability ([#2186](https://github.com/waku-org/nwaku/issues/2186)) ([200a11da](https://github.com/waku-org/nwaku/commit/200a11da)) +- metadata protocol shard subscription ([#2149](https://github.com/waku-org/nwaku/issues/2149)) ([bcf8e963](https://github.com/waku-org/nwaku/commit/bcf8e963)) +- REST APIs discovery handlers ([#2109](https://github.com/waku-org/nwaku/issues/2109)) ([7ca516a5](https://github.com/waku-org/nwaku/commit/7ca516a5)) +- implementing port 0 support ([#2125](https://github.com/waku-org/nwaku/issues/2125)) ([f7b9afc2](https://github.com/waku-org/nwaku/commit/f7b9afc2)) +- messageHash attribute added in SQLite + testcase ([#2142](https://github.com/waku-org/nwaku/issues/2142))" ([#2154](https://github.com/waku-org/nwaku/issues/2154)) ([13aeebe4](https://github.com/waku-org/nwaku/commit/13aeebe4)) +- messageHash attribute added in SQLite + testcase ([#2142](https://github.com/waku-org/nwaku/issues/2142)) ([9cd8c73d](https://github.com/waku-org/nwaku/commit/9cd8c73d)) +- amending computeDigest func. + related test cases ([#2132](https://github.com/waku-org/nwaku/issues/2132)) ([1669f710](https://github.com/waku-org/nwaku/commit/1669f710)) + +### Bug Fixes + +- typo ([6dd28063](https://github.com/waku-org/nwaku/commit/6dd28063)) +- lightpush rest ([#2176](https://github.com/waku-org/nwaku/issues/2176)) ([fa467e24](https://github.com/waku-org/nwaku/commit/fa467e24)) +- **ci:** fix Docker tag for latest and release jobs ([52759faa](https://github.com/waku-org/nwaku/commit/52759faa)) +- **rest:** fix bug in rest api when sending rln message ([#2169](https://github.com/waku-org/nwaku/issues/2169)) ([250e8b98](https://github.com/waku-org/nwaku/commit/250e8b98)) +- updating v0.21.1 release date in changelog ([#2160](https://github.com/waku-org/nwaku/issues/2160)) ([3be61636](https://github.com/waku-org/nwaku/commit/3be61636)) + +### Changes + +- Optimize postgres - prepared statements in select ([#2182](https://github.com/waku-org/nwaku/issues/2182)) ([6da1aeec](https://github.com/waku-org/nwaku/commit/6da1aeec)) +- **release:** update changelog for v0.21.2 release ([#2188](https://github.com/waku-org/nwaku/issues/2188)) ([d0a93e7c](https://github.com/waku-org/nwaku/commit/d0a93e7c)) +- upgrade dependencies v0.22 ([#2185](https://github.com/waku-org/nwaku/issues/2185)) ([b9563ae0](https://github.com/waku-org/nwaku/commit/b9563ae0)) +- Optimize postgres - use of rowCallback approach ([#2171](https://github.com/waku-org/nwaku/issues/2171)) ([2b4ca4d0](https://github.com/waku-org/nwaku/commit/2b4ca4d0)) +- **networking:** lower dhigh to limit amplification factor ([#2168](https://github.com/waku-org/nwaku/issues/2168)) ([f0f69b32](https://github.com/waku-org/nwaku/commit/f0f69b32)) +- Minor Postgres optimizations ([#2166](https://github.com/waku-org/nwaku/issues/2166)) ([282c2e81](https://github.com/waku-org/nwaku/commit/282c2e81)) +- adding patch release instructions to release doc ([#2157](https://github.com/waku-org/nwaku/issues/2157)) ([cc01bb07](https://github.com/waku-org/nwaku/commit/cc01bb07)) +- **release:** update changelog for v0.21.1 release ([#2155](https://github.com/waku-org/nwaku/issues/2155)) ([b109a583](https://github.com/waku-org/nwaku/commit/b109a583)) +- adding ext-multiaddr-only CLI flag ([#2141](https://github.com/waku-org/nwaku/issues/2141)) ([944dfdaa](https://github.com/waku-org/nwaku/commit/944dfdaa)) +- bumping nim-libp2p to include WSS fix ([#2150](https://github.com/waku-org/nwaku/issues/2150)) ([817a7b2e](https://github.com/waku-org/nwaku/commit/817a7b2e)) +- **cbindings:** avoid using global var in libwaku.nim ([#2118](https://github.com/waku-org/nwaku/issues/2118)) ([1e8f5771](https://github.com/waku-org/nwaku/commit/1e8f5771)) +- adding postgres flag to manual docker job instructions ([#2139](https://github.com/waku-org/nwaku/issues/2139)) ([459331e3](https://github.com/waku-org/nwaku/commit/459331e3)) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | + +The Waku v1 implementation has been removed from this repository and can be found in a separate [Waku Legacy](https://github.com/waku-org/waku-legacy) repository. + +## Upgrade instructions + +* Note that the `--topic` CLI option is now deprecated in favor of a more specific options `--pubsub-topic` & `--content-topic`. + +## v0.21.3 (2023-11-09) + +This patch release adds the following feature: +- Adding generateRlnKeystore subcommand for RLN membership generation + +### Features + +- rln-keystore-generator is now a subcommand ([#2189](https://github.com/waku-org/nwaku/issues/2189)) ([1e919177](https://github.com/waku-org/nwaku/commit/1e919177)) + +This is a patch release that is fully backwards-compatible with release `v0.21.0`, `v0.21.1` and `v0.21.2`. + +It supports the same [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation has been removed from this repository and can be found in a separate [Waku Legacy](https://github.com/waku-org/waku-legacy) repository. + +## v0.21.2 (2023-11-07) + +This patch release addresses the following issue: +- Inability to send RLN messages through the REST API + +### Bug Fixes + +- **rest:** fix bug in rest api when sending rln message ([#2169](https://github.com/waku-org/nwaku/issues/2169)) ([33decd7a](https://github.com/waku-org/nwaku/commit/33decd7a)) + +This is a patch release that is fully backwards-compatible with release `v0.21.0` and `v0.21.1`. + +It supports the same [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation has been removed from this repository and can be found in a separate [Waku Legacy](https://github.com/waku-org/waku-legacy) repository. + +## v0.21.1 (2023-10-26) + +This patch release addresses the following issues: +- WSS connections being suddenly terminated under rare conditions +- Ability for the user to control announced multiaddresses + +### Changes + +- adding ext-multiaddr-only CLI flag ([#2141](https://github.com/waku-org/nwaku/issues/2141)) ([e2dfc2ed](https://github.com/waku-org/nwaku/commit/e2dfc2ed)) +- bumping nim-libp2p to include WSS fix ([#2150](https://github.com/waku-org/nwaku/issues/2150)) ([18b5149a](https://github.com/waku-org/nwaku/commit/18b5149a)) + +This is a patch release that is fully backwards-compatible with release `v0.21.0`. + +It supports the same [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation has been removed from this repository and can be found in a separate [Waku Legacy](https://github.com/waku-org/waku-legacy) repository. + +## v0.21.0 (2023-10-18) + +> Note: This is the last release supporting the `--topic` option. It is being deprecated in favor of a more specific options `--pubsub-topic` & `--content-topic` + +## What's Changed + +Release highlights: +* Implemented a req/resp [protocol](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) that provides information about the node's medatadata +* Added REST APIs for Filter v2 and Lightpush protocols' services +* Ported /admin endpoint to REST +* Added a size-based retention policy for the user to set a limit for SQLite storage used + +### Features + +- add new metadata protocol ([#2062](https://github.com/waku-org/nwaku/issues/2062)) ([d5c3ade5](https://github.com/waku-org/nwaku/commit/d5c3ade5)) +- /admin rest api endpoint ([#2094](https://github.com/waku-org/nwaku/issues/2094)) ([7b5c36b1](https://github.com/waku-org/nwaku/commit/7b5c36b1)) +- **coverage:** Add simple coverage ([#2067](https://github.com/waku-org/nwaku/issues/2067)) ([d864db3f](https://github.com/waku-org/nwaku/commit/d864db3f)) +- added RELAY openapi definitions ([#2081](https://github.com/waku-org/nwaku/issues/2081)) ([56dbe2a7](https://github.com/waku-org/nwaku/commit/56dbe2a7)) +- **wakucanary:** add latency measurement using ping protocol ([#2074](https://github.com/waku-org/nwaku/issues/2074)) ([6cb9a8da](https://github.com/waku-org/nwaku/commit/6cb9a8da)) +- Autosharding API for RELAY subscriptions ([#1983](https://github.com/waku-org/nwaku/issues/1983)) ([1763b1ef](https://github.com/waku-org/nwaku/commit/1763b1ef)) +- **networkmonitor:** add ping latencies, optimize reconnections ([#2068](https://github.com/waku-org/nwaku/issues/2068)) ([ed473545](https://github.com/waku-org/nwaku/commit/ed473545)) +- peer manager can filter peers by shard ([#2063](https://github.com/waku-org/nwaku/issues/2063)) ([0d9e9fbd](https://github.com/waku-org/nwaku/commit/0d9e9fbd)) +- lightpush rest api ([#2052](https://github.com/waku-org/nwaku/issues/2052)) ([02a814bd](https://github.com/waku-org/nwaku/commit/02a814bd)) +- HTTP REST API: Filter support v2 ([#1890](https://github.com/waku-org/nwaku/issues/1890)) ([dac072f8](https://github.com/waku-org/nwaku/commit/dac072f8)) + +### Bug Fixes + +- fix wrong install of filter rest api ([#2133](https://github.com/waku-org/nwaku/issues/2133)) ([5277d122](https://github.com/waku-org/nwaku/commit/5277d122)) +- consider WS extMultiAddrs before publishing host address ([#2122](https://github.com/waku-org/nwaku/issues/2122)) ([a5b1cfd0](https://github.com/waku-org/nwaku/commit/a5b1cfd0)) +- return erring response if lightpush request is invalid ([#2083](https://github.com/waku-org/nwaku/issues/2083)) ([2c5eb427](https://github.com/waku-org/nwaku/commit/2c5eb427)) +- sqlite limited delete query bug ([#2111](https://github.com/waku-org/nwaku/issues/2111)) ([06bc433a](https://github.com/waku-org/nwaku/commit/06bc433a)) +- cluster id & sharding terminology ([#2104](https://github.com/waku-org/nwaku/issues/2104)) ([a47dc9e6](https://github.com/waku-org/nwaku/commit/a47dc9e6)) +- **ci:** update the dependency list in pre-release WF ([#2088](https://github.com/waku-org/nwaku/issues/2088)) ([e85f05b0](https://github.com/waku-org/nwaku/commit/e85f05b0)) +- **ci:** fix name of discord notify method ([aaf10e08](https://github.com/waku-org/nwaku/commit/aaf10e08)) +- update wakuv2 fleet DNS discovery enrtree ([89854a96](https://github.com/waku-org/nwaku/commit/89854a96)) +- libwaku.nim: unsubscribe -> unsubscribeAll to make it build properly ([#2082](https://github.com/waku-org/nwaku/issues/2082)) ([3264a4f5](https://github.com/waku-org/nwaku/commit/3264a4f5)) +- **archive:** dburl check ([#2071](https://github.com/waku-org/nwaku/issues/2071)) ([a27d005f](https://github.com/waku-org/nwaku/commit/a27d005f)) +- filter discv5 bootstrap nodes by shards ([#2073](https://github.com/waku-org/nwaku/issues/2073)) ([d178105d](https://github.com/waku-org/nwaku/commit/d178105d)) +- **rln-relay:** segfault when no params except rln-relay are passed in ([#2047](https://github.com/waku-org/nwaku/issues/2047)) ([45fe2d3b](https://github.com/waku-org/nwaku/commit/45fe2d3b)) +- **sqlite:** Properly set user_version to 7 so that the migration procedure is not started ([#2031](https://github.com/waku-org/nwaku/issues/2031)) ([aa3e1a66](https://github.com/waku-org/nwaku/commit/aa3e1a66)) + +### Changes + +- remove js-node tests as release candidate dependencies ([#2123](https://github.com/waku-org/nwaku/issues/2123)) ([ce5fb340](https://github.com/waku-org/nwaku/commit/ce5fb340)) +- added size based retention policy ([#2098](https://github.com/waku-org/nwaku/issues/2098)) ([25d6e52e](https://github.com/waku-org/nwaku/commit/25d6e52e)) +- Clarify running instructions ([#2038](https://github.com/waku-org/nwaku/issues/2038)) ([12e8b122](https://github.com/waku-org/nwaku/commit/12e8b122)) +- **rln:** add more hardcoded memberhips to static group ([#2108](https://github.com/waku-org/nwaku/issues/2108)) ([1042cacd](https://github.com/waku-org/nwaku/commit/1042cacd)) +- Revert lightpush error handling to allow zero peer publish again succeed ([#2099](https://github.com/waku-org/nwaku/issues/2099)) ([f05528d4](https://github.com/waku-org/nwaku/commit/f05528d4)) +- adding NetConfig test suite ([#2091](https://github.com/waku-org/nwaku/issues/2091)) ([23b49ca5](https://github.com/waku-org/nwaku/commit/23b49ca5)) +- **cbindings:** Adding cpp example that integrates the 'libwaku' ([#2079](https://github.com/waku-org/nwaku/issues/2079)) ([8455b8dd](https://github.com/waku-org/nwaku/commit/8455b8dd)) +- **networkmonitor:** refactor setConnectedPeersMetrics, make it partially concurrent, add version ([#2080](https://github.com/waku-org/nwaku/issues/2080)) ([c5aa9704](https://github.com/waku-org/nwaku/commit/c5aa9704)) +- resolving DNS IP and publishing it when no extIp is provided ([#2030](https://github.com/waku-org/nwaku/issues/2030)) ([7797b2cd](https://github.com/waku-org/nwaku/commit/7797b2cd)) +- Adding -d:postgres flag when creating a Docker image for release and PRs ([#2076](https://github.com/waku-org/nwaku/issues/2076)) ([7a376f59](https://github.com/waku-org/nwaku/commit/7a376f59)) +- Moved external APIs out of node ([#2069](https://github.com/waku-org/nwaku/issues/2069)) ([3e72e830](https://github.com/waku-org/nwaku/commit/3e72e830)) +- bump nim-libp2p, nim-toml-serialization, nim-unicodedb, nim-unittest2, nim-websock, nim-zlib, & nimbus-build-system ([#2065](https://github.com/waku-org/nwaku/issues/2065)) ([dc25057a](https://github.com/waku-org/nwaku/commit/dc25057a)) +- **ci:** add js-waku as a dependency for pre-release createion ([#2022](https://github.com/waku-org/nwaku/issues/2022)) ([28b04000](https://github.com/waku-org/nwaku/commit/28b04000)) +- Updating nim-chronicles, nim-chronos, nim-presto, nimcrypto, nim-libp2p, and nim-nat-transversal ([#2043](https://github.com/waku-org/nwaku/issues/2043)) ([f617cd97](https://github.com/waku-org/nwaku/commit/f617cd97)) +- **cbindings:** Thread-safe communication between the main thread and the Waku Thread ([#1978](https://github.com/waku-org/nwaku/issues/1978)) ([72f90663](https://github.com/waku-org/nwaku/commit/72f90663)) +- **rln-relay:** logs, updated submodule, leaves_set metric ([#2024](https://github.com/waku-org/nwaku/issues/2024)) ([2e515a06](https://github.com/waku-org/nwaku/commit/2e515a06)) +- **release:** update changelog for v0.20.0 release ([#2026](https://github.com/waku-org/nwaku/issues/2026)) ([9085b1b3](https://github.com/waku-org/nwaku/commit/9085b1b3)) +- **postgres:** not loading the libpq library by default & better user feedback ([#2028](https://github.com/waku-org/nwaku/issues/2028)) ([e8602021](https://github.com/waku-org/nwaku/commit/e8602021)) +- move SubscriptionManager under waku_core ([#2025](https://github.com/waku-org/nwaku/issues/2025)) ([563b2b20](https://github.com/waku-org/nwaku/commit/563b2b20)) +- **README:** List possible WSL Issue ([#1995](https://github.com/waku-org/nwaku/issues/1995)) ([ebe715e9](https://github.com/waku-org/nwaku/commit/ebe715e9)) +- **ci:** add js-waku test to pre-release workflow ([#2017](https://github.com/waku-org/nwaku/issues/2017)) ([e8776fd6](https://github.com/waku-org/nwaku/commit/e8776fd6)) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation has been removed from this repository and can be found in a separate [Waku Legacy](https://github.com/waku-org/waku-legacy) repository. + +## Upgrade instructions + +* Note that the `--topic` CLI option is being deprecated in favor of a more specific options `--pubsub-topic` & `--content-topic`. This is the last release supporting the `--topic` option. +* The size-based retention policy has been tested with SQLite storage and is still on validation phases for Postgres + +## 2023-09-14 v0.20.0 + +> Note: IP address 0.0.0.0 is no longer advertised by a node + +> Note: Multiple CLI options have been removed in this release, please see _Upgrade instructions_ section for details. + +## What's Changed + +Release highlights: +* RLN is now part of standard release (is no longer EXPERIMENTAL feature) +* Interop tests between nwaku and js-waku are now gating PRs and releases +* Libwaku has been made more threadsafe (1 out of 3 improvements applied.) +* Added autosharding option on various protocol APIs + + + +### Features + +- **rln-relay:** removed rln from experimental 🚀 ([#2001](https://github.com/waku-org/nwaku/issues/2001)) ([645b0343](https://github.com/waku-org/nwaku/commit/645b0343)) +- Rest endoint /health for rln ([#2011](https://github.com/waku-org/nwaku/issues/2011)) ([fc6194bb](https://github.com/waku-org/nwaku/commit/fc6194bb)) +- **rln_db_inspector:** create rln_db_inspector tool ([#1999](https://github.com/waku-org/nwaku/issues/1999)) ([ec42e2c7](https://github.com/waku-org/nwaku/commit/ec42e2c7)) +- **relay:** ordered validator execution ([#1966](https://github.com/waku-org/nwaku/issues/1966)) ([debc5f19](https://github.com/waku-org/nwaku/commit/debc5f19)) +- **discv5:** topic subscriptions update discv5 filter predicate ([#1918](https://github.com/waku-org/nwaku/issues/1918)) ([4539dfc7](https://github.com/waku-org/nwaku/commit/4539dfc7)) +- topic subscriptions updates discv5 ENR ([#1875](https://github.com/waku-org/nwaku/issues/1875)) ([c369b329](https://github.com/waku-org/nwaku/commit/c369b329)) +- **rln_keystore_generator:** wired to onchain group manager ([#1931](https://github.com/waku-org/nwaku/issues/1931)) ([c9b48ea1](https://github.com/waku-org/nwaku/commit/c9b48ea1)) +- **rln:** init rln_keystore_generator ([#1925](https://github.com/waku-org/nwaku/issues/1925)) ([3d849541](https://github.com/waku-org/nwaku/commit/3d849541)) +- update various protocols to autoshard ([#1857](https://github.com/waku-org/nwaku/issues/1857)) ([cf301396](https://github.com/waku-org/nwaku/commit/cf301396)) + +### Bug Fixes + +- **rln-relay:** waku_rln_number_registered_memberships metrics appropriately handled ([#2018](https://github.com/waku-org/nwaku/issues/2018)) ([a4e78330](https://github.com/waku-org/nwaku/commit/a4e78330)) +- prevent IP 0.0.0.0 from being published and update peers with empty ENR data ([#1982](https://github.com/waku-org/nwaku/issues/1982)) ([47ae19c1](https://github.com/waku-org/nwaku/commit/47ae19c1)) +- **rln-relay:** missed roots during sync ([#2015](https://github.com/waku-org/nwaku/issues/2015)) ([21604e6b](https://github.com/waku-org/nwaku/commit/21604e6b)) +- **p2p:** fix possible connectivity issue ([#1996](https://github.com/waku-org/nwaku/issues/1996)) ([7d9d8a3f](https://github.com/waku-org/nwaku/commit/7d9d8a3f)) +- **rln-db-inspector:** use valueOr pattern ([#2012](https://github.com/waku-org/nwaku/issues/2012)) ([a8095d87](https://github.com/waku-org/nwaku/commit/a8095d87)) +- **tests:** relay tests use random port to avoid conflict ([#1998](https://github.com/waku-org/nwaku/issues/1998)) ([b991682b](https://github.com/waku-org/nwaku/commit/b991682b)) +- **ci:** incorrect use of braces ([#1987](https://github.com/waku-org/nwaku/issues/1987)) ([4ed41457](https://github.com/waku-org/nwaku/commit/4ed41457)) +- **Makefile:** invalid path to crate build ([#1981](https://github.com/waku-org/nwaku/issues/1981)) ([1a318c29](https://github.com/waku-org/nwaku/commit/1a318c29)) +- --topic should be ignore when using --pubsub-topic or --content-topic ([#1977](https://github.com/waku-org/nwaku/issues/1977)) ([037b1662](https://github.com/waku-org/nwaku/commit/037b1662)) +- **tests:** fix flaky test ([#1972](https://github.com/waku-org/nwaku/issues/1972)) ([f262397d](https://github.com/waku-org/nwaku/commit/f262397d)) +- **rln-relay:** deserialization of valid merkle roots ([#1973](https://github.com/waku-org/nwaku/issues/1973)) ([d262837e](https://github.com/waku-org/nwaku/commit/d262837e)) +- **ci:** rename tools artifact to prevent conflict ([#1971](https://github.com/waku-org/nwaku/issues/1971)) ([26c06b27](https://github.com/waku-org/nwaku/commit/26c06b27)) +- **Makefile:** rln was enabled by default ([#1964](https://github.com/waku-org/nwaku/issues/1964)) ([9b1d2904](https://github.com/waku-org/nwaku/commit/9b1d2904)) +- **rln-relay:** modify keystore credentials logic ([#1956](https://github.com/waku-org/nwaku/issues/1956)) ([e7b2b88f](https://github.com/waku-org/nwaku/commit/e7b2b88f)) +- **Makefile:** error out if rln-keystore-generator not compiled with rln flag ([#1960](https://github.com/waku-org/nwaku/issues/1960)) ([ac258550](https://github.com/waku-org/nwaku/commit/ac258550)) +- **rln-relay:** sync from deployed block number ([#1955](https://github.com/waku-org/nwaku/issues/1955)) ([bd3be219](https://github.com/waku-org/nwaku/commit/bd3be219)) +- **rln-relay:** window of acceptable roots synced to rln metadata ([#1953](https://github.com/waku-org/nwaku/issues/1953)) ([01634f57](https://github.com/waku-org/nwaku/commit/01634f57)) +- **rln-relay:** bump zerokit to v0.3.2 ([#1951](https://github.com/waku-org/nwaku/issues/1951)) ([32aa1c5b](https://github.com/waku-org/nwaku/commit/32aa1c5b)) +- **rln-relay:** flush_interval incorrectly set ([#1933](https://github.com/waku-org/nwaku/issues/1933)) ([c07d63db](https://github.com/waku-org/nwaku/commit/c07d63db)) +- **rln-relay:** RLN DB should be aware of chain and contract address ([#1932](https://github.com/waku-org/nwaku/issues/1932)) ([1ae5b5a9](https://github.com/waku-org/nwaku/commit/1ae5b5a9)) +- **rln-relay:** waitFor startup, otherwise valid proofs will be marked invalid ([#1920](https://github.com/waku-org/nwaku/issues/1920)) ([6c6302f9](https://github.com/waku-org/nwaku/commit/6c6302f9)) +- **test:** fix flaky rln test ([#1923](https://github.com/waku-org/nwaku/issues/1923)) ([0ac8a7f0](https://github.com/waku-org/nwaku/commit/0ac8a7f0)) +- **rln-relay:** remove registration capability ([#1916](https://github.com/waku-org/nwaku/issues/1916)) ([f08315cd](https://github.com/waku-org/nwaku/commit/f08315cd)) +- **rln-relay:** invalid start index being set results in invalid proofs ([#1915](https://github.com/waku-org/nwaku/issues/1915)) ([b3bb7a11](https://github.com/waku-org/nwaku/commit/b3bb7a11)) +- **rln-relay:** should error out on rln-relay mount failure ([#1904](https://github.com/waku-org/nwaku/issues/1904)) ([8c568cab](https://github.com/waku-org/nwaku/commit/8c568cab)) +- **rln-relay:** timeout on macos runners, use fixed version of ganache ([#1913](https://github.com/waku-org/nwaku/issues/1913)) ([c9772af0](https://github.com/waku-org/nwaku/commit/c9772af0)) +- no enr record in chat2 ([#1907](https://github.com/waku-org/nwaku/issues/1907)) ([fc604ca5](https://github.com/waku-org/nwaku/commit/fc604ca5)) + +### Changes + +- **ci:** add js-waku test to pre-release workflow ([#2017](https://github.com/waku-org/nwaku/issues/2017)) ([e8776fd6](https://github.com/waku-org/nwaku/commit/e8776fd6)) +- **rln-relay:** updated docs ([#1993](https://github.com/waku-org/nwaku/issues/1993)) ([76e34077](https://github.com/waku-org/nwaku/commit/76e34077)) +- **ci:** execute js-waku integration tests on image build ([#2006](https://github.com/waku-org/nwaku/issues/2006)) ([5d976df9](https://github.com/waku-org/nwaku/commit/5d976df9)) +- **rln-relay:** add isReady check ([#1989](https://github.com/waku-org/nwaku/issues/1989)) ([5638bd06](https://github.com/waku-org/nwaku/commit/5638bd06)) +- **rln-relay:** clean up nullifier table every MaxEpochGap ([#1994](https://github.com/waku-org/nwaku/issues/1994)) ([483f40c8](https://github.com/waku-org/nwaku/commit/483f40c8)) +- **ci:** use commit instead of master for docker image ([#1990](https://github.com/waku-org/nwaku/issues/1990)) ([98850192](https://github.com/waku-org/nwaku/commit/98850192)) +- **rln-relay:** log levels for certain logs ([#1986](https://github.com/waku-org/nwaku/issues/1986)) ([97a7c9d0](https://github.com/waku-org/nwaku/commit/97a7c9d0)) +- **rln-relay:** use the only key from keystore if only 1 exists ([#1984](https://github.com/waku-org/nwaku/issues/1984)) ([a14c3261](https://github.com/waku-org/nwaku/commit/a14c3261)) +- **ci:** enable experimental for the PR image builds ([#1976](https://github.com/waku-org/nwaku/issues/1976)) ([1b835b4e](https://github.com/waku-org/nwaku/commit/1b835b4e)) +- **rln-relay:** confirm that the provided credential is correct using onchain query ([#1980](https://github.com/waku-org/nwaku/issues/1980)) ([be48891f](https://github.com/waku-org/nwaku/commit/be48891f)) +- **api:** validate rln message before sending (rest + rpc) ([#1968](https://github.com/waku-org/nwaku/issues/1968)) ([05c98864](https://github.com/waku-org/nwaku/commit/05c98864)) +- **cbindings:** Thread-safe libwaku. WakuNode instance created directly from the Waku Thread ([#1957](https://github.com/waku-org/nwaku/issues/1957)) ([68e8d9a7](https://github.com/waku-org/nwaku/commit/68e8d9a7)) +- add debug log indicating succesful message pushes and also log the message hash ([#1965](https://github.com/waku-org/nwaku/issues/1965)) ([e272bec9](https://github.com/waku-org/nwaku/commit/e272bec9)) +- **rln-keystore-generator:** log out the membership index upon registration ([#1963](https://github.com/waku-org/nwaku/issues/1963)) ([7d53aec1](https://github.com/waku-org/nwaku/commit/7d53aec1)) +- **rln-relay:** integrate waku rln registry ([#1943](https://github.com/waku-org/nwaku/issues/1943)) ([cc9f8d42](https://github.com/waku-org/nwaku/commit/cc9f8d42)) +- **ci:** add a job checking config options and db schema ([#1927](https://github.com/waku-org/nwaku/issues/1927)) ([505d1967](https://github.com/waku-org/nwaku/commit/505d1967)) +- **rln_keystore_generator:** generate and persist credentials ([#1928](https://github.com/waku-org/nwaku/issues/1928)) ([07945a37](https://github.com/waku-org/nwaku/commit/07945a37)) +- **rln-relay:** rename keystore application to waku-rln-relay ([#1924](https://github.com/waku-org/nwaku/issues/1924)) ([8239b455](https://github.com/waku-org/nwaku/commit/8239b455)) +- **rln:** remove old and add new rln metric ([#1926](https://github.com/waku-org/nwaku/issues/1926)) ([56c228f8](https://github.com/waku-org/nwaku/commit/56c228f8)) +- **rln:** run rln in all relay pubsubtopics + remove cli flags ([#1917](https://github.com/waku-org/nwaku/issues/1917)) ([af95b571](https://github.com/waku-org/nwaku/commit/af95b571)) +- **release:** update changelog for delayed v0.19.0 release ([#1911](https://github.com/waku-org/nwaku/issues/1911)) ([78690787](https://github.com/waku-org/nwaku/commit/78690787)) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation has been removed from this repository and can be found in a separate [Waku Legacy](https://github.com/waku-org/waku-legacy) repository. + +## Upgrade instructions + +* Note that the `--topic` CLI option is being deprecated in favor of a more specific options `--pubsub-topic` & `--content-topic`. The `--topic` option will be available for next release with a deprecation note. +* CLI option `--store-resume-peer` has been removed. +* Following options related to RLN have been removed: + * `--rln-relay-membership-group-index` + * `--rln-relay-pubsub-topic` + * `--rln-relay-content-topic` + + +## 2023-08-16 v0.19.0 + +> Note that the `--topic` CLI option is being deprecated in favor a more specific option `--pubsub-topic`. + +> The Waku v1 implementation has been removed from this repository and can be found in a separate [Waku Legacy](https://github.com/waku-org/waku-legacy) repository. + + +## What's Changed + +Release highlights: +* Improved connection management, including management for non-relay peers and limiting the number of connections from a single IP +* Postgres support has been added as a backend for archive module +* RLN initialization optimizations +* Update to the latest nim-libp2p +* Removed Waku v1 and also references to `v2` from the current version +* Basic implementation of Autosharding for the Waku Network +* REST API implementation for Filter protocol + +### Features + +- **ci:** add docker image builds per PR ([#1881](https://github.com/waku-org/nwaku/issues/1881)) ([84f94d5d](https://github.com/waku-org/nwaku/commit/84f94d5d)) +- Rest API interface for legacy (v1) filter service. ([#1851](https://github.com/waku-org/nwaku/issues/1851)) ([08ff6672](https://github.com/waku-org/nwaku/commit/08ff6672)) +- autosharding content topics in config ([#1856](https://github.com/waku-org/nwaku/issues/1856)) ([afb93e29](https://github.com/waku-org/nwaku/commit/afb93e29)) +- autosharding core algorithm ([#1854](https://github.com/waku-org/nwaku/issues/1854)) ([bbff1ac1](https://github.com/waku-org/nwaku/commit/bbff1ac1)) +- **cbindings:** tiny waku relay example in Python ([#1793](https://github.com/waku-org/nwaku/issues/1793)) ([0b2cfae5](https://github.com/waku-org/nwaku/commit/0b2cfae5)) +- **rln-relay:** close db connection appropriately ([#1858](https://github.com/waku-org/nwaku/issues/1858)) ([76c73b62](https://github.com/waku-org/nwaku/commit/76c73b62)) +- enable TcpNoDelay ([#1470](https://github.com/waku-org/nwaku/issues/1470)) ([08f3bba3](https://github.com/waku-org/nwaku/commit/08f3bba3)) +- limit relay connections below max conns ([#1813](https://github.com/waku-org/nwaku/issues/1813)) ([17b24cde](https://github.com/waku-org/nwaku/commit/17b24cde)) +- **postgres:** integration of postgres in wakunode2 ([#1808](https://github.com/waku-org/nwaku/issues/1808)) ([88b7481f](https://github.com/waku-org/nwaku/commit/88b7481f)) +- discovery peer filtering for relay shard ([#1804](https://github.com/waku-org/nwaku/issues/1804)) ([a4da87bb](https://github.com/waku-org/nwaku/commit/a4da87bb)) +- **rln-relay:** resume onchain sync from persisted tree db ([#1805](https://github.com/waku-org/nwaku/issues/1805)) ([bbded9ee](https://github.com/waku-org/nwaku/commit/bbded9ee)) +- **rln-relay:** metadata ffi api ([#1803](https://github.com/waku-org/nwaku/issues/1803)) ([045f07c6](https://github.com/waku-org/nwaku/commit/045f07c6)) + +### Bug Fixes + +- bring back default topic in config ([#1902](https://github.com/waku-org/nwaku/issues/1902)) ([d5d2243c](https://github.com/waku-org/nwaku/commit/d5d2243c)) +- **ci:** only add comment on PR and do not duplicate it ([#1908](https://github.com/waku-org/nwaku/issues/1908)) ([b785b6ba](https://github.com/waku-org/nwaku/commit/b785b6ba)) +- **ci:** add mising OS arch option to image build ([#1905](https://github.com/waku-org/nwaku/issues/1905)) ([2575f3c4](https://github.com/waku-org/nwaku/commit/2575f3c4)) +- **wakucanary:** add missing return on timeout ([#1901](https://github.com/waku-org/nwaku/issues/1901)) ([7dce0b9e](https://github.com/waku-org/nwaku/commit/7dce0b9e)) +- fixes out of bounds crash when waku2 is not set ([#1895](https://github.com/waku-org/nwaku/issues/1895)) ([03363f1b](https://github.com/waku-org/nwaku/commit/03363f1b)) +- **wakucanary:** add enr record to builder ([#1882](https://github.com/waku-org/nwaku/issues/1882)) ([831a093f](https://github.com/waku-org/nwaku/commit/831a093f)) +- check nil before calling clearTimer ([#1869](https://github.com/waku-org/nwaku/issues/1869)) ([2fc48842](https://github.com/waku-org/nwaku/commit/2fc48842)) +- **rln-relay:** mark duplicated messages as spam ([#1867](https://github.com/waku-org/nwaku/issues/1867)) ([4756ccc1](https://github.com/waku-org/nwaku/commit/4756ccc1)) +- **ci:** do not depend on number of procesors with job name ([#1863](https://github.com/waku-org/nwaku/issues/1863)) ([c560af11](https://github.com/waku-org/nwaku/commit/c560af11)) +- **libp2p:** Updating nim-libp2p to fix the `wss` connectivity issue ([#1848](https://github.com/waku-org/nwaku/issues/1848)) ([1d3410c7](https://github.com/waku-org/nwaku/commit/1d3410c7)) +- **rln-relay:** chunk event fetching ([#1830](https://github.com/waku-org/nwaku/issues/1830)) ([e4d9ee1f](https://github.com/waku-org/nwaku/commit/e4d9ee1f)) +- **discv5:** Fixing issue that prevented the wakunode2 from starting ([#1829](https://github.com/waku-org/nwaku/issues/1829)) ([3aefade6](https://github.com/waku-org/nwaku/commit/3aefade6)) +- sanity-check the docker image start ([ae05f0a8](https://github.com/waku-org/nwaku/commit/ae05f0a8)) +- **ci:** fix broken test with wrong import ([#1820](https://github.com/waku-org/nwaku/issues/1820)) ([4573e8c5](https://github.com/waku-org/nwaku/commit/4573e8c5)) +- temporary fix to disable default experimental builds on fleets ([#1810](https://github.com/waku-org/nwaku/issues/1810)) ([e9028618](https://github.com/waku-org/nwaku/commit/e9028618)) +- **rln-relay:** tree race condition upon initialization ([#1807](https://github.com/waku-org/nwaku/issues/1807)) ([f8e270fb](https://github.com/waku-org/nwaku/commit/f8e270fb)) +- fix mac docker build alpine version ([#1801](https://github.com/waku-org/nwaku/issues/1801)) ([fce845bb](https://github.com/waku-org/nwaku/commit/fce845bb)) +- **rln-relay:** flaky static group manager test ([#1798](https://github.com/waku-org/nwaku/issues/1798)) ([0e9ecbd6](https://github.com/waku-org/nwaku/commit/0e9ecbd6)) + +### Changes + +- remove references to v2 ([#1898](https://github.com/waku-org/nwaku/issues/1898)) ([b9d5d28a](https://github.com/waku-org/nwaku/commit/b9d5d28a)) +- **submodules:** use zerokit v0.3.1 only ([#1886](https://github.com/waku-org/nwaku/issues/1886)) ([311f5ea0](https://github.com/waku-org/nwaku/commit/311f5ea0)) +- remove Waku v1 and wakubridge code ([#1874](https://github.com/waku-org/nwaku/issues/1874)) ([ab344a9d](https://github.com/waku-org/nwaku/commit/ab344a9d)) +- **cbindings:** libwaku - run waku node in a secondary working thread ([#1865](https://github.com/waku-org/nwaku/issues/1865)) ([069c1ad2](https://github.com/waku-org/nwaku/commit/069c1ad2)) +- update docs link ([#1850](https://github.com/waku-org/nwaku/issues/1850)) ([d2b6075b](https://github.com/waku-org/nwaku/commit/d2b6075b)) +- **changelog:** release notes for v0.19.0 ([#1861](https://github.com/waku-org/nwaku/issues/1861)) ([32c1276f](https://github.com/waku-org/nwaku/commit/32c1276f)) +- **rln-relay:** verify proofs based on bandwidth usage ([#1844](https://github.com/waku-org/nwaku/issues/1844)) ([3fe4522a](https://github.com/waku-org/nwaku/commit/3fe4522a)) +- **rln-relay:** bump zerokit ([#1838](https://github.com/waku-org/nwaku/issues/1838)) ([4f0bdf9a](https://github.com/waku-org/nwaku/commit/4f0bdf9a)) +- bump nim-libp2p to 224f92e ([661638da](https://github.com/waku-org/nwaku/commit/661638da)) +- **refactor:** Move record creation & fix libwaku compilation ([#1833](https://github.com/waku-org/nwaku/issues/1833)) ([97d3b9f7](https://github.com/waku-org/nwaku/commit/97d3b9f7)) +- discv5 re-org clean-up ([#1823](https://github.com/waku-org/nwaku/issues/1823)) ([cf46fb7c](https://github.com/waku-org/nwaku/commit/cf46fb7c)) +- **networking:** disconnect due to colocation ip in conn handler ([#1821](https://github.com/waku-org/nwaku/issues/1821)) ([e12c979c](https://github.com/waku-org/nwaku/commit/e12c979c)) +- **rln-relay:** bump zerokit for version fix ([#1822](https://github.com/waku-org/nwaku/issues/1822)) ([add294a9](https://github.com/waku-org/nwaku/commit/add294a9)) +- move discv5 out of node. ([#1818](https://github.com/waku-org/nwaku/issues/1818)) ([62d36530](https://github.com/waku-org/nwaku/commit/62d36530)) +- **archive:** Moving waku archive logic from app.nim to the archive module ([#1817](https://github.com/waku-org/nwaku/issues/1817)) ([52894a82](https://github.com/waku-org/nwaku/commit/52894a82)) +- add peer manager config to builder ([#1816](https://github.com/waku-org/nwaku/issues/1816)) ([71c4ac16](https://github.com/waku-org/nwaku/commit/71c4ac16)) +- discv5 re-org setup ([#1815](https://github.com/waku-org/nwaku/issues/1815)) ([44f9d8dc](https://github.com/waku-org/nwaku/commit/44f9d8dc)) +- **databases:** Creation of the databases folder to keep the logic for sqlite and postgres ([#1811](https://github.com/waku-org/nwaku/issues/1811)) ([a44d4bfb](https://github.com/waku-org/nwaku/commit/a44d4bfb)) +- **deps:** bump libp2p & websock ([#1800](https://github.com/waku-org/nwaku/issues/1800)) ([f6e89c31](https://github.com/waku-org/nwaku/commit/f6e89c31)) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation has been removed from this repository and can be found in a separate [Waku Legacy](https://github.com/waku-org/waku-legacy) repository. + +## Upgrade instructions + +* Note that the `--topic` CLI option is being deprecated in favor a more specific option `--pubsub-topic`. The `--topic` option will be available for next 2 releases with a deprecation note. + +## 2023-06-14 v0.18.0 + +> Note that there is a new naming scheme for release artifacts. + +## What's Changed + +Release highlights: +* Support for Gossipsub scoring +* [Rendezvous discovery protocol](https://docs.libp2p.io/concepts/discovery-routing/rendezvous/) enabled by default with relay +* Initial support for postgresql as Store backend +* Atomic operations for insertions and deletions included in rln-relay + +### Features + +- **postgres:** complete implementation of driver and apply more tests ([#1785](https://github.com/waku-org/nwaku/issues/1785)) ([5fc5770d](https://github.com/waku-org/nwaku/commit/5fc5770d)) +- **postgres:** adding a postgres async pool to make the db interactions asynchronous ([#1779](https://github.com/waku-org/nwaku/issues/1779)) ([cb2e3d86](https://github.com/waku-org/nwaku/commit/cb2e3d86)) +- **rln-relay:** pass in index to keystore credentials ([#1777](https://github.com/waku-org/nwaku/issues/1777)) ([a00aa8cc](https://github.com/waku-org/nwaku/commit/a00aa8cc)) +- **networking:** integrate gossipsub scoring ([#1769](https://github.com/waku-org/nwaku/issues/1769)) ([34a92631](https://github.com/waku-org/nwaku/commit/34a92631)) +- **discv5:** added find random nodes with predicate ([#1762](https://github.com/waku-org/nwaku/issues/1762)) ([#1763](https://github.com/waku-org/nwaku/issues/1763)) ([21737c7c](https://github.com/waku-org/nwaku/commit/21737c7c)) +- **wakunode2:** enable libp2p rendezvous protocol by default ([#1770](https://github.com/waku-org/nwaku/issues/1770)) ([835a409d](https://github.com/waku-org/nwaku/commit/835a409d)) +- **postgresql:** align previous work's PR[#1590](https://github.com/waku-org/nwaku/issues/1590) changes into master ([#1764](https://github.com/waku-org/nwaku/issues/1764)) ([7df6f4c8](https://github.com/waku-org/nwaku/commit/7df6f4c8)) +- **networking:** prune peers from same ip beyond collocation limit ([#1765](https://github.com/waku-org/nwaku/issues/1765)) ([047d1cf0](https://github.com/waku-org/nwaku/commit/047d1cf0)) +- **ci:** add nightly builds ([#1758](https://github.com/waku-org/nwaku/issues/1758)) ([473af70a](https://github.com/waku-org/nwaku/commit/473af70a)) +- **postgresql:** 1st commit to async sql (waku_archive/driver...) ([#1755](https://github.com/waku-org/nwaku/issues/1755)) ([59ca03a8](https://github.com/waku-org/nwaku/commit/59ca03a8)) +- **ci:** add release-notes target ([#1734](https://github.com/waku-org/nwaku/issues/1734)) ([ceb54b18](https://github.com/waku-org/nwaku/commit/ceb54b18)) +- **rln-relay:** use new atomic_operation ffi api ([#1733](https://github.com/waku-org/nwaku/issues/1733)) ([611e9539](https://github.com/waku-org/nwaku/commit/611e9539)) + +### Bug Fixes + +- **ci:** enforce basic CPU instruction set to prevent CI issues ([#1759](https://github.com/waku-org/nwaku/issues/1759)) ([35520bd0](https://github.com/waku-org/nwaku/commit/35520bd0)) +- **test:** wait more for gossip ([#1753](https://github.com/waku-org/nwaku/issues/1753)) ([0fce3d83](https://github.com/waku-org/nwaku/commit/0fce3d83)) +- **rln-relay:** keystore usage ([#1750](https://github.com/waku-org/nwaku/issues/1750)) ([36266b43](https://github.com/waku-org/nwaku/commit/36266b43)) +- **ci:** fix flaky test for dos topic ([#1747](https://github.com/waku-org/nwaku/issues/1747)) ([46e231d0](https://github.com/waku-org/nwaku/commit/46e231d0)) +- **rln-relay:** trace log ([#1743](https://github.com/waku-org/nwaku/issues/1743)) ([5eae60e8](https://github.com/waku-org/nwaku/commit/5eae60e8)) +- **ci:** make experimental default to true in fleet deployment ([#1742](https://github.com/waku-org/nwaku/issues/1742)) ([b148c305](https://github.com/waku-org/nwaku/commit/b148c305)) + +### Changes + +- **rln:** bump zerokit ([#1787](https://github.com/waku-org/nwaku/issues/1787)) ([9c04b59b](https://github.com/waku-org/nwaku/commit/9c04b59b)) +- **ci:** extend and rename nightly workflow to support RC builds ([#1784](https://github.com/waku-org/nwaku/issues/1784)) ([96074071](https://github.com/waku-org/nwaku/commit/96074071)) +- **rln-relay:** pass in the path to the tree db ([#1782](https://github.com/waku-org/nwaku/issues/1782)) ([dba84248](https://github.com/waku-org/nwaku/commit/dba84248)) +- **rln-relay:** update tree_config ([#1781](https://github.com/waku-org/nwaku/issues/1781)) ([ba8ec704](https://github.com/waku-org/nwaku/commit/ba8ec704)) +- **ci:** properly set os and architecture for nightly and release ([#1780](https://github.com/waku-org/nwaku/issues/1780)) ([44bcf0f2](https://github.com/waku-org/nwaku/commit/44bcf0f2)) +- **ci:** remove add-to-project workflow ([#1778](https://github.com/waku-org/nwaku/issues/1778)) ([a9505892](https://github.com/waku-org/nwaku/commit/a9505892)) +- **ci:** add experimental builds to nightly ([#1761](https://github.com/waku-org/nwaku/issues/1761)) ([ffac7761](https://github.com/waku-org/nwaku/commit/ffac7761)) +- **px:** close px streams after resp is sent ([#1746](https://github.com/waku-org/nwaku/issues/1746)) ([3c2d2891](https://github.com/waku-org/nwaku/commit/3c2d2891)) +- **docs:** fix docs and mark some as deprecated ([#1754](https://github.com/waku-org/nwaku/issues/1754)) ([b51fb616](https://github.com/waku-org/nwaku/commit/b51fb616)) +- **makefile:** unify where chronicles_log_level is set ([#1748](https://github.com/waku-org/nwaku/issues/1748)) ([39902dc2](https://github.com/waku-org/nwaku/commit/39902dc2)) +- **rln-relay:** docs and config update for testnet 3 ([#1738](https://github.com/waku-org/nwaku/issues/1738)) ([bb9d231b](https://github.com/waku-org/nwaku/commit/bb9d231b)) +- **rln-relay:** update metrics dashboard ([#1745](https://github.com/waku-org/nwaku/issues/1745)) ([0ced2195](https://github.com/waku-org/nwaku/commit/0ced2195)) +- **rln-relay:** updated metrics for testnet 3 ([#1744](https://github.com/waku-org/nwaku/issues/1744)) ([62578746](https://github.com/waku-org/nwaku/commit/62578746)) +- **networking:** set and use target outbound connections + prune ([#1739](https://github.com/waku-org/nwaku/issues/1739)) ([87f694a8](https://github.com/waku-org/nwaku/commit/87f694a8)) +- proper use of setupNat ([#1740](https://github.com/waku-org/nwaku/issues/1740)) ([665484c1](https://github.com/waku-org/nwaku/commit/665484c1)) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation is stable but not under active development. + +## Upgrade instructions + +There is a new naming scheme for release artifacts - `nwaku-${ARCHITECTURE}-${OS}-${VERSION}.tar.gz`. If you use any automation to download latest release, you may need to update it. + +The `--topics` config option has been deprecated to unify the configuration style. It is still available in this release but will be removed in the next one. The new option `--topic` is introduced, which can be used repeatedly to achieve the same behavior. + +## 2023-05-17 v0.17.0 + +> Note that the --topics config item has been deprecated and support will be dropped in future releases. To configure support for multiple pubsub topics, use the new --topic parameter repeatedly. + +## What's Changed + +Release highlights: +* New REST API for Waku Store protocol. +* New Filter protocol implentation. See [12/WAKU2-FILTER](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md). +* Initial C bindings support. +* Support for Heaptrack to investigate memory utilization ([tutorial](https://github.com/waku-org/nwaku/blob/master/docs/tutorial/heaptrack.md)). + +### Features + +- **cbindings:** first commit - waku relay ([#1632](https://github.com/waku-org/nwaku/issues/1632)) ([#1714](https://github.com/waku-org/nwaku/issues/1714)) ([2defbd23](https://github.com/waku-org/nwaku/commit/2defbd23)) +- example using filter and lightpush ([#1720](https://github.com/waku-org/nwaku/issues/1720)) ([8987d4a3](https://github.com/waku-org/nwaku/commit/8987d4a3)) +- configure protected topics via cli ([#1696](https://github.com/waku-org/nwaku/issues/1696)) ([16b44523](https://github.com/waku-org/nwaku/commit/16b44523)) +- **mem-analysis:** Adding Dockerfile_with_heaptrack ([#1681](https://github.com/waku-org/nwaku/issues/1681)) ([9b9172ab](https://github.com/waku-org/nwaku/commit/9b9172ab)) +- add metrics with msg size histogram ([#1697](https://github.com/waku-org/nwaku/issues/1697)) ([67e96ba8](https://github.com/waku-org/nwaku/commit/67e96ba8)) +- curate peers shared over px protocol ([#1671](https://github.com/waku-org/nwaku/issues/1671)) ([14305c61](https://github.com/waku-org/nwaku/commit/14305c61)) +- **enr:** added support for relay shards field ([96162536](https://github.com/waku-org/nwaku/commit/96162536)) +- add tools maket target and build tools in CI ([#1668](https://github.com/waku-org/nwaku/issues/1668)) ([d5979e94](https://github.com/waku-org/nwaku/commit/d5979e94)) +- integrate new filter protocol, other improvements ([#1637](https://github.com/waku-org/nwaku/issues/1637)) ([418efca2](https://github.com/waku-org/nwaku/commit/418efca2)) +- **rest-api-store:** new rest api to retrieve store waku messages ([#1611](https://github.com/waku-org/nwaku/issues/1611)) ([#1630](https://github.com/waku-org/nwaku/issues/1630)) ([b2acb54d](https://github.com/waku-org/nwaku/commit/b2acb54d)) +- **node:** added waku node builder type ([e931fa5d](https://github.com/waku-org/nwaku/commit/e931fa5d)) +- dos protected topic relay msgs based on meta field ([#1614](https://github.com/waku-org/nwaku/issues/1614)) ([c26dcb2b](https://github.com/waku-org/nwaku/commit/c26dcb2b)) +- further filter improvements ([#1617](https://github.com/waku-org/nwaku/issues/1617)) ([d920b973](https://github.com/waku-org/nwaku/commit/d920b973)) +- **common:** added extensible implementation of the enr typed record ([ac56e1dc](https://github.com/waku-org/nwaku/commit/ac56e1dc)) +- **rln-relay:** fetch release from zerokit ci, or build ([#1603](https://github.com/waku-org/nwaku/issues/1603)) ([179be681](https://github.com/waku-org/nwaku/commit/179be681)) +- **filter-v2:** new filter protocol increment - message handling and clients ([#1600](https://github.com/waku-org/nwaku/issues/1600)) ([be446b98](https://github.com/waku-org/nwaku/commit/be446b98)) + +### Fixes + +- **ci:** remove target flag from docker command ([#1725](https://github.com/waku-org/nwaku/issues/1725)) ([d822cdc5](https://github.com/waku-org/nwaku/commit/d822cdc5)) +- wakunode2 config. adding new 'topic' config parameter. ([#1727](https://github.com/waku-org/nwaku/issues/1727)) ([2ec9809c](https://github.com/waku-org/nwaku/commit/2ec9809c)) +- streams was used instead of connections ([#1722](https://github.com/waku-org/nwaku/issues/1722)) ([b9e0763e](https://github.com/waku-org/nwaku/commit/b9e0763e)) +- change filter request default behaviour to ping ([#1721](https://github.com/waku-org/nwaku/issues/1721)) ([7c39be9a](https://github.com/waku-org/nwaku/commit/7c39be9a)) +- **rln-relay:** handle invalid deletes ([#1717](https://github.com/waku-org/nwaku/issues/1717)) ([81dffee8](https://github.com/waku-org/nwaku/commit/81dffee8)) +- fix filter v2 proto fields ([#1716](https://github.com/waku-org/nwaku/issues/1716)) ([68a39c65](https://github.com/waku-org/nwaku/commit/68a39c65)) +- unstable peers in mesh ([#1710](https://github.com/waku-org/nwaku/issues/1710)) ([703c3ab5](https://github.com/waku-org/nwaku/commit/703c3ab5)) +- **networkmonitor:** break import dependency with wakunode2 app ([043feacd](https://github.com/waku-org/nwaku/commit/043feacd)) +- import nimchronos instead heartbeat ([#1695](https://github.com/waku-org/nwaku/issues/1695)) ([7d12adf6](https://github.com/waku-org/nwaku/commit/7d12adf6)) +- **rest:** change rest server result error type to string ([d5ef9331](https://github.com/waku-org/nwaku/commit/d5ef9331)) +- **rln-relay:** scope of getEvents ([#1672](https://github.com/waku-org/nwaku/issues/1672)) ([b62193e5](https://github.com/waku-org/nwaku/commit/b62193e5)) +- **logs:** fix log reporting wrong ok connected peers ([#1675](https://github.com/waku-org/nwaku/issues/1675)) ([1a885b96](https://github.com/waku-org/nwaku/commit/1a885b96)) +- move canBeConnected to PeerManager and check for potential overflow ([#1670](https://github.com/waku-org/nwaku/issues/1670)) ([d5c2770c](https://github.com/waku-org/nwaku/commit/d5c2770c)) +- wrap untracked protocol handler exceptions ([9e1432c9](https://github.com/waku-org/nwaku/commit/9e1432c9)) +- **wakunode2:** made setup nat return errors ([1cfb251b](https://github.com/waku-org/nwaku/commit/1cfb251b)) +- fixed multiple bare except warnings ([caf78249](https://github.com/waku-org/nwaku/commit/caf78249)) +- bump libp2p with traffic metrics fix ([#1642](https://github.com/waku-org/nwaku/issues/1642)) ([0ef46673](https://github.com/waku-org/nwaku/commit/0ef46673)) +- **rln-relay:** buildscript bad cp ([#1636](https://github.com/waku-org/nwaku/issues/1636)) ([bd9857c1](https://github.com/waku-org/nwaku/commit/bd9857c1)) +- **wakunode2:** fix main warnings and drop swap support ([f95147f5](https://github.com/waku-org/nwaku/commit/f95147f5)) +- **rln-relay:** on chain registration ([#1627](https://github.com/waku-org/nwaku/issues/1627)) ([b1bafda2](https://github.com/waku-org/nwaku/commit/b1bafda2)) +- connect instead of dialing relay peers ([#1622](https://github.com/waku-org/nwaku/issues/1622)) ([85f33a8e](https://github.com/waku-org/nwaku/commit/85f33a8e)) +- fix hash size greater than 32 ([#1621](https://github.com/waku-org/nwaku/issues/1621)) ([c42ac16f](https://github.com/waku-org/nwaku/commit/c42ac16f)) + +### Changes + +- **ci:** cache all of submodules/deps to speed up build time ([#1731](https://github.com/waku-org/nwaku/issues/1731)) ([4394c69d](https://github.com/waku-org/nwaku/commit/4394c69d)) +- **rln-relay:** update args to contract ([#1724](https://github.com/waku-org/nwaku/issues/1724)) ([b277ce10](https://github.com/waku-org/nwaku/commit/b277ce10)) +- **rln-relay:** use new config for ffi ([#1718](https://github.com/waku-org/nwaku/issues/1718)) ([44c54312](https://github.com/waku-org/nwaku/commit/44c54312)) +- adding new tutorial on how to handle heaptrack with nim waku ([#1719](https://github.com/waku-org/nwaku/issues/1719)) ([4b59e472](https://github.com/waku-org/nwaku/commit/4b59e472)) +- add timestamp and ephemeral for opt-in dos validator ([#1713](https://github.com/waku-org/nwaku/issues/1713)) ([3e0a693d](https://github.com/waku-org/nwaku/commit/3e0a693d)) +- add test vectors dos protection validator ([#1711](https://github.com/waku-org/nwaku/issues/1711)) ([eaa162ee](https://github.com/waku-org/nwaku/commit/eaa162ee)) +- add validator for dos protec metrics and move to app ([#1704](https://github.com/waku-org/nwaku/issues/1704)) ([3e146869](https://github.com/waku-org/nwaku/commit/3e146869)) +- use QUICK_AND_DIRTY_COMPILER flag for CI ([#1708](https://github.com/waku-org/nwaku/issues/1708)) ([21510425](https://github.com/waku-org/nwaku/commit/21510425)) +- move networkmonitor and wakucanary to apps directory ([209579b0](https://github.com/waku-org/nwaku/commit/209579b0)) +- **wakunode2:** flatten and simplify app setup ([#1705](https://github.com/waku-org/nwaku/issues/1705)) ([ce92fc1a](https://github.com/waku-org/nwaku/commit/ce92fc1a)) +- **wakunode2:** split setup logic into app module ([c8081c88](https://github.com/waku-org/nwaku/commit/c8081c88)) +- add payload bytes to trace log ([#1703](https://github.com/waku-org/nwaku/issues/1703)) ([c6d291d3](https://github.com/waku-org/nwaku/commit/c6d291d3)) +- refactor flaky test with while ([#1698](https://github.com/waku-org/nwaku/issues/1698)) ([dca0e9b2](https://github.com/waku-org/nwaku/commit/dca0e9b2)) +- **core:** move peers utils module to waku_core ([e041e043](https://github.com/waku-org/nwaku/commit/e041e043)) +- decouple test2 target from testcommon ([91baa232](https://github.com/waku-org/nwaku/commit/91baa232)) +- **core:** move utils time module to waku_core ([93b0c071](https://github.com/waku-org/nwaku/commit/93b0c071)) +- add deprecation notice to utils module. move heartbeat to common ([e8dceb2a](https://github.com/waku-org/nwaku/commit/e8dceb2a)) +- **core:** rename waku_message module to waku_core ([c9b6b230](https://github.com/waku-org/nwaku/commit/c9b6b230)) +- flatten waku v2 protocols folder ([d7b72ac7](https://github.com/waku-org/nwaku/commit/d7b72ac7)) +- fix test failing intermittently ([#1679](https://github.com/waku-org/nwaku/issues/1679)) ([8d213e85](https://github.com/waku-org/nwaku/commit/8d213e85)) +- **networking:** get relay number of connections from protocol conns/streams ([#1609](https://github.com/waku-org/nwaku/issues/1609)) ([73cbafa6](https://github.com/waku-org/nwaku/commit/73cbafa6)) +- allow to call store api endpoints without a storenode ([#1575](https://github.com/waku-org/nwaku/issues/1575)) ([#1647](https://github.com/waku-org/nwaku/issues/1647)) ([0b4a2e68](https://github.com/waku-org/nwaku/commit/0b4a2e68)) +- bump container image versions to v0.16.0 in quickstart ([#1640](https://github.com/waku-org/nwaku/issues/1640)) ([5c33d9d1](https://github.com/waku-org/nwaku/commit/5c33d9d1)) +- **node:** remove deprecated constructor and extend testlib with builder ([9dadc1f5](https://github.com/waku-org/nwaku/commit/9dadc1f5)) +- do not mount relay more than once ([#1650](https://github.com/waku-org/nwaku/issues/1650)) ([5d853b86](https://github.com/waku-org/nwaku/commit/5d853b86)) +- pointed all waku node imports to the barrel import ([e8448dfd](https://github.com/waku-org/nwaku/commit/e8448dfd)) +- **node:** added waku_node barrel import and split config module ([13942888](https://github.com/waku-org/nwaku/commit/13942888)) +- remove deprecated enr record init method ([0627b4f8](https://github.com/waku-org/nwaku/commit/0627b4f8)) +- **deps:** upgrade nim-chronos and nim-presto to latest version ([7c229ece](https://github.com/waku-org/nwaku/commit/7c229ece)) +- remove waku swap protocol ([2b5fd2a2](https://github.com/waku-org/nwaku/commit/2b5fd2a2)) +- **deps:** upgrade nim-confutils to latest version ([67fa736d](https://github.com/waku-org/nwaku/commit/67fa736d)) +- **rln-relay:** gracefully handle chain forks ([#1623](https://github.com/waku-org/nwaku/issues/1623)) ([00a3812b](https://github.com/waku-org/nwaku/commit/00a3812b)) +- bump nim-libp2p 53b060f ([#1633](https://github.com/waku-org/nwaku/issues/1633)) ([11ff93c2](https://github.com/waku-org/nwaku/commit/11ff93c2)) +- added testcommon target to makefile ([048ca45d](https://github.com/waku-org/nwaku/commit/048ca45d)) +- increase meta size to 64 bytes + tests ([#1629](https://github.com/waku-org/nwaku/issues/1629)) ([1f793756](https://github.com/waku-org/nwaku/commit/1f793756)) +- **enr:** move waku enr multiaddr to typedrecord and builder extensions ([2ffd2f80](https://github.com/waku-org/nwaku/commit/2ffd2f80)) +- **enr:** added waku2 capabilities accessor ([157724d9](https://github.com/waku-org/nwaku/commit/157724d9)) +- **rln-relay:** reduce exports ([#1615](https://github.com/waku-org/nwaku/issues/1615)) ([2f3ba3d6](https://github.com/waku-org/nwaku/commit/2f3ba3d6)) +- add dash between target and version ([#1613](https://github.com/waku-org/nwaku/issues/1613)) ([24d62791](https://github.com/waku-org/nwaku/commit/24d62791)) +- **release:** added regression checking and clarifications ([#1610](https://github.com/waku-org/nwaku/issues/1610)) ([b495dd7b](https://github.com/waku-org/nwaku/commit/b495dd7b)) + + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation is stable but not under active development. + +## Upgrade instructions + +* The `--topics` config option has been deprecated to unify the configuration style. It still available in this and will be in next release, but will be removed after that. The new option `--topic` is introduced, which can be use repeatedly to achieve the same behaviour. + +## 2023-03-15 v0.16.0 + +## What's Changed + +Release highlights: +- a fix for an issue that prevented the node from generating high-resolution (up to nanosecond) timestamps +- introduction of an application-defined `meta` attribute to the Waku Message. This can be quite valuable for network-wide deduplication, deterministic hashing, validity checking and other planned improvements to the protocol +- many optimizations in RLN implementation and its underlying dependencies + +### Features + +- Integrated a new group manager for RLN-protected relay [1496](https://github.com/waku-org/nwaku/pull/1496) +- Added application-defined meta attribute to Waku Message according to RFC [14/WAKU2-MESSAGE](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/14/message.md#message-attributes) [1581](https://github.com/waku-org/nwaku/pull/1581) +- Implemented deterministic hashing scheme for Waku Messages according to RFC [14/WAKU2-MESSAGE](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/14/message.md#deterministic-message-hashing) [1586](https://github.com/waku-org/nwaku/pull/1586) + +### Changes + +- Upgraded nim-sqlite3-abi to the latest version [1565](https://github.com/waku-org/nwaku/pull/1565) +- Better validation of protocol buffers [1563](https://github.com/waku-org/nwaku/pull/1563) +- Improved underlying Zerokit performance and FFI [1571](https://github.com/waku-org/nwaku/pull/1571) +- Node peer ID now logged with relay trace logging [1574](https://github.com/waku-org/nwaku/pull/1574) +- Continued refactoring of several protocol implementations to improve maintainability and readability +- Refactored and cleaned up peer manager [1539](https://github.com/waku-org/nwaku/pull/1539) +- Removed unused and legacy websocket submodule [1580](https://github.com/waku-org/nwaku/pull/1580) [1582](https://github.com/waku-org/nwaku/pull/1582) +- Use base64 URL-safe encoding for noise [1569](https://github.com/waku-org/nwaku/pull/1569) +- Various general improvements to RLN implementation [1585](https://github.com/waku-org/nwaku/pull/1585) [1587](https://github.com/waku-org/nwaku/pull/1587) +- Started on implementation for new and improved filter protocol [1584](https://github.com/waku-org/nwaku/pull/1584) +- Updated pubsub and content topic namespacing to reflect latest changes in RFC [23/WAKU2-TOPICS](https://github.com/vacp2p/rfc-index/blob/main/waku/informational/23/topics.md) [1589](https://github.com/waku-org/nwaku/pull/1589) +- Unified internal peer data models [1597](https://github.com/waku-org/nwaku/pull/1597) +- Improved internal implementation of Waku ENR encoding and decoding [1598](https://github.com/waku-org/nwaku/pull/1598) [1599](https://github.com/waku-org/nwaku/pull/1599) +- Underlying dependency for RLN implementation now loaded as a static library [1578](https://github.com/waku-org/nwaku/pull/1578) + +### Fixes + +- Fixed internally generated timestamps to allow higher resolution than seconds [1570](https://github.com/waku-org/nwaku/pull/1570) +- Fixed padded base64 usage for encoding and decoding payloads on the JSON RPC API [1572](https://github.com/waku-org/nwaku/pull/1572) +- Fixed incorrect relative module imports [1591](https://github.com/waku-org/nwaku/pull/1591) +- Fixed RLN relay erroneously storing messages from multiple apps [1594](https://github.com/waku-org/nwaku/pull/1594) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`18/WAKU2-SWAP`](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/18/swap.md) | `draft` | `/vac/waku/swap/2.0.0-beta1` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation is stable but not under active development. + +## 2023-02-15 v0.15.0 + +Release highlights: +- Relay connectivity is now maintained by a management loop that selects from the peerstore +- Ability to manually specify `multiaddrs` for the nwaku node to advertise +- Two important fixes related to historical message queries: + - fixed archive bug that resulted in duplicate messages in store query response + - fixed query page size limit not being respected + +### Features + +- New connectivity loop to maintain relay connectivity from peerstore [1482](https://github.com/waku-org/nwaku/pull/1482) [1462](https://github.com/waku-org/nwaku/pull/1462) +- Support for manually specifying `multiaddrs` to advertise [1509](https://github.com/waku-org/nwaku/pull/1509) [1512](https://github.com/waku-org/nwaku/pull/1512) +- Added dynamic keystore for membership credential storage and management [1466](https://github.com/waku-org/nwaku/pull/1466) + +### Changes + +- Abstracted RLN relay group management into its own API [1465](https://github.com/waku-org/nwaku/pull/1465) +- Prune peers from peerstore when exceeding capacity [1513](https://github.com/waku-org/nwaku/pull/1513) +- Removed Kilic submodule [1517](https://github.com/waku-org/nwaku/pull/1517) +- Continued refactoring of several protocol implementations to improve maintainability and readability +- Refactored and improved JSON RPC API +- Added safe default values for peer-store-capacity [1525](https://github.com/waku-org/nwaku/pull/1525) +- Improvements in regular CI test reliability and repeatability +- Improved archive query performance [1510](https://github.com/waku-org/nwaku/pull/1510) +- Added better e2e trace logging for relay messages [1526](https://github.com/waku-org/nwaku/pull/1526) +- Relay RPC API now encodes message payloads in base64 [572](https://github.com/vacp2p/rfc/pull/572) [1555](https://github.com/waku-org/nwaku/pull/1555) + +### Fixes + +- Fixed Waku archive queries returning duplicate messages due to incorrect reordering [1511](https://github.com/waku-org/nwaku/pull/1511) +- Fixed Admin RPC API crashing on returning peer with no multiaddresses [1507](https://github.com/waku-org/nwaku/pull/1507) +- Fixed page size limit not being respected in store query responses [1520](https://github.com/waku-org/nwaku/pull/1520) +- Fixed nwaku subscribing to default pubsub topic even if not configured [1548](https://github.com/waku-org/nwaku/pull/1548) +- Fixed underlying issue causing node to incorrectly report it's unreachable [1518](https://github.com/waku-org/nwaku/pull/1518) [1546](https://github.com/waku-org/nwaku/pull/1546) +- Fixed Relay RPC API not adhering to RFC [1139](https://github.com/waku-org/nwaku/issues/1139) +- Fixed message IDs in nwaku diverging from those in go-waku [1556](https://github.com/waku-org/nwaku/pull/1556) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`18/WAKU2-SWAP`](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/18/swap.md) | `draft` | `/vac/waku/swap/2.0.0-beta1` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation is stable but not under active development. + +## 2023-01-16 v0.14.0 + +Release highlights: +- An important fix for the Waku message archive returning inconsistent responses to history queries. +- Support for [AutoNAT](https://docs.libp2p.io/concepts/nat/autonat/) and [libp2p Circuit Relay](https://docs.libp2p.io/concepts/nat/circuit-relay/) that allows, among other things, for [NAT hole punching](https://docs.libp2p.io/concepts/nat/hole-punching/). +- Support for structured logging in JSON format. +- A fix for an underlying file descriptor leak that affected websocket connections. + +### Features + +- Support for [AutoNAT](https://docs.libp2p.io/concepts/nat/autonat/) +- Support for [libp2p Circuit Relay](https://docs.libp2p.io/concepts/nat/circuit-relay/) (server only) +- New Waku Archive implementation. This allows easy addition of drivers for different technologies to store historical messages. +- Support for structured logging and specifying log format. +- Node now keeps track of its external reachability. + +### Changes + +- Zerokit RLN library now statically linked. +- Use extended key generation in Zerokit API to comply with [32/RLN](https://github.com/vacp2p/rfc-index/blob/main/vac/32/rln-v1.md). +- Re-enable root validation in [`17/WAKU-RLN-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) implementation. +- [Network monitoring tool](https://github.com/status-im/nwaku/tree/2336522d7f478337237a5a4ec8c5702fb4babc7d/tools#networkmonitor) now supports DNS discovery. +- Added [dashboard](https://github.com/waku-org/nwaku/blob/3e0e1cb2398297fca761aa74f52d32fa837d556c/metrics/waku-network-monitor-dashboard.json) for network monitoring. +- Continued refactoring of several protocol implementations to improve maintainability and readability. +- Removed swap integration from store protocol. +- Peerstore now consolidated with libp2p peerstore. +- Peerstore now also tracks peer direction. +- SIGSEGV signals are now handled and logged properly. +- Waku v2 no longer imports libraries from Waku v1. +- Improved build and CI processes: + - Added support for an `EXPERIMENTAL` compiler flag. + - Simplified project Makefile. + - Split Dockerfile into production and experimental stages. + - Removed obsolete simulation libraries from build. +- Improved parallellisation (and therefore processing time) when dialing several peers simultaneously. +- Waku Archive now responds with error to historical queries containing more than 10 content topics. + +### Fixes + +- Fixed support for optional fields in several protocol rpc codecs. [#1393](https://github.com/waku-org/nwaku/pull/1393) [#1395](https://github.com/waku-org/nwaku/pull/1395) [#1396](https://github.com/waku-org/nwaku/pull/1396) +- Fixed clients with `--store=false` not installing Store Client JSON-RPC API handlers. [#1382](https://github.com/waku-org/nwaku/pull/1382) +- Fixed SQLite driver returning inconsistent responses to store queries. [#1415](https://github.com/waku-org/nwaku/pull/1415) +- Fixed peer exchange discv5 loop starting before discv5 has started. [#1407](https://github.com/waku-org/nwaku/pull/1407) +- Fixed wakubridge test timing. [#1429](https://github.com/waku-org/nwaku/pull/1429) +- Fixed bug in Noise module types equating `T_ss` incorrectly to `"se"` and not `"ss"`. [#1432](https://github.com/waku-org/nwaku/pull/1432) +- Fixed Ctrl-C quitting resulting in unreleased resources and exit failures. [#1416](https://github.com/waku-org/nwaku/pull/1416) +- Fixed CI workflows not cloning repo on startup. [#1454](https://github.com/waku-org/nwaku/pull/1454) [#1455](https://github.com/waku-org/nwaku/pull/1455) +- Fixed Admin API peer connection not returning error response if peer can't be connected. [#1476](https://github.com/waku-org/nwaku/pull/1476) +- Fixed underlying file descriptor leak. [#1483](https://github.com/waku-org/nwaku/pull/1483) + +### Docs + +- Added [instructions](https://github.com/waku-org/nwaku/blob/3e0e1cb2398297fca761aa74f52d32fa837d556c/docs/operators/quickstart.md) for running nwaku with docker compose. + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`18/WAKU2-SWAP`](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/18/swap.md) | `draft` | `/vac/waku/swap/2.0.0-beta1` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation is stable but not under active development. + +## 2022-11-15 v0.13.0 + +Release highlights: +- A [Waku canary tool](https://github.com/status-im/nwaku/tree/2336522d7f478337237a5a4ec8c5702fb4babc7d/tools#waku-canary-tool) to check if nodes are reachable and what protocols they support. +- Simplified configuration for store protocol. This [new guide](https://github.com/status-im/nwaku/blob/4e5318bfbb204bd1239c95472d7b84b6a326dd9d/docs/operators/how-to/configure-store.md) explains how to configure store from this release forward. +- Support for environment variables to configure a nwaku node. See our [configuration guide](https://github.com/status-im/nwaku/blob/384abed614050bf3aa90c901d7f5e8bc383e8b22/docs/operators/how-to/configure.md) for more. +- A Waku [network monitoring tool](https://github.com/status-im/nwaku/tree/2336522d7f478337237a5a4ec8c5702fb4babc7d/tools#networkmonitor) to report network metrics, including network size, discoverable peer capabilities and more. + +### Features + +- Added Waku canary tool to check if i) a given node is reachable and ii) it supports a set of protocols. +- Simplified [Waku store configuration](https://github.com/status-im/nwaku/blob/4e5318bfbb204bd1239c95472d7b84b6a326dd9d/docs/operators/how-to/configure-store.md). +- Decoupled Waku peer persistence configuration from message store configuration. +- Added keyfile support for secure storage of RLN credentials. +- Added configurable libp2p agent string to nwaku switch. +- Support for [configuration with environment variables](https://github.com/status-im/nwaku/blob/384abed614050bf3aa90c901d7f5e8bc383e8b22/docs/operators/how-to/configure.md). +- Added [example module](https://github.com/status-im/nwaku/tree/2336522d7f478337237a5a4ec8c5702fb4babc7d/examples/v2) to showcase basic nwaku relay usage. +- Added a nwaku [network monitoring tool](https://github.com/status-im/nwaku/tree/2336522d7f478337237a5a4ec8c5702fb4babc7d/tools#networkmonitor) to provide metrics on peers, network size and more. + +### Changes + +- Removed support for Kilic's RLN library (obsolete). +- Improved logging for [`17/WAKU-RLN-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) implementation. +- Connection to eth node for RLN now more stable, maintains state and logs failures. +- Waku apps and tools now moved to their own subdirectory. +- Continued refactoring of several protocol implementations to improve maintainability and readability. +- Periodically log metrics when running RLN spam protection. +- Added metrics dashboard for RLN spam protection. +- Github CI test workflows are now run selectively, based on the content of a PR. +- Improved reliability of CI runs and added email notifications. +- Discv5 discovery loop now triggered to fill a [34/WAKU2-PEER-EXCHANGE](https://github.com/waku-org/specs/blob/master/standards/core/peer-exchange.md) peer list cache asynchronously. +- Upgraded to Nim v1.6.6. +- Cleaned up compiler warnings on unused imports. +- Improved exception handling and annotation. +- [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) no longer enabled by default on nwaku nodes. +- Merkle tree roots for RLN membership changes now on a per-block basis to allow poorly connected peers to operate within a window of acceptable roots. + +### Fixes + +- Fixed encoding of ID commitments for RLN from Big-Endian to Little-Endian. [#1256](https://github.com/status-im/nwaku/pull/1256) +- Fixed maxEpochGap to be the maximum allowed epoch gap (RLN). [#1257](https://github.com/status-im/nwaku/pull/1257) +- Fixed store cursors being retrieved incorrectly (truncated) from DB. [#1263](https://github.com/status-im/nwaku/pull/1263) +- Fixed message indexed by store cursor being excluded from history query results. [#1263](https://github.com/status-im/nwaku/pull/1263) +- Fixed log-level configuration being ignored by the nwaku node. [#1272](https://github.com/status-im/nwaku/pull/1272) +- Fixed incorrect error message when failing to set [34/WAKU2-PEER-EXCHANGE](https://github.com/waku-org/specs/blob/master/standards/core/peer-exchange.md) peer. [#1298](https://github.com/status-im/nwaku/pull/1298) +- Fixed and replaced deprecated `TaintedString` type. [#1326](https://github.com/status-im/nwaku/pull/1326) +- Fixed and replaced unreliable regex library and usage. [#1327](https://github.com/status-im/nwaku/pull/1327) [#1328](https://github.com/status-im/nwaku/pull/1328) +- Fixed and replaced deprecated `ganache-cli` node package with `ganache` for RLN onchain tests. Added graceful daemon termination. [#1347](https://github.com/status-im/nwaku/pull/1347) + +### Docs + +- Added cross client RLN testnet [tutorial](https://github.com/status-im/nwaku/blob/44d8a2026dc31a37e181043ceb67e2822376dc03/docs/tutorial/rln-chat-cross-client.md). +- Fixed broken link to Kibana in [cluster documentation](https://github.com/status-im/nwaku/blob/5e90085242e9e4d6f3cf307e189efbf7e59da9f9/docs/contributors/cluster-logs.md). +- Added an improved [quickstart guide](https://github.com/status-im/nwaku/blob/8f5363ea8f5e95fc1104307aa0d2fc59fda13698/docs/operators/quickstart.md) for operators. +- Added a [Docker usage guide](https://github.com/status-im/nwaku/blob/8f5363ea8f5e95fc1104307aa0d2fc59fda13698/docs/operators/docker-quickstart.md#prerequisites) for operators. +- Added operator [guide on running RLN spam prevention](https://github.com/status-im/nwaku/blob/bd516788cb39132ccbf0a4dcf0880e9694beb233/docs/operators/how-to/run-with-rln.md) on nwaku nodes. +- Extended guidelines on nwaku [configuration methods](https://github.com/status-im/nwaku/blob/384abed614050bf3aa90c901d7f5e8bc383e8b22/docs/operators/how-to/configure.md) for operators. +- Added new [store configuration guide](https://github.com/status-im/nwaku/blob/4e5318bfbb204bd1239c95472d7b84b6a326dd9d/docs/operators/how-to/configure-store.md) to reflect simplified options. + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`18/WAKU2-SWAP`](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/18/swap.md) | `draft` | `/vac/waku/swap/2.0.0-beta1` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation is stable but not under active development. + +## 2022-10-06 v0.12.0 + +Release highlights: +- The performance and stability of the message `store` has improved dramatically. Query durations, even for long-term stores, have improved by more than a factor of 10. +- Support for Waku Peer Exchange - a discovery method for resource-restricted nodes. +- Messages can now be marked as "ephemeral" to prevent them from being stored. +- [Zerokit](https://github.com/vacp2p/zerokit) is now the default implementation for spam-protected `relay` with RLN. + +The full list of changes is below. + +### Features + +- Default support for [Zerokit](https://github.com/vacp2p/zerokit) version of [`17/WAKU-RLN-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) implementation. +- Added Filter REST API OpenAPI specification. +- Added POC implementation for [43/WAKU2-DEVICE-PAIRING](https://github.com/waku-org/specs/blob/master/standards/application/device-pairing.md). +- [14/WAKU2-MESSAGE](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/14/message.md) can now be marked as `ephemeral` to prevent them from being stored. +- Support for [34/WAKU2-PEER-EXCHANGE](https://github.com/waku-org/specs/blob/master/standards/core/peer-exchange.md). + +### Changes + +- [`17/WAKU-RLN-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) implementation now handles on-chain transaction errors. +- [`17/WAKU-RLN-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) implementation now validates the Merkle tree root against a window of acceptable roots. +- Added metrics for [`17/WAKU-RLN-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) implementation. +- Continued refactoring of several protocol implementations to improve maintainability and readability. +- Cleaned up nwaku imports and dependencies. +- Refactored and organised nwaku unit tests. +- Nwaku now periodically logs node metrics by default. +- Further improvements to the `store` implementation: + - Better logging and query traceability. + - More useful metrics to measure query and insertion time. + - Reworked indexing for faster inserts and queries. + - Reworked data model to use a simple, single timestamp for indexing, ordering and querying. + - Improved retention policy management with periodic execution. + - Run sqlite database vacuum at node start. + - Improved logging when migrating the database to a newer version. +- `relay` no longer auto-mounted on all nwaku nodes. +- The most complete node ENR now included in response to API requests for node `info()`. +- Updated Grafana dashboards included with nwaku. +- Github CI test execution now skipped for doc-only changes. + +### Fixes + +- Fixed nwaku unnecessary sleep when no dynamic bootstrap nodes retrieved. +- Fixed [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) not working from browser-based clients due to nwaku peer manager failing to reuse existing connection. +- Waku Message payload now correctly encoded as base64 in the Relay REST API. +- Fixed handling of bindParam(uint32) in sqlite. +- `chat2` application now correctly selects a random store node on startup. +- Fixed macos builds failing due to an unsupported dependency. +- Fixed nwaku not reconnecting to previously discovered nodes after losing connection. +- Fixed nwaku failing to start switch transports with external IP configuration. +- Fixed SIGSEGV crash when attempting to start nwaku store without `db-path` configuration. + +### Docs + +- Improved [RLN testnet tutorial](https://github.com/status-im/nwaku/blob/14abdef79677ddc828ff396ece321e05cedfca17/docs/tutorial/onchain-rln-relay-chat2.md) +- Added [tutorial](https://github.com/status-im/nwaku/blob/14abdef79677ddc828ff396ece321e05cedfca17/docs/operators/droplet-quickstart.md) on running nwaku from a DigitalOcean droplet. +- Added [guide](https://github.com/status-im/nwaku/blob/14abdef79677ddc828ff396ece321e05cedfca17/docs/operators/how-to/monitor.md) on how to monitor nwaku using Prometheus and Grafana. + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`18/WAKU2-SWAP`](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/18/swap.md) | `draft` | `/vac/waku/swap/2.0.0-beta1` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation is stable but not under active development. + +## 2022-08-15 v0.11 + +Release highlights: +- Major improvements in the performance of historical message queries to longer-term, sqlite-only message stores. +- Introduction of an HTTP REST API with basic functionality +- On-chain RLN group management. This was also integrated into an [example spam-protected chat application](https://github.com/status-im/nwaku/blob/4f93510fc9a938954dd85593f8dc4135a1c367de/docs/tutorial/onchain-rln-relay-chat2.md). + +The full list of changes is below. + +### Features + +- Support for on-chain group membership management in the [`17/WAKU-RLN-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) implementation. +- Integrated HTTP REST API for external access to some `wakunode2` functionality: + - Debug REST API exposes debug information about a `wakunode2`. + - Relay REST API allows basic pub/sub functionality according to [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md). +- [`35/WAKU2-NOISE`](https://github.com/waku-org/specs/blob/master/standards/application/noise.md) implementation now adds padding to ChaChaPoly encryptions to increase security and reduce metadata leakage. + +### Changes + +- Significantly improved the SQLite-only historical message `store` query performance. +- Refactored several protocol implementations to improve maintainability and readability. +- Major code reorganization for the [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) implementation to improve maintainability. This will also make the `store` extensible to support multiple implementations. +- Disabled compiler log colors when running in a CI environment. +- Refactored [`35/WAKU2-NOISE`](https://github.com/waku-org/specs/blob/master/standards/application/noise.md) implementation into smaller submodules. +- [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) implementation can now optionally be compiled with [Zerokit RLN](https://github.com/vacp2p/zerokit/tree/64f508363946b15ac6c52f8b59d8a739a33313ec/rln). Previously only [Kilic's RLN](https://github.com/kilic/rln/tree/7ac74183f8b69b399e3bc96c1ae8ab61c026dc43) was supported. + +### Fixes + +- Fixed wire encoding of protocol buffers to use proto3. +- Fixed Waku v1 <> Waku v2 bridge losing connection to statically configured v1 nodes. +- Fixed underlying issue causing DNS discovery to fail for records containing multiple strings. + +### Docs + +- Updated [release process](https://github.com/status-im/nwaku/blob/4f93510fc9a938954dd85593f8dc4135a1c367de/docs/contributors/release-process.md) documentation. +- Added [tutorial](https://github.com/status-im/nwaku/blob/4f93510fc9a938954dd85593f8dc4135a1c367de/docs/tutorial/onchain-rln-relay-chat2.md) on how to run a spam-protected chat2 application with on-chain group management. + + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`18/WAKU2-SWAP`](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/18/swap.md) | `draft` | `/vac/waku/swap/2.0.0-beta1` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation is stable but not under active development. + +## 2022-06-15 v0.10 + +Release highlights: +- Support for key exchange using Noise handshakes. +- Support for a SQLite-only historical message `store`. This allows for cheaper, longer-term historical message storage on disk rather than in memory. +- Several fixes for native WebSockets, including slow or hanging connections and connections dropping unexpectedly due to timeouts. +- A fix for a memory leak in nodes running a local SQLite database. + +### Features + +- Support for [`35/WAKU2-NOISE`](https://github.com/waku-org/specs/blob/master/standards/application/noise.md) handshakes as key exchange protocols. +- Support for TOML config files via `--config-file=`. +- Support for `--version` command. This prints the current tagged version (or compiled commit hash, if not on a version). +- Support for running `store` protocol from a `filter` client, storing only the filtered messages. +- Start of an HTTP REST API implementation. +- Support for a memory-efficient SQLite-only `store` configuration. + +### Changes + +- Added index on `receiverTimestamp` in the SQLite `store` to improve query performance. +- GossipSub [Peer Exchange](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#prune-backoff-and-peer-exchange) is now disabled by default. This is a more secure option. +- Progress towards dynamic group management for the [`17/WAKU-RLN-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) implementation. +- Nodes with `--keep-alive` enabled now sends more regular pings to keep connections more reliably alive. +- Disabled `swap` protocol by default. +- Reduced unnecessary and confusing logging, especially during startup. +- Added discv5 UDP port to the node's main discoverable ENR. + +### Fixes + +- The in-memory `store` now checks the validity of message timestamps before storing. +- Fixed underlying bug that caused connection leaks in the HTTP client. +- Fixed Docker image compilation to use the correct external variable for compile-time flags (`NIMFLAGS` instead of `NIM_PARAMS`). +- Fixed issue where `--dns4-domain-name` caused an unhandled exception if no external port was available. +- Avoids unnecessarily calling DB migration if a `--db-path` is set but nothing is persisted in the DB. This led to a misleading warning log. +- Fixed underlying issues that caused WebSocket connections to hang. +- Fixed underlying issue that caused WebSocket connections to time out after 10 mins. +- Fixed memory leak in nodes that implements a SQLite database. + +### Docs + +- Added [tutorial](https://github.com/status-im/nwaku/blob/16dd267bd9d25ff24c64fc5c92a20eb0d322217c/docs/operators/how-to/configure-key.md) on how to generate and configure a node key. +- Added first [guide](https://github.com/status-im/nwaku/tree/16dd267bd9d25ff24c64fc5c92a20eb0d322217c/docs/operators) for nwaku operators. + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`18/WAKU2-SWAP`](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/18/swap.md) | `draft` | `/vac/waku/swap/2.0.0-beta1` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation is stable but not under active development. + +## 2022-03-31 v0.9 + +Release highlights: + +- Support for Peer Exchange (PX) when a peer prunes a [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) mesh due to oversubscription. This can significantly increase mesh stability. +- Improved start-up times through managing the size of the underlying persistent message storage. +- New websocket connections are no longer blocked due to parsing failures in other connections. + +The full list of changes is below. + +### Features + +- Support for bootstrapping [`33/WAKU-DISCV5`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/33/discv5.md) via [DNS discovery](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/10/waku2.md#discovery-methods) +- Support for GossipSub [Peer Exchange](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#prune-backoff-and-peer-exchange) + +### Changes + +- Waku v1 <> v2 bridge now supports DNS `multiaddrs` +- Waku v1 <> v2 bridge now validates content topics before attempting to bridge a message from Waku v2 to Waku v1 +- Persistent message storage now auto deletes messages once over specified `--store-capacity`. This can significantly improve node start-up times. +- Renamed Waku v1 <> v2 bridge `make` target and binary to `wakubridge` +- Increased `store` logging to assist with debugging +- Increased `rln-relay` logging to assist with debugging +- Message metrics no longer include the content topic as a dimension to keep Prometheus metric cardinality under control +- Waku v2 `toy-chat` application now sets the sender timestamp when creating messages +- The type of the `proof` field of the `WakuMessage` is changed to `RateLimitProof` +- Added method to the JSON-RPC API that returns the git tag and commit hash of the binary +- The node's ENR is now included in the JSON-RPC API response when requesting node info + +### Fixes + +- Fixed incorrect conversion of seconds to nanosecond timestamps +- Fixed store queries blocking due to failure in resource clean up +- Fixed underlying issue where new websocket connections are blocked due to parsing failures in other connections +- Fixed failure to log the ENR necessary for a discv5 connection to the node + +### Docs + +- Added [RAM requirements](https://github.com/status-im/nim-waku/tree/ee96705c7fbe4063b780ac43b7edee2f6c4e351b/waku/v2#wakunode) to `wakunode2` build instructions +- Added [tutorial](https://github.com/status-im/nim-waku/blob/ee96705c7fbe4063b780ac43b7edee2f6c4e351b/docs/tutorial/rln-chat2-live-testnet.md) on communicating with waku2 test fleets via the chat2 `toy-chat` application in spam-protected mode using [`17/WAKU-RLN-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md). +- Added a [section on bug reporting](https://github.com/status-im/nim-waku/blob/ee96705c7fbe4063b780ac43b7edee2f6c4e351b/README.md#bugs-questions--features) to `wakunode2` README +- Fixed broken links in the [JSON-RPC API Tutorial](https://github.com/status-im/nim-waku/blob/5ceef37e15a15c52cbc589f0b366018e81a958ef/docs/tutorial/jsonrpc-api.md) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`18/WAKU2-SWAP`](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/18/swap.md) | `draft` | `/vac/waku/swap/2.0.0-beta1` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation is stable but not under active development. + +## 2022-03-03 v0.8 + +Release highlights: + +- Working demonstration and integration of [`17/WAKU-RLN-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) in the Waku v2 `toy-chat` application +- Beta support for ambient peer discovery using [a version of Discovery v5](https://github.com/vacp2p/rfc/pull/487) +- A fix for the issue that caused a `store` node to run out of memory after serving a number of historical queries +- Ability to configure a `dns4` domain name for a node and resolve other dns-based `multiaddrs` + +The full list of changes is below. + +### Features + +- [`17/WAKU-RLN-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) implementation now supports spam-protection for a specific combination of `pubsubTopic` and `contentTopic` (available under the `rln` compiler flag). +- [`17/WAKU-RLN-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) integrated into chat2 `toy-chat` (available under the `rln` compiler flag) +- Added support for resolving dns-based `multiaddrs` +- A Waku v2 node can now be configured with a domain name and `dns4` `multiaddr` +- Support for ambient peer discovery using [`33/WAKU-DISCV5`](https://github.com/vacp2p/rfc/pull/487) + +### Changes + +- Metrics: now monitoring content topics and the sources of new connections +- Metrics: improved default fleet monitoring dashboard +- Introduced a `Timestamp` type (currently an alias for int64). +- All timestamps changed to nanosecond resolution. +- `timestamp` field number in WakuMessage object changed from `4` to `10` +- [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) identifier updated to `/vac/waku/store/2.0.0-beta4` +- `toy-chat` application now uses DNS discovery to connect to existing fleets + +### Fixes + +- Fixed underlying bug that caused occasional failures when reading the certificate for secure websockets +- Fixed `store` memory usage issues when responding to history queries + +### Docs + +- Documented [use of domain certificates](https://github.com/status-im/nim-waku/tree/2972a5003568848164033da3fe0d7f52a3d54824/waku/v2#enabling-websocket) for secure websockets +- Documented [how to configure a `dns4` domain name](https://github.com/status-im/nim-waku/tree/2972a5003568848164033da3fe0d7f52a3d54824/waku/v2#using-dns-discovery-to-connect-to-existing-nodes) for a node +- Clarified [use of DNS discovery](https://github.com/status-im/nim-waku/tree/2972a5003568848164033da3fe0d7f52a3d54824/waku/v2#using-dns-discovery-to-connect-to-existing-nodes) and provided current URLs for discoverable fleet nodes +- Added [tutorial](https://github.com/status-im/nim-waku/blob/2972a5003568848164033da3fe0d7f52a3d54824/docs/tutorial/rln-chat2-local-test.md) on using [`17/WAKU-RLN-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) with the chat2 `toy-chat` application +- Added [tutorial](https://github.com/status-im/nim-waku/blob/2972a5003568848164033da3fe0d7f52a3d54824/docs/tutorial/bridge.md) on how to configure and a use a [`15/WAKU-BRIDGE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/15/bridge.md) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`18/WAKU2-SWAP`](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/18/swap.md) | `draft` | `/vac/waku/swap/2.0.0-beta1` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation is stable but not under active development. + +## 2022-01-19 v0.7 + +Release highlights: + +- Support for secure websockets. +- Ability to remove unreachable clients in a `filter` node. +- Several fixes to improve `store` performance and decrease query times. Query time for large stores decreased from longer than 8 min to under 100 ms. +- Fix for a long-standing bug that prevented proper database migration in some deployed Docker containers. + +The full list of changes is below. + +### Features + +- Support for secure websocket transport + +### Changes + +- Filter nodes can now remove unreachable clients +- The WakuInfo `listenStr` is deprecated and replaced with a sequence of `listenAddresses` to accommodate multiple transports +- Removed cached `peerInfo` on local node. Rely on underlying libp2p switch instead +- Metrics: added counters for protocol messages +- Waku v2 node discovery now supports [`31/WAKU2-ENR`](https://github.com/waku-org/specs/blob/master/standards/core/enr.md) +- resuming the history via `resume` now takes the answers of all peers in `peerList` into consideration and consolidates them into one deduplicated list + +### Fixes + +- Fixed database migration failure in the Docker image +- All `HistoryResponse` messages are now auto-paginated to a maximum of 100 messages per response +- Increased maximum length for reading from a libp2p input stream to allow largest possible protocol messages, including `HistoryResponse` messages at max size +- Significantly improved `store` node query performance +- Implemented a GossipSub `MessageIdProvider` for `11/WAKU2-RELAY` messages instead of relying on the unstable default +- Receiver timestamps for message indexing in the `store` now have consistent millisecond resolution + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`17/WAKU-RLN-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) | `raw` | `/vac/waku/waku-rln-relay/2.0.0-alpha1` | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta3` | +| [`18/WAKU2-SWAP`](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/18/swap.md) | `draft` | `/vac/waku/swap/2.0.0-beta1` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation is stable but not under active development. + +## 2021-11-05 v0.6 + +Some useful features and fixes in this release, include: +- two methods for Waku v2 node discovery +- support for unsecure websockets, which paves the way for native browser usage +- a fix for `nim-waku` store nodes running out of memory due to store size: the number of stored messages can now easily be configured +- a fix for densely connected nodes refusing new connections: the maximum number of allowed connections can now easily be configured +- support for larger message sizes (up from 64kb to 1Mb per message) + +The full list of changes is below. + +### Features + +- Waku v2 node discovery via DNS following [EIP-1459](https://eips.ethereum.org/EIPS/eip-1459) +- Waku v2 node discovery via [Node Discovery v5](https://github.com/ethereum/devp2p/blob/master/discv5/discv5-theory.md) + +### Changes + +- Pagination of historical queries are now simplified +- GossipSub [prune backoff period](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#prune-backoff-and-peer-exchange) is now the recommended 1 minute +- Bridge now uses content topic format according to [23/WAKU2-TOPICS](https://github.com/vacp2p/rfc-index/blob/main/waku/informational/23/topics.md) +- Better internal differentiation between local and remote peer info +- Maximum number of libp2p connections is now configurable +- `udp-port` CLI option has been removed for binaries where it's not used +- Waku v2 now supports unsecure WebSockets +- Waku v2 now supports larger message sizes of up to 1 Mb by default +- Further experimental development of [RLN for spam protection](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md). +These changes are disabled by default under a compiler flag. Changes include: + - Per-message rate limit proof defined + - RLN proof generation and verification integrated into Waku v2 + - RLN tree depth changed from 32 to 20 + - Support added for static membership group formation + +#### Docs + +- Added [contributor guidelines](https://github.com/status-im/nim-waku/blob/master/docs/contributors/waku-fleets.md) on Waku v2 fleet monitoring and management +- Added [basic tutorial](https://github.com/status-im/nim-waku/blob/master/docs/tutorial/dns-disc.md) on using Waku v2 DNS-based discovery + +### Fixes + +- Bridge between `toy-chat` and matterbridge now shows correct announced addresses +- Bridge no longer re-encodes already encoded payloads when publishing to V1 +- Bridge now populates WakuMessage timestamps when publishing to V2 +- Store now has a configurable maximum number of stored messages +- Network simulations for Waku v1 and Waku v2 are runnable again + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`17/WAKU-RLN`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) | `raw` | `/vac/waku/waku-rln-relay/2.0.0-alpha1` | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta3` | +| [`18/WAKU2-SWAP`](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/18/swap.md) | `draft` | `/vac/waku/swap/2.0.0-beta1` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation is stable but not under active development. + +## 2021-07-26 v0.5.1 + +This patch release contains the following fix: +- Support for multiple protocol IDs when reconnecting to previously connected peers: +A bug in `v0.5` caused clients using persistent peer storage to only support the mounted protocol ID. + +This is a patch release that is fully backwards-compatible with release `v0.5`. +It supports the same [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`17/WAKU-RLN`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) | `raw` | `/vac/waku/waku-rln-relay/2.0.0-alpha1` | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta3` | +| [`18/WAKU2-SWAP`](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/18/swap.md) | `draft` | `/vac/waku/swap/2.0.0-beta1` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation is stable but not under active development. + +## 2021-07-23 v0.5 + +This release contains the following: + +### Features +- Support for keep-alives using [libp2p ping protocol](https://docs.libp2p.io/concepts/protocols/#ping). +- DB migration for the message and peer stores. +- Support for multiple protocol IDs. Mounted protocols now match versions of the same protocol that adds a postfix to the stable protocol ID. + +### Changes +- Bridge topics are now configurable. +- The `resume` Nim API now eliminates duplicates messages before storing them. +- The `resume` Nim API now fetches historical messages in page sequence. +- Added support for stable version of `relay` protocol, with protocol ID `/vac/waku/relay/2.0.0`. +- Added optional `timestamp` to `WakuRelayMessage`. +- Removed `PCRE` as a prerequisite for building Waku v1 and Waku v2. +- Improved [`swap`](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/18/swap.md) metrics. + +#### General refactoring +- Refactored modules according to [Nim best practices](https://hackmd.io/1imOGULZRsed2HpgmzGleA). +- Simplified the [way protocols get notified](https://github.com/status-im/nim-waku/issues/574) of new messages. +- Refactored `wakunode2` setup into 6 distinct phases with improved logging and error handling. +- Moved `Whisper` types and protocol from the `nim-eth` module to `nim-waku`. + +#### Docs +- Added [database migration tutorial](https://github.com/status-im/nim-waku/blob/master/docs/tutorial/db-migration.md). +- Added [tutorial to setup `websockify`](https://github.com/status-im/nim-waku/blob/master/docs/tutorial/websocket.md). + +#### Schema +- Updated the `Message` table of the persistent message store: + - Added `senderTimestamp` column. + - Renamed the `timestamp` column to `receiverTimestamp` and changes its type to `REAL`. + +#### API +- Added optional `timestamp` to [`WakuRelayMessage`](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/16/rpc.md) on JSON-RPC API. + +### Fixes +- Conversion between topics for the Waku v1 <-> v2 bridge now follows the [RFC recommendation](https://github.com/vacp2p/rfc-index/blob/main/waku/informational/23/topics.md). +- Fixed field order of `HistoryResponse` protobuf message: the field numbers of the `HistoryResponse` are shifted up by one to match up the [13/WAKU2-STORE](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) specs. + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`17/WAKU-RLN`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) | `raw` | `/vac/waku/waku-rln-relay/2.0.0-alpha1` | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta3` | +| [`18/WAKU2-SWAP`](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/18/swap.md) | `draft` | `/vac/waku/swap/2.0.0-beta1` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation is stable but not under active development. + +## 2021-06-03 v0.4 + +This release contains the following: + +### Features + +- Initial [`toy-chat` implementation](https://github.com/vacp2p/rfc-index/blob/main/waku/informational/22/toy-chat.md) + +### Changes + +- The [toy-chat application](https://github.com/status-im/nim-waku/blob/master/docs/tutorial/chat2.md) can now perform `lightpush` and request content-filtered messages from remote peers. +- The [toy-chat application](https://github.com/status-im/nim-waku/blob/master/docs/tutorial/chat2.md) now uses default content topic `/toy-chat/2/huilong/proto` +- Improve `toy-chat` [briding to matterbridge]((https://github.com/status-im/nim-waku/blob/master/docs/tutorial/chat2.md#bridge-messages-between-chat2-and-matterbridge)) +- Improve [`swap`](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/18/swap.md) logging and enable soft mode by default +- Content topics are no longer in a redundant nested structure +- Improve error handling + +#### API + +- [JSON-RPC Store API](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/16/rpc.md): Added an optional time-based query to filter historical messages. +- [Nim API](https://github.com/status-im/nim-waku/blob/master/docs/api/v2/node.md): Added `resume` method. + +### Fixes + +- Connections between nodes no longer become unstable due to keep-alive errors if mesh grows large +- Re-enable `lightpush` tests and fix Windows CI failure + +The [Waku v2 suite of protocols](https://github.com/waku-org/specs) are still in a raw/draft state. +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`17/WAKU-RLN`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) | `raw` | `/vac/waku/waku-rln-relay/2.0.0-alpha1` | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `draft` | `/vac/waku/relay/2.0.0-beta2` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta3` | +| [`18/WAKU2-SWAP`](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/18/swap.md) | `draft` | `/vac/waku/swap/2.0.0-beta1` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | + +The Waku v1 implementation is stable but not under active development. + +## 2021-05-11 v0.3 + +This release contains the following: + +### Features + +- Start of [`RLN relay` implementation](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) +- Start of [`swap` implementation](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/18/swap.md) +- Start of [fault-tolerant `store` implementation](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/application/21/fault-tolerant-store.md) +- Initial [`bridge` implementation](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/15/bridge.md) between Waku v1 and v2 protocols +- Initial [`lightpush` implementation](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) +- A peer manager for `relay`, `filter`, `store` and `swap` peers +- Persistent storage for peers: A node with this feature enabled will now attempt to reconnect to `relay` peers after a restart. It will respect the gossipsub [PRUNE backoff](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#prune-backoff-and-peer-exchange) period before attempting to do so. +- `--persist-peers` CLI option to persist peers in local storage +- `--persist-messages` CLI option to store historical messages locally +- `--keep-alive` CLI option to maintain a stable connection to `relay` peers on idle topics +- A CLI chat application ([`chat2`](https://github.com/status-im/nim-waku/blob/master/docs/tutorial/chat2.md)) over Waku v2 with [bridging to matterbridge](https://github.com/status-im/nim-waku/blob/master/docs/tutorial/chat2.md#bridge-messages-between-chat2-and-matterbridge) + +### Changes +- Enable `swap` protocol by default and improve logging +#### General refactoring + +- Split out `waku_types` types into the right place; create `utils` folder. +- Change type of `contentTopic` in [`ContentFilter`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md#protobuf) to `string`. +- Replace sequence of `contentTopics` in [`ContentFilter`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md#protobuf) with a single `contentTopic`. +- Add `timestamp` field to [`WakuMessage`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/14/message.md#payloads). +- Ensure CLI config parameters use a consistent naming scheme. Summary of changes [here](https://github.com/status-im/nim-waku/pull/543). + +#### Docs + +Several clarifications and additions aimed at contributors, including + - information on [how to query Status test fleet](https://github.com/status-im/nim-waku/blob/master/docs/faq.md) for node addresses, + - [how to view logs](https://github.com/status-im/nim-waku/blob/master/docs/contributors/cluster-logs.md), and + - [how to update submodules](https://github.com/status-im/nim-waku/blob/master/docs/contributors/git-submodules.md). + +#### Schema + +- Add `Message` table to the persistent message store. This table replaces the old `messages` table. It has two additional columns, namely + - `pubsubTopic`, and + - `version`. +- Add `Peer` table for persistent peer storage. + +#### API + +- [JSON-RPC Admin API](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/16/rpc.md): Added a [`post` method](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/16/rpc.md#post_waku_v2_admin_v1_peers) to connect to peers on an ad-hoc basis. +- [Nim API](https://github.com/status-im/nim-waku/blob/master/docs/api/v2/node.md): PubSub topic `subscribe` and `unsubscribe` no longer returns a future (removed `async` designation). +- [`HistoryQuery`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md#historyquery): Added `pubsubTopic` field. Message history can now be filtered and queried based on the `pubsubTopic`. +- [`HistoryQuery`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md#historyquery): Added support for querying a time window by specifying start and end times. + +### Fixes + +- Running nodes can now be shut down gracefully +- Content filtering now works on any PubSub topic and not just the `waku` default. +- Nodes can now mount protocols without supporting `relay` as a capability + +The [Waku v2 suite of protocols](https://github.com/waku-org/specs) are still in a raw/draft state. +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`17/WAKU-RLN`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md) | `raw` | `/vac/waku/waku-rln-relay/2.0.0-alpha1` | +| [`18/WAKU2-SWAP`](https://github.com/vacp2p/rfc-index/blob/main/waku/deprecated/18/swap.md) | `raw` | `/vac/waku/swap/2.0.0-alpha1` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `raw` | `/vac/waku/lightpush/2.0.0-alpha1` | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `draft` | `/vac/waku/relay/2.0.0-beta2` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta3` | + +The Waku v1 implementation is stable but not under active development. + +## 2021-01-05 v0.2 + +This release contains the following changes: + +- Calls to `publish` a message on `wakunode2` now `await` instead of `discard` dispatched [`WakuRelay`](https://github.com/vacp2p/specs/blob/master/specs/waku/v2/waku-relay.md) procedures. +- [`StrictNoSign`](https://github.com/libp2p/specs/tree/master/pubsub#message-signing) enabled. +- Add JSON-RPC API for external access to `wakunode2` functionality: + - Admin API retrieves information about peers registered on the `wakunode2`. + - Debug API exposes debug information about a `wakunode2`. + - Filter API saves bandwidth by allowing light nodes to filter for specific content. + - Private API enables symmetric or asymmetric cryptography to encrypt/decrypt message payloads. + - Relay API allows basic pub/sub functionality. + - Store API retrieves historical messages. +- Add tutorial on how to use JSON-RPC API. +- Refactor: Move `waku_filter` protocol into its own module. + +The Waku v2 implementation, and [most protocols it consist of](https://specs.vac.dev/specs/waku/), +are still in a draft/beta state. The Waku v1 implementation is stable but not under active development. + +## 2020-11-30 v0.1 + +Initial beta release. + +This release contains: + +- A Nim implementation of the [Waku v1 protocol](https://specs.vac.dev/waku/waku.html). +- A Nim implementation of the [Waku v2 protocol](https://specs.vac.dev/specs/waku/v2/waku-v2.html). +- CLI applications `wakunode` and `wakunode2` that allows you to run a Waku v1 or v2 node. +- Examples of Waku v1 and v2 usage. +- Various tests of above. + +Currenty the Waku v2 implementation, and [most protocols it consist of](https://specs.vac.dev/specs/waku/), +are in a draft/beta state. The Waku v1 implementation is stable but not under active development. + +Feedback welcome! diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6afb2bc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,93 @@ +# BUILD NIM APP ---------------------------------------------------------------- +FROM rust:1.81.0-alpine3.19 AS nim-build + +ARG NIMFLAGS +ARG MAKE_TARGET=wakunode2 +ARG NIM_COMMIT +ARG LOG_LEVEL=TRACE +ARG HEAPTRACK_BUILD=0 + +# Get build tools and required header files +RUN apk add --no-cache bash git build-base openssl-dev linux-headers curl jq + +WORKDIR /app +COPY . . + +# workaround for alpine issue: https://github.com/alpinelinux/docker-alpine/issues/383 +RUN apk update && apk upgrade + +# Ran separately from 'make' to avoid re-doing +RUN git submodule update --init --recursive + +RUN if [ "$HEAPTRACK_BUILD" = "1" ]; then \ + git apply --directory=vendor/nimbus-build-system/vendor/Nim docs/tutorial/nim.2.2.4_heaptracker_addon.patch; \ + fi + +# Slowest build step for the sake of caching layers +RUN make -j$(nproc) deps QUICK_AND_DIRTY_COMPILER=1 ${NIM_COMMIT} + +# Build the final node binary +RUN make -j$(nproc) ${NIM_COMMIT} $MAKE_TARGET LOG_LEVEL=${LOG_LEVEL} NIMFLAGS="${NIMFLAGS}" + + +# PRODUCTION IMAGE ------------------------------------------------------------- + +FROM alpine:3.18 AS prod + +ARG MAKE_TARGET=wakunode2 + +LABEL maintainer="jakub@status.im" +LABEL source="https://github.com/waku-org/nwaku" +LABEL description="Wakunode: Waku client" +LABEL commit="unknown" +LABEL version="unknown" + +# DevP2P, LibP2P, and JSON RPC ports +EXPOSE 30303 60000 8545 + +# Referenced in the binary +RUN apk add --no-cache libgcc libpq-dev bind-tools + +# Copy to separate location to accomodate different MAKE_TARGET values +COPY --from=nim-build /app/build/$MAKE_TARGET /usr/local/bin/ + +# Copy migration scripts for DB upgrades +COPY --from=nim-build /app/migrations/ /app/migrations/ + +# Symlink the correct wakunode binary +RUN ln -sv /usr/local/bin/$MAKE_TARGET /usr/bin/wakunode + +ENTRYPOINT ["/usr/bin/wakunode"] + +# By default just show help if called without arguments +CMD ["--help"] + + +# DEBUG IMAGE ------------------------------------------------------------------ + +# Build debug tools: heaptrack +FROM alpine:3.18 AS heaptrack-build + +RUN apk update +RUN apk add -- gdb git g++ make cmake zlib-dev boost-dev libunwind-dev +RUN git clone https://github.com/KDE/heaptrack.git /heaptrack + +WORKDIR /heaptrack/build +# going to a commit that builds properly. We will revisit this for new releases +RUN git reset --hard f9cc35ebbdde92a292fe3870fe011ad2874da0ca +RUN cmake -DCMAKE_BUILD_TYPE=Release .. +RUN make -j$(nproc) + + +# Debug image +FROM prod AS debug-with-heaptrack + +RUN apk add --no-cache gdb libunwind + +# Add heaptrack +COPY --from=heaptrack-build /heaptrack/build/ /heaptrack/build/ + +ENV LD_LIBRARY_PATH=/heaptrack/build/lib/heaptrack/ +RUN ln -s /heaptrack/build/bin/heaptrack /usr/local/bin/heaptrack + +ENTRYPOINT ["/heaptrack/build/bin/heaptrack", "/usr/bin/wakunode"] diff --git a/Dockerfile.lightpushWithMix.compile b/Dockerfile.lightpushWithMix.compile new file mode 100644 index 0000000..e39b88d --- /dev/null +++ b/Dockerfile.lightpushWithMix.compile @@ -0,0 +1,58 @@ +# BUILD NIM APP ---------------------------------------------------------------- +FROM rust:1.81.0-alpine3.19 AS nim-build + +ARG NIMFLAGS +ARG MAKE_TARGET=lightpushwithmix +ARG NIM_COMMIT +ARG LOG_LEVEL=TRACE + +# Get build tools and required header files +RUN apk add --no-cache bash git build-base openssl-dev pcre-dev linux-headers curl jq + +WORKDIR /app +COPY . . + +# workaround for alpine issue: https://github.com/alpinelinux/docker-alpine/issues/383 +RUN apk update && apk upgrade + +# Ran separately from 'make' to avoid re-doing +RUN git submodule update --init --recursive + +# Slowest build step for the sake of caching layers +RUN make -j$(nproc) deps QUICK_AND_DIRTY_COMPILER=1 ${NIM_COMMIT} + +# Build the final node binary +RUN make -j$(nproc) ${NIM_COMMIT} $MAKE_TARGET LOG_LEVEL=${LOG_LEVEL} NIMFLAGS="${NIMFLAGS}" + + +# REFERENCE IMAGE as BASE for specialized PRODUCTION IMAGES---------------------------------------- +FROM alpine:3.18 AS base_lpt + +ARG MAKE_TARGET=lightpushwithmix + +LABEL maintainer="prem@waku.org" +LABEL source="https://github.com/waku-org/nwaku" +LABEL description="Lite Push With Mix: Waku light-client" +LABEL commit="unknown" +LABEL version="unknown" + +# DevP2P, LibP2P, and JSON RPC ports +EXPOSE 30303 60000 8545 + +# Referenced in the binary +RUN apk add --no-cache libgcc pcre-dev libpq-dev \ + wget \ + iproute2 \ + python3 \ + jq + +# Fix for 'Error loading shared library libpcre.so.3: No such file or directory' +RUN ln -s /usr/lib/libpcre.so /usr/lib/libpcre.so.3 + +COPY --from=nim-build /app/build/lightpush_publisher_mix /usr/bin/ +RUN chmod +x /usr/bin/lightpush_publisher_mix + +# Standalone image to be used manually and in lpt-runner ------------------------------------------- +FROM base_lpt AS standalone_lpt + +ENTRYPOINT ["/usr/bin/lightpush_publisher_mix"] diff --git a/LICENSE-APACHEv2 b/LICENSE-APACHEv2 new file mode 100644 index 0000000..7b6a3cb --- /dev/null +++ b/LICENSE-APACHEv2 @@ -0,0 +1,205 @@ +nim-waku is licensed under the Apache License version 2 +Copyright (c) 2018 Status Research & Development GmbH +----------------------------------------------------- + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018 Status Research & Development GmbH + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..aab8020 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,25 @@ +nim-waku is licensed under the MIT License +Copyright (c) 2018 Status Research & Development GmbH +----------------------------------------------------- + +The MIT License (MIT) + +Copyright (c) 2018 Status Research & Development GmbH + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d5cf088 --- /dev/null +++ b/Makefile @@ -0,0 +1,546 @@ +# Copyright (c) 2022 Status Research & Development GmbH. Licensed under +# either of: +# - Apache License, version 2.0 +# - MIT license +# at your option. This file may not be copied, modified, or distributed except +# according to those terms. +export BUILD_SYSTEM_DIR := vendor/nimbus-build-system +export EXCLUDED_NIM_PACKAGES := vendor/nim-dnsdisc/vendor +LINK_PCRE := 0 +FORMAT_MSG := "\\x1B[95mFormatting:\\x1B[39m" +# we don't want an error here, so we can handle things later, in the ".DEFAULT" target +-include $(BUILD_SYSTEM_DIR)/makefiles/variables.mk + + +ifeq ($(NIM_PARAMS),) +# "variables.mk" was not included, so we update the submodules. +GIT_SUBMODULE_UPDATE := git submodule update --init --recursive +.DEFAULT: + +@ echo -e "Git submodules not found. Running '$(GIT_SUBMODULE_UPDATE)'.\n"; \ + $(GIT_SUBMODULE_UPDATE); \ + echo +# Now that the included *.mk files appeared, and are newer than this file, Make will restart itself: +# https://www.gnu.org/software/make/manual/make.html#Remaking-Makefiles +# +# After restarting, it will execute its original goal, so we don't have to start a child Make here +# with "$(MAKE) $(MAKECMDGOALS)". Isn't hidden control flow great? + +else # "variables.mk" was included. Business as usual until the end of this file. + +# Determine the OS +detected_OS := $(shell uname -s) +ifneq (,$(findstring MINGW,$(detected_OS))) + detected_OS := Windows +endif + +ifeq ($(detected_OS),Windows) + # Update MINGW_PATH to standard MinGW location + MINGW_PATH = /mingw64 + NIM_PARAMS += --passC:"-I$(MINGW_PATH)/include" + NIM_PARAMS += --passL:"-L$(MINGW_PATH)/lib" + NIM_PARAMS += --passL:"-Lvendor/nim-nat-traversal/vendor/miniupnp/miniupnpc" + NIM_PARAMS += --passL:"-Lvendor/nim-nat-traversal/vendor/libnatpmp-upstream" + + LIBS = -lws2_32 -lbcrypt -liphlpapi -luserenv -lntdll -lminiupnpc -lnatpmp -lpq + NIM_PARAMS += $(foreach lib,$(LIBS),--passL:"$(lib)") +endif + +########## +## Main ## +########## +.PHONY: all test update clean + +# default target, because it's the first one that doesn't start with '.' +all: | wakunode2 example2 chat2 chat2bridge libwaku + +test_file := $(word 2,$(MAKECMDGOALS)) +define test_name +$(shell echo '$(MAKECMDGOALS)' | cut -d' ' -f3-) +endef + +test: +ifeq ($(strip $(test_file)),) + $(MAKE) testcommon + $(MAKE) testwaku +else + $(MAKE) compile-test TEST_FILE="$(test_file)" TEST_NAME="$(call test_name)" +endif +# this prevents make from erroring on unknown targets like "Index" +%: + @true + +waku.nims: + ln -s waku.nimble $@ + +update: | update-common + rm -rf waku.nims && \ + $(MAKE) waku.nims $(HANDLE_OUTPUT) + $(MAKE) build-nph + +clean: + rm -rf build + +# must be included after the default target +-include $(BUILD_SYSTEM_DIR)/makefiles/targets.mk + +## Possible values: prod; debug +TARGET ?= prod + +## Git version +GIT_VERSION ?= $(shell git describe --abbrev=6 --always --tags) +## Compilation parameters. If defined in the CLI the assignments won't be executed +NIM_PARAMS := $(NIM_PARAMS) -d:git_version=\"$(GIT_VERSION)\" + +## Heaptracker options +HEAPTRACKER ?= 0 +HEAPTRACKER_INJECT ?= 0 +ifeq ($(HEAPTRACKER), 1) +# Assumes Nim's lib/system/alloc.nim is patched! +TARGET := debug-with-heaptrack + +ifeq ($(HEAPTRACKER_INJECT), 1) +# the Nim compiler will load 'libheaptrack_inject.so' +HEAPTRACK_PARAMS := -d:heaptracker -d:heaptracker_inject +NIM_PARAMS := $(NIM_PARAMS) -d:heaptracker -d:heaptracker_inject +else +# the Nim compiler will load 'libheaptrack_preload.so' +HEAPTRACK_PARAMS := -d:heaptracker +NIM_PARAMS := $(NIM_PARAMS) -d:heaptracker +endif + +endif +## end of Heaptracker options + +################## +## Dependencies ## +################## +.PHONY: deps libbacktrace + +rustup: +ifeq (, $(shell which cargo)) +# Install Rustup if it's not installed +# -y: Assume "yes" for all prompts +# --default-toolchain stable: Install the stable toolchain + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain stable +endif + +rln-deps: rustup + ./scripts/install_rln_tests_dependencies.sh + +deps: | deps-common nat-libs waku.nims + + +### nim-libbacktrace + +# "-d:release" implies "--stacktrace:off" and it cannot be added to config.nims +ifeq ($(DEBUG), 0) +NIM_PARAMS := $(NIM_PARAMS) -d:release +else +NIM_PARAMS := $(NIM_PARAMS) -d:debug +endif + +ifeq ($(USE_LIBBACKTRACE), 0) +NIM_PARAMS := $(NIM_PARAMS) -d:disable_libbacktrace +endif + +libbacktrace: + + $(MAKE) -C vendor/nim-libbacktrace --no-print-directory BUILD_CXX_LIB=0 + +clean-libbacktrace: + + $(MAKE) -C vendor/nim-libbacktrace clean $(HANDLE_OUTPUT) + +# Extend deps and clean targets +ifneq ($(USE_LIBBACKTRACE), 0) +deps: | libbacktrace +endif + +ifeq ($(POSTGRES), 1) +NIM_PARAMS := $(NIM_PARAMS) -d:postgres -d:nimDebugDlOpen +endif + +ifeq ($(DEBUG_DISCV5), 1) +NIM_PARAMS := $(NIM_PARAMS) -d:debugDiscv5 +endif + +clean: | clean-libbacktrace + +### Create nimble links (used when building with Nix) + +nimbus-build-system-nimble-dir: + NIMBLE_DIR="$(CURDIR)/$(NIMBLE_DIR)" \ + PWD_CMD="$(PWD)" \ + $(CURDIR)/scripts/generate_nimble_links.sh + +################## +## RLN ## +################## +.PHONY: librln + +LIBRLN_BUILDDIR := $(CURDIR)/vendor/zerokit +LIBRLN_VERSION := v0.7.0 + +ifeq ($(detected_OS),Windows) +LIBRLN_FILE := rln.lib +else +LIBRLN_FILE := librln_$(LIBRLN_VERSION).a +endif + +$(LIBRLN_FILE): + echo -e $(BUILD_MSG) "$@" && \ + ./scripts/build_rln.sh $(LIBRLN_BUILDDIR) $(LIBRLN_VERSION) $(LIBRLN_FILE) + +librln: | $(LIBRLN_FILE) + $(eval NIM_PARAMS += --passL:$(LIBRLN_FILE) --passL:-lm) + +clean-librln: + cargo clean --manifest-path vendor/zerokit/rln/Cargo.toml + rm -f $(LIBRLN_FILE) + +# Extend clean target +clean: | clean-librln + +################# +## Waku Common ## +################# +.PHONY: testcommon + +testcommon: | build deps + echo -e $(BUILD_MSG) "build/$@" && \ + $(ENV_SCRIPT) nim testcommon $(NIM_PARAMS) waku.nims + + +########## +## Waku ## +########## +.PHONY: testwaku wakunode2 testwakunode2 example2 chat2 chat2bridge liteprotocoltester + +# install rln-deps only for the testwaku target +testwaku: | build deps rln-deps librln + echo -e $(BUILD_MSG) "build/$@" && \ + $(ENV_SCRIPT) nim test -d:os=$(shell uname) $(NIM_PARAMS) waku.nims + +wakunode2: | build deps librln + echo -e $(BUILD_MSG) "build/$@" && \ + \ + $(ENV_SCRIPT) nim wakunode2 $(NIM_PARAMS) waku.nims + +benchmarks: | build deps librln + echo -e $(BUILD_MSG) "build/$@" && \ + $(ENV_SCRIPT) nim benchmarks $(NIM_PARAMS) waku.nims + +testwakunode2: | build deps librln + echo -e $(BUILD_MSG) "build/$@" && \ + $(ENV_SCRIPT) nim testwakunode2 $(NIM_PARAMS) waku.nims + +example2: | build deps librln + echo -e $(BUILD_MSG) "build/$@" && \ + $(ENV_SCRIPT) nim example2 $(NIM_PARAMS) waku.nims + +chat2: | build deps librln + echo -e $(BUILD_MSG) "build/$@" && \ + $(ENV_SCRIPT) nim chat2 $(NIM_PARAMS) waku.nims + +chat2mix: | build deps librln + echo -e $(BUILD_MSG) "build/$@" && \ + $(ENV_SCRIPT) nim chat2mix $(NIM_PARAMS) waku.nims + +rln-db-inspector: | build deps librln + echo -e $(BUILD_MSG) "build/$@" && \ + $(ENV_SCRIPT) nim rln_db_inspector $(NIM_PARAMS) waku.nims + +chat2bridge: | build deps librln + echo -e $(BUILD_MSG) "build/$@" && \ + $(ENV_SCRIPT) nim chat2bridge $(NIM_PARAMS) waku.nims + +liteprotocoltester: | build deps librln + echo -e $(BUILD_MSG) "build/$@" && \ + $(ENV_SCRIPT) nim liteprotocoltester $(NIM_PARAMS) waku.nims + +lightpushwithmix: | build deps librln + echo -e $(BUILD_MSG) "build/$@" && \ + $(ENV_SCRIPT) nim lightpushwithmix $(NIM_PARAMS) waku.nims + +build/%: | build deps librln + echo -e $(BUILD_MSG) "build/$*" && \ + $(ENV_SCRIPT) nim buildone $(NIM_PARAMS) waku.nims $* + +compile-test: | build deps librln + echo -e $(BUILD_MSG) "$(TEST_FILE)" "\"$(TEST_NAME)\"" && \ + $(ENV_SCRIPT) nim buildTest $(NIM_PARAMS) waku.nims $(TEST_FILE) && \ + $(ENV_SCRIPT) nim execTest $(NIM_PARAMS) waku.nims $(TEST_FILE) "\"$(TEST_NAME)\""; \ + +################ +## Waku tools ## +################ +.PHONY: tools wakucanary networkmonitor + +tools: networkmonitor wakucanary + +wakucanary: | build deps librln + echo -e $(BUILD_MSG) "build/$@" && \ + $(ENV_SCRIPT) nim wakucanary $(NIM_PARAMS) waku.nims + +networkmonitor: | build deps librln + echo -e $(BUILD_MSG) "build/$@" && \ + $(ENV_SCRIPT) nim networkmonitor $(NIM_PARAMS) waku.nims + +############ +## Format ## +############ +.PHONY: build-nph install-nph clean-nph print-nph-path + +# Default location for nph binary shall be next to nim binary to make it available on the path. +NPH:=$(shell dirname $(NIM_BINARY))/nph + +build-nph: | build deps +ifeq ("$(wildcard $(NPH))","") + $(ENV_SCRIPT) nim c --skipParentCfg:on vendor/nph/src/nph.nim && \ + mv vendor/nph/src/nph $(shell dirname $(NPH)) + echo "nph utility is available at " $(NPH) +else + echo "nph utility already exists at " $(NPH) +endif + +GIT_PRE_COMMIT_HOOK := .git/hooks/pre-commit + +install-nph: build-nph +ifeq ("$(wildcard $(GIT_PRE_COMMIT_HOOK))","") + cp ./scripts/git_pre_commit_format.sh $(GIT_PRE_COMMIT_HOOK) +else + echo "$(GIT_PRE_COMMIT_HOOK) already present, will NOT override" + exit 1 +endif + +nph/%: | build-nph + echo -e $(FORMAT_MSG) "nph/$*" && \ + $(NPH) $* + +clean-nph: + rm -f $(NPH) + +# To avoid hardcoding nph binary location in several places +print-nph-path: + echo "$(NPH)" + +clean: | clean-nph + +################### +## Documentation ## +################### +.PHONY: docs coverage + +# TODO: Remove unused target +docs: | build deps + echo -e $(BUILD_MSG) "build/$@" && \ + $(ENV_SCRIPT) nim doc --run --index:on --project --out:.gh-pages waku/waku.nim waku.nims + +coverage: + echo -e $(BUILD_MSG) "build/$@" && \ + $(ENV_SCRIPT) ./scripts/run_cov.sh -y + + +##################### +## Container image ## +##################### +# -d:insecure - Necessary to enable Prometheus HTTP endpoint for metrics +# -d:chronicles_colors:none - Necessary to disable colors in logs for Docker +DOCKER_IMAGE_NIMFLAGS ?= -d:chronicles_colors:none -d:insecure -d:postgres +DOCKER_IMAGE_NIMFLAGS := $(DOCKER_IMAGE_NIMFLAGS) $(HEAPTRACK_PARAMS) + +# build a docker image for the fleet +docker-image: MAKE_TARGET ?= wakunode2 +docker-image: DOCKER_IMAGE_TAG ?= $(MAKE_TARGET)-$(GIT_VERSION) +docker-image: DOCKER_IMAGE_NAME ?= wakuorg/nwaku:$(DOCKER_IMAGE_TAG) +docker-image: + docker build \ + --build-arg="MAKE_TARGET=$(MAKE_TARGET)" \ + --build-arg="NIMFLAGS=$(DOCKER_IMAGE_NIMFLAGS)" \ + --build-arg="NIM_COMMIT=$(DOCKER_NIM_COMMIT)" \ + --build-arg="LOG_LEVEL=$(LOG_LEVEL)" \ + --build-arg="HEAPTRACK_BUILD=$(HEAPTRACKER)" \ + --label="commit=$(shell git rev-parse HEAD)" \ + --label="version=$(GIT_VERSION)" \ + --target $(TARGET) \ + --tag $(DOCKER_IMAGE_NAME) . + +docker-quick-image: MAKE_TARGET ?= wakunode2 +docker-quick-image: DOCKER_IMAGE_TAG ?= $(MAKE_TARGET)-$(GIT_VERSION) +docker-quick-image: DOCKER_IMAGE_NAME ?= wakuorg/nwaku:$(DOCKER_IMAGE_TAG) +docker-quick-image: NIM_PARAMS := $(NIM_PARAMS) -d:chronicles_colors:none -d:insecure -d:postgres --passL:$(LIBRLN_FILE) --passL:-lm +docker-quick-image: | build deps librln wakunode2 + docker build \ + --build-arg="MAKE_TARGET=$(MAKE_TARGET)" \ + --tag $(DOCKER_IMAGE_NAME) \ + --target $(TARGET) \ + --file docker/binaries/Dockerfile.bn.local \ + . + +docker-push: + docker push $(DOCKER_IMAGE_NAME) + +#################################### +## Container lite-protocol-tester ## +#################################### +# -d:insecure - Necessary to enable Prometheus HTTP endpoint for metrics +# -d:chronicles_colors:none - Necessary to disable colors in logs for Docker +DOCKER_LPT_NIMFLAGS ?= -d:chronicles_colors:none -d:insecure + +# build a docker image for the fleet +docker-liteprotocoltester: DOCKER_LPT_TAG ?= latest +docker-liteprotocoltester: DOCKER_LPT_NAME ?= wakuorg/liteprotocoltester:$(DOCKER_LPT_TAG) +# --no-cache +docker-liteprotocoltester: + docker build \ + --build-arg="MAKE_TARGET=liteprotocoltester" \ + --build-arg="NIMFLAGS=$(DOCKER_LPT_NIMFLAGS)" \ + --build-arg="NIM_COMMIT=$(DOCKER_NIM_COMMIT)" \ + --build-arg="LOG_LEVEL=TRACE" \ + --label="commit=$(shell git rev-parse HEAD)" \ + --label="version=$(GIT_VERSION)" \ + --target $(if $(filter deploy,$(DOCKER_LPT_TAG)),deployment_lpt,standalone_lpt) \ + --tag $(DOCKER_LPT_NAME) \ + --file apps/liteprotocoltester/Dockerfile.liteprotocoltester.compile \ + . + +docker-quick-liteprotocoltester: DOCKER_LPT_TAG ?= latest +docker-quick-liteprotocoltester: DOCKER_LPT_NAME ?= wakuorg/liteprotocoltester:$(DOCKER_LPT_TAG) +docker-quick-liteprotocoltester: | liteprotocoltester + docker build \ + --tag $(DOCKER_LPT_NAME) \ + --file apps/liteprotocoltester/Dockerfile.liteprotocoltester \ + . + +docker-liteprotocoltester-push: + docker push $(DOCKER_LPT_NAME) + + +################ +## C Bindings ## +################ +.PHONY: cbindings cwaku_example libwaku + +STATIC ?= 0 + + +libwaku: | build deps librln + rm -f build/libwaku* + +ifeq ($(STATIC), 1) + echo -e $(BUILD_MSG) "build/$@.a" && $(ENV_SCRIPT) nim libwakuStatic $(NIM_PARAMS) waku.nims +else ifeq ($(detected_OS),Windows) + echo -e $(BUILD_MSG) "build/$@.dll" && $(ENV_SCRIPT) nim libwakuDynamic $(NIM_PARAMS) waku.nims +else + echo -e $(BUILD_MSG) "build/$@.so" && $(ENV_SCRIPT) nim libwakuDynamic $(NIM_PARAMS) waku.nims +endif + +##################### +## Mobile Bindings ## +##################### +.PHONY: libwaku-android \ + libwaku-android-precheck \ + libwaku-android-arm64 \ + libwaku-android-amd64 \ + libwaku-android-x86 \ + libwaku-android-arm \ + rebuild-nat-libs \ + build-libwaku-for-android-arch + +ANDROID_TARGET ?= 30 +ifeq ($(detected_OS),Darwin) + ANDROID_TOOLCHAIN_DIR := $(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/darwin-x86_64 +else + ANDROID_TOOLCHAIN_DIR := $(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/linux-x86_64 +endif + +rebuild-nat-libs: | clean-cross nat-libs + +libwaku-android-precheck: +ifndef ANDROID_NDK_HOME + $(error ANDROID_NDK_HOME is not set) +endif + +build-libwaku-for-android-arch: + $(MAKE) rebuild-nat-libs CC=$(ANDROID_TOOLCHAIN_DIR)/bin/$(ANDROID_COMPILER) && \ + ./scripts/build_rln_android.sh $(CURDIR)/build $(LIBRLN_BUILDDIR) $(LIBRLN_VERSION) $(CROSS_TARGET) $(ABIDIR) && \ + CPU=$(CPU) ABIDIR=$(ABIDIR) ANDROID_ARCH=$(ANDROID_ARCH) ANDROID_COMPILER=$(ANDROID_COMPILER) ANDROID_TOOLCHAIN_DIR=$(ANDROID_TOOLCHAIN_DIR) $(ENV_SCRIPT) nim libWakuAndroid $(NIM_PARAMS) waku.nims + +libwaku-android-arm64: ANDROID_ARCH=aarch64-linux-android +libwaku-android-arm64: CPU=arm64 +libwaku-android-arm64: ABIDIR=arm64-v8a +libwaku-android-arm64: | libwaku-android-precheck build deps + $(MAKE) build-libwaku-for-android-arch ANDROID_ARCH=$(ANDROID_ARCH) CROSS_TARGET=$(ANDROID_ARCH) CPU=$(CPU) ABIDIR=$(ABIDIR) ANDROID_COMPILER=$(ANDROID_ARCH)$(ANDROID_TARGET)-clang + +libwaku-android-amd64: ANDROID_ARCH=x86_64-linux-android +libwaku-android-amd64: CPU=amd64 +libwaku-android-amd64: ABIDIR=x86_64 +libwaku-android-amd64: | libwaku-android-precheck build deps + $(MAKE) build-libwaku-for-android-arch ANDROID_ARCH=$(ANDROID_ARCH) CROSS_TARGET=$(ANDROID_ARCH) CPU=$(CPU) ABIDIR=$(ABIDIR) ANDROID_COMPILER=$(ANDROID_ARCH)$(ANDROID_TARGET)-clang + +libwaku-android-x86: ANDROID_ARCH=i686-linux-android +libwaku-android-x86: CPU=i386 +libwaku-android-x86: ABIDIR=x86 +libwaku-android-x86: | libwaku-android-precheck build deps + $(MAKE) build-libwaku-for-android-arch ANDROID_ARCH=$(ANDROID_ARCH) CROSS_TARGET=$(ANDROID_ARCH) CPU=$(CPU) ABIDIR=$(ABIDIR) ANDROID_COMPILER=$(ANDROID_ARCH)$(ANDROID_TARGET)-clang + +libwaku-android-arm: ANDROID_ARCH=armv7a-linux-androideabi +libwaku-android-arm: CPU=arm +libwaku-android-arm: ABIDIR=armeabi-v7a +libwaku-android-arm: | libwaku-android-precheck build deps +# cross-rs target architecture name does not match the one used in android + $(MAKE) build-libwaku-for-android-arch ANDROID_ARCH=$(ANDROID_ARCH) CROSS_TARGET=armv7-linux-androideabi CPU=$(CPU) ABIDIR=$(ABIDIR) ANDROID_COMPILER=$(ANDROID_ARCH)$(ANDROID_TARGET)-clang + +libwaku-android: + $(MAKE) libwaku-android-amd64 + $(MAKE) libwaku-android-arm64 + $(MAKE) libwaku-android-x86 +# This target is disabled because on recent versions of cross-rs complain with the following error +# relocation R_ARM_THM_ALU_PREL_11_0 cannot be used against symbol 'stack_init_trampoline_return'; recompile with -fPIC +# It's likely this architecture is not used so we might just not support it. +# $(MAKE) libwaku-android-arm + +cwaku_example: | build libwaku + echo -e $(BUILD_MSG) "build/$@" && \ + cc -o "build/$@" \ + ./examples/cbindings/waku_example.c \ + ./examples/cbindings/base64.c \ + -lwaku -Lbuild/ \ + -pthread -ldl -lm \ + -lminiupnpc -Lvendor/nim-nat-traversal/vendor/miniupnp/miniupnpc/build/ \ + -lnatpmp -Lvendor/nim-nat-traversal/vendor/libnatpmp-upstream/ \ + vendor/nim-libbacktrace/libbacktrace_wrapper.o \ + vendor/nim-libbacktrace/install/usr/lib/libbacktrace.a + +cppwaku_example: | build libwaku + echo -e $(BUILD_MSG) "build/$@" && \ + g++ -o "build/$@" \ + ./examples/cpp/waku.cpp \ + ./examples/cpp/base64.cpp \ + -lwaku -Lbuild/ \ + -pthread -ldl -lm \ + -lminiupnpc -Lvendor/nim-nat-traversal/vendor/miniupnp/miniupnpc/build/ \ + -lnatpmp -Lvendor/nim-nat-traversal/vendor/libnatpmp-upstream/ \ + vendor/nim-libbacktrace/libbacktrace_wrapper.o \ + vendor/nim-libbacktrace/install/usr/lib/libbacktrace.a + +nodejswaku: | build deps + echo -e $(BUILD_MSG) "build/$@" && \ + node-gyp build --directory=examples/nodejs/ + +endif # "variables.mk" was not included + +################### +# Release Targets # +################### + +release-notes: + docker run \ + -it \ + --rm \ + -v $${PWD}:/opt/sv4git/repo:z \ + -u $(shell id -u) \ + docker.io/wakuorg/sv4git:latest \ + release-notes |\ + sed -E 's@#([0-9]+)@[#\1](https://github.com/waku-org/nwaku/issues/\1)@g' +# I could not get the tool to replace issue ids with links, so using sed for now, +# asked here: https://github.com/bvieira/sv4git/discussions/101 + diff --git a/README.md b/README.md new file mode 100644 index 0000000..ce352d6 --- /dev/null +++ b/README.md @@ -0,0 +1,186 @@ +# Nwaku + +## Introduction + +The nwaku repository implements Waku, and provides tools related to it. + +- A Nim implementation of the [Waku (v2) protocol](https://specs.vac.dev/specs/waku/v2/waku-v2.html). +- CLI application `wakunode2` that allows you to run a Waku node. +- Examples of Waku usage. +- Various tests of above. + +For more details see the [source code](waku/README.md) + +## How to Build & Run ( Linux, MacOS & WSL ) + +These instructions are generic. For more detailed instructions, see the Waku source code above. + +### Prerequisites + +The standard developer tools, including a C compiler, GNU Make, Bash, and Git. More information on these installations can be found [here](https://docs.waku.org/guides/nwaku/build-source#install-dependencies). + +> In some distributions (Fedora linux for example), you may need to install `which` utility separately. Nimbus build system is relying on it. + +You'll also need an installation of Rust and its toolchain (specifically `rustc` and `cargo`). +The easiest way to install these, is using `rustup`: + +```bash +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +``` + +### Wakunode + +```bash +# The first `make` invocation will update all Git submodules. +# You'll run `make update` after each `git pull` in the future to keep those submodules updated. +make wakunode2 + +# Build with custom compilation flags. Do not use NIM_PARAMS unless you know what you are doing. +# Replace with your own flags +make wakunode2 NIMFLAGS="-d:chronicles_colors:none -d:disableMarchNative" + +# Run with DNS bootstrapping +./build/wakunode2 --dns-discovery --dns-discovery-url=DNS_BOOTSTRAP_NODE_URL + +# See available command line options +./build/wakunode2 --help +``` +To join the network, you need to know the address of at least one bootstrap node. +Please refer to the [Waku README](https://github.com/waku-org/nwaku/blob/master/waku/README.md) for more information. + +For more on how to run `wakunode2`, refer to: +- [Run using binaries](https://docs.waku.org/guides/nwaku/build-source) +- [Run using docker](https://docs.waku.org/guides/nwaku/run-docker) +- [Run using docker-compose](https://docs.waku.org/guides/nwaku/run-docker-compose) + +#### Issues +##### WSL +If you encounter difficulties building the project on WSL, consider placing the project within WSL's filesystem, avoiding the `/mnt/` directory. + +### How to Build & Run ( Windows ) + +### Windows Build Instructions + +#### 1. Install Required Tools +- **Git Bash Terminal**: Download and install from https://git-scm.com/download/win +- **MSYS2**: + a. Download installer from https://www.msys2.org + b. Install at "C:\" (default location). Remove/rename the msys folder in case of previous installation. + c. Use the mingw64 terminal from msys64 directory for package installation. + +#### 2. Install Dependencies +Open MSYS2 mingw64 terminal and run the following one-by-one : +```bash +pacman -Syu --noconfirm +pacman -S --noconfirm --needed mingw-w64-x86_64-toolchain +pacman -S --noconfirm --needed base-devel make cmake upx +pacman -S --noconfirm --needed mingw-w64-x86_64-rust +pacman -S --noconfirm --needed mingw-w64-x86_64-postgresql +pacman -S --noconfirm --needed mingw-w64-x86_64-gcc +pacman -S --noconfirm --needed mingw-w64-x86_64-gcc-libs +pacman -S --noconfirm --needed mingw-w64-x86_64-libwinpthread-git +pacman -S --noconfirm --needed mingw-w64-x86_64-zlib +pacman -S --noconfirm --needed mingw-w64-x86_64-openssl +pacman -S --noconfirm --needed mingw-w64-x86_64-python +``` + +#### 3. Build Wakunode +- Open Git Bash as administrator +- clone nwaku and cd nwaku +- Execute: `./scripts/build_windows.sh` + +#### 4. Troubleshooting +If `wakunode2.exe` isn't generated: +- **Missing Dependencies**: Verify with: + `which make cmake gcc g++ rustc cargo python3 upx` + If missing, revisit Step 2 or ensure MSYS2 is at `C:\` +- **Installation Conflicts**: Remove existing MinGW/MSYS2/Git Bash installations and perform fresh install + +### Developing + +#### Nim Runtime +This repository is bundled with a Nim runtime that includes the necessary dependencies for the project. + +Before you can utilize the runtime you'll need to build the project, as detailed in a previous section. +This will generate a `vendor` directory containing various dependencies, including the `nimbus-build-system` which has the bundled nim runtime. + +After successfully building the project, you may bring the bundled runtime into scope by running: +```bash +source env.sh +``` +If everything went well, you should see your prompt suffixed with `[Nimbus env]$`. Now you can run `nim` commands as usual. + +### Test Suite + +```bash +# Run all the Waku tests +make test + +# Run a specific test file +make test +# e.g. : make test tests/wakunode2/test_all.nim + +# Run a specific test name from a specific test file +make test +# e.g. : make test tests/wakunode2/test_all.nim "node setup is successful with default configuration" +``` + +### Building single test files + +During development it is helpful to build and run a single test file. +To support this make has a specific target: + +targets: +- `build/` +- `test/` + +Binary will be created as `.bin` under the `build` directory . + +```bash +# Build and run your test file separately +make test/tests/common/test_enr_builder.nim +``` + +### Testing against `js-waku` +Refer to [js-waku repo](https://github.com/waku-org/js-waku/tree/master/packages/tests) for instructions. + +## Formatting + +Nim files are expected to be formatted using the [`nph`](https://github.com/arnetheduck/nph) version present in `vendor/nph`. + +You can easily format file with the `make nph/ file` command. +For example: + +``` +make nph/waku/waku_core.nim +``` + +A convenient git hook is provided to automatically format file at commit time. +Run the following command to install it: + +```shell +make install-nph +``` + +### Examples + +Examples can be found in the examples folder. +This includes a fully featured chat example. + +### Tools + +Different tools and their corresponding how-to guides can be found in the `tools` folder. + +### Bugs, Questions & Features + +For an inquiry, or if you would like to propose new features, feel free to [open a general issue](https://github.com/waku-org/nwaku/issues/new). + +For bug reports, please [tag your issue with the `bug` label](https://github.com/waku-org/nwaku/issues/new). + +If you believe the reported issue requires critical attention, please [use the `critical` label](https://github.com/waku-org/nwaku/issues/new?labels=critical,bug) to assist with triaging. + +To get help, or participate in the conversation, join the [Waku Discord](https://discord.waku.org/) server. + +### Docs + +* [REST API Documentation](https://waku-org.github.io/waku-rest-api/) diff --git a/apps/benchmarks/benchmarks.nim b/apps/benchmarks/benchmarks.nim new file mode 100644 index 0000000..75686c8 --- /dev/null +++ b/apps/benchmarks/benchmarks.nim @@ -0,0 +1,74 @@ +import + std/[strutils, times, sequtils, osproc], math, results, options, testutils/unittests + +import + waku/[ + waku_rln_relay/protocol_types, + waku_rln_relay/rln, + waku_rln_relay, + waku_rln_relay/conversion_utils, + waku_rln_relay/group_manager/on_chain/group_manager, + ], + tests/waku_rln_relay/utils_onchain + +proc benchmark( + manager: OnChainGroupManager, registerCount: int, messageLimit: int +): Future[string] {.async, gcsafe.} = + # Register a new member so that we can later generate proofs + let idCredentials = generateCredentials(manager.rlnInstance, registerCount) + + var start_time = getTime() + for i in 0 .. registerCount - 1: + try: + await manager.register(idCredentials[i], UserMessageLimit(messageLimit + 1)) + except Exception, CatchableError: + assert false, "exception raised: " & getCurrentExceptionMsg() + + debug "registration finished", + iter = i, elapsed_ms = (getTime() - start_time).inMilliseconds + + discard await manager.updateRoots() + let proofResult = await manager.fetchMerkleProofElements() + if proofResult.isErr(): + error "Failed to fetch Merkle proof", error = proofResult.error + manager.merkleProofCache = proofResult.get() + + let epoch = default(Epoch) + debug "epoch in bytes", epochHex = epoch.inHex() + let data: seq[byte] = newSeq[byte](1024) + + var proofGenTimes: seq[times.Duration] = @[] + var proofVerTimes: seq[times.Duration] = @[] + + start_time = getTime() + for i in 1 .. messageLimit: + var generate_time = getTime() + let proof = manager.generateProof(data, epoch, MessageId(i.uint8)).valueOr: + raiseAssert $error + proofGenTimes.add(getTime() - generate_time) + + let verify_time = getTime() + let ok = manager.verifyProof(data, proof).valueOr: + raiseAssert $error + proofVerTimes.add(getTime() - verify_time) + debug "iteration finished", + iter = i, elapsed_ms = (getTime() - start_time).inMilliseconds + + echo "Proof generation times: ", sum(proofGenTimes) div len(proofGenTimes) + echo "Proof verification times: ", sum(proofVerTimes) div len(proofVerTimes) + +proc main() = + # Start a local Ethereum JSON-RPC (Anvil) so that the group-manager setup can connect. + let anvilProc = runAnvil() + defer: + stopAnvil(anvilProc) + + # Set up an On-chain group manager (includes contract deployment) + let manager = waitFor setupOnchainGroupManager() + (waitFor manager.init()).isOkOr: + raiseAssert $error + + discard waitFor benchmark(manager, 200, 20) + +when isMainModule: + main() diff --git a/apps/chat2/chat2.nim b/apps/chat2/chat2.nim new file mode 100644 index 0000000..1531a46 --- /dev/null +++ b/apps/chat2/chat2.nim @@ -0,0 +1,626 @@ +## chat2 is an example of usage of Waku v2. For suggested usage options, please +## see dingpu tutorial in docs folder. + +when not (compileOption("threads")): + {.fatal: "Please, compile this program with the --threads:on option!".} + +{.push raises: [].} + +import std/[strformat, strutils, times, options, random, sequtils] +import + confutils, + chronicles, + chronos, + eth/keys, + bearssl, + stew/[byteutils, results], + metrics, + metrics/chronos_httpserver +import + libp2p/[ + switch, # manage transports, a single entry point for dialing and listening + crypto/crypto, # cryptographic functions + stream/connection, # create and close stream read / write connections + multiaddress, + # encode different addressing schemes. For example, /ip4/7.7.7.7/tcp/6543 means it is using IPv4 protocol and TCP + peerinfo, + # manage the information of a peer, such as peer ID and public / private key + peerid, # Implement how peers interact + protobuf/minprotobuf, # message serialisation/deserialisation from and to protobufs + nameresolving/dnsresolver, + ] # define DNS resolution +import + waku/[ + waku_core, + waku_lightpush_legacy/common, + waku_lightpush_legacy/rpc, + waku_enr, + discovery/waku_dnsdisc, + waku_store_legacy, + waku_node, + node/waku_metrics, + node/peer_manager, + factory/builder, + common/utils/nat, + waku_relay, + waku_store/common, + ], + ./config_chat2 + +import libp2p/protocols/pubsub/rpc/messages, libp2p/protocols/pubsub/pubsub +import ../../waku/waku_rln_relay + +const Help = + """ + Commands: /[?|help|connect|nick|exit] + help: Prints this help + connect: dials a remote peer + nick: change nickname for current chat session + exit: exits chat session +""" + +# XXX Connected is a bit annoying, because incoming connections don't trigger state change +# Could poll connection pool or something here, I suppose +# TODO Ensure connected turns true on incoming connections, or get rid of it +type Chat = ref object + node: WakuNode # waku node for publishing, subscribing, etc + transp: StreamTransport # transport streams between read & write file descriptor + subscribed: bool # indicates if a node is subscribed or not to a topic + connected: bool # if the node is connected to another peer + started: bool # if the node has started + nick: string # nickname for this chat session + prompt: bool # chat prompt is showing + contentTopic: string # default content topic for chat messages + +type + PrivateKey* = crypto.PrivateKey + Topic* = waku_core.PubsubTopic + +##################### +## chat2 protobufs ## +##################### + +type + SelectResult*[T] = Result[T, string] + + Chat2Message* = object + timestamp*: int64 + nick*: string + payload*: seq[byte] + +proc init*(T: type Chat2Message, buffer: seq[byte]): ProtoResult[T] = + var msg = Chat2Message() + let pb = initProtoBuffer(buffer) + + var timestamp: uint64 + discard ?pb.getField(1, timestamp) + msg.timestamp = int64(timestamp) + + discard ?pb.getField(2, msg.nick) + discard ?pb.getField(3, msg.payload) + + ok(msg) + +proc encode*(message: Chat2Message): ProtoBuffer = + var serialised = initProtoBuffer() + + serialised.write(1, uint64(message.timestamp)) + serialised.write(2, message.nick) + serialised.write(3, message.payload) + + return serialised + +proc toString*(message: Chat2Message): string = + # Get message date and timestamp in local time + let time = message.timestamp.fromUnix().local().format("'<'MMM' 'dd,' 'HH:mm'>'") + + return time & " " & message.nick & ": " & string.fromBytes(message.payload) + +##################### + +proc connectToNodes(c: Chat, nodes: seq[string]) {.async.} = + echo "Connecting to nodes" + await c.node.connectToNodes(nodes) + c.connected = true + +proc showChatPrompt(c: Chat) = + if not c.prompt: + try: + stdout.write(">> ") + stdout.flushFile() + c.prompt = true + except IOError: + discard + +proc getChatLine(c: Chat, msg: WakuMessage): Result[string, string] = + # No payload encoding/encryption from Waku + let + pb = Chat2Message.init(msg.payload) + chatLine = + if pb.isOk: + pb[].toString() + else: + string.fromBytes(msg.payload) + return ok(chatline) + +proc printReceivedMessage(c: Chat, msg: WakuMessage) = + let + pb = Chat2Message.init(msg.payload) + chatLine = + if pb.isOk: + pb[].toString() + else: + string.fromBytes(msg.payload) + try: + echo &"{chatLine}" + except ValueError: + # Formatting fail. Print chat line in any case. + echo chatLine + + c.prompt = false + showChatPrompt(c) + trace "Printing message", + topic = DefaultPubsubTopic, chatLine, contentTopic = msg.contentTopic + +proc readNick(transp: StreamTransport): Future[string] {.async.} = + # Chat prompt + stdout.write("Choose a nickname >> ") + stdout.flushFile() + return await transp.readLine() + +proc startMetricsServer( + serverIp: IpAddress, serverPort: Port +): Result[MetricsHttpServerRef, string] = + info "Starting metrics HTTP server", serverIp = $serverIp, serverPort = $serverPort + + let metricsServerRes = MetricsHttpServerRef.new($serverIp, serverPort) + if metricsServerRes.isErr(): + return err("metrics HTTP server start failed: " & $metricsServerRes.error) + + let server = metricsServerRes.value + try: + waitFor server.start() + except CatchableError: + return err("metrics HTTP server start failed: " & getCurrentExceptionMsg()) + + info "Metrics HTTP server started", serverIp = $serverIp, serverPort = $serverPort + ok(metricsServerRes.value) + +proc publish(c: Chat, line: string) = + # First create a Chat2Message protobuf with this line of text + let time = getTime().toUnix() + let chat2pb = + Chat2Message(timestamp: time, nick: c.nick, payload: line.toBytes()).encode() + + ## @TODO: error handling on failure + proc handler(response: PushResponse) {.gcsafe, closure.} = + trace "lightpush response received", response = response + + var message = WakuMessage( + payload: chat2pb.buffer, + contentTopic: c.contentTopic, + version: 0, + timestamp: getNanosecondTime(time), + ) + if not isNil(c.node.wakuRlnRelay): + # for future version when we support more than one rln protected content topic, + # we should check the message content topic as well + let appendRes = c.node.wakuRlnRelay.appendRLNProof(message, float64(time)) + if appendRes.isErr(): + debug "could not append rate limit proof to the message" + else: + debug "rate limit proof is appended to the message" + let decodeRes = RateLimitProof.init(message.proof) + if decodeRes.isErr(): + error "could not decode the RLN proof" + + let proof = decodeRes.get() + # TODO move it to log after dogfooding + let msgEpoch = fromEpoch(proof.epoch) + if fromEpoch(c.node.wakuRlnRelay.lastEpoch) == msgEpoch: + echo "--rln epoch: ", + msgEpoch, " ⚠️ message rate violation! you are spamming the network!" + else: + echo "--rln epoch: ", msgEpoch + # update the last epoch + c.node.wakuRlnRelay.lastEpoch = proof.epoch + + try: + if not c.node.wakuLegacyLightPush.isNil(): + # Attempt lightpush + (waitFor c.node.legacyLightpushPublish(some(DefaultPubsubTopic), message)).isOkOr: + error "failed to publish lightpush message", error = error + else: + (waitFor c.node.publish(some(DefaultPubsubTopic), message)).isOkOr: + error "failed to publish message", error = error + except CatchableError: + error "caught error publishing message: ", error = getCurrentExceptionMsg() + +# TODO This should read or be subscribe handler subscribe +proc readAndPrint(c: Chat) {.async.} = + while true: + # while p.connected: + # # TODO: echo &"{p.id} -> " + # + # echo cast[string](await p.conn.readLp(1024)) + #echo "readAndPrint subscribe NYI" + await sleepAsync(100.millis) + +# TODO Implement +proc writeAndPrint(c: Chat) {.async.} = + while true: + # Connect state not updated on incoming WakuRelay connections + # if not c.connected: + # echo "type an address or wait for a connection:" + # echo "type /[help|?] for help" + + # Chat prompt + showChatPrompt(c) + + let line = await c.transp.readLine() + if line.startsWith("/help") or line.startsWith("/?") or not c.started: + echo Help + continue + + # if line.startsWith("/disconnect"): + # echo "Ending current session" + # if p.connected and p.conn.closed.not: + # await p.conn.close() + # p.connected = false + elif line.startsWith("/connect"): + # TODO Should be able to connect to multiple peers for Waku chat + if c.connected: + echo "already connected to at least one peer" + continue + + echo "enter address of remote peer" + let address = await c.transp.readLine() + if address.len > 0: + await c.connectToNodes(@[address]) + elif line.startsWith("/nick"): + # Set a new nickname + c.nick = await readNick(c.transp) + echo "You are now known as " & c.nick + elif line.startsWith("/exit"): + echo "quitting..." + + try: + await c.node.stop() + except: + echo "exception happened when stopping: " & getCurrentExceptionMsg() + + quit(QuitSuccess) + else: + # XXX connected state problematic + if c.started: + c.publish(line) + # TODO Connect to peer logic? + else: + try: + if line.startsWith("/") and "p2p" in line: + await c.connectToNodes(@[line]) + except: + echo &"unable to dial remote peer {line}" + echo getCurrentExceptionMsg() + +proc readWriteLoop(c: Chat) {.async.} = + asyncSpawn c.writeAndPrint() # execute the async function but does not block + asyncSpawn c.readAndPrint() + +proc readInput(wfd: AsyncFD) {.thread, raises: [Defect, CatchableError].} = + ## This procedure performs reading from `stdin` and sends data over + ## pipe to main thread. + let transp = fromPipe(wfd) + + while true: + let line = stdin.readLine() + discard waitFor transp.write(line & "\r\n") + +{.pop.} + # @TODO confutils.nim(775, 17) Error: can raise an unlisted exception: ref IOError +proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} = + let + transp = fromPipe(rfd) + conf = Chat2Conf.load() + nodekey = + if conf.nodekey.isSome(): + conf.nodekey.get() + else: + PrivateKey.random(Secp256k1, rng[]).tryGet() + + # set log level + if conf.logLevel != LogLevel.NONE: + setLogLevel(conf.logLevel) + + let natRes = setupNat( + conf.nat, + clientId, + Port(uint16(conf.tcpPort) + conf.portsShift), + Port(uint16(conf.udpPort) + conf.portsShift), + ) + + if natRes.isErr(): + raise newException(ValueError, "setupNat error " & natRes.error) + + let (extIp, extTcpPort, extUdpPort) = natRes.get() + + var enrBuilder = EnrBuilder.init(nodeKey) + + let recordRes = enrBuilder.build() + let record = + if recordRes.isErr(): + error "failed to create enr record", error = recordRes.error + quit(QuitFailure) + else: + recordRes.get() + + let node = block: + var builder = WakuNodeBuilder.init() + builder.withNodeKey(nodeKey) + builder.withRecord(record) + + builder + .withNetworkConfigurationDetails( + conf.listenAddress, + Port(uint16(conf.tcpPort) + conf.portsShift), + extIp, + extTcpPort, + wsBindPort = Port(uint16(conf.websocketPort) + conf.portsShift), + wsEnabled = conf.websocketSupport, + wssEnabled = conf.websocketSecureSupport, + ) + .tryGet() + builder.build().tryGet() + + await node.start() + + if conf.rlnRelayCredPath == "": + raise newException(ConfigurationError, "rln-relay-cred-path MUST be passed") + + if conf.relay: + let shards = + conf.shards.mapIt(RelayShard(clusterId: conf.clusterId, shardId: uint16(it))) + (await node.mountRelay()).isOkOr: + echo "failed to mount relay: " & error + return + + await node.mountLibp2pPing() + + let nick = await readNick(transp) + echo "Welcome, " & nick & "!" + + var chat = Chat( + node: node, + transp: transp, + subscribed: true, + connected: false, + started: true, + nick: nick, + prompt: false, + contentTopic: conf.contentTopic, + ) + + if conf.staticnodes.len > 0: + echo "Connecting to static peers..." + await connectToNodes(chat, conf.staticnodes) + + var dnsDiscoveryUrl = 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( + "enrtree://AOGYWMBYOUIMOENHXCHILPKY3ZRFEULMFI4DOM442QSZ73TT2A7VI@test.waku.nodes.status.im" + ) + else: + # Connect to sandbox by default + dnsDiscoveryUrl = some( + "enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im" + ) + elif conf.dnsDiscoveryUrl != "": + # No pre-selected fleet. Discover nodes via DNS using user config + debug "Discovering nodes using Waku DNS discovery", url = conf.dnsDiscoveryUrl + dnsDiscoveryUrl = some(conf.dnsDiscoveryUrl) + + var discoveredNodes: seq[RemotePeerInfo] + + if dnsDiscoveryUrl.isSome: + var nameServers: seq[TransportAddress] + for ip in conf.dnsAddrsNameServers: + nameServers.add(initTAddress(ip, Port(53))) # Assume all servers use port 53 + + let dnsResolver = DnsResolver.new(nameServers) + + proc resolver(domain: string): Future[string] {.async, gcsafe.} = + trace "resolving", domain = domain + let resolved = await dnsResolver.resolveTxt(domain) + return resolved[0] # Use only first answer + + var wakuDnsDiscovery = WakuDnsDiscovery.init(dnsDiscoveryUrl.get(), resolver) + if wakuDnsDiscovery.isOk: + let discoveredPeers = await wakuDnsDiscovery.get().findPeers() + if discoveredPeers.isOk: + info "Connecting to discovered peers" + discoveredNodes = discoveredPeers.get() + echo "Discovered and connecting to " & $discoveredNodes + waitFor chat.node.connectToNodes(discoveredNodes) + else: + warn "Failed to init Waku DNS discovery" + + let peerInfo = node.switch.peerInfo + let listenStr = $peerInfo.addrs[0] & "/p2p/" & $peerInfo.peerId + echo &"Listening on\n {listenStr}" + + if (conf.storenode != "") or (conf.store == true): + await node.mountStore() + + var storenode: Option[RemotePeerInfo] + + if conf.storenode != "": + let peerInfo = parsePeerInfo(conf.storenode) + if peerInfo.isOk(): + storenode = 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)]) + + if storenode.isSome(): + # We have a viable storenode. Let's query it for historical messages. + echo "Connecting to storenode: " & $(storenode.get()) + + node.mountStoreClient() + node.peerManager.addServicePeer(storenode.get(), WakuStoreCodec) + + proc storeHandler(response: StoreQueryResponse) {.gcsafe.} = + for msg in response.messages: + let payload = + if msg.message.isSome(): + msg.message.get().payload + else: + newSeq[byte](0) + + let + pb = Chat2Message.init(payload) + chatLine = + if pb.isOk: + pb[].toString() + else: + string.fromBytes(payload) + echo &"{chatLine}" + info "Hit store handler" + + let queryRes = await node.query( + StoreQueryRequest(contentTopics: @[chat.contentTopic]), storenode.get() + ) + if queryRes.isOk(): + storeHandler(queryRes.value) + + # NOTE Must be mounted after relay + if conf.lightpushnode != "": + let peerInfo = parsePeerInfo(conf.lightpushnode) + if peerInfo.isOk(): + await mountLegacyLightPush(node) + node.mountLegacyLightPushClient() + node.peerManager.addServicePeer(peerInfo.value, WakuLightpushCodec) + else: + error "LightPush not mounted. Couldn't parse conf.lightpushnode", + error = peerInfo.error + + if conf.filternode != "": + let peerInfo = parsePeerInfo(conf.filternode) + if peerInfo.isOk(): + await node.mountFilter() + await node.mountFilterClient() + + proc filterHandler( + pubsubTopic: PubsubTopic, msg: WakuMessage + ) {.async, gcsafe, closure.} = + trace "Hit filter handler", contentTopic = msg.contentTopic + chat.printReceivedMessage(msg) + + # TODO: Here to support FilterV2 relevant subscription. + else: + error "Filter not mounted. Couldn't parse conf.filternode", error = peerInfo.error + + # Subscribe to a topic, if relay is mounted + if conf.relay: + proc handler(topic: PubsubTopic, msg: WakuMessage): Future[void] {.async, gcsafe.} = + trace "Hit subscribe handler", topic + + if msg.contentTopic == chat.contentTopic: + chat.printReceivedMessage(msg) + + node.subscribe( + (kind: PubsubSub, topic: DefaultPubsubTopic), WakuRelayHandler(handler) + ).isOkOr: + error "failed to subscribe to pubsub topic", + topic = DefaultPubsubTopic, error = error + + if conf.rlnRelay: + info "WakuRLNRelay is enabled" + + proc spamHandler(wakuMessage: WakuMessage) {.gcsafe, closure.} = + debug "spam handler is called" + let chatLineResult = chat.getChatLine(wakuMessage) + if chatLineResult.isOk(): + echo "A spam message is found and discarded : ", chatLineResult.value + else: + echo "A spam message is found and discarded" + chat.prompt = false + showChatPrompt(chat) + + echo "rln-relay preparation is in progress..." + + let rlnConf = WakuRlnConfig( + dynamic: conf.rlnRelayDynamic, + credIndex: conf.rlnRelayCredIndex, + chainId: UInt256.fromBytesBE(conf.rlnRelayChainId.toBytesBE()), + ethClientUrls: conf.ethClientUrls.mapIt(string(it)), + creds: some( + RlnRelayCreds( + path: conf.rlnRelayCredPath, password: conf.rlnRelayCredPassword + ) + ), + userMessageLimit: conf.rlnRelayUserMessageLimit, + epochSizeSec: conf.rlnEpochSizeSec, + ) + + waitFor node.mountRlnRelay(rlnConf, spamHandler = some(spamHandler)) + + let membershipIndex = node.wakuRlnRelay.groupManager.membershipIndex.get() + let identityCredential = node.wakuRlnRelay.groupManager.idCredentials.get() + echo "your membership index is: ", membershipIndex + echo "your rln identity commitment key is: ", + identityCredential.idCommitment.inHex() + else: + info "WakuRLNRelay is disabled" + echo "WakuRLNRelay is disabled, please enable it by passing in the --rln-relay flag" + if conf.metricsLogging: + startMetricsLog() + + if conf.metricsServer: + let metricsServer = startMetricsServer( + conf.metricsServerAddress, Port(conf.metricsServerPort + conf.portsShift) + ) + + await chat.readWriteLoop() + + runForever() + +proc main(rng: ref HmacDrbgContext) {.async.} = + let (rfd, wfd) = createAsyncPipe() + if rfd == asyncInvalidPipe or wfd == asyncInvalidPipe: + raise newException(ValueError, "Could not initialize pipe!") + + var thread: Thread[AsyncFD] + thread.createThread(readInput, wfd) + try: + await processInput(rfd, rng) + # Handle only ConfigurationError for now + # TODO: Throw other errors from the mounting procedure + except ConfigurationError as e: + raise e + +when isMainModule: # isMainModule = true when the module is compiled as the main file + let rng = crypto.newRng() + try: + waitFor(main(rng)) + except CatchableError as e: + raise e + +## Dump of things that can be improved: +## +## - Incoming dialed peer does not change connected state (not relying on it for now) +## - Unclear if staticnode argument works (can enter manually) +## - Don't trigger self / double publish own messages +## - Integrate store protocol (fetch messages in beginning) +## - Integrate filter protocol (default/option to be light node, connect to filter node) +## - Test/default to cluster node connection (diff protocol version) +## - Redirect logs to separate file +## - Expose basic publish/subscribe etc commands with /syntax +## - Show part of peerid to know who sent message +## - Deal with protobuf messages (e.g. other chat protocol, or encrypted) diff --git a/apps/chat2/config_chat2.nim b/apps/chat2/config_chat2.nim new file mode 100644 index 0000000..fe7865c --- /dev/null +++ b/apps/chat2/config_chat2.nim @@ -0,0 +1,351 @@ +import + chronicles, + chronos, + confutils, + confutils/defs, + confutils/std/net, + eth/keys, + libp2p/crypto/crypto, + libp2p/crypto/secp, + nimcrypto/utils, + std/strutils, + regex +import waku/waku_core + +type + Fleet* = enum + none + prod + test + + EthRpcUrl* = distinct string + + Chat2Conf* = object ## General node config + logLevel* {. + desc: "Sets the log level.", defaultValue: LogLevel.INFO, name: "log-level" + .}: LogLevel + + nodekey* {.desc: "P2P node private key as 64 char hex string.", name: "nodekey".}: + Option[crypto.PrivateKey] + + listenAddress* {. + defaultValue: defaultListenAddress(config), + desc: "Listening address for the LibP2P traffic.", + name: "listen-address" + .}: IpAddress + + tcpPort* {.desc: "TCP listening port.", defaultValue: 60000, name: "tcp-port".}: + Port + + udpPort* {.desc: "UDP listening port.", defaultValue: 60000, name: "udp-port".}: + Port + + portsShift* {. + desc: "Add a shift to all port numbers.", defaultValue: 0, name: "ports-shift" + .}: uint16 + + nat* {. + desc: + "Specify method to use for determining public address. " & + "Must be one of: any, none, upnp, pmp, extip:.", + defaultValue: "any" + .}: string + + ## Persistence config + dbPath* {. + desc: "The database path for peristent storage", defaultValue: "", name: "db-path" + .}: string + + persistPeers* {. + desc: "Enable peer persistence: true|false", + defaultValue: false, + name: "persist-peers" + .}: bool + + persistMessages* {. + desc: "Enable message persistence: true|false", + defaultValue: false, + name: "persist-messages" + .}: bool + + ## Relay config + relay* {. + desc: "Enable relay protocol: true|false", defaultValue: true, name: "relay" + .}: bool + + staticnodes* {. + desc: "Peer multiaddr to directly connect with. Argument may be repeated.", + name: "staticnode" + .}: seq[string] + + keepAlive* {. + desc: "Enable keep-alive for idle connections: true|false", + defaultValue: false, + name: "keep-alive" + .}: bool + + clusterId* {. + desc: + "Cluster id that the node is running in. Node in a different cluster id is disconnected.", + defaultValue: 0, + name: "cluster-id" + .}: uint16 + + shards* {. + desc: + "Shards index to subscribe to [0..NUM_SHARDS_IN_NETWORK-1]. Argument may be repeated.", + defaultValue: @[uint16(0)], + name: "shard" + .}: seq[uint16] + + ## Store config + store* {. + desc: "Enable store protocol: true|false", defaultValue: true, name: "store" + .}: bool + + storenode* {. + desc: "Peer multiaddr to query for storage.", defaultValue: "", name: "storenode" + .}: string + + ## Filter config + filter* {. + desc: "Enable filter protocol: true|false", defaultValue: false, name: "filter" + .}: bool + + filternode* {. + desc: "Peer multiaddr to request content filtering of messages.", + defaultValue: "", + name: "filternode" + .}: string + + ## Lightpush config + lightpush* {. + desc: "Enable lightpush protocol: true|false", + defaultValue: false, + name: "lightpush" + .}: bool + + lightpushnode* {. + desc: "Peer multiaddr to request lightpush of published messages.", + defaultValue: "", + name: "lightpushnode" + .}: string + + ## Metrics config + metricsServer* {. + desc: "Enable the metrics server: true|false", + defaultValue: false, + name: "metrics-server" + .}: bool + + metricsServerAddress* {. + desc: "Listening address of the metrics server.", + defaultValue: parseIpAddress("127.0.0.1"), + name: "metrics-server-address" + .}: IpAddress + + metricsServerPort* {. + desc: "Listening HTTP port of the metrics server.", + defaultValue: 8008, + name: "metrics-server-port" + .}: uint16 + + metricsLogging* {. + desc: "Enable metrics logging: true|false", + defaultValue: true, + name: "metrics-logging" + .}: bool + + ## DNS discovery config + dnsDiscovery* {. + desc: + "Deprecated, please set dns-discovery-url instead. Enable discovering nodes via DNS", + defaultValue: false, + name: "dns-discovery" + .}: bool + + dnsDiscoveryUrl* {. + desc: "URL for DNS node list in format 'enrtree://@'", + defaultValue: "", + name: "dns-discovery-url" + .}: string + + dnsAddrsNameServers* {. + desc: + "DNS name server IPs to query for DNS multiaddrs resolution. Argument may be repeated.", + defaultValue: @[parseIpAddress("1.1.1.1"), parseIpAddress("1.0.0.1")], + name: "dns-addrs-name-server" + .}: seq[IpAddress] + + ## Chat2 configuration + fleet* {. + desc: + "Select the fleet to connect to. This sets the DNS discovery URL to the selected fleet.", + defaultValue: Fleet.prod, + name: "fleet" + .}: Fleet + + contentTopic* {. + desc: "Content topic for chat messages.", + defaultValue: "/toy-chat/2/huilong/proto", + name: "content-topic" + .}: string + + ## Websocket Configuration + websocketSupport* {. + desc: "Enable websocket: true|false", + defaultValue: false, + name: "websocket-support" + .}: bool + + websocketPort* {. + desc: "WebSocket listening port.", defaultValue: 8000, name: "websocket-port" + .}: Port + + websocketSecureSupport* {. + desc: "WebSocket Secure Support.", + defaultValue: false, + name: "websocket-secure-support" + .}: bool + + ## rln-relay configuration + rlnRelay* {. + desc: "Enable spam protection through rln-relay: true|false", + defaultValue: false, + name: "rln-relay" + .}: bool + + rlnRelayChainId* {. + desc: + "Chain ID of the provided contract (optional, will fetch from RPC provider if not used)", + defaultValue: 0, + name: "rln-relay-chain-id" + .}: uint + + rlnRelayCredPath* {. + desc: "The path for peristing rln-relay credential", + defaultValue: "", + name: "rln-relay-cred-path" + .}: string + + rlnRelayCredIndex* {. + desc: "the index of the onchain commitment to use", name: "rln-relay-cred-index" + .}: Option[uint] + + rlnRelayDynamic* {. + desc: "Enable waku-rln-relay with on-chain dynamic group management: true|false", + defaultValue: false, + name: "rln-relay-dynamic" + .}: bool + + rlnRelayIdKey* {. + desc: "Rln relay identity secret key as a Hex string", + defaultValue: "", + name: "rln-relay-id-key" + .}: string + + rlnRelayIdCommitmentKey* {. + desc: "Rln relay identity commitment key as a Hex string", + defaultValue: "", + name: "rln-relay-id-commitment-key" + .}: string + + ethClientUrls* {. + desc: + "HTTP address of an Ethereum testnet client e.g., http://localhost:8540/. Argument may be repeated.", + defaultValue: newSeq[EthRpcUrl](0), + name: "rln-relay-eth-client-address" + .}: seq[EthRpcUrl] + + rlnRelayEthContractAddress* {. + desc: "Address of membership contract on an Ethereum testnet", + defaultValue: "", + name: "rln-relay-eth-contract-address" + .}: string + + rlnRelayCredPassword* {. + desc: "Password for encrypting RLN credentials", + defaultValue: "", + name: "rln-relay-cred-password" + .}: string + + rlnRelayUserMessageLimit* {. + desc: + "Set a user message limit for the rln membership registration. Must be a positive integer. Default is 1.", + defaultValue: 1, + name: "rln-relay-user-message-limit" + .}: uint64 + + rlnEpochSizeSec* {. + desc: + "Epoch size in seconds used to rate limit RLN memberships. Default is 1 second.", + defaultValue: 1, + name: "rln-relay-epoch-sec" + .}: uint64 + +# NOTE: Keys are different in nim-libp2p +proc parseCmdArg*(T: type crypto.PrivateKey, p: string): T = + try: + let key = SkPrivateKey.init(utils.fromHex(p)).tryGet() + # XXX: Here at the moment + result = crypto.PrivateKey(scheme: Secp256k1, skkey: key) + except CatchableError as e: + raise newException(ValueError, "Invalid private key") + +proc completeCmdArg*(T: type crypto.PrivateKey, val: string): seq[string] = + return @[] + +proc parseCmdArg*(T: type IpAddress, p: string): T = + try: + result = parseIpAddress(p) + except CatchableError as e: + raise newException(ValueError, "Invalid IP address") + +proc completeCmdArg*(T: type IpAddress, val: string): seq[string] = + return @[] + +proc parseCmdArg*(T: type Port, p: string): T = + try: + result = Port(parseInt(p)) + except CatchableError as e: + raise newException(ValueError, "Invalid Port number") + +proc completeCmdArg*(T: type Port, val: string): seq[string] = + return @[] + +proc parseCmdArg*(T: type Option[uint], p: string): T = + try: + some(parseUint(p)) + except CatchableError: + raise newException(ValueError, "Invalid unsigned integer") + +proc completeCmdArg*(T: type EthRpcUrl, val: string): seq[string] = + return @[] + +proc parseCmdArg*(T: type EthRpcUrl, s: string): T = + ## allowed patterns: + ## http://url:port + ## https://url:port + ## http://url:port/path + ## https://url:port/path + ## http://url/with/path + ## http://url:port/path?query + ## https://url:port/path?query + ## disallowed patterns: + ## any valid/invalid ws or wss url + var httpPattern = + re2"^(https?):\/\/((localhost)|([\w_-]+(?:(?:\.[\w_-]+)+)))(:[0-9]{1,5})?([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])*" + var wsPattern = + re2"^(wss?):\/\/((localhost)|([\w_-]+(?:(?:\.[\w_-]+)+)))(:[0-9]{1,5})?([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])*" + if regex.match(s, wsPattern): + raise newException( + ValueError, "Websocket RPC URL is not supported, Please use an HTTP URL" + ) + if not regex.match(s, httpPattern): + raise newException(ValueError, "Invalid HTTP RPC URL") + return EthRpcUrl(s) + +func defaultListenAddress*(conf: Chat2Conf): IpAddress = + # TODO: How should we select between IPv4 and IPv6 + # Maybe there should be a config option for this. + (static parseIpAddress("0.0.0.0")) diff --git a/apps/chat2/nim.cfg b/apps/chat2/nim.cfg new file mode 100644 index 0000000..2231f2e --- /dev/null +++ b/apps/chat2/nim.cfg @@ -0,0 +1,4 @@ +-d:chronicles_line_numbers +-d:chronicles_runtime_filtering:on +-d:discv5_protocol_id:d5waku +path = "../.." diff --git a/apps/chat2bridge/chat2bridge.nim b/apps/chat2bridge/chat2bridge.nim new file mode 100644 index 0000000..c2bf9c0 --- /dev/null +++ b/apps/chat2bridge/chat2bridge.nim @@ -0,0 +1,328 @@ +{.push raises: [].} + +import + std/[tables, times, strutils, hashes, sequtils, json], + chronos, + confutils, + chronicles, + chronicles/topics_registry, + chronos/streams/tlsstream, + metrics, + metrics/chronos_httpserver, + stew/byteutils, + eth/net/nat, + # Matterbridge client imports + # Waku v2 imports + libp2p/crypto/crypto, + libp2p/errors, + waku/[ + waku_core, + waku_node, + node/peer_manager, + waku_filter_v2, + waku_store, + factory/builder, + common/utils/matterbridge_client, + common/rate_limit/setting, + ], + # Chat 2 imports + ../chat2/chat2, + # Common cli config + ./config_chat2bridge + +declarePublicCounter chat2_mb_transfers, + "Number of messages transferred between chat2 and Matterbridge", ["type"] +declarePublicCounter chat2_mb_dropped, "Number of messages dropped", ["reason"] + +logScope: + topics = "chat2bridge" + +################## +# Default values # +################## + +const DeduplQSize = 20 # Maximum number of seen messages to keep in deduplication queue + +######### +# Types # +######### + +type + Chat2MatterBridge* = ref object of RootObj + mbClient*: MatterbridgeClient + nodev2*: WakuNode + running: bool + pollPeriod: chronos.Duration + seen: seq[Hash] #FIFO queue + contentTopic: string + + MbMessageHandler = proc(jsonNode: JsonNode) {.async.} + +################### +# Helper functions # +###################S + +proc containsOrAdd(sequence: var seq[Hash], hash: Hash): bool = + if sequence.contains(hash): + return true + + if sequence.len >= DeduplQSize: + trace "Deduplication queue full. Removing oldest item." + sequence.delete 0, 0 # Remove first item in queue + + sequence.add(hash) + + return false + +proc toWakuMessage( + cmb: Chat2MatterBridge, jsonNode: JsonNode +): WakuMessage {.raises: [Defect, KeyError].} = + # Translates a Matterbridge API JSON response to a Waku v2 message + let msgFields = jsonNode.getFields() + + # @TODO error handling here - verify expected fields + + let chat2pb = Chat2Message( + timestamp: getTime().toUnix(), # @TODO use provided timestamp + nick: msgFields["username"].getStr(), + payload: msgFields["text"].getStr().toBytes(), + ).encode() + + WakuMessage(payload: chat2pb.buffer, contentTopic: cmb.contentTopic, version: 0) + +proc toChat2(cmb: Chat2MatterBridge, jsonNode: JsonNode) {.async.} = + let msg = cmb.toWakuMessage(jsonNode) + + if cmb.seen.containsOrAdd(msg.payload.hash()): + # This is a duplicate message. Return. + chat2_mb_dropped.inc(labelValues = ["duplicate"]) + return + + trace "Post Matterbridge message to chat2" + + chat2_mb_transfers.inc(labelValues = ["mb_to_chat2"]) + + (await cmb.nodev2.publish(some(DefaultPubsubTopic), msg)).isOkOr: + error "failed to publish message", error = error + +proc toMatterbridge( + cmb: Chat2MatterBridge, msg: WakuMessage +) {.gcsafe, raises: [Exception].} = + if cmb.seen.containsOrAdd(msg.payload.hash()): + # This is a duplicate message. Return. + chat2_mb_dropped.inc(labelValues = ["duplicate"]) + return + + if msg.contentTopic != cmb.contentTopic: + # Only bridge messages on the configured content topic + chat2_mb_dropped.inc(labelValues = ["filtered"]) + return + + trace "Post chat2 message to Matterbridge" + + chat2_mb_transfers.inc(labelValues = ["chat2_to_mb"]) + + let chat2Msg = Chat2Message.init(msg.payload) + + assert chat2Msg.isOk + + let postRes = cmb.mbClient.postMessage( + text = string.fromBytes(chat2Msg[].payload), username = chat2Msg[].nick + ) + + if postRes.isErr() or (postRes[] == false): + chat2_mb_dropped.inc(labelValues = ["duplicate"]) + error "Matterbridge host unreachable. Dropping message." + +proc pollMatterbridge(cmb: Chat2MatterBridge, handler: MbMessageHandler) {.async.} = + while cmb.running: + let getRes = cmb.mbClient.getMessages() + + if getRes.isOk(): + for jsonNode in getRes[]: + await handler(jsonNode) + else: + error "Matterbridge host unreachable. Sleeping before retrying." + await sleepAsync(chronos.seconds(10)) + + await sleepAsync(cmb.pollPeriod) + +############## +# Public API # +############## +proc new*( + T: type Chat2MatterBridge, + # Matterbridge initialisation + mbHostUri: string, + mbGateway: string, + # NodeV2 initialisation + nodev2Key: crypto.PrivateKey, + nodev2BindIp: IpAddress, + nodev2BindPort: Port, + nodev2ExtIp = none[IpAddress](), + nodev2ExtPort = none[Port](), + contentTopic: string, +): T {. + raises: [Defect, ValueError, KeyError, TLSStreamProtocolError, IOError, LPError] +.} = + # Setup Matterbridge + let mbClient = MatterbridgeClient.new(mbHostUri, mbGateway) + + # Let's verify the Matterbridge configuration before continuing + let clientHealth = mbClient.isHealthy() + + if clientHealth.isOk() and clientHealth[]: + info "Reached Matterbridge host", host = mbClient.host + else: + raise newException(ValueError, "Matterbridge client not reachable/healthy") + + # Setup Waku v2 node + let nodev2 = block: + var builder = WakuNodeBuilder.init() + builder.withNodeKey(nodev2Key) + + builder + .withNetworkConfigurationDetails( + nodev2BindIp, nodev2BindPort, nodev2ExtIp, nodev2ExtPort + ) + .tryGet() + builder.build().tryGet() + + return Chat2MatterBridge( + mbClient: mbClient, + nodev2: nodev2, + running: false, + pollPeriod: chronos.seconds(1), + contentTopic: contentTopic, + ) + +proc start*(cmb: Chat2MatterBridge) {.async.} = + info "Starting Chat2MatterBridge" + + cmb.running = true + + debug "Start polling Matterbridge" + + # Start Matterbridge polling (@TODO: use streaming interface) + proc mbHandler(jsonNode: JsonNode) {.async.} = + trace "Bridging message from Matterbridge to chat2", jsonNode = jsonNode + waitFor cmb.toChat2(jsonNode) + + asyncSpawn cmb.pollMatterbridge(mbHandler) + + # Start Waku v2 node + debug "Start listening on Waku v2" + await cmb.nodev2.start() + + # Always mount relay for bridge + # `triggerSelf` is false on a `bridge` to avoid duplicates + (await cmb.nodev2.mountRelay()).isOkOr: + error "failed to mount relay", error = error + return + + cmb.nodev2.wakuRelay.triggerSelf = false + + # Bridging + # Handle messages on Waku v2 and bridge to Matterbridge + proc relayHandler( + pubsubTopic: PubsubTopic, msg: WakuMessage + ): Future[void] {.async.} = + trace "Bridging message from Chat2 to Matterbridge", msg = msg + try: + cmb.toMatterbridge(msg) + except: + error "exception in relayHandler: " & getCurrentExceptionMsg() + + cmb.nodev2.subscribe((kind: PubsubSub, topic: DefaultPubsubTopic), relayHandler).isOkOr: + error "failed to subscribe to relay", topic = DefaultPubsubTopic, error = error + return + +proc stop*(cmb: Chat2MatterBridge) {.async: (raises: [Exception]).} = + info "Stopping Chat2MatterBridge" + + cmb.running = false + + await cmb.nodev2.stop() + +{.pop.} + # @TODO confutils.nim(775, 17) Error: can raise an unlisted exception: ref IOError +when isMainModule: + import waku/common/utils/nat, waku/waku_api/message_cache + + let + rng = newRng() + conf = Chat2MatterbridgeConf.load() + + if conf.logLevel != LogLevel.NONE: + setLogLevel(conf.logLevel) + + let natRes = setupNat( + conf.nat, + clientId, + Port(uint16(conf.libp2pTcpPort) + conf.portsShift), + Port(uint16(conf.udpPort) + conf.portsShift), + ) + if natRes.isErr(): + error "Error in setupNat", error = natRes.error + + # Load address configuration + let + (nodev2ExtIp, nodev2ExtPort, _) = natRes.get() + ## The following heuristic assumes that, in absence of manual + ## config, the external port is the same as the bind port. + extPort = + if nodev2ExtIp.isSome() and nodev2ExtPort.isNone(): + some(Port(uint16(conf.libp2pTcpPort) + conf.portsShift)) + else: + nodev2ExtPort + + let bridge = Chat2Matterbridge.new( + mbHostUri = "http://" & $initTAddress(conf.mbHostAddress, Port(conf.mbHostPort)), + mbGateway = conf.mbGateway, + nodev2Key = conf.nodekey, + nodev2BindIp = conf.listenAddress, + nodev2BindPort = Port(uint16(conf.libp2pTcpPort) + conf.portsShift), + nodev2ExtIp = nodev2ExtIp, + nodev2ExtPort = extPort, + contentTopic = conf.contentTopic, + ) + + waitFor bridge.start() + + # Now load rest of config + # Mount configured Waku v2 protocols + waitFor mountLibp2pPing(bridge.nodev2) + + if conf.store: + waitFor mountStore(bridge.nodev2) + + if conf.filter: + waitFor mountFilter(bridge.nodev2) + + if conf.staticnodes.len > 0: + waitFor connectToNodes(bridge.nodev2, conf.staticnodes) + + if conf.storenode != "": + let storePeer = parsePeerInfo(conf.storenode) + if storePeer.isOk(): + bridge.nodev2.peerManager.addServicePeer(storePeer.value, WakuStoreCodec) + else: + error "Error parsing conf.storenode", error = storePeer.error + + if conf.filternode != "": + let filterPeer = parsePeerInfo(conf.filternode) + if filterPeer.isOk(): + bridge.nodev2.peerManager.addServicePeer( + filterPeer.value, WakuFilterSubscribeCodec + ) + else: + error "Error parsing conf.filternode", error = filterPeer.error + + if conf.metricsServer: + let + address = conf.metricsServerAddress + port = conf.metricsServerPort + conf.portsShift + info "Starting metrics HTTP server", address, port + startMetricsHttpServer($address, Port(port)) + + runForever() diff --git a/apps/chat2bridge/config_chat2bridge.nim b/apps/chat2bridge/config_chat2bridge.nim new file mode 100644 index 0000000..c7d8bb5 --- /dev/null +++ b/apps/chat2bridge/config_chat2bridge.nim @@ -0,0 +1,148 @@ +import + confutils, + confutils/defs, + confutils/std/net, + chronicles, + chronos, + libp2p/crypto/[crypto, secp], + eth/keys + +type Chat2MatterbridgeConf* = object + logLevel* {. + desc: "Sets the log level", defaultValue: LogLevel.INFO, name: "log-level" + .}: LogLevel + + listenAddress* {. + defaultValue: defaultListenAddress(config), + desc: "Listening address for the LibP2P traffic", + name: "listen-address" + .}: IpAddress + + libp2pTcpPort* {. + desc: "Libp2p TCP listening port (for Waku v2)", + defaultValue: 9000, + name: "libp2p-tcp-port" + .}: uint16 + + udpPort* {.desc: "UDP listening port", defaultValue: 9000, name: "udp-port".}: uint16 + + portsShift* {. + desc: "Add a shift to all default port numbers", + defaultValue: 0, + name: "ports-shift" + .}: uint16 + + nat* {. + desc: + "Specify method to use for determining public address. " & + "Must be one of: any, none, upnp, pmp, extip:", + defaultValue: "any" + .}: string + + metricsServer* {. + desc: "Enable the metrics server", defaultValue: false, name: "metrics-server" + .}: bool + + metricsServerAddress* {. + desc: "Listening address of the metrics server", + defaultValue: parseIpAddress("127.0.0.1"), + name: "metrics-server-address" + .}: IpAddress + + metricsServerPort* {. + desc: "Listening HTTP port of the metrics server", + defaultValue: 8008, + name: "metrics-server-port" + .}: uint16 + + ### Waku v2 options + staticnodes* {. + desc: "Multiaddr of peer to directly connect with. Argument may be repeated", + name: "staticnode" + .}: seq[string] + + nodekey* {. + desc: "P2P node private key as hex", + defaultValue: crypto.PrivateKey.random(Secp256k1, newRng()[]).tryGet(), + name: "nodekey" + .}: crypto.PrivateKey + + store* {. + desc: "Flag whether to start store protocol", defaultValue: true, name: "store" + .}: bool + + filter* {. + desc: "Flag whether to start filter protocol", defaultValue: false, name: "filter" + .}: bool + + relay* {. + desc: "Flag whether to start relay protocol", defaultValue: true, name: "relay" + .}: bool + + storenode* {. + desc: "Multiaddr of peer to connect with for waku store protocol", + defaultValue: "", + name: "storenode" + .}: string + + filternode* {. + desc: "Multiaddr of peer to connect with for waku filter protocol", + defaultValue: "", + name: "filternode" + .}: string + + # Matterbridge options + mbHostAddress* {. + desc: "Listening address of the Matterbridge host", + defaultValue: parseIpAddress("127.0.0.1"), + name: "mb-host-address" + .}: IpAddress + + mbHostPort* {. + desc: "Listening port of the Matterbridge host", + defaultValue: 4242, + name: "mb-host-port" + .}: uint16 + + mbGateway* {. + desc: "Matterbridge gateway", defaultValue: "gateway1", name: "mb-gateway" + .}: string + + ## Chat2 options + contentTopic* {. + desc: "Content topic to bridge chat messages to.", + defaultValue: "/toy-chat/2/huilong/proto", + name: "content-topic" + .}: string + +proc parseCmdArg*(T: type keys.KeyPair, p: string): T = + try: + let privkey = keys.PrivateKey.fromHex(string(p)).tryGet() + result = privkey.toKeyPair() + except CatchableError: + raise newException(ValueError, "Invalid private key") + +proc completeCmdArg*(T: type keys.KeyPair, val: string): seq[string] = + return @[] + +proc parseCmdArg*(T: type crypto.PrivateKey, p: string): T = + let key = SkPrivateKey.init(p) + if key.isOk(): + crypto.PrivateKey(scheme: Secp256k1, skkey: key.get()) + else: + raise newException(ValueError, "Invalid private key") + +proc completeCmdArg*(T: type crypto.PrivateKey, val: string): seq[string] = + return @[] + +proc parseCmdArg*(T: type IpAddress, p: string): T = + try: + result = parseIpAddress(p) + except CatchableError: + raise newException(ValueError, "Invalid IP address") + +proc completeCmdArg*(T: type IpAddress, val: string): seq[string] = + return @[] + +func defaultListenAddress*(conf: Chat2MatterbridgeConf): IpAddress = + (parseIpAddress("0.0.0.0")) diff --git a/apps/chat2bridge/nim.cfg b/apps/chat2bridge/nim.cfg new file mode 100644 index 0000000..2231f2e --- /dev/null +++ b/apps/chat2bridge/nim.cfg @@ -0,0 +1,4 @@ +-d:chronicles_line_numbers +-d:chronicles_runtime_filtering:on +-d:discv5_protocol_id:d5waku +path = "../.." diff --git a/apps/chat2mix/chat2mix.nim b/apps/chat2mix/chat2mix.nim new file mode 100644 index 0000000..e75ca75 --- /dev/null +++ b/apps/chat2mix/chat2mix.nim @@ -0,0 +1,703 @@ +## chat2 is an example of usage of Waku v2. For suggested usage options, please +## see dingpu tutorial in docs folder. + +when not (compileOption("threads")): + {.fatal: "Please, compile this program with the --threads:on option!".} + +{.push raises: [].} + +import std/[strformat, strutils, times, options, random, sequtils] +import + confutils, + chronicles, + chronos, + eth/keys, + bearssl, + results, + stew/[byteutils], + metrics, + metrics/chronos_httpserver +import + libp2p/[ + switch, # manage transports, a single entry point for dialing and listening + crypto/crypto, # cryptographic functions + stream/connection, # create and close stream read / write connections + multiaddress, + # encode different addressing schemes. For example, /ip4/7.7.7.7/tcp/6543 means it is using IPv4 protocol and TCP + peerinfo, + # manage the information of a peer, such as peer ID and public / private key + peerid, # Implement how peers interact + protobuf/minprotobuf, # message serialisation/deserialisation from and to protobufs + nameresolving/dnsresolver, + ] # define DNS resolution +import mix/curve25519 +import + waku/[ + waku_core, + waku_lightpush/common, + waku_lightpush/rpc, + waku_enr, + discovery/waku_dnsdisc, + waku_node, + node/waku_metrics, + node/peer_manager, + factory/builder, + common/utils/nat, + waku_store/common, + waku_filter_v2/client, + common/logging, + ], + ./config_chat2mix + +import libp2p/protocols/pubsub/rpc/messages, libp2p/protocols/pubsub/pubsub +import ../../waku/waku_rln_relay + +logScope: + topics = "chat2 mix" + +const Help = + """ + Commands: /[?|help|connect|nick|exit] + help: Prints this help + connect: dials a remote peer + nick: change nickname for current chat session + exit: exits chat session +""" + +# XXX Connected is a bit annoying, because incoming connections don't trigger state change +# Could poll connection pool or something here, I suppose +# TODO Ensure connected turns true on incoming connections, or get rid of it +type Chat = ref object + node: WakuNode # waku node for publishing, subscribing, etc + transp: StreamTransport # transport streams between read & write file descriptor + subscribed: bool # indicates if a node is subscribed or not to a topic + connected: bool # if the node is connected to another peer + started: bool # if the node has started + nick: string # nickname for this chat session + prompt: bool # chat prompt is showing + contentTopic: string # default content topic for chat messages + conf: Chat2Conf # configuration for chat2 + +type + PrivateKey* = crypto.PrivateKey + Topic* = waku_core.PubsubTopic + +##################### +## chat2 protobufs ## +##################### + +type + SelectResult*[T] = Result[T, string] + + Chat2Message* = object + timestamp*: int64 + nick*: string + payload*: seq[byte] + +proc getPubsubTopic*( + conf: Chat2Conf, node: WakuNode, contentTopic: string +): PubsubTopic = + let shard = node.wakuAutoSharding.get().getShard(contentTopic).valueOr: + echo "Could not parse content topic: " & error + return "" #TODO: fix this. + return $RelayShard(clusterId: conf.clusterId, shardId: shard.shardId) + +proc init*(T: type Chat2Message, buffer: seq[byte]): ProtoResult[T] = + var msg = Chat2Message() + let pb = initProtoBuffer(buffer) + + var timestamp: uint64 + discard ?pb.getField(1, timestamp) + msg.timestamp = int64(timestamp) + + discard ?pb.getField(2, msg.nick) + discard ?pb.getField(3, msg.payload) + + ok(msg) + +proc encode*(message: Chat2Message): ProtoBuffer = + var serialised = initProtoBuffer() + + serialised.write(1, uint64(message.timestamp)) + serialised.write(2, message.nick) + serialised.write(3, message.payload) + + return serialised + +proc toString*(message: Chat2Message): string = + # Get message date and timestamp in local time + let time = message.timestamp.fromUnix().local().format("'<'MMM' 'dd,' 'HH:mm'>'") + + return time & " " & message.nick & ": " & string.fromBytes(message.payload) + +##################### + +proc connectToNodes(c: Chat, nodes: seq[string]) {.async.} = + echo "Connecting to nodes" + await c.node.connectToNodes(nodes) + c.connected = true + +proc showChatPrompt(c: Chat) = + if not c.prompt: + try: + stdout.write(">> ") + stdout.flushFile() + c.prompt = true + except IOError: + discard + +proc getChatLine(c: Chat, msg: WakuMessage): Result[string, string] = + # No payload encoding/encryption from Waku + let + pb = Chat2Message.init(msg.payload) + chatLine = + if pb.isOk: + pb[].toString() + else: + string.fromBytes(msg.payload) + return ok(chatline) + +proc printReceivedMessage(c: Chat, msg: WakuMessage) = + let + pb = Chat2Message.init(msg.payload) + chatLine = + if pb.isOk: + pb[].toString() + else: + string.fromBytes(msg.payload) + try: + echo &"{chatLine}" + except ValueError: + # Formatting fail. Print chat line in any case. + echo chatLine + + c.prompt = false + showChatPrompt(c) + trace "Printing message", chatLine, contentTopic = msg.contentTopic + +proc readNick(transp: StreamTransport): Future[string] {.async.} = + # Chat prompt + stdout.write("Choose a nickname >> ") + stdout.flushFile() + return await transp.readLine() + +proc startMetricsServer( + serverIp: IpAddress, serverPort: Port +): Result[MetricsHttpServerRef, string] = + info "Starting metrics HTTP server", serverIp = $serverIp, serverPort = $serverPort + + let metricsServerRes = MetricsHttpServerRef.new($serverIp, serverPort) + if metricsServerRes.isErr(): + return err("metrics HTTP server start failed: " & $metricsServerRes.error) + + let server = metricsServerRes.value + try: + waitFor server.start() + except CatchableError: + return err("metrics HTTP server start failed: " & getCurrentExceptionMsg()) + + info "Metrics HTTP server started", serverIp = $serverIp, serverPort = $serverPort + ok(metricsServerRes.value) + +proc publish(c: Chat, line: string) {.async.} = + # First create a Chat2Message protobuf with this line of text + let time = getTime().toUnix() + let chat2pb = + Chat2Message(timestamp: time, nick: c.nick, payload: line.toBytes()).encode() + + ## @TODO: error handling on failure + proc handler(response: LightPushResponse) {.gcsafe, closure.} = + trace "lightpush response received", response = response + + var message = WakuMessage( + payload: chat2pb.buffer, + contentTopic: c.contentTopic, + version: 0, + timestamp: getNanosecondTime(time), + ) + + try: + if not c.node.wakuLightpushClient.isNil(): + # Attempt lightpush with mix + + ( + waitFor c.node.lightpushPublish( + some(c.conf.getPubsubTopic(c.node, c.contentTopic)), + message, + none(RemotePeerInfo), + true, + ) + ).isOkOr: + error "failed to publish lightpush message", error = error + else: + error "failed to publish message as lightpush client is not initialized" + except CatchableError: + error "caught error publishing message: ", error = getCurrentExceptionMsg() + +# TODO This should read or be subscribe handler subscribe +proc readAndPrint(c: Chat) {.async.} = + while true: + # while p.connected: + # # TODO: echo &"{p.id} -> " + # + # echo cast[string](await p.conn.readLp(1024)) + #echo "readAndPrint subscribe NYI" + await sleepAsync(100) + +# TODO Implement +proc writeAndPrint(c: Chat) {.async.} = + while true: + # Connect state not updated on incoming WakuRelay connections + # if not c.connected: + # echo "type an address or wait for a connection:" + # echo "type /[help|?] for help" + + # Chat prompt + showChatPrompt(c) + + let line = await c.transp.readLine() + if line.startsWith("/help") or line.startsWith("/?") or not c.started: + echo Help + continue + + # if line.startsWith("/disconnect"): + # echo "Ending current session" + # if p.connected and p.conn.closed.not: + # await p.conn.close() + # p.connected = false + elif line.startsWith("/connect"): + # TODO Should be able to connect to multiple peers for Waku chat + if c.connected: + echo "already connected to at least one peer" + continue + + echo "enter address of remote peer" + let address = await c.transp.readLine() + if address.len > 0: + await c.connectToNodes(@[address]) + elif line.startsWith("/nick"): + # Set a new nickname + c.nick = await readNick(c.transp) + echo "You are now known as " & c.nick + elif line.startsWith("/exit"): + echo "quitting..." + + try: + await c.node.stop() + except: + echo "exception happened when stopping: " & getCurrentExceptionMsg() + + quit(QuitSuccess) + else: + # XXX connected state problematic + if c.started: + echo "publishing message: " & line + await c.publish(line) + # TODO Connect to peer logic? + else: + try: + if line.startsWith("/") and "p2p" in line: + await c.connectToNodes(@[line]) + except: + echo &"unable to dial remote peer {line}" + echo getCurrentExceptionMsg() + +proc readWriteLoop(c: Chat) {.async.} = + asyncSpawn c.writeAndPrint() # execute the async function but does not block + asyncSpawn c.readAndPrint() + +proc readInput(wfd: AsyncFD) {.thread, raises: [Defect, CatchableError].} = + ## This procedure performs reading from `stdin` and sends data over + ## pipe to main thread. + let transp = fromPipe(wfd) + + while true: + let line = stdin.readLine() + discard waitFor transp.write(line & "\r\n") + +var alreadyUsedServicePeers {.threadvar.}: seq[RemotePeerInfo] + +proc selectRandomServicePeer*( + pm: PeerManager, actualPeer: Option[RemotePeerInfo], codec: string +): Result[RemotePeerInfo, void] = + if actualPeer.isSome(): + alreadyUsedServicePeers.add(actualPeer.get()) + + let supportivePeers = pm.switch.peerStore.getPeersByProtocol(codec).filterIt( + it notin alreadyUsedServicePeers + ) + if supportivePeers.len == 0: + return err() + + let rndPeerIndex = rand(0 .. supportivePeers.len - 1) + return ok(supportivePeers[rndPeerIndex]) + +proc maintainSubscription( + wakuNode: WakuNode, + filterPubsubTopic: PubsubTopic, + filterContentTopic: ContentTopic, + filterPeer: RemotePeerInfo, + preventPeerSwitch: bool, +) {.async.} = + var actualFilterPeer = filterPeer + const maxFailedSubscribes = 3 + const maxFailedServiceNodeSwitches = 10 + var noFailedSubscribes = 0 + var noFailedServiceNodeSwitches = 0 + while true: + info "maintaining subscription at", peer = constructMultiaddrStr(actualFilterPeer) + # First use filter-ping to check if we have an active subscription + let pingRes = await wakuNode.wakuFilterClient.ping(actualFilterPeer) + if pingRes.isErr(): + # No subscription found. Let's subscribe. + error "ping failed.", err = pingRes.error + trace "no subscription found. Sending subscribe request" + + let subscribeRes = await wakuNode.filterSubscribe( + some(filterPubsubTopic), filterContentTopic, actualFilterPeer + ) + + if subscribeRes.isErr(): + noFailedSubscribes += 1 + error "Subscribe request failed.", + err = subscribeRes.error, + peer = actualFilterPeer, + failCount = noFailedSubscribes + + # TODO: disconnet from failed actualFilterPeer + # asyncSpawn(wakuNode.peerManager.switch.disconnect(p)) + # wakunode.peerManager.peerStore.delete(actualFilterPeer) + + if noFailedSubscribes < maxFailedSubscribes: + await sleepAsync(2000) # Wait a bit before retrying + continue + elif not preventPeerSwitch: + let peerOpt = selectRandomServicePeer( + wakuNode.peerManager, some(actualFilterPeer), WakuFilterSubscribeCodec + ) + if peerOpt.isOk(): + actualFilterPeer = peerOpt.get() + + info "Found new peer for codec", + codec = filterPubsubTopic, peer = constructMultiaddrStr(actualFilterPeer) + + noFailedSubscribes = 0 + continue # try again with new peer without delay + else: + error "Failed to find new service peer. Exiting." + noFailedServiceNodeSwitches += 1 + break + else: + if noFailedSubscribes > 0: + noFailedSubscribes -= 1 + + notice "subscribe request successful." + else: + info "subscription is live." + + await sleepAsync(30000) # Subscription maintenance interval + +proc processMixNodes(localnode: WakuNode, nodes: seq[string]) {.async.} = + if nodes.len == 0: + return + + info "Processing mix nodes: ", nodes = $nodes + for node in nodes: + var enrRec: enr.Record + if enrRec.fromURI(node): + let peerInfo = enrRec.toRemotePeerInfo().valueOr: + error "Failed to parse mix node", error = error + continue + localnode.peermanager.addPeer(peerInfo, Discv5) + info "Added mix node", peer = peerInfo + else: + error "Failed to parse mix node ENR", node = node + +{.pop.} + # @TODO confutils.nim(775, 17) Error: can raise an unlisted exception: ref IOError +proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} = + let + transp = fromPipe(rfd) + conf = Chat2Conf.load() + nodekey = + if conf.nodekey.isSome(): + conf.nodekey.get() + else: + PrivateKey.random(Secp256k1, rng[]).tryGet() + + # set log level + if conf.logLevel != LogLevel.NONE: + setLogLevel(conf.logLevel) + + let natRes = setupNat( + conf.nat, + clientId, + Port(uint16(conf.tcpPort) + conf.portsShift), + Port(uint16(conf.udpPort) + conf.portsShift), + ) + + if natRes.isErr(): + raise newException(ValueError, "setupNat error " & natRes.error) + + let (extIp, extTcpPort, extUdpPort) = natRes.get() + + var enrBuilder = EnrBuilder.init(nodeKey) + + enrBuilder.withWakuRelaySharding( + RelayShards(clusterId: conf.clusterId, shardIds: conf.shards) + ).isOkOr: + error "failed to add sharded topics to ENR", error = error + quit(QuitFailure) + + let recordRes = enrBuilder.build() + let record = + if recordRes.isErr(): + error "failed to create enr record", error = recordRes.error + quit(QuitFailure) + else: + recordRes.get() + + let node = block: + var builder = WakuNodeBuilder.init() + builder.withNodeKey(nodeKey) + builder.withRecord(record) + + builder + .withNetworkConfigurationDetails( + conf.listenAddress, + Port(uint16(conf.tcpPort) + conf.portsShift), + extIp, + extTcpPort, + wsBindPort = Port(uint16(conf.websocketPort) + conf.portsShift), + wsEnabled = conf.websocketSupport, + wssEnabled = conf.websocketSecureSupport, + ) + .tryGet() + builder.build().tryGet() + + node.mountAutoSharding(conf.clusterId, conf.numShardsInNetwork).isOkOr: + error "failed to mount waku sharding: ", error = error + quit(QuitFailure) + node.mountMetadata(conf.clusterId, conf.shards).isOkOr: + error "failed to mount waku metadata protocol: ", err = error + quit(QuitFailure) + + let (mixPrivKey, mixPubKey) = generateKeyPair().valueOr: + error "failed to generate mix key pair", error = error + return + + (await node.mountMix(conf.clusterId, mixPrivKey)).isOkOr: + error "failed to mount waku mix protocol: ", error = $error + quit(QuitFailure) + if conf.mixnodes.len > 0: + await processMixNodes(node, conf.mixnodes) + await node.start() + + node.peerManager.start() + + await node.mountLibp2pPing() + await node.mountPeerExchangeClient() + let pubsubTopic = conf.getPubsubTopic(node, conf.contentTopic) + echo "pubsub topic is: " & pubsubTopic + let nick = await readNick(transp) + echo "Welcome, " & nick & "!" + + var chat = Chat( + node: node, + transp: transp, + subscribed: true, + connected: false, + started: true, + nick: nick, + prompt: false, + contentTopic: conf.contentTopic, + conf: conf, + ) + + var dnsDiscoveryUrl = 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( + "enrtree://AOGYWMBYOUIMOENHXCHILPKY3ZRFEULMFI4DOM442QSZ73TT2A7VI@test.waku.nodes.status.im" + ) + else: + # Connect to sandbox by default + dnsDiscoveryUrl = some( + "enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im" + ) + elif conf.dnsDiscoveryUrl != "": + # No pre-selected fleet. Discover nodes via DNS using user config + debug "Discovering nodes using Waku DNS discovery", url = conf.dnsDiscoveryUrl + dnsDiscoveryUrl = some(conf.dnsDiscoveryUrl) + + var discoveredNodes: seq[RemotePeerInfo] + + if dnsDiscoveryUrl.isSome: + var nameServers: seq[TransportAddress] + for ip in conf.dnsDiscoveryNameServers: + nameServers.add(initTAddress(ip, Port(53))) # Assume all servers use port 53 + + let dnsResolver = DnsResolver.new(nameServers) + + proc resolver(domain: string): Future[string] {.async, gcsafe.} = + trace "resolving", domain = domain + let resolved = await dnsResolver.resolveTxt(domain) + return resolved[0] # Use only first answer + + var wakuDnsDiscovery = WakuDnsDiscovery.init(dnsDiscoveryUrl.get(), resolver) + if wakuDnsDiscovery.isOk: + let discoveredPeers = await wakuDnsDiscovery.get().findPeers() + if discoveredPeers.isOk: + info "Connecting to discovered peers" + discoveredNodes = discoveredPeers.get() + echo "Discovered and connecting to " & $discoveredNodes + waitFor chat.node.connectToNodes(discoveredNodes) + else: + warn "Failed to init Waku DNS discovery" + + let peerInfo = node.switch.peerInfo + let listenStr = $peerInfo.addrs[0] & "/p2p/" & $peerInfo.peerId + echo &"Listening on\n {listenStr}" + + if (conf.storenode != "") or (conf.store == true): + await node.mountStore() + + var storenode: Option[RemotePeerInfo] + + if conf.storenode != "": + let peerInfo = parsePeerInfo(conf.storenode) + if peerInfo.isOk(): + storenode = 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)]) + + if storenode.isSome(): + # We have a viable storenode. Let's query it for historical messages. + echo "Connecting to storenode: " & $(storenode.get()) + + node.mountStoreClient() + node.peerManager.addServicePeer(storenode.get(), WakuStoreCodec) + + proc storeHandler(response: StoreQueryResponse) {.gcsafe.} = + for msg in response.messages: + let payload = + if msg.message.isSome(): + msg.message.get().payload + else: + newSeq[byte](0) + + let + pb = Chat2Message.init(payload) + chatLine = + if pb.isOk: + pb[].toString() + else: + string.fromBytes(payload) + echo &"{chatLine}" + info "Hit store handler" + + let queryRes = await node.query( + StoreQueryRequest(contentTopics: @[chat.contentTopic]), storenode.get() + ) + if queryRes.isOk(): + storeHandler(queryRes.value) + + if conf.edgemode: #Mount light protocol clients + node.mountLightPushClient() + await node.mountFilterClient() + let filterHandler = proc( + pubsubTopic: PubsubTopic, msg: WakuMessage + ): Future[void] {.async, closure.} = + trace "Hit filter handler", contentTopic = msg.contentTopic + chat.printReceivedMessage(msg) + + node.wakuFilterClient.registerPushHandler(filterHandler) + var servicePeerInfo: RemotePeerInfo + if conf.serviceNode != "": + servicePeerInfo = parsePeerInfo(conf.serviceNode).valueOr: + error "Couldn't parse conf.serviceNode", error = error + RemotePeerInfo() + if $servicePeerInfo.peerId == "": + # Assuming that service node supports all services + servicePeerInfo = selectRandomServicePeer( + node.peerManager, none(RemotePeerInfo), WakuLightpushCodec + ).valueOr: + error "Couldn't find any service peer" + quit(QuitFailure) + + #await mountLegacyLightPush(node) + node.peerManager.addServicePeer(servicePeerInfo, WakuLightpushCodec) + node.peerManager.addServicePeer(servicePeerInfo, WakuPeerExchangeCodec) + + # Start maintaining subscription + asyncSpawn maintainSubscription( + node, pubsubTopic, conf.contentTopic, servicePeerInfo, false + ) + echo "waiting for mix nodes to be discovered..." + while true: + if node.getMixNodePoolSize() >= 3: + break + discard await node.fetchPeerExchangePeers() + await sleepAsync(1000) + + while node.getMixNodePoolSize() < 3: + info "waiting for mix nodes to be discovered", + currentpoolSize = node.getMixNodePoolSize() + await sleepAsync(1000) + notice "ready to publish with mix node pool size ", + currentpoolSize = node.getMixNodePoolSize() + echo "ready to publish messages now" + + # Once min mixnodes are discovered loop as per default setting + node.startPeerExchangeLoop() + + if conf.metricsLogging: + startMetricsLog() + + if conf.metricsServer: + let metricsServer = startMetricsServer( + conf.metricsServerAddress, Port(conf.metricsServerPort + conf.portsShift) + ) + + await chat.readWriteLoop() + + runForever() + +proc main(rng: ref HmacDrbgContext) {.async.} = + let (rfd, wfd) = createAsyncPipe() + if rfd == asyncInvalidPipe or wfd == asyncInvalidPipe: + raise newException(ValueError, "Could not initialize pipe!") + + var thread: Thread[AsyncFD] + thread.createThread(readInput, wfd) + try: + await processInput(rfd, rng) + # Handle only ConfigurationError for now + # TODO: Throw other errors from the mounting procedure + except ConfigurationError as e: + raise e + +when isMainModule: # isMainModule = true when the module is compiled as the main file + let rng = crypto.newRng() + try: + waitFor(main(rng)) + except CatchableError as e: + raise e + +## Dump of things that can be improved: +## +## - Incoming dialed peer does not change connected state (not relying on it for now) +## - Unclear if staticnode argument works (can enter manually) +## - Don't trigger self / double publish own messages +## - Test/default to cluster node connection (diff protocol version) +## - Redirect logs to separate file +## - Expose basic publish/subscribe etc commands with /syntax +## - Show part of peerid to know who sent message +## - Deal with protobuf messages (e.g. other chat protocol, or encrypted) diff --git a/apps/chat2mix/config_chat2mix.nim b/apps/chat2mix/config_chat2mix.nim new file mode 100644 index 0000000..1d28149 --- /dev/null +++ b/apps/chat2mix/config_chat2mix.nim @@ -0,0 +1,293 @@ +import chronicles, chronos, std/strutils, regex + +import + eth/keys, + libp2p/crypto/crypto, + libp2p/crypto/secp, + nimcrypto/utils, + confutils, + confutils/defs, + confutils/std/net + +import waku/waku_core + +type + Fleet* = enum + none + sandbox + test + + EthRpcUrl* = distinct string + + Chat2Conf* = object ## General node config + edgemode* {. + defaultValue: true, desc: "Run the app in edge mode", name: "edge-mode" + .}: bool + + logLevel* {. + desc: "Sets the log level.", defaultValue: LogLevel.INFO, name: "log-level" + .}: LogLevel + + nodekey* {.desc: "P2P node private key as 64 char hex string.", name: "nodekey".}: + Option[crypto.PrivateKey] + + listenAddress* {. + defaultValue: defaultListenAddress(config), + desc: "Listening address for the LibP2P traffic.", + name: "listen-address" + .}: IpAddress + + tcpPort* {.desc: "TCP listening port.", defaultValue: 60000, name: "tcp-port".}: + Port + + udpPort* {.desc: "UDP listening port.", defaultValue: 60000, name: "udp-port".}: + Port + + portsShift* {. + desc: "Add a shift to all port numbers.", defaultValue: 0, name: "ports-shift" + .}: uint16 + + nat* {. + desc: + "Specify method to use for determining public address. " & + "Must be one of: any, none, upnp, pmp, extip:.", + defaultValue: "any" + .}: string + + ## Persistence config + dbPath* {. + desc: "The database path for peristent storage", defaultValue: "", name: "db-path" + .}: string + + persistPeers* {. + desc: "Enable peer persistence: true|false", + defaultValue: false, + name: "persist-peers" + .}: bool + + persistMessages* {. + desc: "Enable message persistence: true|false", + defaultValue: false, + name: "persist-messages" + .}: bool + + ## Relay config + relay* {. + desc: "Enable relay protocol: true|false", defaultValue: true, name: "relay" + .}: bool + + staticnodes* {. + desc: "Peer multiaddr to directly connect with. Argument may be repeated.", + name: "staticnode", + defaultValue: @[] + .}: seq[string] + + mixnodes* {. + desc: "Peer ENR to add as a mixnode. Argument may be repeated.", name: "mixnode" + .}: seq[string] + + keepAlive* {. + desc: "Enable keep-alive for idle connections: true|false", + defaultValue: false, + name: "keep-alive" + .}: bool + + clusterId* {. + desc: + "Cluster id that the node is running in. Node in a different cluster id is disconnected.", + defaultValue: 1, + name: "cluster-id" + .}: uint16 + + numShardsInNetwork* {. + desc: "Number of shards in the network", + defaultValue: 8, + name: "num-shards-in-network" + .}: uint32 + + shards* {. + desc: + "Shards index to subscribe to [0..NUM_SHARDS_IN_NETWORK-1]. Argument may be repeated.", + defaultValue: + @[ + uint16(0), + uint16(1), + uint16(2), + uint16(3), + uint16(4), + uint16(5), + uint16(6), + uint16(7), + ], + name: "shard" + .}: seq[uint16] + + ## Store config + store* {. + desc: "Enable store protocol: true|false", defaultValue: false, name: "store" + .}: bool + + storenode* {. + desc: "Peer multiaddr to query for storage.", defaultValue: "", name: "storenode" + .}: string + + ## Filter config + filter* {. + desc: "Enable filter protocol: true|false", defaultValue: false, name: "filter" + .}: bool + + ## Lightpush config + lightpush* {. + desc: "Enable lightpush protocol: true|false", + defaultValue: false, + name: "lightpush" + .}: bool + + servicenode* {. + desc: "Peer multiaddr to request lightpush and filter services", + defaultValue: "", + name: "servicenode" + .}: string + + ## Metrics config + metricsServer* {. + desc: "Enable the metrics server: true|false", + defaultValue: false, + name: "metrics-server" + .}: bool + + metricsServerAddress* {. + desc: "Listening address of the metrics server.", + defaultValue: parseIpAddress("127.0.0.1"), + name: "metrics-server-address" + .}: IpAddress + + metricsServerPort* {. + desc: "Listening HTTP port of the metrics server.", + defaultValue: 8008, + name: "metrics-server-port" + .}: uint16 + + metricsLogging* {. + desc: "Enable metrics logging: true|false", + defaultValue: true, + name: "metrics-logging" + .}: bool + + ## DNS discovery config + dnsDiscovery* {. + desc: + "Deprecated, please set dns-discovery-url instead. Enable discovering nodes via DNS", + defaultValue: false, + name: "dns-discovery" + .}: bool + + dnsDiscoveryUrl* {. + desc: "URL for DNS node list in format 'enrtree://@'", + defaultValue: "", + name: "dns-discovery-url" + .}: string + + dnsDiscoveryNameServers* {. + desc: "DNS name server IPs to query. Argument may be repeated.", + defaultValue: @[parseIpAddress("1.1.1.1"), parseIpAddress("1.0.0.1")], + name: "dns-discovery-name-server" + .}: seq[IpAddress] + + ## Chat2 configuration + fleet* {. + desc: + "Select the fleet to connect to. This sets the DNS discovery URL to the selected fleet.", + defaultValue: Fleet.test, + name: "fleet" + .}: Fleet + + contentTopic* {. + desc: "Content topic for chat messages.", + defaultValue: "/toy-chat-mix/2/huilong/proto", + name: "content-topic" + .}: string + + ## Websocket Configuration + websocketSupport* {. + desc: "Enable websocket: true|false", + defaultValue: false, + name: "websocket-support" + .}: bool + + websocketPort* {. + desc: "WebSocket listening port.", defaultValue: 8000, name: "websocket-port" + .}: Port + + websocketSecureSupport* {. + desc: "WebSocket Secure Support.", + defaultValue: false, + name: "websocket-secure-support" + .}: bool ## rln-relay configuration + +# NOTE: Keys are different in nim-libp2p +proc parseCmdArg*(T: type crypto.PrivateKey, p: string): T = + try: + let key = SkPrivateKey.init(utils.fromHex(p)).tryGet() + # XXX: Here at the moment + result = crypto.PrivateKey(scheme: Secp256k1, skkey: key) + except CatchableError as e: + raise newException(ValueError, "Invalid private key") + +proc completeCmdArg*(T: type crypto.PrivateKey, val: string): seq[string] = + return @[] + +proc parseCmdArg*(T: type IpAddress, p: string): T = + try: + result = parseIpAddress(p) + except CatchableError as e: + raise newException(ValueError, "Invalid IP address") + +proc completeCmdArg*(T: type IpAddress, val: string): seq[string] = + return @[] + +proc parseCmdArg*(T: type Port, p: string): T = + try: + result = Port(parseInt(p)) + except CatchableError as e: + raise newException(ValueError, "Invalid Port number") + +proc completeCmdArg*(T: type Port, val: string): seq[string] = + return @[] + +proc parseCmdArg*(T: type Option[uint], p: string): T = + try: + some(parseUint(p)) + except CatchableError: + raise newException(ValueError, "Invalid unsigned integer") + +proc completeCmdArg*(T: type EthRpcUrl, val: string): seq[string] = + return @[] + +proc parseCmdArg*(T: type EthRpcUrl, s: string): T = + ## allowed patterns: + ## http://url:port + ## https://url:port + ## http://url:port/path + ## https://url:port/path + ## http://url/with/path + ## http://url:port/path?query + ## https://url:port/path?query + ## disallowed patterns: + ## any valid/invalid ws or wss url + var httpPattern = + re2"^(https?):\/\/((localhost)|([\w_-]+(?:(?:\.[\w_-]+)+)))(:[0-9]{1,5})?([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])*" + var wsPattern = + re2"^(wss?):\/\/((localhost)|([\w_-]+(?:(?:\.[\w_-]+)+)))(:[0-9]{1,5})?([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])*" + if regex.match(s, wsPattern): + raise newException( + ValueError, "Websocket RPC URL is not supported, Please use an HTTP URL" + ) + if not regex.match(s, httpPattern): + raise newException(ValueError, "Invalid HTTP RPC URL") + return EthRpcUrl(s) + +func defaultListenAddress*(conf: Chat2Conf): IpAddress = + # TODO: How should we select between IPv4 and IPv6 + # Maybe there should be a config option for this. + (static parseIpAddress("0.0.0.0")) diff --git a/apps/chat2mix/nim.cfg b/apps/chat2mix/nim.cfg new file mode 100644 index 0000000..2231f2e --- /dev/null +++ b/apps/chat2mix/nim.cfg @@ -0,0 +1,4 @@ +-d:chronicles_line_numbers +-d:chronicles_runtime_filtering:on +-d:discv5_protocol_id:d5waku +path = "../.." diff --git a/apps/liteprotocoltester/.env b/apps/liteprotocoltester/.env new file mode 100644 index 0000000..0330284 --- /dev/null +++ b/apps/liteprotocoltester/.env @@ -0,0 +1,27 @@ +START_PUBLISHING_AFTER_SECS=45 +# can add some seconds delay before SENDER starts publishing + +NUM_MESSAGES=0 +# 0 for infinite number of messages + +MESSAGE_INTERVAL_MILLIS=8000 +# ms delay between messages + + +MIN_MESSAGE_SIZE=15Kb +MAX_MESSAGE_SIZE=145Kb + +## for wakusim +#SHARD=0 +#CONTENT_TOPIC=/tester/2/light-pubsub-test/wakusim +#CLUSTER_ID=66 + +## for status.prod +#SHARDS=32 +CONTENT_TOPIC=/tester/2/light-pubsub-test/fleet +CLUSTER_ID=16 + +## for TWN +#SHARD=4 +#CONTENT_TOPIC=/tester/2/light-pubsub-test/twn +#CLUSTER_ID=1 diff --git a/apps/liteprotocoltester/Dockerfile.liteprotocoltester b/apps/liteprotocoltester/Dockerfile.liteprotocoltester new file mode 100644 index 0000000..1948300 --- /dev/null +++ b/apps/liteprotocoltester/Dockerfile.liteprotocoltester @@ -0,0 +1,37 @@ + # TESTING IMAGE -------------------------------------------------------------- + + ## NOTICE: This is a short cut build file for ubuntu users who compiles nwaku in ubuntu distro. + ## This is used for faster turnaround time for testing the compiled binary. + ## Prerequisites: compiled liteprotocoltester binary in build/ directory + + FROM ubuntu:noble AS prod + + LABEL maintainer="zoltan@status.im" + LABEL source="https://github.com/waku-org/nwaku" + LABEL description="Lite Protocol Tester: Waku light-client" + LABEL commit="unknown" + LABEL version="unknown" + + # DevP2P, LibP2P, and JSON RPC ports + EXPOSE 30303 60000 8545 + + # Referenced in the binary + RUN apt-get update && apt-get install -y --no-install-recommends \ + libgcc1 \ + libpcre3 \ + libpq-dev \ + wget \ + iproute2 \ + && rm -rf /var/lib/apt/lists/* + + # Fix for 'Error loading shared library libpcre.so.3: No such file or directory' + RUN ln -s /usr/lib/libpcre.so /usr/lib/libpcre.so.3 + + COPY build/liteprotocoltester /usr/bin/ + COPY apps/liteprotocoltester/run_tester_node.sh /usr/bin/ + COPY apps/liteprotocoltester/run_tester_node_on_fleet.sh /usr/bin/ + + ENTRYPOINT ["/usr/bin/run_tester_node.sh", "/usr/bin/liteprotocoltester"] + + # # By default just show help if called without arguments + CMD ["--help"] diff --git a/apps/liteprotocoltester/Dockerfile.liteprotocoltester.compile b/apps/liteprotocoltester/Dockerfile.liteprotocoltester.compile new file mode 100644 index 0000000..497570c --- /dev/null +++ b/apps/liteprotocoltester/Dockerfile.liteprotocoltester.compile @@ -0,0 +1,76 @@ +# BUILD NIM APP ---------------------------------------------------------------- +FROM rust:1.77.1-alpine3.18 AS nim-build + +ARG NIMFLAGS +ARG MAKE_TARGET=liteprotocoltester +ARG NIM_COMMIT +ARG LOG_LEVEL=TRACE + +# Get build tools and required header files +RUN apk add --no-cache bash git build-base openssl-dev linux-headers curl jq + +WORKDIR /app +COPY . . + +# workaround for alpine issue: https://github.com/alpinelinux/docker-alpine/issues/383 +RUN apk update && apk upgrade + +# Ran separately from 'make' to avoid re-doing +RUN git submodule update --init --recursive + +# Slowest build step for the sake of caching layers +RUN make -j$(nproc) deps QUICK_AND_DIRTY_COMPILER=1 ${NIM_COMMIT} + +# Build the final node binary +RUN make -j$(nproc) ${NIM_COMMIT} $MAKE_TARGET LOG_LEVEL=${LOG_LEVEL} NIMFLAGS="${NIMFLAGS}" + + +# REFERENCE IMAGE as BASE for specialized PRODUCTION IMAGES---------------------------------------- +FROM alpine:3.18 AS base_lpt + +ARG MAKE_TARGET=liteprotocoltester + +LABEL maintainer="zoltan@status.im" +LABEL source="https://github.com/waku-org/nwaku" +LABEL description="Lite Protocol Tester: Waku light-client" +LABEL commit="unknown" +LABEL version="unknown" + +# DevP2P, LibP2P, and JSON RPC ports +EXPOSE 30303 60000 8545 + +# Referenced in the binary +RUN apk add --no-cache libgcc libpq-dev \ + wget \ + iproute2 \ + python3 + +# Fix for 'Error loading shared library libpcre.so.3: No such file or directory' +RUN ln -s /usr/lib/libpcre.so /usr/lib/libpcre.so.3 + +COPY --from=nim-build /app/build/liteprotocoltester /usr/bin/ +RUN chmod +x /usr/bin/liteprotocoltester + +# Standalone image to be used manually and in lpt-runner ------------------------------------------- +FROM base_lpt AS standalone_lpt + +COPY --from=nim-build /app/apps/liteprotocoltester/run_tester_node.sh /usr/bin/ +COPY --from=nim-build /app/apps/liteprotocoltester/run_tester_node_on_fleet.sh /usr/bin/ + +RUN chmod +x /usr/bin/run_tester_node.sh + +ENTRYPOINT ["/usr/bin/run_tester_node.sh", "/usr/bin/liteprotocoltester"] + +# Image for infra deployment ------------------------------------------- +FROM base_lpt AS deployment_lpt + +# let supervisor python script flush logs immediately +ENV PYTHONUNBUFFERED="1" + +COPY --from=nim-build /app/apps/liteprotocoltester/run_tester_node_at_infra.sh /usr/bin/ +COPY --from=nim-build /app/apps/liteprotocoltester/infra.env /usr/bin/ +COPY --from=nim-build /app/apps/liteprotocoltester/lpt_supervisor.py /usr/bin/ +RUN chmod +x /usr/bin/run_tester_node_at_infra.sh +RUN chmod +x /usr/bin/lpt_supervisor.py + +ENTRYPOINT ["/usr/bin/lpt_supervisor.py"] diff --git a/apps/liteprotocoltester/README.md b/apps/liteprotocoltester/README.md new file mode 100644 index 0000000..ea02ec1 --- /dev/null +++ b/apps/liteprotocoltester/README.md @@ -0,0 +1,329 @@ +# Waku - Lite Protocol Tester + +## Aim + +Testing reliability of light client protocols in different scale. +Measure message delivery reliability and latency between light push client(s) and a filter client(s) node(s). + +## Concept of testing + +A tester node is configured either 'publisher' or 'receiver' and connects to a certain service node. +All service protocols are disabled except for lightpush client or filter client. This way we would like to simulate +a light client application. +Each publisher pumps messages to the network in a preconfigured way (number of messages, frequency) while on the receiver side +we would like to track and measure message losses, mis-ordered receives, late arrived messages and latencies. +Ideally the tester nodes will connect to different edge of the network where we can gather more result from mulitple publishers +and multiple receivers. + +Publishers are fill all message payloads with information about the test message and sender, helping the receiver side to calculate results. + +## Usage + +### Using lpt-runner + +For ease of use, you can clone lpt-runner repository. That will utilize previously pushed liteprotocoltester docker image. +It is recommended to use this method for fleet testing. + +```bash +git clone https://github.com/waku-org/lpt-runner.git +cd lpt-runner + +# check Reame.md for more information +# edit .env file to your needs + +docker compose up -d + +# navigate localhost:3033 to see the lite-protocol-tester dashboard +``` + +> See more detailed examples below. + +### Integration with waku-simulator! + +- For convenience, integration is done in cooperation with waku-simulator repository, but nothing is tightly coupled. +- waku-simulator must be started separately with its own configuration. +- To enable waku-simulator working without RLN currently a separate branch is to be used. +- When waku-simulator is configured and up and running, lite-protocol-tester composite docker setup can be started. + +```bash + +# Start waku-simulator + +git clone https://github.com/waku-org/waku-simulator.git ../waku-simulator +cd ../waku-simulator +git checkout chore-integrate-liteprotocoltester + +# optionally edit .env file + +docker compose -f docker-compose-norln.yml up -d + +# navigate localhost:30001 to see the waku-simulator dashboard + +cd ../{your-repository} + +make LOG_LEVEL=DEBUG liteprotocoltester + +cd apps/liteprotocoltester + +# optionally edit .env file + +docker compose -f docker-compose-on-simularor.yml build +docker compose -f docker-compose-on-simularor.yml up -d +docker compose -f docker-compose-on-simularor.yml logs -f receivernode +``` +#### Current setup + +- waku-simulator is configured to run with 25 full node +- liteprotocoltester is configured to run with 3 publisher and 1 receiver +- liteprotocoltester is configured to run 1 lightpush service and a filter service node + - light clients are connected accordingly +- publishers will send 250 messages in every 200ms with size between 1KiB and 120KiB +- Notice there is a configurable wait before start publishing messages as it is noticed time is needed for the service nodes to get connected to full nodes from simulator +- light clients will print report on their and the connected service node's connectivity to the network in every 20 secs. + +#### Test monitoring + +Navigate to http://localhost:3033 to see the lite-protocol-tester dashboard. + +### Run independently on a chosen waku fleet + +This option is simple as is just to run the built liteprotocoltester binary with run_tester_node.sh script. + +Syntax: +`./run_tester_node.sh ` + +How to run from you nwaku repository: +```bash +cd ../{your-repository} + +make LOG_LEVEL=DEBUG liteprotocoltester + +cd apps/liteprotocoltester + +# optionally edit .env file + +# run publisher side +./run_tester_node.sh ../../build/liteprotocoltester SENDER [chosen service node address that support lightpush] + +# or run receiver side +./run_tester_node.sh ../../build/liteprotocoltester RECEIVER [chosen service node address that support filter service] +``` + +#### Recommendations + +In order to run on any kind of network, it is recommended to deploy the built `liteprotocoltester` binary with the `.env` file and the `run_tester_node.sh` script to the desired machine. + +Select a lightpush service node and a filter service node from the targeted network, or you can run your own. Note down the selected peers peer_id. + +Run a SENDER role liteprotocoltester and a RECEIVER role one on different terminals. Depending on the test aim, you may want to redirect the output to a file. + +> RECEIVER side will periodically print statistics to standard output. + +## Configuration + +### Environment variables for docker compose runs + +| Variable | Description | Default | +| ---: | :--- | :--- | +| NUM_MESSAGES | Number of message to publish, 0 means infinite | 120 | +| MESSAGE_INTERVAL_MILLIS | Frequency of messages in milliseconds | 1000 | +| SHARD | Used shard for testing | 0 | +| CONTENT_TOPIC | content_topic for testing | /tester/1/light-pubsub-example/proto | +| CLUSTER_ID | cluster_id of the network | 16 | +| START_PUBLISHING_AFTER_SECS | Delay in seconds before starting to publish to let service node connected | 5 | +| MIN_MESSAGE_SIZE | Minimum message size in bytes | 1KiB | +| MAX_MESSAGE_SIZE | Maximum message size in bytes | 120KiB | + + +### Lite Protocol Tester application cli options + +| Option | Description | Default | +| :--- | :--- | :--- | +| --test_func | separation of PUBLISHER or RECEIVER mode | RECEIVER | +| --service-node| Address of the service node to use for lightpush and/or filter service | - | +| --bootstrap-node| Address of the fleet's bootstrap node to use to determine service peer randomly choosen from the network. `--service-node` switch has precedence over this | - | +| --num-messages | Number of message to publish | 120 | +| --message-interval | Frequency of messages in milliseconds | 1000 | +| --min-message-size | Minimum message size in bytes | 1KiB | +| --max-message-size | Maximum message size in bytes | 120KiB | +| --start-publishing-after | Delay in seconds before starting to publish to let service node connected in seconds | 5 | +| --pubsub-topic | Used pubsub_topic for testing | /waku/2/default-waku/proto | +| --content_topic | content_topic for testing | /tester/1/light-pubsub-example/proto | +| --cluster-id | Cluster id for the test | 0 | +| --config-file | TOML configuration file to fine tune the light waku node
Note that some configurations (full node services) are not taken into account | - | +| --nat |Same as wakunode "nat" configuration, appear here to ease test setup | any | +| --rest-address | For convenience rest configuration can be done here | 127.0.0.1 | +| --rest-port | For convenience rest configuration can be done here | 8654 | +| --rest-allow-origin | For convenience rest configuration can be done here | * | +| --log-level | Log level for the application | DEBUG | +| --log-format | Logging output format (TEXT or JSON) | TEXT | +| --metrics-port | Metrics scarpe port | 8003 | + +### Specifying peer addresses + +Service node or bootstrap addresses can be specified in multiadress or ENR form. + +### Using bootstrap nodes + +There are multiple benefits of using bootstrap nodes. By using them liteprotocoltester will use Peer Exchange protocol to get possible peers from the network that are capable to serve as service peers for testing. Additionally it will test dial them to verify their connectivity - this will be reported in the logs and on dashboard metrics. +Also by using bootstrap node and peer exchange discovery, litprotocoltester will be able to simulate service peer switch in case of failures. There are built in tresholds count for service peer failures (3) after service peer will be switched during the test. Also there will be max 10 trials of switching peer before test declared failed and quit. +These service peer failures are reported, thus extending network reliability measures. + +### Building docker image + +Easiest way to build the docker image is to use the provided Makefile target. + +```bash +cd +make docker-liteprotocoltester +``` +This will build liteprotocoltester from the ground up and create a docker image with the binary copied to it under image name and tag `wakuorg/liteprotocoltester:latest`. + +#### Building public image + +If you want to push the image to a public registry, you can use the jenkins job to do so. +The job is available at https://ci.status.im/job/waku/job/liteprotocoltester/job/build-liteprotocoltester-image + +#### Building and deployment for infra testing + +For specific and continuous testing purposes we have a deployment of `liteprotocoltester` test suite to our infra appliances. +This has its own configuration, constraints and requirements. To ease this job, image shall be built and pushed with `deploy` tag. +This can be done by the jenkins job mentioned above. + +or manually by: +```bash +cd +make DOCKER_LPT_TAG=deploy docker-liteprotocoltester +``` + +The image created with this method will be different from under any other tag. It prepared to run a preconfigured test suite continuously. +It will also miss prometheus metrics scraping endpoint and grafana, thus it is not recommended to use it for general testing. + +#### Manually building for docker compose runs on simulator or standalone +Please note that currently to ease testing and development tester application docker image is based on ubuntu and uses the externally pre-built binary of 'liteprotocoltester'. +This speeds up image creation. Another dokcer build file is provided for proper build of boundle image. + +> `Dockerfile.liteprotocoltester` will create an ubuntu based image with the binary copied from the build directory. + +> `Dockerfile.liteprotocoltester.compile` will create an ubuntu based image completely compiled from source. This can be slow. + +#### Creating standalone runner docker image + +To ease the work with lite-protocol-tester, a docker image is possible to build. +With that image it is easy to run the application in a container. + +> `Dockerfile.liteprotocoltester` will create an ubuntu image with the binary copied from the build directory. You need to pre-build the application. + +Here is how to build and run: +```bash +cd +make liteprotocoltester + +cd apps/liteprotocoltester +docker build -t liteprotocoltester:latest -f Dockerfile.liteprotocoltester ../.. + +# alternatively you can push it to a registry + +# edit and adjust .env file to your needs and for the network configuration + +docker run --env-file .env liteprotocoltester:latest RECEIVER + +docker run --env-file .env liteprotocoltester:latest SENDER +``` + +#### Run test with auto service peer selection from a fleet using bootstrap node + +```bash + +docker run --env-file .env liteprotocoltester:latest RECEIVER BOOTSTRAP + +docker run --env-file .env liteprotocoltester:latest SENDER BOOTSTRAP +``` + +> Notice that official image is also available at harbor.status.im/wakuorg/liteprotocoltester:latest + +## Examples + +### Bootstrap or Service node selection + +The easiest way to get the proper bootstrap nodes for the tests from https://fleets.status.im page. +Adjust on which fleets you would like to run the tests. + +> Please note that not all of them configured to support Peer Exchange protocol, those ones cannot be for bootstrap nodes for `liteprotocoltester`. + +### Environment variables +You need not necessary to use .env file, although it can be more convenient. +Anytime you can override all or part of the environment variables defined in the .env file. + +### Run standalone + +Example of running the liteprotocoltester in standalone mode on status.stagin network. +Testing includes using bootstrap nodes to gather service peers from the network via Peer Exchange protocol. +Both parties will test-dial all the peers retrieved with the corresponding protocol. +Sender will start publishing messages after 60 seconds, sending 200 messages with 1 second delay between them. +Message size will be between 15KiB and 145KiB. +Cluster id and Pubsub-topic must be accurately set according to the network configuration. + +The example shows that either multiaddress or ENR form accepted. + +```bash +export START_PUBLISHING_AFTER_SECS=60 +export NUM_MESSAGES=200 +export MESSAGE_INTERVAL_MILLIS=1000 +export MIN_MESSAGE_SIZE=15Kb +export MAX_MESSAGE_SIZE=145Kb +export SHARD=32 +export CONTENT_TOPIC=/tester/2/light-pubsub-test/fleet +export CLUSTER_ID=16 + +docker run harbor.status.im/wakuorg/liteprotocoltester:latest RECEIVER /dns4/boot-01.do-ams3.status.staging.status.im/tcp/30303/p2p/16Uiu2HAmQE7FXQc6iZHdBzYfw3qCSDa9dLc1wsBJKoP4aZvztq2d BOOTSTRAP + +# in different terminal session, repeat the exports and run the other party of the test. +docker run harbor.status.im/wakuorg/liteprotocoltester:latest SENDER enr:-QEiuECJPv2vL00Jp5sTEMAFyW7qXkK2cFgphlU_G8-FJuJqoW_D5aWIy3ylGdv2K8DkiG7PWgng4Ql_VI7Qc2RhBdwfAYJpZIJ2NIJpcIQvTKi6im11bHRpYWRkcnO4cgA2NjFib290LTAxLmFjLWNuLWhvbmdrb25nLWMuc3RhdHVzLnN0YWdpbmcuc3RhdHVzLmltBnZfADg2MWJvb3QtMDEuYWMtY24taG9uZ2tvbmctYy5zdGF0dXMuc3RhZ2luZy5zdGF0dXMuaW0GAbveA4Jyc40AEAUAAQAgAEAAgAEAiXNlY3AyNTZrMaEDkbgV7oqPNmFtX5FzSPi9WH8kkmrPB1R3n9xRXge91M-DdGNwgnZfg3VkcIIjKIV3YWt1Mg0 BOOTSTRAP + +``` + +### Use of lpt-runner + +Another method is to use [lpt-runner repository](https://github.com/waku-org/lpt-runner/tree/master). +This extends testing with grafana dashboard and ease the test setup. +Please read the corresponding [README](https://github.com/waku-org/lpt-runner/blob/master/README.md) there as well. + +In this example we will run similar test as above but there will be 3 instances of publisher nodes and 1 receiver node. +This test uses waku.sandbox fleet which is connected to TWN. This implies lower message rates due to the RLN rate limation. +Also leave a gap of 120 seconds before starting to publish messages to let receiver side fully finish peer test-dialing. +For TWN network it is always wise to use bootstrap nodes with Peer Exchange support. + +> Theoritically we can use the same bootstrap nodes for both parties, but it is recommended to use different ones to simulate different network edges, thus getting more meaningful results. + +```bash +git clone https://github.com/waku-org/lpt-runner.git +cd lpt-runner + +export NUM_PUBLISHER_NODES=3 +export NUM_RECEIVER_NODES=1 +export START_PUBLISHING_AFTER_SECS=120 +export NUM_MESSAGES=300 +export MESSAGE_INTERVAL_MILLIS=7000 +export MIN_MESSAGE_SIZE=15Kb +export MAX_MESSAGE_SIZE=145Kb +export SHARD=4 +export CONTENT_TOPIC=/tester/2/light-pubsub-test/twn +export CLUSTER_ID=1 + +export FILTER_BOOTSTRAP=/dns4/node-01.ac-cn-hongkong-c.waku.sandbox.status.im/tcp/30303/p2p/16Uiu2HAmQYiojgZ8APsh9wqbWNyCstVhnp9gbeNrxSEQnLJchC92 +export LIGHTPUSH_BOOTSTRAP=/dns4/node-01.do-ams3.waku.sandbox.status.im/tcp/30303/p2p/16Uiu2HAmNaeL4p3WEYzC9mgXBmBWSgWjPHRvatZTXnp8Jgv3iKsb + +docker compose up -d + +# we can check logs from one or all SENDER +docker compose logs -f --index 1 publishernode + +# for checking receiver side performance +docker compose logs -f receivernode + +# when test completed +docker compose down +``` + +For dashboard navigate to http://localhost:3033 diff --git a/apps/liteprotocoltester/diagnose_connections.nim b/apps/liteprotocoltester/diagnose_connections.nim new file mode 100644 index 0000000..f595b4e --- /dev/null +++ b/apps/liteprotocoltester/diagnose_connections.nim @@ -0,0 +1,65 @@ +when (NimMajor, NimMinor) < (1, 4): + {.push raises: [Defect].} +else: + {.push raises: [].} + +import + std/[options, net, strformat], + chronicles, + chronos, + metrics, + libbacktrace, + libp2p/crypto/crypto, + confutils, + libp2p/wire + +import + ../../tools/confutils/cli_args, + waku/[ + node/peer_manager, + waku_lightpush/common, + waku_relay, + waku_filter_v2, + waku_peer_exchange/protocol, + waku_core/multiaddrstr, + waku_enr/capabilities, + ] +logScope: + topics = "diagnose connections" + +proc allPeers(pm: PeerManager): string = + var allStr: string = "" + for idx, peer in pm.switch.peerStore.peers(): + allStr.add( + " " & $idx & ". | " & constructMultiaddrStr(peer) & " | agent: " & + peer.getAgent() & " | protos: " & $peer.protocols & " | caps: " & + $peer.enr.map(getCapabilities) & "\n" + ) + return allStr + +proc logSelfPeers*(pm: PeerManager) = + let selfLighpushPeers = pm.switch.peerStore.getPeersByProtocol(WakuLightPushCodec) + let selfRelayPeers = pm.switch.peerStore.getPeersByProtocol(WakuRelayCodec) + let selfFilterPeers = pm.switch.peerStore.getPeersByProtocol(WakuFilterSubscribeCodec) + let selfPxPeers = pm.switch.peerStore.getPeersByProtocol(WakuPeerExchangeCodec) + + let printable = catch: + """*------------------------------------------------------------------------------------------* +| Self ({constructMultiaddrStr(pm.switch.peerInfo)}) peers: +*------------------------------------------------------------------------------------------* +| Lightpush peers({selfLighpushPeers.len()}): ${selfLighpushPeers} +*------------------------------------------------------------------------------------------* +| Filter peers({selfFilterPeers.len()}): ${selfFilterPeers} +*------------------------------------------------------------------------------------------* +| Relay peers({selfRelayPeers.len()}): ${selfRelayPeers} +*------------------------------------------------------------------------------------------* +| PX peers({selfPxPeers.len()}): ${selfPxPeers} +*------------------------------------------------------------------------------------------* +| All peers with protocol support: +{allPeers(pm)} +*------------------------------------------------------------------------------------------*""".fmt() + + if printable.isErr(): + echo "Error while printing statistics: " & printable.error().msg + else: + echo printable.get() diff --git a/apps/liteprotocoltester/docker-compose-on-simularor.yml b/apps/liteprotocoltester/docker-compose-on-simularor.yml new file mode 100644 index 0000000..9e899f7 --- /dev/null +++ b/apps/liteprotocoltester/docker-compose-on-simularor.yml @@ -0,0 +1,227 @@ +version: "3.7" +x-logging: &logging + logging: + driver: json-file + options: + max-size: 1000m + +# Environment variable definitions +x-eth-client-address: ð_client_address ${ETH_CLIENT_ADDRESS:-} # Add your ETH_CLIENT_ADDRESS after the "-" + +x-rln-environment: &rln_env + RLN_RELAY_CONTRACT_ADDRESS: ${RLN_RELAY_CONTRACT_ADDRESS:-0xF471d71E9b1455bBF4b85d475afb9BB0954A29c4} + RLN_RELAY_CRED_PATH: ${RLN_RELAY_CRED_PATH:-} # Optional: Add your RLN_RELAY_CRED_PATH after the "-" + RLN_RELAY_CRED_PASSWORD: ${RLN_RELAY_CRED_PASSWORD:-} # Optional: Add your RLN_RELAY_CRED_PASSWORD after the "-" + +x-test-running-conditions: &test_running_conditions + NUM_MESSAGES: ${NUM_MESSAGES:-120} + MESSAGE_INTERVAL_MILLIS: "${MESSAGE_INTERVAL_MILLIS:-1000}" + SHARD: ${SHARD:-0} + CONTENT_TOPIC: ${CONTENT_TOPIC:-/tester/2/light-pubsub-test/wakusim} + CLUSTER_ID: ${CLUSTER_ID:-66} + MIN_MESSAGE_SIZE: ${MIN_MESSAGE_SIZE:-1Kb} + MAX_MESSAGE_SIZE: ${MAX_MESSAGE_SIZE:-150Kb} + START_PUBLISHING_AFTER_SECS: ${START_PUBLISHING_AFTER_SECS:-5} # seconds + + +# Services definitions +services: + lightpush-service: + image: ${NWAKU_IMAGE:-harbor.status.im/wakuorg/nwaku:latest-release} + # ports: + # - 30304:30304/tcp + # - 30304:30304/udp + # - 9005:9005/udp + # - 127.0.0.1:8003:8003 + # - 80:80 #Let's Encrypt + # - 8000:8000/tcp #WSS + # - 127.0.0.1:8645:8645 + <<: + - *logging + environment: + DOMAIN: ${DOMAIN} + RLN_RELAY_CRED_PASSWORD: "${RLN_RELAY_CRED_PASSWORD}" + ETH_CLIENT_ADDRESS: *eth_client_address + EXTRA_ARGS: ${EXTRA_ARGS} + <<: + - *rln_env + - *test_running_conditions + volumes: + - ./run_service_node.sh:/opt/run_service_node.sh:Z + - ${CERTS_DIR:-./certs}:/etc/letsencrypt/:Z + - ./rln_tree:/etc/rln_tree/:Z + - ./keystore:/keystore:Z + entrypoint: sh + command: + - /opt/run_service_node.sh + - LIGHTPUSH + networks: + - waku-simulator_simulation + + publishernode: + image: waku.liteprotocoltester:latest + build: + context: ../.. + dockerfile: ./apps/liteprotocoltester/Dockerfile.liteprotocoltester + deploy: + replicas: ${NUM_PUBLISHER_NODES:-3} + # ports: + # - 30304:30304/tcp + # - 30304:30304/udp + # - 9005:9005/udp + # - 127.0.0.1:8003:8003 + # - 80:80 #Let's Encrypt + # - 8000:8000/tcp #WSS + # - 127.0.0.1:8646:8646 + <<: + - *logging + environment: + DOMAIN: ${DOMAIN} + RLN_RELAY_CRED_PASSWORD: "${RLN_RELAY_CRED_PASSWORD}" + ETH_CLIENT_ADDRESS: *eth_client_address + EXTRA_ARGS: ${EXTRA_ARGS} + <<: + - *rln_env + - *test_running_conditions + volumes: + - ${CERTS_DIR:-./certs}:/etc/letsencrypt/:Z + - ./rln_tree:/etc/rln_tree/:Z + - ./keystore:/keystore:Z + entrypoint: sh + command: + - /usr/bin/run_tester_node.sh + - /usr/bin/liteprotocoltester + - SENDER + - waku-sim + depends_on: + - lightpush-service + configs: + - source: cfg_tester_node.toml + target: config.toml + networks: + - waku-simulator_simulation + + filter-service: + image: ${NWAKU_IMAGE:-harbor.status.im/wakuorg/nwaku:latest-release} + # ports: + # - 30304:30305/tcp + # - 30304:30305/udp + # - 9005:9005/udp + # - 127.0.0.1:8003:8003 + # - 80:80 #Let's Encrypt + # - 8000:8000/tcp #WSS + # - 127.0.0.1:8645:8645 + <<: + - *logging + environment: + DOMAIN: ${DOMAIN} + RLN_RELAY_CRED_PASSWORD: "${RLN_RELAY_CRED_PASSWORD}" + ETH_CLIENT_ADDRESS: *eth_client_address + EXTRA_ARGS: ${EXTRA_ARGS} + <<: + - *rln_env + - *test_running_conditions + volumes: + - ./run_service_node.sh:/opt/run_service_node.sh:Z + - ${CERTS_DIR:-./certs}:/etc/letsencrypt/:Z + - ./rln_tree:/etc/rln_tree/:Z + - ./keystore:/keystore:Z + entrypoint: sh + command: + - /opt/run_service_node.sh + - FILTER + networks: + - waku-simulator_simulation + + + receivernode: + image: waku.liteprotocoltester:latest + build: + context: ../.. + dockerfile: ./apps/liteprotocoltester/Dockerfile.liteprotocoltester + deploy: + replicas: ${NUM_RECEIVER_NODES:-1} + # ports: + # - 30304:30304/tcp + # - 30304:30304/udp + # - 9005:9005/udp + # - 127.0.0.1:8003:8003 + # - 80:80 #Let's Encrypt + # - 8000:8000/tcp #WSS + # - 127.0.0.1:8647:8647 + <<: + - *logging + environment: + DOMAIN: ${DOMAIN} + RLN_RELAY_CRED_PASSWORD: "${RLN_RELAY_CRED_PASSWORD}" + ETH_CLIENT_ADDRESS: *eth_client_address + EXTRA_ARGS: ${EXTRA_ARGS} + <<: + - *rln_env + - *test_running_conditions + volumes: + - ${CERTS_DIR:-./certs}:/etc/letsencrypt/:Z + - ./rln_tree:/etc/rln_tree/:Z + - ./keystore:/keystore:Z + entrypoint: sh + command: + - /usr/bin/run_tester_node.sh + - /usr/bin/liteprotocoltester + - RECEIVER + - waku-sim + depends_on: + - filter-service + - publishernode + configs: + - source: cfg_tester_node.toml + target: config.toml + networks: + - waku-simulator_simulation + + # We have prometheus and grafana defined in waku-simulator already + prometheus: + image: docker.io/prom/prometheus:latest + volumes: + - ./monitoring/prometheus-config.yml:/etc/prometheus/prometheus.yml:Z + command: + - --config.file=/etc/prometheus/prometheus.yml + - --web.listen-address=:9099 + # ports: + # - 127.0.0.1:9090:9090 + restart: on-failure:5 + depends_on: + - filter-service + - lightpush-service + - publishernode + - receivernode + networks: + - waku-simulator_simulation + + grafana: + image: docker.io/grafana/grafana:latest + env_file: + - ./monitoring/configuration/grafana-plugins.env + volumes: + - ./monitoring/configuration/grafana.ini:/etc/grafana/grafana.ini:Z + - ./monitoring/configuration/dashboards.yaml:/etc/grafana/provisioning/dashboards/dashboards.yaml:Z + - ./monitoring/configuration/datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml:Z + - ./monitoring/configuration/dashboards:/var/lib/grafana/dashboards/:Z + - ./monitoring/configuration/customizations/custom-logo.svg:/usr/share/grafana/public/img/grafana_icon.svg:Z + - ./monitoring/configuration/customizations/custom-logo.svg:/usr/share/grafana/public/img/grafana_typelogo.svg:Z + - ./monitoring/configuration/customizations/custom-logo.png:/usr/share/grafana/public/img/fav32.png:Z + ports: + - 0.0.0.0:3033:3033 + restart: on-failure:5 + depends_on: + - prometheus + networks: + - waku-simulator_simulation + +configs: + cfg_tester_node.toml: + content: | + max-connections = 100 + +networks: + waku-simulator_simulation: + external: true diff --git a/apps/liteprotocoltester/docker-compose.yml b/apps/liteprotocoltester/docker-compose.yml new file mode 100644 index 0000000..16b5446 --- /dev/null +++ b/apps/liteprotocoltester/docker-compose.yml @@ -0,0 +1,172 @@ +version: "3.7" +x-logging: &logging + logging: + driver: json-file + options: + max-size: 1000m + +# Environment variable definitions +x-eth-client-address: ð_client_address ${ETH_CLIENT_ADDRESS:-} # Add your ETH_CLIENT_ADDRESS after the "-" + +x-rln-environment: &rln_env + RLN_RELAY_CONTRACT_ADDRESS: ${RLN_RELAY_CONTRACT_ADDRESS:-0xB9cd878C90E49F797B4431fBF4fb333108CB90e6} + RLN_RELAY_CRED_PATH: ${RLN_RELAY_CRED_PATH:-} # Optional: Add your RLN_RELAY_CRED_PATH after the "-" + RLN_RELAY_CRED_PASSWORD: ${RLN_RELAY_CRED_PASSWORD:-} # Optional: Add your RLN_RELAY_CRED_PASSWORD after the "-" + +x-test-running-conditions: &test_running_conditions + NUM_MESSAGES: ${NUM_MESSAGES:-120} + MESSAGE_INTERVAL_MILLIS: "${MESSAGE_INTERVAL_MILLIS:-1000}" + SHARD: ${SHARD:-0} + CONTENT_TOPIC: ${CONTENT_TOPIC:-/tester/2/light-pubsub-test/wakusim} + CLUSTER_ID: ${CLUSTER_ID:-66} + MIN_MESSAGE_SIZE: ${MIN_MESSAGE_SIZE:-1Kb} + MAX_MESSAGE_SIZE: ${MAX_MESSAGE_SIZE:-150Kb} + START_PUBLISHING_AFTER_SECS: ${START_PUBLISHING_AFTER_SECS:-5} # seconds + STANDALONE: ${STANDALONE:-1} + RECEIVER_METRICS_PORT: 8003 + PUBLISHER_METRICS_PORT: 8003 + + +# Services definitions +services: + servicenode: + image: ${NWAKU_IMAGE:-harbor.status.im/wakuorg/nwaku:latest-release} + ports: + - 30304:30304/tcp + - 30304:30304/udp + - 9005:9005/udp + - 127.0.0.1:8003:8003 + - 80:80 #Let's Encrypt + - 8000:8000/tcp #WSS + - 127.0.0.1:8645:8645 + <<: + - *logging + environment: + DOMAIN: ${DOMAIN} + RLN_RELAY_CRED_PASSWORD: "${RLN_RELAY_CRED_PASSWORD}" + ETH_CLIENT_ADDRESS: *eth_client_address + EXTRA_ARGS: ${EXTRA_ARGS} + <<: + - *rln_env + - *test_running_conditions + volumes: + - ./run_service_node.sh:/opt/run_service_node.sh:Z + - ${CERTS_DIR:-./certs}:/etc/letsencrypt/:Z + - ./rln_tree:/etc/rln_tree/:Z + - ./keystore:/keystore:Z + entrypoint: sh + command: + - /opt/run_service_node.sh + + publishernode: + image: waku.liteprotocoltester:latest + build: + context: ../.. + dockerfile: ./apps/liteprotocoltester/Dockerfile.liteprotocoltester + ports: + # - 30304:30304/tcp + # - 30304:30304/udp + # - 9005:9005/udp + # - 127.0.0.1:8003:8003 + # - 80:80 #Let's Encrypt + # - 8000:8000/tcp #WSS + - 127.0.0.1:8646:8646 + <<: + - *logging + environment: + DOMAIN: ${DOMAIN} + RLN_RELAY_CRED_PASSWORD: "${RLN_RELAY_CRED_PASSWORD}" + ETH_CLIENT_ADDRESS: *eth_client_address + EXTRA_ARGS: ${EXTRA_ARGS} + <<: + - *rln_env + - *test_running_conditions + volumes: + - ${CERTS_DIR:-./certs}:/etc/letsencrypt/:Z + - ./rln_tree:/etc/rln_tree/:Z + - ./keystore:/keystore:Z + entrypoint: sh + command: + - /usr/bin/run_tester_node.sh + - /usr/bin/liteprotocoltester + - SENDER + - servicenode + depends_on: + - servicenode + configs: + - source: cfg_tester_node.toml + target: config.toml + + receivernode: + image: waku.liteprotocoltester:latest + build: + context: ../.. + dockerfile: ./apps/liteprotocoltester/Dockerfile.liteprotocoltester + ports: + # - 30304:30304/tcp + # - 30304:30304/udp + # - 9005:9005/udp + # - 127.0.0.1:8003:8003 + # - 80:80 #Let's Encrypt + # - 8000:8000/tcp #WSS + - 127.0.0.1:8647:8647 + <<: + - *logging + environment: + DOMAIN: ${DOMAIN} + RLN_RELAY_CRED_PASSWORD: "${RLN_RELAY_CRED_PASSWORD}" + ETH_CLIENT_ADDRESS: *eth_client_address + EXTRA_ARGS: ${EXTRA_ARGS} + <<: + - *rln_env + - *test_running_conditions + volumes: + - ./run_tester_node.sh:/opt/run_tester_node.sh:Z + - ${CERTS_DIR:-./certs}:/etc/letsencrypt/:Z + - ./rln_tree:/etc/rln_tree/:Z + - ./keystore:/keystore:Z + entrypoint: sh + command: + - /usr/bin/run_tester_node.sh + - /usr/bin/liteprotocoltester + - RECEIVER + - servicenode + depends_on: + - servicenode + - publishernode + configs: + - source: cfg_tester_node.toml + target: config.toml + + prometheus: + image: docker.io/prom/prometheus:latest + volumes: + - ./monitoring/prometheus-config.yml:/etc/prometheus/prometheus.yml:Z + command: + - --config.file=/etc/prometheus/prometheus.yml + ports: + - 127.0.0.1:9090:9090 + depends_on: + - servicenode + + grafana: + image: docker.io/grafana/grafana:latest + env_file: + - ./monitoring/configuration/grafana-plugins.env + volumes: + - ./monitoring/configuration/grafana.ini:/etc/grafana/grafana.ini:Z + - ./monitoring/configuration/dashboards.yaml:/etc/grafana/provisioning/dashboards/dashboards.yaml:Z + - ./monitoring/configuration/datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml:Z + - ./monitoring/configuration/dashboards:/var/lib/grafana/dashboards/:Z + - ./monitoring/configuration/customizations/custom-logo.svg:/usr/share/grafana/public/img/grafana_icon.svg:Z + - ./monitoring/configuration/customizations/custom-logo.svg:/usr/share/grafana/public/img/grafana_typelogo.svg:Z + - ./monitoring/configuration/customizations/custom-logo.png:/usr/share/grafana/public/img/fav32.png:Z + ports: + - 0.0.0.0:3000:3000 + depends_on: + - prometheus + +configs: + cfg_tester_node.toml: + content: | + max-connections = 100 diff --git a/apps/liteprotocoltester/infra.env b/apps/liteprotocoltester/infra.env new file mode 100644 index 0000000..ebf6147 --- /dev/null +++ b/apps/liteprotocoltester/infra.env @@ -0,0 +1,11 @@ +TEST_INTERVAL_MINUTES=180 +START_PUBLISHING_AFTER_SECS=120 +NUM_MESSAGES=300 +MESSAGE_INTERVAL_MILLIS=1000 +MIN_MESSAGE_SIZE=15Kb +MAX_MESSAGE_SIZE=145Kb +SHARD=32 +CONTENT_TOPIC=/tester/2/light-pubsub-test-at-infra/status-prod +CLUSTER_ID=16 +LIGHTPUSH_BOOTSTRAP=enr:-QEKuED9AJm2HGgrRpVaJY2nj68ao_QiPeUT43sK-aRM7sMJ6R4G11OSDOwnvVacgN1sTw-K7soC5dzHDFZgZkHU0u-XAYJpZIJ2NIJpcISnYxMvim11bHRpYWRkcnO4WgAqNiVib290LTAxLmRvLWFtczMuc3RhdHVzLnByb2Quc3RhdHVzLmltBnZfACw2JWJvb3QtMDEuZG8tYW1zMy5zdGF0dXMucHJvZC5zdGF0dXMuaW0GAbveA4Jyc40AEAUAAQAgAEAAgAEAiXNlY3AyNTZrMaEC3rRtFQSgc24uWewzXaxTY8hDAHB8sgnxr9k8Rjb5GeSDdGNwgnZfg3VkcIIjKIV3YWt1Mg0 +FILTER_BOOTSTRAP=enr:-QEcuED7ww5vo2rKc1pyBp7fubBUH-8STHEZHo7InjVjLblEVyDGkjdTI9VdqmYQOn95vuQH-Htku17WSTzEufx-Wg4mAYJpZIJ2NIJpcIQihw1Xim11bHRpYWRkcnO4bAAzNi5ib290LTAxLmdjLXVzLWNlbnRyYWwxLWEuc3RhdHVzLnByb2Quc3RhdHVzLmltBnZfADU2LmJvb3QtMDEuZ2MtdXMtY2VudHJhbDEtYS5zdGF0dXMucHJvZC5zdGF0dXMuaW0GAbveA4Jyc40AEAUAAQAgAEAAgAEAiXNlY3AyNTZrMaECxjqgDQ0WyRSOilYU32DA5k_XNlDis3m1VdXkK9xM6kODdGNwgnZfg3VkcIIjKIV3YWt1Mg0 diff --git a/apps/liteprotocoltester/legacy_publisher.nim b/apps/liteprotocoltester/legacy_publisher.nim new file mode 100644 index 0000000..12733ad --- /dev/null +++ b/apps/liteprotocoltester/legacy_publisher.nim @@ -0,0 +1,24 @@ +import chronos, results, options +import waku/[waku_node, waku_core] +import publisher_base + +type LegacyPublisher* = ref object of PublisherBase + +proc new*(T: type LegacyPublisher, wakuNode: WakuNode): T = + if isNil(wakuNode.wakuLegacyLightpushClient): + wakuNode.mountLegacyLightPushClient() + + return LegacyPublisher(wakuNode: wakuNode) + +method send*( + self: LegacyPublisher, + topic: PubsubTopic, + message: WakuMessage, + servicePeer: RemotePeerInfo, +): 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) + ).valueOr: + return err(error) + return ok() diff --git a/apps/liteprotocoltester/liteprotocoltester.nim b/apps/liteprotocoltester/liteprotocoltester.nim new file mode 100644 index 0000000..2db9bf5 --- /dev/null +++ b/apps/liteprotocoltester/liteprotocoltester.nim @@ -0,0 +1,217 @@ +{.push raises: [].} + +import + std/[options, strutils, os, sequtils, net], + chronicles, + chronos, + metrics, + libbacktrace, + system/ansi_c, + libp2p/crypto/crypto, + confutils + +import + ../../tools/confutils/cli_args, + waku/[ + common/enr, + common/logging, + factory/waku as waku_factory, + waku_node, + node/waku_metrics, + node/peer_manager, + waku_lightpush/common, + waku_filter_v2, + waku_peer_exchange/protocol, + waku_core/peers, + waku_core/multiaddrstr, + ], + ./tester_config, + ./publisher, + ./receiver, + ./diagnose_connections, + ./service_peer_management + +logScope: + topics = "liteprotocoltester main" + +proc logConfig(conf: LiteProtocolTesterConf) = + info "Configuration: Lite protocol tester", conf = $conf + +{.pop.} +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: " & waku_factory.git_version + + let confRes = LiteProtocolTesterConf.load(version = versionString) + if confRes.isErr(): + error "failure while loading the configuration", error = confRes.error + quit(QuitFailure) + + var conf = confRes.get() + + ## Logging setup + logging.setupLog(conf.logLevel, conf.logFormat) + + info "Running Lite Protocol Tester node", version = waku_factory.git_version + logConfig(conf) + + ##Prepare Waku configuration + ## - load from config file + ## - override according to tester functionality + ## + + var wakuNodeConf: WakuNodeConf + + if conf.configFile.isSome(): + try: + var configFile {.threadvar.}: InputFile + configFile = conf.configFile.get() + wakuNodeConf = WakuNodeConf.load( + version = versionString, + printUsage = false, + secondarySources = proc( + wnconf: WakuNodeConf, sources: auto + ) {.gcsafe, raises: [ConfigurationError].} = + echo "Loading secondary configuration file into WakuNodeConf" + sources.addConfigFile(Toml, configFile), + ) + except CatchableError: + error "Loading Waku configuration failed", error = getCurrentExceptionMsg() + quit(QuitFailure) + + wakuNodeConf.logLevel = conf.logLevel + wakuNodeConf.logFormat = conf.logFormat + wakuNodeConf.nat = conf.nat + wakuNodeConf.maxConnections = 500 + wakuNodeConf.restAddress = conf.restAddress + wakuNodeConf.restPort = conf.restPort + wakuNodeConf.restAllowOrigin = conf.restAllowOrigin + + wakuNodeConf.dnsAddrsNameServers = + @[parseIpAddress("8.8.8.8"), parseIpAddress("1.1.1.1")] + + wakuNodeConf.shards = @[conf.shard] + wakuNodeConf.contentTopics = conf.contentTopics + wakuNodeConf.clusterId = conf.clusterId + ## TODO: Depending on the tester needs we might extend here with shards, clusterId, etc... + + wakuNodeConf.metricsServer = true + wakuNodeConf.metricsServerAddress = parseIpAddress("0.0.0.0") + wakuNodeConf.metricsServerPort = conf.metricsPort + + # If bootstrap option is chosen we expect our clients will not mounted + # so we will mount PeerExchange manually to gather possible service peers, + # if got some we will mount the client protocols afterward. + wakuNodeConf.peerExchange = false + wakuNodeConf.relay = false + wakuNodeConf.filter = false + wakuNodeConf.lightpush = false + wakuNodeConf.store = false + + wakuNodeConf.rest = false + wakuNodeConf.relayServiceRatio = "40:60" + + let wakuConf = wakuNodeConf.toWakuConf().valueOr: + error "Issue converting toWakuConf", error = $error + quit(QuitFailure) + + var waku = (waitFor Waku.new(wakuConf)).valueOr: + error "Waku initialization failed", error = error + quit(QuitFailure) + + (waitFor startWaku(addr waku)).isOkOr: + error "Starting waku failed", error = error + quit(QuitFailure) + + debug "Setting up shutdown hooks" + + proc asyncStopper(waku: Waku) {.async: (raises: [Exception]).} = + await waku.stop() + 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(waku) + + setControlCHook(handleCtrlC) + + # Handle SIGTERM + when defined(posix): + proc handleSigterm(signal: cint) {.noconv.} = + notice "Shutting down after receiving SIGTERM" + asyncSpawn asyncStopper(waku) + + 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", stacktrace = getBacktrace() + + # Not available in -d:release mode + writeStackTrace() + + waitFor waku.stop() + quit(QuitFailure) + + c_signal(ansi_c.SIGSEGV, handleSigsegv) + + info "Node setup complete" + + var codec = WakuLightPushCodec + # mounting relevant client, for PX filter client must be mounted ahead + if conf.testFunc == TesterFunctionality.SENDER: + codec = WakuLightPushCodec + else: + codec = WakuFilterSubscribeCodec + + var lookForServiceNode = false + var serviceNodePeerInfo: RemotePeerInfo + if conf.serviceNode.len == 0: + if conf.bootstrapNode.len > 0: + info "Bootstrapping with PeerExchange to gather random service node" + let futForServiceNode = pxLookupServiceNode(waku.node, conf) + if not (waitFor futForServiceNode.withTimeout(20.minutes)): + error "Service node not found in time via PX" + quit(QuitFailure) + + if futForServiceNode.read().isErr(): + error "Service node for test not found via PX" + quit(QuitFailure) + + serviceNodePeerInfo = selectRandomServicePeer( + waku.node.peerManager, none(RemotePeerInfo), codec + ).valueOr: + error "Service node selection failed" + quit(QuitFailure) + else: + error "No service or bootstrap node provided" + quit(QuitFailure) + else: + # support for both ENR and URI formatted service node addresses + serviceNodePeerInfo = translateToRemotePeerInfo(conf.serviceNode).valueOr: + error "failed to parse service-node", node = conf.serviceNode + quit(QuitFailure) + + info "Service node to be used", serviceNode = $serviceNodePeerInfo + + logSelfPeers(waku.node.peerManager) + + if conf.testFunc == TesterFunctionality.SENDER: + setupAndPublish(waku.node, conf, serviceNodePeerInfo) + else: + setupAndListen(waku.node, conf, serviceNodePeerInfo) + + runForever() diff --git a/apps/liteprotocoltester/lpt_metrics.nim b/apps/liteprotocoltester/lpt_metrics.nim new file mode 100644 index 0000000..8b30619 --- /dev/null +++ b/apps/liteprotocoltester/lpt_metrics.nim @@ -0,0 +1,56 @@ +## Example showing how a resource restricted client may +## subscribe to messages without relay + +import metrics + +export metrics + +declarePublicGauge lpt_receiver_sender_peer_count, "count of sender peers" + +declarePublicCounter lpt_receiver_received_messages_count, + "number of messages received per peer", ["peer"] + +declarePublicCounter lpt_receiver_received_bytes, + "number of received bytes per peer", ["peer"] + +declarePublicGauge lpt_receiver_missing_messages_count, + "number of missing messages per peer", ["peer"] + +declarePublicCounter lpt_receiver_duplicate_messages_count, + "number of duplicate messages per peer", ["peer"] + +declarePublicGauge lpt_receiver_distinct_duplicate_messages_count, + "number of distinct duplicate messages per peer", ["peer"] + +declarePublicGauge lpt_receiver_latencies, + "Message delivery latency per peer (min-avg-max)", ["peer", "latency"] + +declarePublicCounter lpt_receiver_lost_subscription_count, + "number of filter service peer failed PING requests - lost subscription" + +declarePublicCounter lpt_publisher_sent_messages_count, "number of messages published" + +declarePublicCounter lpt_publisher_failed_messages_count, + "number of messages failed to publish per failure cause", ["cause"] + +declarePublicCounter lpt_publisher_sent_bytes, "number of total bytes sent" + +declarePublicCounter lpt_service_peer_failure_count, + "number of failure during using service peer [publisher/receiever]", ["role", "agent"] + +declarePublicCounter lpt_change_service_peer_count, + "number of times [publisher/receiver] had to change service peer", ["role"] + +declarePublicGauge lpt_px_peers, + "Number of peers PeerExchange discovered and can be dialed" + +declarePublicGauge lpt_dialed_peers, "Number of peers successfully dialed", ["agent"] + +declarePublicGauge lpt_dial_failures, "Number of dial failures by cause", ["agent"] + +declarePublicHistogram lpt_publish_duration_seconds, + "duration to lightpush messages", + buckets = [ + 0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1.0, 2.5, 5.0, 7.5, 10.0, + 15.0, 20.0, 30.0, Inf, + ] diff --git a/apps/liteprotocoltester/lpt_supervisor.py b/apps/liteprotocoltester/lpt_supervisor.py new file mode 100755 index 0000000..7d882af --- /dev/null +++ b/apps/liteprotocoltester/lpt_supervisor.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 + +import os +import time +from subprocess import Popen +import sys + +def load_env(file_path): + predefined_test_env = {} + with open(file_path) as f: + for line in f: + if line.strip() and not line.startswith('#'): + key, value = line.strip().split('=', 1) + predefined_test_env[key] = value + return predefined_test_env + +def run_tester_node(predefined_test_env): + role = sys.argv[1] + # override incoming environment variables with the ones from the file to prefer predefined testing environment. + for key, value in predefined_test_env.items(): + os.environ[key] = value + + script_cmd = "/usr/bin/run_tester_node_at_infra.sh /usr/bin/liteprotocoltester {role}".format(role=role) + return os.system(script_cmd) + +if __name__ == "__main__": + if len(sys.argv) < 2 or sys.argv[1] not in ["RECEIVER", "SENDER", "SENDERV3"]: + print("Error: First argument must be either 'RECEIVER' or 'SENDER' or 'SENDERV3'") + sys.exit(1) + + predefined_test_env_file = '/usr/bin/infra.env' + predefined_test_env = load_env(predefined_test_env_file) + + test_interval_minutes = int(predefined_test_env.get('TEST_INTERVAL_MINUTES', 60)) # Default to 60 minutes if not set + print(f"supervisor: Start testing loop. Interval is {test_interval_minutes} minutes") + counter = 0 + + while True: + counter += 1 + start_time = time.time() + print(f"supervisor: Run #{counter} started at {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(start_time))}") + print(f"supervisor: with arguments: {predefined_test_env}") + + exit_code = run_tester_node(predefined_test_env) + + end_time = time.time() + run_time = end_time - start_time + sleep_time = max(5 * 60, (test_interval_minutes * 60) - run_time) + + print(f"supervisor: Tester node finished at {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(end_time))}") + print(f"supervisor: Runtime was {run_time:.2f} seconds") + print(f"supervisor: Next run scheduled in {sleep_time // 60:.2f} minutes") + + time.sleep(sleep_time) diff --git a/apps/liteprotocoltester/monitoring/configuration/customizations/custom-logo.png b/apps/liteprotocoltester/monitoring/configuration/customizations/custom-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..dcf13b931be20127443409243f18a69329dc3d7e GIT binary patch literal 10938 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 q{LyJ(_S!`{;r~|P_y6SD>yt2q?MdW2>6pg< + + diff --git a/apps/liteprotocoltester/monitoring/configuration/dashboards.yaml b/apps/liteprotocoltester/monitoring/configuration/dashboards.yaml new file mode 100644 index 0000000..e59ac96 --- /dev/null +++ b/apps/liteprotocoltester/monitoring/configuration/dashboards.yaml @@ -0,0 +1,9 @@ +apiVersion: 1 + +providers: +- name: 'Prometheus' + orgId: 1 + folder: '' + type: file + options: + path: /var/lib/grafana/dashboards \ No newline at end of file diff --git a/apps/liteprotocoltester/monitoring/configuration/dashboards/liter-protocol-test-monitoring.json b/apps/liteprotocoltester/monitoring/configuration/dashboards/liter-protocol-test-monitoring.json new file mode 100644 index 0000000..22770e2 --- /dev/null +++ b/apps/liteprotocoltester/monitoring/configuration/dashboards/liter-protocol-test-monitoring.json @@ -0,0 +1,1949 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Monitoring of lite-protocol-tester's send/receiver performance and failure counters.", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 13, + "panels": [], + "title": "Peer statistics", + "type": "row" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "fieldMinMax": false, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 15, + "w": 5, + "x": 0, + "y": 1 + }, + "id": 15, + "options": { + "displayMode": "lcd", + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "lpt_px_peers{instance=~\".*publisher.*\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{instance}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Lightpush capable peers found via PX", + "type": "bargauge" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 15, + "w": 7, + "x": 5, + "y": 1 + }, + "id": 22, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "lpt_dialed_peers{instance=~\".*publisher.*\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Working filter peers {{instance}}", + "range": true, + "refId": "B", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "lpt_dial_failures{instance=~\".*publisher.*\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Failed to dial {{instance}}", + "range": true, + "refId": "C", + "useBackend": false + } + ], + "title": "Tested lightpush peers", + "type": "timeseries" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "fieldMinMax": false, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 15, + "w": 5, + "x": 12, + "y": 1 + }, + "id": 21, + "options": { + "displayMode": "lcd", + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "lpt_px_peers{instance=~\".*receiver.*\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{instance}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Filter capable peers found via PX", + "type": "bargauge" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 15, + "w": 7, + "x": 17, + "y": 1 + }, + "id": 14, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "lpt_dialed_peers{instance=~\".*receivernode.*\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Working filter peers {{instance}}", + "range": true, + "refId": "B", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "lpt_dial_failures{instance=~\".*receivernode.*\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Failed to dial {{instance}}", + "range": true, + "refId": "C", + "useBackend": false + } + ], + "title": "Tested filter peers", + "type": "timeseries" + }, + { + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 12, + "title": "Test publisher monitor", + "type": "row" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 23, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 17 + }, + "id": 16, + "options": { + "legend": { + "calcs": [ + "last" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "sum by(instace) (lpt_service_peer_failure_count_total{instance=~\".*publishernode.*\", role=\"publisher\"})", + "format": "time_series", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Push failed", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "sum by(instace) (lpt_change_service_peer_count_total{instance=~\".*publishernode.*\", role=\"publisher\"})", + "hide": false, + "instant": false, + "legendFormat": "Peer switch", + "range": true, + "refId": "B" + } + ], + "title": "Lightpush service peer failures and switches", + "type": "timeseries" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 23, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 17 + }, + "id": 17, + "options": { + "legend": { + "calcs": [ + "last" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "sum by(instace) (lpt_service_peer_failure_count_total{instance=~\".*receivernode.*\", role=\"receiver\"})", + "format": "time_series", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Subscribe failed", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "sum by(instace) (lpt_change_service_peer_count_total{instance=~\".*receivernode.*\", role=\"receiver\"})", + "hide": false, + "instant": false, + "legendFormat": "Peer switch", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "sum by(instace) (lpt_receiver_lost_subscription_count_total{instance=~\".*receivernode.*\"})", + "hide": false, + "instant": false, + "legendFormat": "Subscription loss - ping fail", + "range": true, + "refId": "C" + } + ], + "title": "Filter service peer failures and switches", + "type": "timeseries" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 70 + }, + { + "color": "red", + "value": 85 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 25 + }, + "id": 18, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": false, + "sizing": "auto" + }, + "pluginVersion": "11.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "count(\n group(\n last_over_time(lpt_px_peers{instance=~\".*publishernode.*\"}[24h])\n ) by (instance)\n)", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Number or publishers", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "count(\n group(\n last_over_time(lpt_px_peers{instance=~\".*receivernode.*\"}[24h])\n ) by (instance)\n)", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Number or receivers", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "Number of tester nodes", + "type": "gauge" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 12, + "y": 25 + }, + "id": 8, + "options": { + "displayMode": "lcd", + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "top", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "lpt_receiver_sender_peer_count{instance=~\".*receivernode.*\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{instance}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Receiver detected message from number of publisher peers", + "type": "bargauge" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 37 + }, + "id": 11, + "panels": [], + "title": "Test performance", + "type": "row" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Publishing rate" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.gradientMode", + "value": "hue" + }, + { + "id": "custom.fillOpacity", + "value": 15 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "unit", + "value": "reqps" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 38 + }, + "id": 1, + "options": { + "legend": { + "calcs": [ + "last" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "sum by(instace) (lpt_publisher_sent_messages_count_total{instance=~\".*publishernode.*\"})", + "format": "time_series", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Total published count", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "sum by(instance) (rate(lpt_publisher_sent_messages_count_total{instance=~\".*publishernode.*\"}[$__rate_interval]))", + "format": "time_series", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Publishing rate", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "Published test messages", + "type": "timeseries" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Received message rate" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.scaleDistribution", + "value": { + "type": "linear" + } + }, + { + "id": "custom.fillOpacity", + "value": 9 + }, + { + "id": "custom.gradientMode", + "value": "hue" + }, + { + "id": "unit", + "value": "reqps" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 38 + }, + "id": 2, + "options": { + "legend": { + "calcs": [ + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "sum by(instance) (lpt_receiver_received_messages_count_total{instance=~\".*receivernode.*\"})", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Total message received", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "sum by(instance) (rate(lpt_receiver_received_messages_count_total{instance=~\".*receivernode.*\"}[$__rate_interval]))", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Received message rate", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "Received test messages", + "type": "timeseries" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "left", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "kbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Send message transfer rate" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.drawStyle", + "value": "line" + }, + { + "id": "custom.fillOpacity", + "value": 22 + }, + { + "id": "custom.scaleDistribution", + "value": { + "type": "linear" + } + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "unit", + "value": "KiBs" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 46 + }, + "id": 5, + "options": { + "legend": { + "calcs": [ + "last" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "sum by(instance) (lpt_publisher_sent_bytes_total{instance=~\".*publishernode.*\"})", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Total sent bytes", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "sum by(instance) (rate(lpt_publisher_sent_bytes_total{instance=~\".*publishernode.*\"}[$__rate_interval]))", + "format": "time_series", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Send message transfer rate", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "Sent bytes", + "type": "timeseries" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "left", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "kbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Test message transfer rate" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.drawStyle", + "value": "line" + }, + { + "id": "custom.fillOpacity", + "value": 22 + }, + { + "id": "custom.scaleDistribution", + "value": { + "type": "linear" + } + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "unit", + "value": "KiBs" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 46 + }, + "id": 4, + "options": { + "legend": { + "calcs": [ + "last" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "sum by(instance) (lpt_receiver_received_bytes_total{instance=~\".*receivernode.*\"})", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Total received bytes", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "sum by(instance) (rate(lpt_receiver_received_bytes_total{instance=~\".*receivernode.*\"}[$__rate_interval]))", + "format": "time_series", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Test message transfer rate", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "Received bytes", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 54 + }, + "id": 10, + "panels": [], + "title": "Failure statistics", + "type": "row" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 23, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Published message rate" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.gradientMode", + "value": "hue" + }, + { + "id": "custom.fillOpacity", + "value": 15 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 55 + }, + "id": 6, + "options": { + "legend": { + "calcs": [ + "last" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "lpt_publisher_failed_messages_count_total{instance=~\".*publishernode.*\"}", + "format": "time_series", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{instance}} - {{cause}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Failed publish count per cause", + "type": "timeseries" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 55 + }, + "id": 7, + "options": { + "legend": { + "calcs": [ + "last" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "lpt_receiver_duplicate_messages_count_total{instance=~\".*receivernode.*\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Total duplicates at {{instance}}", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "lpt_receiver_distinct_duplicate_messages_count{instance=~\".*receivernode.*\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Distinct duplicates at {{instance}}", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "Received duplicated messages", + "type": "timeseries" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 63 + }, + "id": 9, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "lpt_receiver_missing_messages_count{instance=~\".*receivernode.*\"}", + "format": "time_series", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Receiver {{instance}}:Publisher {{peer}}", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "Not arrived messages", + "type": "timeseries" + } + ], + "refresh": "", + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": true, + "text": "lpt-runner-publishernode-1:8003", + "value": "lpt-runner-publishernode-1:8003" + }, + "definition": "label_values({instance=~\".*publishernode.*\"},instance)", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "publisher", + "options": [], + "query": { + "qryType": 1, + "query": "label_values({instance=~\".*publishernode.*\"},instance)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": { + "selected": true, + "text": "lpt-runner-receivernode-1:8003", + "value": "lpt-runner-receivernode-1:8003" + }, + "definition": "label_values({instance=~\".*receivernode.*\"},instance)", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "receiver", + "options": [], + "query": { + "qryType": 1, + "query": "label_values({instance=~\".*receivernode.*\"},instance)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "2024-10-02T22:07:37.000Z", + "to": "2024-10-02T22:23:21.000Z" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Liteprotocoltester monitoring", + "uid": "fdw6pgh9odszkd", + "version": 1, + "weekStart": "" +} diff --git a/apps/liteprotocoltester/monitoring/configuration/datasources.yaml b/apps/liteprotocoltester/monitoring/configuration/datasources.yaml new file mode 100644 index 0000000..2cc211f --- /dev/null +++ b/apps/liteprotocoltester/monitoring/configuration/datasources.yaml @@ -0,0 +1,11 @@ +apiVersion: 1 + +datasources: + - name: Prometheus + type: prometheus + access: proxy + org_id: 1 + url: http://prometheus:9099 + is_default: true + version: 1 + editable: true diff --git a/apps/liteprotocoltester/monitoring/configuration/grafana-plugins.env b/apps/liteprotocoltester/monitoring/configuration/grafana-plugins.env new file mode 100644 index 0000000..2780809 --- /dev/null +++ b/apps/liteprotocoltester/monitoring/configuration/grafana-plugins.env @@ -0,0 +1,2 @@ +#GF_INSTALL_PLUGINS=grafana-worldmap-panel,grafana-piechart-panel,digrich-bubblechart-panel,yesoreyeram-boomtheme-panel,briangann-gauge-panel,jdbranham-diagram-panel,agenty-flowcharting-panel,citilogics-geoloop-panel,savantly-heatmap-panel,mtanda-histogram-panel,pierosavi-imageit-panel,michaeldmoore-multistat-panel,zuburqan-parity-report-panel,natel-plotly-panel,bessler-pictureit-panel,grafana-polystat-panel,corpglory-progresslist-panel,snuids-radar-panel,fzakaria-simple-config.config.annotations-datasource,vonage-status-panel,snuids-trafficlights-panel,pr0ps-trackmap-panel,alexandra-trackmap-panel,btplc-trend-box-panel +GF_INSTALL_PLUGINS=grafana-worldmap-panel,grafana-piechart-panel,yesoreyeram-boomtheme-panel,briangann-gauge-panel,pierosavi-imageit-panel,bessler-pictureit-panel,vonage-status-panel diff --git a/apps/liteprotocoltester/monitoring/configuration/grafana.ini b/apps/liteprotocoltester/monitoring/configuration/grafana.ini new file mode 100644 index 0000000..631fbb7 --- /dev/null +++ b/apps/liteprotocoltester/monitoring/configuration/grafana.ini @@ -0,0 +1,53 @@ +instance_name = liteprotocoltester dashboard + +;[dashboards.json] +;enabled = true +;path = /home/git/grafana/grafana-dashboards/dashboards + +[server] +http_port = 3033 + +#################################### Auth ########################## +[auth] +disable_login_form = false + +#################################### Anonymous Auth ########################## +[auth.anonymous] +# enable anonymous access +enabled = true + +# specify organization name that should be used for unauthenticated users +;org_name = Public + +# specify role for unauthenticated users +org_role = Admin +; org_role = Viewer + +;[security] +;admin_user = ocr +;admin_password = ocr + +;[users] +# disable user signup / registration +;allow_sign_up = false + +# Set to true to automatically assign new users to the default organization (id 1) +;auto_assign_org = true + +# Default role new users will be automatically assigned (if disabled above is set to true) +;auto_assign_org_role = Viewer + +#################################### SMTP / Emailing ########################## +;[smtp] +;enabled = false +;host = localhost:25 +;user = +;password = +;cert_file = +;key_file = +;skip_verify = false +;from_address = admin@grafana.localhost + +;[emails] +;welcome_email_on_sign_up = false + diff --git a/apps/liteprotocoltester/monitoring/prometheus-config.yml b/apps/liteprotocoltester/monitoring/prometheus-config.yml new file mode 100644 index 0000000..d04eaf0 --- /dev/null +++ b/apps/liteprotocoltester/monitoring/prometheus-config.yml @@ -0,0 +1,35 @@ +global: + scrape_interval: 15s + evaluation_interval: 15s + external_labels: + monitor: "Monitoring" + +scrape_configs: + - job_name: "liteprotocoltester" + static_configs: + - targets: ["liteprotocoltester-publishernode-1:8003", + "liteprotocoltester-publishernode-2:8003", + "liteprotocoltester-publishernode-3:8003", + "liteprotocoltester-publishernode-4:8003", + "liteprotocoltester-publishernode-5:8003", + "liteprotocoltester-publishernode-6:8003", + "liteprotocoltester-receivernode-1:8003", + "liteprotocoltester-receivernode-2:8003", + "liteprotocoltester-receivernode-3:8003", + "liteprotocoltester-receivernode-4:8003", + "liteprotocoltester-receivernode-5:8003", + "liteprotocoltester-receivernode-6:8003", + "publishernode:8003", + "publishernode-1:8003", + "publishernode-2:8003", + "publishernode-3:8003", + "publishernode-4:8003", + "publishernode-5:8003", + "publishernode-6:8003", + "receivernode:8003", + "receivernode-1:8003", + "receivernode-2:8003", + "receivernode-3:8003", + "receivernode-4:8003", + "receivernode-5:8003", + "receivernode-6:8003",] diff --git a/apps/liteprotocoltester/nim.cfg b/apps/liteprotocoltester/nim.cfg new file mode 100644 index 0000000..2231f2e --- /dev/null +++ b/apps/liteprotocoltester/nim.cfg @@ -0,0 +1,4 @@ +-d:chronicles_line_numbers +-d:chronicles_runtime_filtering:on +-d:discv5_protocol_id:d5waku +path = "../.." diff --git a/apps/liteprotocoltester/publisher.nim b/apps/liteprotocoltester/publisher.nim new file mode 100644 index 0000000..d803147 --- /dev/null +++ b/apps/liteprotocoltester/publisher.nim @@ -0,0 +1,272 @@ +import + std/[strformat, sysrand, random, strutils, sequtils], + system/ansi_c, + chronicles, + chronos, + chronos/timer as chtimer, + stew/byteutils, + results, + json_serialization as js +import + waku/[ + common/logging, + waku_node, + node/peer_manager, + waku_core, + waku_lightpush/client, + waku_lightpush/common, + common/utils/parse_size_units, + ], + ./tester_config, + ./tester_message, + ./lpt_metrics, + ./diagnose_connections, + ./service_peer_management, + ./publisher_base, + ./legacy_publisher, + ./v3_publisher + +randomize() + +type SizeRange* = tuple[min: uint64, max: uint64] + +var RANDOM_PAYLOAD {.threadvar.}: seq[byte] +RANDOM_PAYLOAD = urandom(1024 * 1024) + # 1MiB of random payload to be used to extend message + +proc prepareMessage( + sender: string, + messageIndex, numMessages: uint32, + startedAt: TimeStamp, + prevMessageAt: var Timestamp, + contentTopic: ContentTopic, + size: SizeRange, +): (WakuMessage, uint64) = + var renderSize = rand(size.min .. size.max) + let current = getNowInNanosecondTime() + let payload = ProtocolTesterMessage( + sender: sender, + index: messageIndex, + count: numMessages, + startedAt: startedAt, + sinceStart: current - startedAt, + sincePrev: current - prevMessageAt, + size: renderSize, + ) + + prevMessageAt = current + + let text = js.Json.encode(payload) + let contentPayload = toBytes(text & " \0") + + if renderSize < len(contentPayload).uint64: + renderSize = len(contentPayload).uint64 + + let finalPayload = + concat(contentPayload, RANDOM_PAYLOAD[0 .. renderSize - len(contentPayload).uint64]) + let message = WakuMessage( + payload: finalPayload, # content of the message + contentTopic: contentTopic, # content topic to publish to + ephemeral: true, # tell store nodes to not store it + timestamp: current, # current timestamp + ) + + return (message, renderSize) + +var sentMessages {.threadvar.}: OrderedTable[uint32, tuple[hash: string, relayed: bool]] +var failedToSendCause {.threadvar.}: Table[string, uint32] +var failedToSendCount {.threadvar.}: uint32 +var numMessagesToSend {.threadvar.}: uint32 +var messagesSent {.threadvar.}: uint32 +var noOfServicePeerSwitches {.threadvar.}: uint32 + +proc reportSentMessages() = + let report = catch: + """*----------------------------------------* +| Service Peer Switches: {noOfServicePeerSwitches:>15} | +*----------------------------------------* +| Expected | Sent | Failed | +|{numMessagesToSend+failedToSendCount:>11} |{messagesSent:>11} |{failedToSendCount:>11} | +*----------------------------------------*""".fmt() + + if report.isErr: + echo "Error while printing statistics" + else: + echo report.get() + + echo "*--------------------------------------------------------------------------------------------------*" + echo "| Failure cause | count |" + for (cause, count) in failedToSendCause.pairs: + echo fmt"|{cause:<87}|{count:>10}|" + echo "*--------------------------------------------------------------------------------------------------*" + + echo "*--------------------------------------------------------------------------------------------------*" + echo "| Index | Relayed | Hash |" + for (index, info) in sentMessages.pairs: + echo fmt"|{index+1:>10}|{info.relayed:<9}| {info.hash:<76}|" + echo "*--------------------------------------------------------------------------------------------------*" + # evere sent message hash should logged once + sentMessages.clear() + +proc publishMessages( + wakuNode: WakuNode, + publisher: PublisherBase, + servicePeer: RemotePeerInfo, + lightpushPubsubTopic: PubsubTopic, + lightpushContentTopic: ContentTopic, + numMessages: uint32, + messageSizeRange: SizeRange, + messageInterval: Duration, + preventPeerSwitch: bool, +) {.async.} = + var actualServicePeer = servicePeer + let startedAt = getNowInNanosecondTime() + var prevMessageAt = startedAt + var renderMsgSize = messageSizeRange + # sets some default of min max message size to avoid conflict with meaningful payload size + renderMsgSize.min = max(1024.uint64, renderMsgSize.min) # do not use less than 1KB + renderMsgSize.max = max(2048.uint64, renderMsgSize.max) # minimum of max is 2KB + renderMsgSize.min = min(renderMsgSize.min, renderMsgSize.max) + renderMsgSize.max = max(renderMsgSize.min, renderMsgSize.max) + + const maxFailedPush = 3 + var noFailedPush = 0 + var noFailedServiceNodeSwitches = 0 + + let selfPeerId = $wakuNode.switch.peerInfo.peerId + failedToSendCount = 0 + numMessagesToSend = if numMessages == 0: uint32.high else: numMessages + messagesSent = 0 + + while messagesSent < numMessagesToSend: + let (message, msgSize) = prepareMessage( + selfPeerId, + messagesSent + 1, + numMessagesToSend, + startedAt, + prevMessageAt, + lightpushContentTopic, + renderMsgSize, + ) + + let publishStartTime = Moment.now() + + let wlpRes = await publisher.send(lightpushPubsubTopic, message, actualServicePeer) + + let publishDuration = Moment.now() - publishStartTime + + let msgHash = computeMessageHash(lightpushPubsubTopic, message).to0xHex + + if wlpRes.isOk(): + lpt_publish_duration_seconds.observe(publishDuration.milliseconds.float / 1000) + + sentMessages[messagesSent] = (hash: msgHash, relayed: true) + notice "published message using lightpush", + index = messagesSent + 1, + count = numMessagesToSend, + size = msgSize, + pubsubTopic = lightpushPubsubTopic, + hash = msgHash + inc(messagesSent) + lpt_publisher_sent_messages_count.inc() + lpt_publisher_sent_bytes.inc(amount = msgSize.int64) + if noFailedPush > 0: + noFailedPush -= 1 + else: + sentMessages[messagesSent] = (hash: msgHash, relayed: false) + failedToSendCause.mgetOrPut(wlpRes.error, 1).inc() + error "failed to publish message using lightpush", + err = wlpRes.error, hash = msgHash + inc(failedToSendCount) + lpt_publisher_failed_messages_count.inc(labelValues = [wlpRes.error]) + if not wlpRes.error.toLower().contains("dial"): + # retry sending after shorter wait + await sleepAsync(2.seconds) + continue + else: + noFailedPush += 1 + lpt_service_peer_failure_count.inc( + labelValues = ["publisher", actualServicePeer.getAgent()] + ) + if not preventPeerSwitch and noFailedPush > maxFailedPush: + info "Max push failure limit reached, Try switching peer." + let peerOpt = selectRandomServicePeer( + wakuNode.peerManager, some(actualServicePeer), WakuLightPushCodec + ) + if peerOpt.isOk(): + actualServicePeer = peerOpt.get() + + info "New service peer in use", + codec = lightpushPubsubTopic, + peer = constructMultiaddrStr(actualServicePeer) + + noFailedPush = 0 + noOfServicePeerSwitches += 1 + lpt_change_service_peer_count.inc(labelValues = ["publisher"]) + continue # try again with new peer without delay + else: + error "Failed to find new service peer. Exiting." + noFailedServiceNodeSwitches += 1 + break + + await sleepAsync(messageInterval) + +proc setupAndPublish*( + wakuNode: WakuNode, conf: LiteProtocolTesterConf, servicePeer: RemotePeerInfo +) = + var publisher: PublisherBase + if conf.lightpushVersion == LightpushVersion.LEGACY: + info "Using legacy lightpush protocol for publishing messages" + publisher = LegacyPublisher.new(wakuNode) + else: + info "Using lightpush v3 protocol for publishing messages" + publisher = V3Publisher.new(wakuNode) + + # give some time to receiver side to set up + let waitTillStartTesting = conf.startPublishingAfter.seconds + + let parsedMinMsgSize = parseMsgSize(conf.minTestMessageSize).valueOr: + error "failed to parse 'min-test-msg-size' param: ", error = error + return + + let parsedMaxMsgSize = parseMsgSize(conf.maxTestMessageSize).valueOr: + error "failed to parse 'max-test-msg-size' param: ", error = error + return + + info "Sending test messages in", wait = waitTillStartTesting + waitFor sleepAsync(waitTillStartTesting) + + info "Start sending messages to service node using lightpush" + + sentMessages.sort(system.cmp) + + let interval = secs(60) + var printStats: CallbackFunc + + printStats = CallbackFunc( + proc(udata: pointer) {.gcsafe.} = + reportSentMessages() + + if messagesSent >= numMessagesToSend: + info "All messages are sent. Exiting." + + ## for gracefull shutdown through signal hooks + discard c_raise(ansi_c.SIGTERM) + else: + discard setTimer(Moment.fromNow(interval), printStats) + ) + + discard setTimer(Moment.fromNow(interval), printStats) + + # Start maintaining subscription + asyncSpawn publishMessages( + wakuNode, + publisher, + servicePeer, + conf.getPubsubTopic(), + conf.contentTopics[0], + conf.numMessages, + (min: parsedMinMsgSize, max: parsedMaxMsgSize), + conf.messageInterval.milliseconds, + conf.fixedServicePeer, + ) diff --git a/apps/liteprotocoltester/publisher_base.nim b/apps/liteprotocoltester/publisher_base.nim new file mode 100644 index 0000000..de88d82 --- /dev/null +++ b/apps/liteprotocoltester/publisher_base.nim @@ -0,0 +1,14 @@ +import chronos, results +import waku/[waku_node, waku_core] + +type PublisherBase* = ref object of RootObj + wakuNode*: WakuNode + +method send*( + self: PublisherBase, + topic: PubsubTopic, + message: WakuMessage, + servicePeer: RemotePeerInfo, +): Future[Result[void, string]] {.base, async.} = + discard + # when error it must return original error desc due the text is used for distinction between error types in metrics. diff --git a/apps/liteprotocoltester/receiver.nim b/apps/liteprotocoltester/receiver.nim new file mode 100644 index 0000000..f0f41b1 --- /dev/null +++ b/apps/liteprotocoltester/receiver.nim @@ -0,0 +1,182 @@ +## Example showing how a resource restricted client may +## subscribe to messages without relay + +import + std/options, + system/ansi_c, + chronicles, + chronos, + chronos/timer as chtimer, + stew/byteutils, + results, + serialization, + json_serialization as js + +import + waku/[ + common/logging, + node/peer_manager, + waku_node, + waku_core, + waku_filter_v2/client, + waku_filter_v2/common, + waku_core/multiaddrstr, + ], + ./tester_config, + ./tester_message, + ./statistics, + ./diagnose_connections, + ./service_peer_management, + ./lpt_metrics + +var actualFilterPeer {.threadvar.}: RemotePeerInfo + +proc unsubscribe( + wakuNode: WakuNode, filterPubsubTopic: PubsubTopic, filterContentTopic: ContentTopic +) {.async.} = + notice "unsubscribing from filter" + let unsubscribeRes = await wakuNode.wakuFilterClient.unsubscribe( + actualFilterPeer, filterPubsubTopic, @[filterContentTopic] + ) + if unsubscribeRes.isErr: + notice "unsubscribe request failed", err = unsubscribeRes.error + else: + notice "unsubscribe request successful" + +proc maintainSubscription( + wakuNode: WakuNode, + filterPubsubTopic: PubsubTopic, + filterContentTopic: ContentTopic, + preventPeerSwitch: bool, +) {.async.} = + const maxFailedSubscribes = 3 + const maxFailedServiceNodeSwitches = 10 + var noFailedSubscribes = 0 + var noFailedServiceNodeSwitches = 0 + var isFirstPingOnNewPeer = true + while true: + info "maintaining subscription at", peer = constructMultiaddrStr(actualFilterPeer) + # First use filter-ping to check if we have an active subscription + let pingRes = await wakuNode.wakuFilterClient.ping(actualFilterPeer) + if pingRes.isErr(): + if isFirstPingOnNewPeer == false: + # Very first ping expected to fail as we have not yet subscribed at all + lpt_receiver_lost_subscription_count.inc() + isFirstPingOnNewPeer = false + # No subscription found. Let's subscribe. + error "ping failed.", err = pingRes.error + trace "no subscription found. Sending subscribe request" + + let subscribeRes = await wakuNode.filterSubscribe( + some(filterPubsubTopic), filterContentTopic, actualFilterPeer + ) + + if subscribeRes.isErr(): + noFailedSubscribes += 1 + lpt_service_peer_failure_count.inc( + labelValues = ["receiver", actualFilterPeer.getAgent()] + ) + error "Subscribe request failed.", + err = subscribeRes.error, + peer = actualFilterPeer, + failCount = noFailedSubscribes + + # TODO: disconnet from failed actualFilterPeer + # asyncSpawn(wakuNode.peerManager.switch.disconnect(p)) + # wakunode.peerManager.peerStore.delete(actualFilterPeer) + + if noFailedSubscribes < maxFailedSubscribes: + await sleepAsync(2.seconds) # Wait a bit before retrying + continue + elif not preventPeerSwitch: + let peerOpt = selectRandomServicePeer( + wakuNode.peerManager, some(actualFilterPeer), WakuFilterSubscribeCodec + ) + if peerOpt.isOk(): + actualFilterPeer = peerOpt.get() + + info "Found new peer for codec", + codec = filterPubsubTopic, peer = constructMultiaddrStr(actualFilterPeer) + + noFailedSubscribes = 0 + lpt_change_service_peer_count.inc(labelValues = ["receiver"]) + isFirstPingOnNewPeer = true + continue # try again with new peer without delay + else: + error "Failed to find new service peer. Exiting." + noFailedServiceNodeSwitches += 1 + break + else: + if noFailedSubscribes > 0: + noFailedSubscribes -= 1 + + notice "subscribe request successful." + else: + info "subscription is live." + + await sleepAsync(30.seconds) # Subscription maintenance interval + +proc setupAndListen*( + wakuNode: WakuNode, conf: LiteProtocolTesterConf, servicePeer: RemotePeerInfo +) = + if isNil(wakuNode.wakuFilterClient): + # if we have not yet initialized lightpush client, then do it as the only way we can get here is + # by having a service peer discovered. + waitFor wakuNode.mountFilterClient() + + info "Start receiving messages to service node using filter", + servicePeer = servicePeer + + var stats: PerPeerStatistics + actualFilterPeer = servicePeer + + let pushHandler = proc( + pubsubTopic: PubsubTopic, message: WakuMessage + ): Future[void] {.async, closure.} = + let payloadStr = string.fromBytes(message.payload) + let testerMessage = js.Json.decode(payloadStr, ProtocolTesterMessage) + let msgHash = computeMessageHash(pubsubTopic, message).to0xHex + + stats.addMessage(testerMessage.sender, testerMessage, msgHash) + + notice "message received", + index = testerMessage.index, + count = testerMessage.count, + startedAt = $testerMessage.startedAt, + sinceStart = $testerMessage.sinceStart, + sincePrev = $testerMessage.sincePrev, + size = $testerMessage.size, + pubsubTopic = pubsubTopic, + hash = msgHash + + wakuNode.wakuFilterClient.registerPushHandler(pushHandler) + + let interval = millis(20000) + var printStats: CallbackFunc + + # calculate max wait after the last known message arrived before exiting + # 20% of expected messages times the expected interval but capped to 10min + let maxWaitForLastMessage: Duration = + min(conf.messageInterval.milliseconds * (conf.numMessages div 5), 10.minutes) + + printStats = CallbackFunc( + proc(udata: pointer) {.gcsafe.} = + stats.echoStats() + + if conf.numMessages > 0 and + waitFor stats.checkIfAllMessagesReceived(maxWaitForLastMessage): + waitFor unsubscribe(wakuNode, conf.getPubsubTopic(), conf.contentTopics[0]) + info "All messages received. Exiting." + + ## for gracefull shutdown through signal hooks + discard c_raise(ansi_c.SIGTERM) + else: + discard setTimer(Moment.fromNow(interval), printStats) + ) + + discard setTimer(Moment.fromNow(interval), printStats) + + # Start maintaining subscription + asyncSpawn maintainSubscription( + wakuNode, conf.getPubsubTopic(), conf.contentTopics[0], conf.fixedServicePeer + ) diff --git a/apps/liteprotocoltester/run_service_node.sh b/apps/liteprotocoltester/run_service_node.sh new file mode 100755 index 0000000..07fdbe9 --- /dev/null +++ b/apps/liteprotocoltester/run_service_node.sh @@ -0,0 +1,63 @@ +#!/bin/sh + +echo "I am a service node" +IP=$(ip a | grep "inet " | grep -Fv 127.0.0.1 | sed 's/.*inet \([^/]*\).*/\1/') + +echo "Service node IP: ${IP}" + +if [ -n "${SHARD}" ]; then + SHARD=--shard="${SHARD}" +else + SHARD=--shard="0" +fi + +if [ -n "${CLUSTER_ID}" ]; then + CLUSTER_ID=--cluster-id="${CLUSTER_ID}" +fi + +echo "STANDALONE: ${STANDALONE}" + +if [ -z "${STANDALONE}" ]; then + + RETRIES=${RETRIES:=20} + + while [ -z "${BOOTSTRAP_ENR}" ] && [ ${RETRIES} -ge 0 ]; do + BOOTSTRAP_ENR=$(wget -qO- http://bootstrap:8645/debug/v1/info --header='Content-Type:application/json' 2> /dev/null | sed 's/.*"enrUri":"\([^"]*\)".*/\1/'); + echo "Bootstrap node not ready, retrying (retries left: ${RETRIES})" + sleep 3 + RETRIES=$(( $RETRIES - 1 )) + done + + if [ -z "${BOOTSTRAP_ENR}" ]; then + echo "Could not get BOOTSTRAP_ENR and none provided. Failing" + exit 1 + fi + + echo "Using bootstrap node: ${BOOTSTRAP_ENR}" + +fi + + +exec /usr/bin/wakunode\ + --relay=true\ + --filter=true\ + --lightpush=true\ + --store=false\ + --rest=true\ + --rest-admin=true\ + --rest-private=true\ + --rest-address=0.0.0.0\ + --rest-allow-origin="*"\ + --keep-alive=true\ + --max-connections=300\ + --dns-discovery=true\ + --discv5-discovery=true\ + --discv5-enr-auto-update=True\ + --discv5-bootstrap-node=${BOOTSTRAP_ENR}\ + --log-level=INFO\ + --metrics-server=True\ + --metrics-server-port=8003\ + --metrics-server-address=0.0.0.0\ + --nat=extip:${IP}\ + ${SHARD}\ + ${CLUSTER_ID} diff --git a/apps/liteprotocoltester/run_tester_node.sh b/apps/liteprotocoltester/run_tester_node.sh new file mode 100755 index 0000000..3c2d60e --- /dev/null +++ b/apps/liteprotocoltester/run_tester_node.sh @@ -0,0 +1,161 @@ +#!/bin/sh + +#set -x + +if test -f .env; then + echo "Using .env file" + . $(pwd)/.env +fi + + +echo "I am a lite-protocol-tester node" + +BINARY_PATH=$1 + +if [ ! -x "${BINARY_PATH}" ]; then + echo "Invalid binary path '${BINARY_PATH}'. Failing" + exit 1 +fi + +if [ "${2}" = "--help" ]; then + echo "You might want to check nwaku/apps/liteprotocoltester/README.md" + exec "${BINARY_PATH}" --help + exit 0 +fi + +FUNCTION=$2 +if [ "${FUNCTION}" = "SENDER" ]; then + FUNCTION="--test-func=SENDER --lightpush-version=LEGACY" + SERVICENAME=lightpush-service +fi + +if [ "${FUNCTION}" = "SENDERV3" ]; then + FUNCTION="--test-func=SENDER --lightpush-version=V3" + SERVICENAME=lightpush-service +fi + +if [ "${FUNCTION}" = "RECEIVER" ]; then + FUNCTION=--test-func=RECEIVER + SERVICENAME=filter-service +fi + +SERIVCE_NODE_ADDR=$3 +if [ -z "${SERIVCE_NODE_ADDR}" ]; then + echo "Service node peer_id provided. Failing" + exit 1 +fi + +SELECTOR=$4 +if [ -z "${SELECTOR}" ] || [ "${SELECTOR}" = "SERVICE" ]; then + SERVICE_NODE_DIRECT=true +elif [ "${SELECTOR}" = "BOOTSTRAP" ]; then + SERVICE_NODE_DIRECT=false +else + echo "Invalid selector '${SELECTOR}'. Failing" + exit 1 +fi + +DO_DETECT_SERVICENODE=0 + +if [ "${SERIVCE_NODE_ADDR}" = "servicenode" ]; then + DO_DETECT_SERVICENODE=1 + SERIVCE_NODE_ADDR="" + SERVICENAME=servicenode +fi + +if [ "${SERIVCE_NODE_ADDR}" = "waku-sim" ]; then + DO_DETECT_SERVICENODE=1 + SERIVCE_NODE_ADDR="" + MY_EXT_IP=$(ip a | grep "inet " | grep -Fv 127.0.0.1 | sed 's/.*inet \([^/]*\).*/\1/') +else + MY_EXT_IP=$(wget -qO- --no-check-certificate https://api4.ipify.org) +fi + + +if [ $DO_DETECT_SERVICENODE -eq 1 ]; then + RETRIES=${RETRIES:=20} + + while [ -z "${SERIVCE_NODE_ADDR}" ] && [ ${RETRIES} -ge 0 ]; do + SERVICE_DEBUG_INFO=$(wget -qO- http://${SERVICENAME}:8645/debug/v1/info --header='Content-Type:application/json' 2> /dev/null); + echo "SERVICE_DEBUG_INFO: ${SERVICE_DEBUG_INFO}" + + SERIVCE_NODE_ADDR=$(wget -qO- http://${SERVICENAME}:8645/debug/v1/info --header='Content-Type:application/json' 2> /dev/null | sed 's/.*"listenAddresses":\["\([^"]*\)".*/\1/'); + echo "Service node not ready, retrying (retries left: ${RETRIES})" + sleep 3 + RETRIES=$(( $RETRIES - 1 )) + done + +fi + +if [ -z "${SERIVCE_NODE_ADDR}" ]; then + echo "Could not get SERIVCE_NODE_ADDR and none provided. Failing" + exit 1 +fi + +if $SERVICE_NODE_DIRECT; then + FULL_NODE=--service-node="${SERIVCE_NODE_ADDR} --fixed-service-peer" +else + FULL_NODE=--bootstrap-node="${SERIVCE_NODE_ADDR}" +fi + +if [ -n "${SHARD}" ]; then + SHARD=--shard="${SHARD}" +else + SHARD=--shard="0" +fi + +if [ -n "${CONTENT_TOPIC}" ]; then + CONTENT_TOPIC=--content-topic="${CONTENT_TOPIC}" +fi + +if [ -n "${CLUSTER_ID}" ]; then + CLUSTER_ID=--cluster-id="${CLUSTER_ID}" +fi + +if [ -n "${START_PUBLISHING_AFTER_SECS}" ]; then + START_PUBLISHING_AFTER_SECS=--start-publishing-after="${START_PUBLISHING_AFTER_SECS}" +fi + +if [ -n "${MIN_MESSAGE_SIZE}" ]; then + MIN_MESSAGE_SIZE=--min-test-msg-size="${MIN_MESSAGE_SIZE}" +fi + +if [ -n "${MAX_MESSAGE_SIZE}" ]; then + MAX_MESSAGE_SIZE=--max-test-msg-size="${MAX_MESSAGE_SIZE}" +fi + + +if [ -n "${NUM_MESSAGES}" ]; then + NUM_MESSAGES=--num-messages="${NUM_MESSAGES}" +fi + +if [ -n "${MESSAGE_INTERVAL_MILLIS}" ]; then + MESSAGE_INTERVAL_MILLIS=--message-interval="${MESSAGE_INTERVAL_MILLIS}" +fi + +if [ -n "${LOG_LEVEL}" ]; then + LOG_LEVEL=--log-level=${LOG_LEVEL} +else + LOG_LEVEL=--log-level=INFO +fi + +echo "Running binary: ${BINARY_PATH}" +echo "Tester node: ${FUNCTION}" +echo "Using service node: ${SERIVCE_NODE_ADDR}" +echo "My external IP: ${MY_EXT_IP}" + +exec "${BINARY_PATH}"\ + --nat=extip:${MY_EXT_IP}\ + --test-peers\ + ${LOG_LEVEL}\ + ${FULL_NODE}\ + ${MESSAGE_INTERVAL_MILLIS}\ + ${NUM_MESSAGES}\ + ${SHARD}\ + ${CONTENT_TOPIC}\ + ${CLUSTER_ID}\ + ${FUNCTION}\ + ${START_PUBLISHING_AFTER_SECS}\ + ${MIN_MESSAGE_SIZE}\ + ${MAX_MESSAGE_SIZE} + # --config-file=config.toml\ diff --git a/apps/liteprotocoltester/run_tester_node_at_infra.sh b/apps/liteprotocoltester/run_tester_node_at_infra.sh new file mode 100644 index 0000000..db26eb0 --- /dev/null +++ b/apps/liteprotocoltester/run_tester_node_at_infra.sh @@ -0,0 +1,119 @@ +#!/bin/sh + +#set -x +#echo "$@" + +if test -f .env; then + echo "Using .env file" + . $(pwd)/.env +fi + + +echo "I am a lite-protocol-tester node" + +BINARY_PATH=$1 + +if [ ! -x "${BINARY_PATH}" ]; then + echo "Invalid binary path '${BINARY_PATH}'. Failing" + exit 1 +fi + +if [ "${2}" = "--help" ]; then + echo "You might want to check nwaku/apps/liteprotocoltester/README.md" + exec "${BINARY_PATH}" --help + exit 0 +fi + +FUNCTION=$2 +if [ "${FUNCTION}" = "SENDER" ]; then + FUNCTION="--test-func=SENDER --lightpush-version=LEGACY" + SERIVCE_NODE_ADDR=${LIGHTPUSH_SERVICE_PEER:-${LIGHTPUSH_BOOTSTRAP:-}} + NODE_ARG=${LIGHTPUSH_SERVICE_PEER:+--service-node="${LIGHTPUSH_SERVICE_PEER}"} + NODE_ARG=${NODE_ARG:---bootstrap-node="${LIGHTPUSH_BOOTSTRAP}"} + METRICS_PORT=--metrics-port="${PUBLISHER_METRICS_PORT:-8003}" +fi + +if [ "${FUNCTION}" = "SENDERV3" ]; then + FUNCTION="--test-func=SENDER --lightpush-version=V3" + SERIVCE_NODE_ADDR=${LIGHTPUSH_SERVICE_PEER:-${LIGHTPUSH_BOOTSTRAP:-}} + NODE_ARG=${LIGHTPUSH_SERVICE_PEER:+--service-node="${LIGHTPUSH_SERVICE_PEER}"} + NODE_ARG=${NODE_ARG:---bootstrap-node="${LIGHTPUSH_BOOTSTRAP}"} + METRICS_PORT=--metrics-port="${PUBLISHER_METRICS_PORT:-8003}" +fi + +if [ "${FUNCTION}" = "RECEIVER" ]; then + FUNCTION=--test-func=RECEIVER + SERIVCE_NODE_ADDR=${FILTER_SERVICE_PEER:-${FILTER_BOOTSTRAP:-}} + NODE_ARG=${FILTER_SERVICE_PEER:+--service-node="${FILTER_SERVICE_PEER}"} + NODE_ARG=${NODE_ARG:---bootstrap-node="${FILTER_BOOTSTRAP}"} + METRICS_PORT=--metrics-port="${RECEIVER_METRICS_PORT:-8003}" +fi + +if [ -z "${SERIVCE_NODE_ADDR}" ]; then + echo "Service/Bootsrap node peer_id or enr is not provided. Failing" + exit 1 +fi + +MY_EXT_IP=$(wget -qO- --no-check-certificate https://api4.ipify.org) + +if [ -n "${SHARD}" ]; then + SHARD=--shard="${SHARD}" +else + SHARD=--shard="0" +fi + +if [ -n "${CONTENT_TOPIC}" ]; then + CONTENT_TOPIC=--content-topic="${CONTENT_TOPIC}" +fi + +if [ -n "${CLUSTER_ID}" ]; then + CLUSTER_ID=--cluster-id="${CLUSTER_ID}" +fi + +if [ -n "${START_PUBLISHING_AFTER_SECS}" ]; then + START_PUBLISHING_AFTER_SECS=--start-publishing-after="${START_PUBLISHING_AFTER_SECS}" +fi + +if [ -n "${MIN_MESSAGE_SIZE}" ]; then + MIN_MESSAGE_SIZE=--min-test-msg-size="${MIN_MESSAGE_SIZE}" +fi + +if [ -n "${MAX_MESSAGE_SIZE}" ]; then + MAX_MESSAGE_SIZE=--max-test-msg-size="${MAX_MESSAGE_SIZE}" +fi + + +if [ -n "${NUM_MESSAGES}" ]; then + NUM_MESSAGES=--num-messages="${NUM_MESSAGES}" +fi + +if [ -n "${MESSAGE_INTERVAL_MILLIS}" ]; then + MESSAGE_INTERVAL_MILLIS=--message-interval="${MESSAGE_INTERVAL_MILLIS}" +fi + +if [ -n "${LOG_LEVEL}" ]; then + LOG_LEVEL=--log-level=${LOG_LEVEL} +else + LOG_LEVEL=--log-level=INFO +fi + +echo "Running binary: ${BINARY_PATH}" +echo "Node function is: ${FUNCTION}" +echo "Using service/bootstrap node as: ${NODE_ARG}" +echo "My external IP: ${MY_EXT_IP}" + +exec "${BINARY_PATH}"\ + --nat=extip:${MY_EXT_IP}\ + --test-peers\ + ${LOG_LEVEL}\ + ${NODE_ARG}\ + ${MESSAGE_INTERVAL_MILLIS}\ + ${NUM_MESSAGES}\ + ${SHARD}\ + ${CONTENT_TOPIC}\ + ${CLUSTER_ID}\ + ${FUNCTION}\ + ${START_PUBLISHING_AFTER_SECS}\ + ${MIN_MESSAGE_SIZE}\ + ${MAX_MESSAGE_SIZE}\ + ${METRICS_PORT} diff --git a/apps/liteprotocoltester/run_tester_node_on_fleet.sh b/apps/liteprotocoltester/run_tester_node_on_fleet.sh new file mode 100644 index 0000000..533f5b1 --- /dev/null +++ b/apps/liteprotocoltester/run_tester_node_on_fleet.sh @@ -0,0 +1,118 @@ +#!/bin/sh + +#set -x +#echo "$@" + +if test -f .env; then + echo "Using .env file" + . $(pwd)/.env +fi + + +echo "I am a lite-protocol-tester node" + +BINARY_PATH=$1 + +if [ ! -x "${BINARY_PATH}" ]; then + echo "Invalid binary path '${BINARY_PATH}'. Failing" + exit 1 +fi + +if [ "${2}" = "--help" ]; then + echo "You might want to check nwaku/apps/liteprotocoltester/README.md" + exec "${BINARY_PATH}" --help + exit 0 +fi + +FUNCTION=$2 +if [ "${FUNCTION}" = "SENDER" ]; then + FUNCTION="--test-func=SENDER --lightpush-version=LEGACY" + SERIVCE_NODE_ADDR=${LIGHTPUSH_SERVICE_PEER:-${LIGHTPUSH_BOOTSTRAP:-}} + NODE_ARG=${LIGHTPUSH_SERVICE_PEER:+--service-node="${LIGHTPUSH_SERVICE_PEER}"} + NODE_ARG=${NODE_ARG:---bootstrap-node="${LIGHTPUSH_BOOTSTRAP}"} + METRICS_PORT=--metrics-port="${PUBLISHER_METRICS_PORT:-8003}" +fi + +if [ "${FUNCTION}" = "SENDERV3" ]; then + FUNCTION="--test-func=SENDER --lightpush-version=V3" + SERIVCE_NODE_ADDR=${LIGHTPUSH_SERVICE_PEER:-${LIGHTPUSH_BOOTSTRAP:-}} + NODE_ARG=${LIGHTPUSH_SERVICE_PEER:+--service-node="${LIGHTPUSH_SERVICE_PEER}"} + NODE_ARG=${NODE_ARG:---bootstrap-node="${LIGHTPUSH_BOOTSTRAP}"} + METRICS_PORT=--metrics-port="${PUBLISHER_METRICS_PORT:-8003}" +fi + +if [ "${FUNCTION}" = "RECEIVER" ]; then + FUNCTION=--test-func=RECEIVER + SERIVCE_NODE_ADDR=${FILTER_SERVICE_PEER:-${FILTER_BOOTSTRAP:-}} + NODE_ARG=${FILTER_SERVICE_PEER:+--service-node="${FILTER_SERVICE_PEER}"} + NODE_ARG=${NODE_ARG:---bootstrap-node="${FILTER_BOOTSTRAP}"} + METRICS_PORT=--metrics-port="${RECEIVER_METRICS_PORT:-8003}" +fi + +if [ -z "${SERIVCE_NODE_ADDR}" ]; then + echo "Service/Bootsrap node peer_id or enr is not provided. Failing" + exit 1 +fi + +MY_EXT_IP=$(wget -qO- --no-check-certificate https://api4.ipify.org) + +if [ -n "${SHARD}" ]; then + SHARD=--shard=${SHARD} +else + SHARD=--shard=0 +fi + +if [ -n "${CONTENT_TOPIC}" ]; then + CONTENT_TOPIC=--content-topic="${CONTENT_TOPIC}" +fi + +if [ -n "${CLUSTER_ID}" ]; then + CLUSTER_ID=--cluster-id="${CLUSTER_ID}" +fi + +if [ -n "${START_PUBLISHING_AFTER}" ]; then + START_PUBLISHING_AFTER=--start-publishing-after="${START_PUBLISHING_AFTER}" +fi + +if [ -n "${MIN_MESSAGE_SIZE}" ]; then + MIN_MESSAGE_SIZE=--min-test-msg-size="${MIN_MESSAGE_SIZE}" +fi + +if [ -n "${MAX_MESSAGE_SIZE}" ]; then + MAX_MESSAGE_SIZE=--max-test-msg-size="${MAX_MESSAGE_SIZE}" +fi + + +if [ -n "${NUM_MESSAGES}" ]; then + NUM_MESSAGES=--num-messages="${NUM_MESSAGES}" +fi + +if [ -n "${MESSAGE_INTERVAL_MILLIS}" ]; then + MESSAGE_INTERVAL_MILLIS=--message-interval="${MESSAGE_INTERVAL_MILLIS}" +fi + +if [ -n "${LOG_LEVEL}" ]; then + LOG_LEVEL=--log-level=${LOG_LEVEL} +else + LOG_LEVEL=--log-level=INFO +fi + +echo "Running binary: ${BINARY_PATH}" +echo "Node function is: ${FUNCTION}" +echo "Using service/bootstrap node as: ${NODE_ARG}" +echo "My external IP: ${MY_EXT_IP}" + +exec "${BINARY_PATH}"\ + --nat=extip:${MY_EXT_IP}\ + ${LOG_LEVEL}\ + ${NODE_ARG}\ + ${MESSAGE_INTERVAL_MILLIS}\ + ${NUM_MESSAGES}\ + ${SHARD}\ + ${CONTENT_TOPIC}\ + ${CLUSTER_ID}\ + ${FUNCTION}\ + ${START_PUBLISHING_AFTER}\ + ${MIN_MESSAGE_SIZE}\ + ${MAX_MESSAGE_SIZE}\ + ${METRICS_PORT} diff --git a/apps/liteprotocoltester/service_peer_management.nim b/apps/liteprotocoltester/service_peer_management.nim new file mode 100644 index 0000000..a72daa2 --- /dev/null +++ b/apps/liteprotocoltester/service_peer_management.nim @@ -0,0 +1,223 @@ +{.push raises: [].} + +import + std/[options, net, sysrand, random, strformat, strutils, sequtils], + chronicles, + chronos, + metrics, + libbacktrace, + libp2p/crypto/crypto, + confutils, + libp2p/wire + +import + ../wakunode2/cli_args, + waku/[ + common/enr, + waku_node, + node/peer_manager, + waku_lightpush/common, + waku_relay, + waku_filter_v2, + waku_peer_exchange/protocol, + waku_core/multiaddrstr, + waku_core/topics/pubsub_topic, + waku_enr/capabilities, + waku_enr/sharding, + ], + ./tester_config, + ./diagnose_connections, + ./lpt_metrics + +logScope: + topics = "service peer mgmt" + +randomize() + +proc translateToRemotePeerInfo*(peerAddress: string): Result[RemotePeerInfo, void] = + var peerInfo: RemotePeerInfo + var enrRec: enr.Record + if enrRec.fromURI(peerAddress): + trace "Parsed ENR", enrRec = $enrRec + peerInfo = enrRec.toRemotePeerInfo().valueOr: + error "failed to convert ENR to RemotePeerInfo", error = error + return err() + else: + peerInfo = parsePeerInfo(peerAddress).valueOr: + error "failed to parse node waku peer-exchange peerId", error = error + return err() + + return ok(peerInfo) + +## To retrieve peers from PeerExchange partner and return one randomly selected one +## among the ones successfully dialed +## Note: This is kept for future use. +proc selectRandomCapablePeer*( + pm: PeerManager, codec: string, pubsubTopic: PubsubTopic +): Future[Option[RemotePeerInfo]] {.async.} = + var cap = Capabilities.Filter + if codec.contains("lightpush"): + cap = Capabilities.Lightpush + elif codec.contains("filter"): + cap = Capabilities.Filter + + var supportivePeers = pm.switch.peerStore.getPeersByCapability(cap) + + trace "Found supportive peers count", count = supportivePeers.len() + trace "Found supportive peers", supportivePeers = $supportivePeers + if supportivePeers.len == 0: + return none(RemotePeerInfo) + + var found = none(RemotePeerInfo) + while found.isNone() and supportivePeers.len > 0: + let rndPeerIndex = rand(0 .. supportivePeers.len - 1) + let randomPeer = supportivePeers[rndPeerIndex] + + debug "Dialing random peer", + idx = $rndPeerIndex, peer = constructMultiaddrStr(randomPeer) + + supportivePeers.delete(rndPeerIndex .. rndPeerIndex) + + let connOpt = pm.dialPeer(randomPeer, codec) + if (await connOpt.withTimeout(10.seconds)): + if connOpt.value().isSome(): + found = some(randomPeer) + debug "Dialing successful", + peer = constructMultiaddrStr(randomPeer), codec = codec + else: + debug "Dialing failed", peer = constructMultiaddrStr(randomPeer), codec = codec + else: + debug "Timeout dialing service peer", + peer = constructMultiaddrStr(randomPeer), codec = codec + + return found + +# Debugging PX gathered peers connectivity +proc tryCallAllPxPeers*( + pm: PeerManager, codec: string, pubsubTopic: PubsubTopic +): Future[Option[seq[RemotePeerInfo]]] {.async.} = + var capability = Capabilities.Filter + if codec.contains("lightpush"): + capability = Capabilities.Lightpush + elif codec.contains("filter"): + capability = Capabilities.Filter + + var supportivePeers = pm.switch.peerStore.getPeersByCapability(capability) + + lpt_px_peers.set(supportivePeers.len) + debug "Found supportive peers count", count = supportivePeers.len() + debug "Found supportive peers", supportivePeers = $supportivePeers + if supportivePeers.len == 0: + return none(seq[RemotePeerInfo]) + + var okPeers: seq[RemotePeerInfo] = @[] + + while supportivePeers.len > 0: + let rndPeerIndex = rand(0 .. supportivePeers.len - 1) + let randomPeer = supportivePeers[rndPeerIndex] + + debug "Dialing random peer", + idx = $rndPeerIndex, peer = constructMultiaddrStr(randomPeer) + + supportivePeers.delete(rndPeerIndex, rndPeerIndex) + + let connOpt = pm.dialPeer(randomPeer, codec) + if (await connOpt.withTimeout(10.seconds)): + if connOpt.value().isSome(): + okPeers.add(randomPeer) + info "Dialing successful", + peer = constructMultiaddrStr(randomPeer), + agent = randomPeer.getAgent(), + codec = codec + lpt_dialed_peers.inc(labelValues = [randomPeer.getAgent()]) + else: + lpt_dial_failures.inc(labelValues = [randomPeer.getAgent()]) + error "Dialing failed", + peer = constructMultiaddrStr(randomPeer), + agent = randomPeer.getAgent(), + codec = codec + else: + lpt_dial_failures.inc(labelValues = [randomPeer.getAgent()]) + error "Timeout dialing service peer", + peer = constructMultiaddrStr(randomPeer), + agent = randomPeer.getAgent(), + codec = codec + + var okPeersStr: string = "" + for idx, peer in okPeers: + okPeersStr.add( + " " & $idx & ". | " & constructMultiaddrStr(peer) & " | agent: " & + peer.getAgent() & " | protos: " & $peer.protocols & " | caps: " & + $peer.enr.map(getCapabilities) & "\n" + ) + echo "PX returned peers found callable for " & codec & " / " & $capability & ":\n" + echo okPeersStr + + return some(okPeers) + +proc pxLookupServiceNode*( + node: WakuNode, conf: LiteProtocolTesterConf +): Future[Result[bool, void]] {.async.} = + let codec: string = conf.getCodec() + + if node.wakuPeerExchange.isNil(): + let peerExchangeNode = translateToRemotePeerInfo(conf.bootstrapNode).valueOr: + error "Failed to parse bootstrap node - cannot use PeerExchange.", + node = conf.bootstrapNode + return err() + info "PeerExchange node", peer = constructMultiaddrStr(peerExchangeNode) + node.peerManager.addServicePeer(peerExchangeNode, WakuPeerExchangeCodec) + + try: + await node.mountPeerExchange(some(conf.clusterId)) + except CatchableError: + error "failed to mount waku peer-exchange protocol", + error = getCurrentExceptionMsg() + return err() + + var trialCount = 5 + while trialCount > 0: + let futPeers = node.fetchPeerExchangePeers(conf.reqPxPeers) + if not await futPeers.withTimeout(30.seconds): + notice "Cannot get peers from PX", round = 5 - trialCount + else: + if futPeers.value().isErr(): + info "PeerExchange reported error", error = futPeers.read().error + return err() + + if conf.testPeers: + let peersOpt = + await tryCallAllPxPeers(node.peerManager, codec, conf.getPubsubTopic()) + if peersOpt.isSome(): + info "Found service peers for codec", + codec = codec, peer_count = peersOpt.get().len() + return ok(peersOpt.get().len > 0) + else: + let peerOpt = + await selectRandomCapablePeer(node.peerManager, codec, conf.getPubsubTopic()) + if peerOpt.isSome(): + info "Found service peer for codec", codec = codec, peer = peerOpt.get() + return ok(true) + + await sleepAsync(5.seconds) + trialCount -= 1 + + return err() + +var alreadyUsedServicePeers {.threadvar.}: seq[RemotePeerInfo] + +## Select service peers by codec from peer store randomly. +proc selectRandomServicePeer*( + pm: PeerManager, actualPeer: Option[RemotePeerInfo], codec: string +): Result[RemotePeerInfo, void] = + if actualPeer.isSome(): + alreadyUsedServicePeers.add(actualPeer.get()) + + let supportivePeers = pm.switch.peerStore.getPeersByProtocol(codec).filterIt( + it notin alreadyUsedServicePeers + ) + if supportivePeers.len == 0: + return err() + + let rndPeerIndex = rand(0 .. supportivePeers.len - 1) + return ok(supportivePeers[rndPeerIndex]) diff --git a/apps/liteprotocoltester/statistics.nim b/apps/liteprotocoltester/statistics.nim new file mode 100644 index 0000000..8322edd --- /dev/null +++ b/apps/liteprotocoltester/statistics.nim @@ -0,0 +1,336 @@ +{.push raises: [].} + +import + std/[sets, tables, sequtils, options, strformat], + chronos/timer as chtimer, + chronicles, + chronos, + results, + libp2p/peerid + +import ./tester_message, ./lpt_metrics + +type + ArrivalInfo = object + arrivedAt: Moment + prevArrivedAt: Moment + prevIndex: uint32 + + MessageInfo = tuple[msg: ProtocolTesterMessage, info: ArrivalInfo] + DupStat = tuple[hash: string, dupCount: int, size: uint64] + + StatHelper = object + prevIndex: uint32 + prevArrivedAt: Moment + lostIndices: HashSet[uint32] + seenIndices: HashSet[uint32] + maxIndex: uint32 + duplicates: OrderedTable[uint32, DupStat] + + Statistics* = object + received: Table[uint32, MessageInfo] + firstReceivedIdx*: uint32 + allMessageCount*: uint32 + receivedMessages*: uint32 + misorderCount*: uint32 + lateCount*: uint32 + duplicateCount*: uint32 + helper: StatHelper + + PerPeerStatistics* = Table[string, Statistics] + +func `$`*(a: Duration): string {.inline.} = + ## Original stringify implementation from chronos/timer.nim is not capable of printing 0ns + ## Returns string representation of Duration ``a`` as nanoseconds value. + + if a.isZero: + return "0ns" + + return chtimer.`$`(a) + +proc init*(T: type Statistics, expectedMessageCount: int = 1000): T = + result.helper.prevIndex = 0 + result.helper.maxIndex = 0 + result.helper.seenIndices.init(expectedMessageCount) + result.received = initTable[uint32, MessageInfo](expectedMessageCount) + return result + +proc addMessage*( + self: var Statistics, sender: string, msg: ProtocolTesterMessage, msgHash: string +) = + if self.allMessageCount == 0: + self.allMessageCount = msg.count + self.firstReceivedIdx = msg.index + elif self.allMessageCount != msg.count: + error "Message count mismatch at message", + index = msg.index, expected = self.allMessageCount, got = msg.count + + let currentArrived: MessageInfo = ( + msg: msg, + info: ArrivalInfo( + arrivedAt: Moment.now(), + prevArrivedAt: self.helper.prevArrivedAt, + prevIndex: self.helper.prevIndex, + ), + ) + lpt_receiver_received_bytes.inc(labelValues = [sender], amount = msg.size.int64) + if self.received.hasKeyOrPut(msg.index, currentArrived): + inc(self.duplicateCount) + self.helper.duplicates.mgetOrPut(msg.index, (msgHash, 0, msg.size)).dupCount.inc() + warn "Duplicate message", + index = msg.index, + hash = msgHash, + times_duplicated = self.helper.duplicates[msg.index].dupCount + lpt_receiver_duplicate_messages_count.inc(labelValues = [sender]) + lpt_receiver_distinct_duplicate_messages_count.set( + labelValues = [sender], value = self.helper.duplicates.len() + ) + return + + ## detect misorder arrival and possible lost messages + if self.helper.prevIndex + 1 < msg.index: + inc(self.misorderCount) + warn "Misordered message arrival", + index = msg.index, expected = self.helper.prevIndex + 1 + elif self.helper.prevIndex > msg.index: + inc(self.lateCount) + warn "Late message arrival", index = msg.index, expected = self.helper.prevIndex + 1 + + self.helper.maxIndex = max(self.helper.maxIndex, msg.index) + self.helper.prevIndex = msg.index + self.helper.prevArrivedAt = currentArrived.info.arrivedAt + inc(self.receivedMessages) + lpt_receiver_received_messages_count.inc(labelValues = [sender]) + lpt_receiver_missing_messages_count.set( + labelValues = [sender], value = (self.helper.maxIndex - self.receivedMessages).int64 + ) + +proc addMessage*( + self: var PerPeerStatistics, + peerId: string, + msg: ProtocolTesterMessage, + msgHash: string, +) = + if not self.contains(peerId): + self[peerId] = Statistics.init() + + let shortSenderId = block: + let senderPeer = PeerId.init(msg.sender) + if senderPeer.isErr(): + msg.sender + else: + senderPeer.get().shortLog() + + discard catch: + self[peerId].addMessage(shortSenderId, msg, msgHash) + + lpt_receiver_sender_peer_count.set(value = self.len) + +proc lastMessageArrivedAt*(self: Statistics): Option[Moment] = + if self.receivedMessages > 0: + return some(self.helper.prevArrivedAt) + return none(Moment) + +proc lossCount*(self: Statistics): uint32 = + self.helper.maxIndex - self.receivedMessages + +proc calcLatency*(self: Statistics): tuple[min, max, avg: Duration] = + var + minLatency = nanos(0) + maxLatency = nanos(0) + avgLatency = nanos(0) + + if self.receivedMessages > 2: + try: + var prevArrivedAt = self.received[self.firstReceivedIdx].info.arrivedAt + + for idx, (msg, arrival) in self.received.pairs: + if idx <= 1: + continue + let expectedDelay = nanos(msg.sincePrev) + + ## latency will be 0 if arrived in shorter time than expected + var latency = arrival.arrivedAt - arrival.prevArrivedAt - expectedDelay + + ## will not measure zero latency, it is unlikely to happen but in case happens could + ## ditort the min latency calulculation as we want to calculate the feasible minimum. + if latency > nanos(0): + if minLatency == nanos(0): + minLatency = latency + else: + minLatency = min(minLatency, latency) + + maxLatency = max(maxLatency, latency) + avgLatency += latency + + avgLatency = avgLatency div (self.receivedMessages - 1) + except KeyError: + error "Error while calculating latency: " & getCurrentExceptionMsg() + + return (minLatency, maxLatency, avgLatency) + +proc missingIndices*(self: Statistics): seq[uint32] = + var missing: seq[uint32] = @[] + for idx in 1 .. self.helper.maxIndex: + if not self.received.hasKey(idx): + missing.add(idx) + return missing + +proc distinctDupCount(self: Statistics): int {.inline.} = + return self.helper.duplicates.len() + +proc allDuplicates(self: Statistics): int {.inline.} = + var total = 0 + for _, (_, dupCount, _) in self.helper.duplicates.pairs: + total += dupCount + return total + +proc dupMsgs(self: Statistics): string = + var dupMsgs: string = "" + for idx, (hash, dupCount, size) in self.helper.duplicates.pairs: + dupMsgs.add( + " index: " & $idx & " | hash: " & hash & " | count: " & $dupCount & " | size: " & + $size & "\n" + ) + return dupMsgs + +proc echoStat*(self: Statistics, peerId: string) = + let (minL, maxL, avgL) = self.calcLatency() + lpt_receiver_latencies.set(labelValues = [peerId, "min"], value = minL.nanos()) + lpt_receiver_latencies.set(labelValues = [peerId, "avg"], value = avgL.nanos()) + lpt_receiver_latencies.set(labelValues = [peerId, "max"], value = maxL.nanos()) + + let printable = catch: + """*------------------------------------------------------------------------------------------* +| Expected | Received | Target | Loss | Misorder | Late | | +|{self.helper.maxIndex:>11} |{self.receivedMessages:>11} |{self.allMessageCount:>11} |{self.lossCount():>11} |{self.misorderCount:>11} |{self.lateCount:>11} | | +*------------------------------------------------------------------------------------------* +| Latency stat: | +| min latency: {$minL:<73}| +| avg latency: {$avgL:<73}| +| max latency: {$maxL:<73}| +*------------------------------------------------------------------------------------------* +| Duplicate stat: | +| distinct duplicate messages: {$self.distinctDupCount():<57}| +| sum duplicates : {$self.allDuplicates():<57}| + Duplicated messages: + {self.dupMsgs()} +*------------------------------------------------------------------------------------------* +| Lost indices: | +| {self.missingIndices()} | +*------------------------------------------------------------------------------------------*""".fmt() + + if printable.isErr(): + echo "Error while printing statistics: " & printable.error().msg + else: + echo printable.get() + +proc jsonStat*(self: Statistics): string = + let minL, maxL, avgL = self.calcLatency() + + let json = catch: + """{{"expected":{self.helper.maxIndex}, + "received": {self.receivedMessages}, + "target": {self.allMessageCount}, + "loss": {self.lossCount()}, + "misorder": {self.misorderCount}, + "late": {self.lateCount}, + "duplicate": {self.duplicateCount}, + "latency": + {{"avg": "{avgL}", + "min": "{minL}", + "max": "{maxL}" + }}, + "lostIndices": {self.missingIndices()} + }}""".fmt() + if json.isErr: + return "{\"result:\": \"" & json.error.msg & "\"}" + + return json.get() + +proc echoStats*(self: var PerPeerStatistics) = + for peerId, stats in self.pairs: + let peerLine = catch: + "Receiver statistics from peer {peerId}".fmt() + if peerLine.isErr: + echo "Error while printing statistics" + else: + echo peerLine.get() + stats.echoStat(peerId) + +proc jsonStats*(self: PerPeerStatistics): string = + try: + #!fmt: off + var json = "{\"statistics\": [" + var first = true + for peerId, stats in self.pairs: + if first: + first = false + else: + json.add(", ") + json.add("{{\"sender\": \"{peerId}\", \"stat\":".fmt()) + json.add(stats.jsonStat()) + json.add("}") + json.add("]}") + return json + #!fmt: on + except CatchableError: + return + "{\"result:\": \"Error while generating json stats: " & getCurrentExceptionMsg() & + "\"}" + +proc lastMessageArrivedAt*(self: PerPeerStatistics): Option[Moment] = + var lastArrivedAt = Moment.init(0, Millisecond) + for stat in self.values: + let lastMsgFromPeerAt = stat.lastMessageArrivedAt().valueOr: + continue + + if lastMsgFromPeerAt > lastArrivedAt: + lastArrivedAt = lastMsgFromPeerAt + + if lastArrivedAt == Moment.init(0, Millisecond): + return none(Moment) + + return some(lastArrivedAt) + +proc checkIfAllMessagesReceived*( + self: PerPeerStatistics, maxWaitForLastMessage: Duration +): Future[bool] {.async.} = + # if there are no peers have sent messages, assume we just have started. + if self.len == 0: + return false + + # check if numerically all messages are received. + # this suggest we received at least one message already from one peer + var isAlllMessageReceived = true + for stat in self.values: + if (stat.allMessageCount == 0 and stat.receivedMessages == 0) or + stat.helper.maxIndex < stat.allMessageCount: + isAlllMessageReceived = false + break + + if not isAlllMessageReceived: + # if not all message received we still need to check if last message arrived within a time frame + # to avoid endless waiting while publishers are already quit. + let lastMessageAt = self.lastMessageArrivedAt() + if lastMessageAt.isNone(): + return false + + # last message shall arrived within time limit + if Moment.now() - lastMessageAt.get() < maxWaitForLastMessage: + return false + else: + info "No message since max wait time", maxWait = $maxWaitForLastMessage + + ## Ok, we see last message arrived from all peers, + ## lets check if all messages are received + ## and if not let's wait another 20 secs to give chance the system will send them. + var shallWait = false + for stat in self.values: + if stat.receivedMessages < stat.allMessageCount: + shallWait = true + + if shallWait: + await sleepAsync(20.seconds) + + return true diff --git a/apps/liteprotocoltester/tester_config.nim b/apps/liteprotocoltester/tester_config.nim new file mode 100644 index 0000000..dee918b --- /dev/null +++ b/apps/liteprotocoltester/tester_config.nim @@ -0,0 +1,208 @@ +import + results, + chronos, + confutils, + confutils/defs, + confutils/std/net, + confutils/toml/defs as confTomlDefs, + confutils/toml/std/net as confTomlNet, + libp2p/crypto/crypto, + libp2p/crypto/secp, + libp2p/multiaddress, + secp256k1 + +import + ../../tools/confutils/ + [cli_args, envvar as confEnvvarDefs, envvar_net as confEnvvarNet], + waku/[common/logging, waku_core, waku_core/topics/pubsub_topic] + +export confTomlDefs, confTomlNet, confEnvvarDefs, confEnvvarNet + +const + LitePubsubTopic* = PubsubTopic("/waku/2/rs/66/0") + LiteContentTopic* = ContentTopic("/tester/1/light-pubsub-example/proto") + DefaultMinTestMessageSizeStr* = "1KiB" + DefaultMaxTestMessageSizeStr* = "150KiB" + +type TesterFunctionality* = enum + SENDER # pumps messages to the network + RECEIVER # gather and analyze messages from the network + +type LightpushVersion* = enum + LEGACY # legacy lightpush protocol + V3 # lightpush v3 protocol + +type LiteProtocolTesterConf* = object + configFile* {. + desc: + "Loads configuration from a TOML file (cmd-line parameters take precedence) for the light waku node", + name: "config-file" + .}: Option[InputFile] + + ## Log configuration + logLevel* {. + desc: + "Sets the log level for process. Supported levels: TRACE, DEBUG, INFO, NOTICE, WARN, ERROR or FATAL", + defaultValue: logging.LogLevel.DEBUG, + name: "log-level" + .}: logging.LogLevel + + logFormat* {. + desc: + "Specifies what kind of logs should be written to stdout. Supported formats: TEXT, JSON", + defaultValue: logging.LogFormat.TEXT, + name: "log-format" + .}: logging.LogFormat + + ## Test configuration + serviceNode* {. + desc: "Peer multiaddr of the service node.", defaultValue: "", name: "service-node" + .}: string + + bootstrapNode* {. + desc: + "Peer multiaddr of the bootstrap node. If `service-node` not set, it is used to retrieve potential service nodes of the network.", + defaultValue: "", + name: "bootstrap-node" + .}: string + + nat* {. + desc: + "Specify method to use for determining public address. " & + "Must be one of: any, none, upnp, pmp, extip:.", + defaultValue: "any" + .}: string + + testFunc* {. + desc: "Specifies the lite protocol tester side. Supported values: sender, receiver.", + defaultValue: TesterFunctionality.RECEIVER, + name: "test-func" + .}: TesterFunctionality + + lightpushVersion* {. + desc: "Version of the sender to use. Supported values: legacy, v3.", + defaultValue: LightpushVersion.LEGACY, + name: "lightpush-version" + .}: LightpushVersion + + numMessages* {. + desc: "Number of messages to send.", defaultValue: 120, name: "num-messages" + .}: uint32 + + startPublishingAfter* {. + desc: "Wait number of seconds before start publishing messages.", + defaultValue: 5, + name: "start-publishing-after" + .}: uint32 + + messageInterval* {. + desc: "Delay between messages in milliseconds.", + defaultValue: 1000, + name: "message-interval" + .}: uint32 + + shard* {.desc: "Shards index to subscribe to. ", defaultValue: 0, name: "shard".}: + uint16 + + contentTopics* {. + desc: "Default content topic to subscribe to. Argument may be repeated.", + defaultValue: @[LiteContentTopic], + name: "content-topic" + .}: seq[ContentTopic] + + clusterId* {. + desc: + "Cluster id that the node is running in. Node in a different cluster id is disconnected.", + defaultValue: 0, + name: "cluster-id" + .}: uint16 + + minTestMessageSize* {. + desc: + "Minimum message size. Accepted units: KiB, KB, and B. e.g. 1024KiB; 1500 B; etc.", + defaultValue: DefaultMinTestMessageSizeStr, + name: "min-test-msg-size" + .}: string + + maxTestMessageSize* {. + desc: + "Maximum message size. Accepted units: KiB, KB, and B. e.g. 1024KiB; 1500 B; etc.", + defaultValue: DefaultMaxTestMessageSizeStr, + name: "max-test-msg-size" + .}: string + ## Tester REST service configuration + restAddress* {. + desc: "Listening address of the REST HTTP server.", + defaultValue: parseIpAddress("127.0.0.1"), + name: "rest-address" + .}: IpAddress + + testPeers* {. + desc: "Run dial test on gathered PeerExchange peers.", + defaultValue: false, + name: "test-peers" + .}: bool + + reqPxPeers* {. + desc: "Number of peers to request on PeerExchange.", + defaultValue: 100, + name: "req-px-peers" + .}: uint16 + + restPort* {. + desc: "Listening port of the REST HTTP server.", + defaultValue: 8654, + name: "rest-port" + .}: uint16 + + fixedServicePeer* {. + desc: + "Prevent changing the service peer in case of failures, the full test will stict to the first service peer in use.", + defaultValue: false, + name: "fixed-service-peer" + .}: bool + + restAllowOrigin* {. + desc: + "Allow cross-origin requests from the specified origin." & + "Argument may be repeated." & "Wildcards: * or ? allowed." & + "Ex.: \"localhost:*\" or \"127.0.0.1:8080\"", + defaultValue: @["*"], + name: "rest-allow-origin" + .}: seq[string] + + metricsPort* {. + desc: "Listening port of the Metrics HTTP server.", + defaultValue: 8003, + name: "metrics-port" + .}: uint16 + +{.push warning[ProveInit]: off.} + +proc load*(T: type LiteProtocolTesterConf, version = ""): ConfResult[T] = + try: + let conf = LiteProtocolTesterConf.load( + version = version, + secondarySources = proc( + conf: LiteProtocolTesterConf, sources: auto + ) {.gcsafe, raises: [ConfigurationError].} = + sources.addConfigFile(Envvar, InputFile("liteprotocoltester")), + ) + ok(conf) + except CatchableError: + err(getCurrentExceptionMsg()) + +proc getPubsubTopic*(conf: LiteProtocolTesterConf): PubsubTopic = + return $RelayShard(clusterId: conf.clusterId, shardId: conf.shard) + +proc getCodec*(conf: LiteProtocolTesterConf): string = + return + if conf.testFunc == TesterFunctionality.RECEIVER: + WakuFilterSubscribeCodec + else: + if conf.lightpushVersion == LightpushVersion.LEGACY: + WakuLegacyLightPushCodec + else: + WakuLightPushCodec + +{.pop.} diff --git a/apps/liteprotocoltester/tester_message.nim b/apps/liteprotocoltester/tester_message.nim new file mode 100644 index 0000000..eeff7b5 --- /dev/null +++ b/apps/liteprotocoltester/tester_message.nim @@ -0,0 +1,121 @@ +{.push raises: [].} + +import + chronicles, + json_serialization, + json_serialization/std/options, + json_serialization/lexer + +import ../../waku/waku_api/rest/serdes + +type ProtocolTesterMessage* = object + sender*: string + index*: uint32 + count*: uint32 + startedAt*: int64 + sinceStart*: int64 + sincePrev*: int64 + size*: uint64 + +proc writeValue*( + writer: var JsonWriter[RestJson], value: ProtocolTesterMessage +) {.raises: [IOError].} = + writer.beginRecord() + writer.writeField("sender", value.sender) + writer.writeField("index", value.index) + writer.writeField("count", value.count) + writer.writeField("startedAt", value.startedAt) + writer.writeField("sinceStart", value.sinceStart) + writer.writeField("sincePrev", value.sincePrev) + writer.writeField("size", value.size) + writer.endRecord() + +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] + + for fieldName in readObjectFields(reader): + case fieldName + of "sender": + if sender.isSome(): + reader.raiseUnexpectedField( + "Multiple `sender` fields found", "ProtocolTesterMessage" + ) + sender = some(reader.readValue(string)) + of "index": + if index.isSome(): + reader.raiseUnexpectedField( + "Multiple `index` fields found", "ProtocolTesterMessage" + ) + index = some(reader.readValue(uint32)) + of "count": + if count.isSome(): + reader.raiseUnexpectedField( + "Multiple `count` fields found", "ProtocolTesterMessage" + ) + count = some(reader.readValue(uint32)) + of "startedAt": + if startedAt.isSome(): + reader.raiseUnexpectedField( + "Multiple `startedAt` fields found", "ProtocolTesterMessage" + ) + startedAt = some(reader.readValue(int64)) + of "sinceStart": + if sinceStart.isSome(): + reader.raiseUnexpectedField( + "Multiple `sinceStart` fields found", "ProtocolTesterMessage" + ) + sinceStart = some(reader.readValue(int64)) + of "sincePrev": + if sincePrev.isSome(): + reader.raiseUnexpectedField( + "Multiple `sincePrev` fields found", "ProtocolTesterMessage" + ) + sincePrev = some(reader.readValue(int64)) + of "size": + if size.isSome(): + reader.raiseUnexpectedField( + "Multiple `size` fields found", "ProtocolTesterMessage" + ) + size = some(reader.readValue(uint64)) + else: + unrecognizedFieldWarning(value) + + if sender.isNone(): + reader.raiseUnexpectedValue("Field `sender` is missing") + + if index.isNone(): + reader.raiseUnexpectedValue("Field `index` is missing") + + if count.isNone(): + reader.raiseUnexpectedValue("Field `count` is missing") + + if startedAt.isNone(): + reader.raiseUnexpectedValue("Field `startedAt` is missing") + + if sinceStart.isNone(): + reader.raiseUnexpectedValue("Field `sinceStart` is missing") + + if sincePrev.isNone(): + reader.raiseUnexpectedValue("Field `sincePrev` is missing") + + if size.isNone(): + reader.raiseUnexpectedValue("Field `size` is missing") + + value = ProtocolTesterMessage( + sender: sender.get(), + index: index.get(), + count: count.get(), + startedAt: startedAt.get(), + sinceStart: sinceStart.get(), + sincePrev: sincePrev.get(), + size: size.get(), + ) diff --git a/apps/liteprotocoltester/v3_publisher.nim b/apps/liteprotocoltester/v3_publisher.nim new file mode 100644 index 0000000..c8353b5 --- /dev/null +++ b/apps/liteprotocoltester/v3_publisher.nim @@ -0,0 +1,29 @@ +import results, options, chronos +import waku/[waku_node, waku_core, waku_lightpush, waku_lightpush/common] +import publisher_base + +type V3Publisher* = ref object of PublisherBase + +proc new*(T: type V3Publisher, wakuNode: WakuNode): T = + if isNil(wakuNode.wakuLightpushClient): + wakuNode.mountLightPushClient() + + return V3Publisher(wakuNode: wakuNode) + +method send*( + self: V3Publisher, + topic: PubsubTopic, + message: WakuMessage, + servicePeer: RemotePeerInfo, +): 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)) + ).valueOr: + if error.code == LightPushErrorCode.NO_PEERS_TO_RELAY and + error.desc != 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: + return err($error.code) + return ok() diff --git a/apps/networkmonitor/README.md b/apps/networkmonitor/README.md new file mode 100644 index 0000000..3e10367 --- /dev/null +++ b/apps/networkmonitor/README.md @@ -0,0 +1,84 @@ +# networkmonitor + +Monitoring tool to run in an existing `waku` network with the following features: + +* Keeps discovering new peers using `discv5` +* Tracks advertised capabilities of each node as per stored in the ENR `waku` field +* Attempts to connect to all nodes, tracking which protocols each node supports +* Presents grafana-ready metrics showing the state of the network in terms of locations, ips, number discovered peers, number of peers we could connect to, user-agent that each peer contains, content topics and the amount of rx messages in each one. +* Metrics are exposed through prometheus metrics but also with a custom rest api, presenting detailed information about each peer. These metrics are exposed via a rest api. + +## Usage + +```console +./build/networkmonitor --help +Usage: + +networkmonitor [OPTIONS]... + +The following options are available: + + -l, --log-level Sets the log level [=LogLevel.INFO]. + -t, --timeout Timeout to consider that the connection failed [=chronos.seconds(10)]. + -b, --bootstrap-node Bootstrap ENR node. Argument may be repeated. [=@[""]]. + --dns-discovery-url URL for DNS node list in format 'enrtree://@'. + --pubsub-topic Default pubsub topic to subscribe to. Argument may be repeated.. + -r, --refresh-interval How often new peers are discovered and connected to (in seconds) [=5]. + --cluster-id Cluster id that the node is running in. Node in a different cluster id is + disconnected. [=1]. + --rln-relay Enable spam protection through rln-relay: true|false [=true]. + --rln-relay-dynamic Enable waku-rln-relay with on-chain dynamic group management: true|false + [=true]. + --rln-relay-eth-client-address HTTP address of an Ethereum testnet client e.g., http://localhost:8540/ + [=http://localhost:8540/]. + --rln-relay-eth-contract-address Address of membership contract on an Ethereum testnet. + --rln-relay-epoch-sec Epoch size in seconds used to rate limit RLN memberships. Default is 1 second. + [=1]. + --rln-relay-user-message-limit Set a user message limit for the rln membership registration. Must be a positive + integer. Default is 1. [=1]. + --metrics-server Enable the metrics server: true|false [=true]. + --metrics-server-address Listening address of the metrics server. [=parseIpAddress("127.0.0.1")]. + --metrics-server-port Listening HTTP port of the metrics server. [=8008]. + --metrics-rest-address Listening address of the metrics rest server. [=127.0.0.1]. + --metrics-rest-port Listening HTTP port of the metrics rest server. [=8009]. +``` + +## Example + +Connect to the network through a given bootstrap node, with default parameters. See metrics section for the data that it exposes. + +```console +./build/networkmonitor --log-level=INFO --b="enr:-QEkuEB3WHNS-xA3RDpfu9A2Qycr3bN3u7VoArMEiDIFZJ66F1EB3d4wxZN1hcdcOX-RfuXB-MQauhJGQbpz3qUofOtLAYJpZIJ2NIJpcIQI2SVcim11bHRpYWRkcnO4bgA0Ni9ub2RlLTAxLmFjLWNuLWhvbmdrb25nLWMud2FrdS5zYW5kYm94LnN0YXR1cy5pbQZ2XwA2Ni9ub2RlLTAxLmFjLWNuLWhvbmdrb25nLWMud2FrdS5zYW5kYm94LnN0YXR1cy5pbQYfQN4DgnJzkwABCAAAAAEAAgADAAQABQAGAAeJc2VjcDI1NmsxoQPK35Nnz0cWUtSAhBp7zvHEhyU_AqeQUlqzLiLxfP2L4oN0Y3CCdl-DdWRwgiMohXdha3UyDw" +``` + +```console +./build/networkmonitor --log-level=INFO --dns-discovery-url=enrtree://AL65EKLJAUXKKPG43HVTML5EFFWEZ7L4LOKTLZCLJASG4DSESQZEC@prod.status.nodes.status.im +``` + +## Metrics + +Metrics are divided into two categories: + +* Prometheus metrics, exposed as i.e. gauges. +* Custom metrics, used for unconstrained labels such as peer information or content topics. + - These metrics are not exposed through prometheus because since they are unconstrained, they can end up breaking the backend, as a new datapoint is generated for each one and it can reach up a point where is too much to handle. + +### Prometheus Metrics + +The following metrics are available. See `http://localhost:8008/metrics` + +* `peer_type_as_per_enr`: Number of peers supporting each capability according to the ENR (Relay, Store, Lightpush, Filter) +* `peer_type_as_per_protocol`: Number of peers supporting each protocol, after a successful connection) +* `peer_user_agents`: List of useragents found in the network and their count + +Other relevant metrics reused from `nim-eth`: + +* `routing_table_nodes`: Inherited from nim-eth, number of nodes in the routing table +* `discovery_message_requests_outgoing_total`: Inherited from nim-eth, number of outgoing discovery requests, useful to know if the node is actively looking for new peers + +### Custom Metrics + +The following endpoints are available: + +* `http://localhost:8009/allpeersinfo`: json list of all peers with extra information such as ip, location, supported protocols and last connection time. +* `http://localhost:8009/contenttopics`: content topic messages and its message count. diff --git a/apps/networkmonitor/docker-compose.yml b/apps/networkmonitor/docker-compose.yml new file mode 100644 index 0000000..d7bf661 --- /dev/null +++ b/apps/networkmonitor/docker-compose.yml @@ -0,0 +1,34 @@ +version: '3.8' +networks: + monitoring: + driver: bridge + +volumes: + prometheus-data: + driver: local + grafana-data: + driver: local + +# Services definitions +services: + + prometheus: + image: docker.io/prom/prometheus:latest + container_name: prometheus + ports: + - 9090:9090 + command: + - '--config.file=/etc/prometheus/prometheus.yaml' + volumes: + - ./prometheus.yaml:/etc/prometheus/prometheus.yaml:ro + - ./data:/prometheus + restart: unless-stopped + + grafana: + image: grafana/grafana-oss:latest + container_name: grafana + ports: + - '3000:3000' + volumes: + - grafana-data:/var/lib/grafana + restart: unless-stopped diff --git a/apps/networkmonitor/networkmonitor.nim b/apps/networkmonitor/networkmonitor.nim new file mode 100644 index 0000000..a9144ae --- /dev/null +++ b/apps/networkmonitor/networkmonitor.nim @@ -0,0 +1,668 @@ +{.push raises: [].} + +import + std/[net, tables, strutils, times, sequtils, random], + results, + chronicles, + chronicles/topics_registry, + chronos, + chronos/timer as ctime, + confutils, + eth/keys, + eth/p2p/discoveryv5/enr, + libp2p/crypto/crypto, + libp2p/nameresolving/dnsresolver, + libp2p/protocols/ping, + metrics, + metrics/chronos_httpserver, + presto/[route, server, client] +import + waku/[ + waku_core, + node/peer_manager, + waku_node, + waku_enr, + discovery/waku_discv5, + discovery/waku_dnsdisc, + waku_relay, + waku_rln_relay, + factory/builder, + factory/networks_config, + ], + ./networkmonitor_metrics, + ./networkmonitor_config, + ./networkmonitor_utils + +logScope: + topics = "networkmonitor" + +const ReconnectTime = 60 +const MaxConnectionRetries = 5 +const ResetRetriesAfter = 1200 +const PingSmoothing = 0.3 +const MaxConnectedPeers = 150 + +const git_version* {.strdefine.} = "n/a" + +proc setDiscoveredPeersCapabilities(routingTableNodes: seq[waku_enr.Record]) = + for capability in @[Relay, Store, Filter, Lightpush]: + let nOfNodesWithCapability = + routingTableNodes.countIt(it.supportsCapability(capability)) + info "capabilities as per ENR waku flag", + capability = capability, amount = nOfNodesWithCapability + networkmonitor_peer_type_as_per_enr.set( + int64(nOfNodesWithCapability), labelValues = [$capability] + ) + +proc setDiscoveredPeersCluster(routingTableNodes: seq[Node]) = + var clusters: CountTable[uint16] + + for node in routingTableNodes: + let typedRec = node.record.toTyped().valueOr: + clusters.inc(0) + continue + + let relayShard = typedRec.relaySharding().valueOr: + clusters.inc(0) + continue + + clusters.inc(relayShard.clusterId) + + for (key, value) in clusters.pairs: + networkmonitor_peer_cluster_as_per_enr.set(int64(value), labelValues = [$key]) + +proc analyzePeer( + customPeerInfo: CustomPeerInfoRef, + peerInfo: RemotePeerInfo, + node: WakuNode, + timeout: chronos.Duration, +): Future[Result[string, string]] {.async.} = + var pingDelay: chronos.Duration + + proc ping(): Future[Result[void, string]] {.async, gcsafe.} = + try: + let conn = await node.switch.dial(peerInfo.peerId, peerInfo.addrs, PingCodec) + pingDelay = await node.libp2pPing.ping(conn) + return ok() + except CatchableError: + var msg = getCurrentExceptionMsg() + if msg == "Future operation cancelled!": + msg = "timedout" + warn "failed to ping the peer", peer = peerInfo, err = msg + + customPeerInfo.connError = msg + return err("could not ping peer: " & msg) + + let timedOut = not await ping().withTimeout(timeout) + # need this check for pingDelat == 0 because there may be a conn error before timeout + if timedOut or pingDelay == 0.millis: + customPeerInfo.retries += 1 + return err(customPeerInfo.connError) + + customPeerInfo.connError = "" + info "successfully pinged peer", peer = peerInfo, duration = pingDelay.millis + networkmonitor_peer_ping.observe(pingDelay.millis) + + # We are using a smoothed moving average + customPeerInfo.avgPingDuration = + if customPeerInfo.avgPingDuration.millis == 0: + pingDelay + else: + let newAvg = + (float64(pingDelay.millis) * PingSmoothing) + + float64(customPeerInfo.avgPingDuration.millis) * (1.0 - PingSmoothing) + + int64(newAvg).millis + + customPeerInfo.lastPingDuration = pingDelay + + return ok(customPeerInfo.peerId) + +proc shouldReconnect(customPeerInfo: CustomPeerInfoRef): bool = + let reconnetIntervalCheck = + getTime().toUnix() >= customPeerInfo.lastTimeConnected + ReconnectTime + var retriesCheck = customPeerInfo.retries < MaxConnectionRetries + + if not retriesCheck and + getTime().toUnix() >= customPeerInfo.lastTimeConnected + ResetRetriesAfter: + customPeerInfo.retries = 0 + retriesCheck = true + info "resetting retries counter", peerId = customPeerInfo.peerId + + return reconnetIntervalCheck and retriesCheck + +# TODO: Split in discover, connect +proc setConnectedPeersMetrics( + discoveredNodes: seq[waku_enr.Record], + node: WakuNode, + timeout: chronos.Duration, + restClient: RestClientRef, + allPeers: CustomPeersTableRef, +) {.async.} = + let currentTime = getTime().toUnix() + + var newPeers = 0 + var successfulConnections = 0 + + var analyzeFuts: seq[Future[Result[string, string]]] + + var (inConns, outConns) = node.peer_manager.connectedPeers(WakuRelayCodec) + info "connected peers", inConns = inConns.len, outConns = outConns.len + + shuffle(outConns) + + if outConns.len >= toInt(MaxConnectedPeers / 2): + for p in outConns[0 ..< toInt(outConns.len / 2)]: + trace "Pruning Peer", Peer = $p + asyncSpawn(node.switch.disconnect(p)) + + # iterate all newly discovered nodes + for discNode in discoveredNodes: + let peerRes = toRemotePeerInfo(discNode) + + let peerInfo = peerRes.valueOr: + warn "error converting record to remote peer info", record = discNode + continue + + # create new entry if new peerId found + let peerId = $peerInfo.peerId + + if not allPeers.hasKey(peerId): + allPeers[peerId] = CustomPeerInfoRef(peerId: peerId) + newPeers += 1 + else: + info "already seen", peerId = peerId + + let customPeerInfo = allPeers[peerId] + + customPeerInfo.lastTimeDiscovered = currentTime + customPeerInfo.enr = discNode.toURI() + customPeerInfo.enrCapabilities = discNode.getCapabilities().mapIt($it) + customPeerInfo.discovered += 1 + + for maddr in peerInfo.addrs: + if $maddr notin customPeerInfo.maddrs: + customPeerInfo.maddrs.add $maddr + let typedRecord = discNode.toTypedRecord() + if not typedRecord.isOk(): + warn "could not convert record to typed record", record = discNode + continue + if not typedRecord.get().ip.isSome(): + warn "ip field is not set", record = typedRecord.get() + continue + + let ip = $typedRecord.get().ip.get().join(".") + customPeerInfo.ip = ip + + # try to ping the peer + if shouldReconnect(customPeerInfo): + if customPeerInfo.retries > 0: + warn "trying to dial failed peer again", + peerId = peerId, retry = customPeerInfo.retries + analyzeFuts.add(analyzePeer(customPeerInfo, peerInfo, node, timeout)) + + # Wait for all connection attempts to finish + let analyzedPeers = await allFinished(analyzeFuts) + + for peerIdFut in analyzedPeers: + let peerIdRes = await peerIdFut + let peerIdStr = peerIdRes.valueOr: + continue + + successfulConnections += 1 + let peerId = PeerId.init(peerIdStr).valueOr: + warn "failed to parse peerId", peerId = peerIdStr + continue + var customPeerInfo = allPeers[peerIdStr] + + debug "connected to peer", peer = customPeerInfo[] + + # after connection, get supported protocols + let lp2pPeerStore = node.switch.peerStore + let nodeProtocols = lp2pPeerStore[ProtoBook][peerId] + customPeerInfo.supportedProtocols = nodeProtocols + customPeerInfo.lastTimeConnected = currentTime + + # after connection, get user-agent + let nodeUserAgent = lp2pPeerStore[AgentBook][peerId] + customPeerInfo.userAgent = nodeUserAgent + + info "number of newly discovered peers", amount = newPeers + # inform the total connections that we did in this round + info "number of successful connections", amount = successfulConnections + +proc updateMetrics(allPeersRef: CustomPeersTableRef) {.gcsafe.} = + var allProtocols: Table[string, int] + var allAgentStrings: Table[string, int] + var countries: Table[string, int] + var connectedPeers = 0 + var failedPeers = 0 + + for peerInfo in allPeersRef.values: + if peerInfo.connError == "": + for protocol in peerInfo.supportedProtocols: + allProtocols[protocol] = allProtocols.mgetOrPut(protocol, 0) + 1 + + # store available user-agents in the network + allAgentStrings[peerInfo.userAgent] = + allAgentStrings.mgetOrPut(peerInfo.userAgent, 0) + 1 + + if peerInfo.country != "": + countries[peerInfo.country] = countries.mgetOrPut(peerInfo.country, 0) + 1 + + connectedPeers += 1 + else: + failedPeers += 1 + + networkmonitor_peer_count.set(int64(connectedPeers), labelValues = ["true"]) + networkmonitor_peer_count.set(int64(failedPeers), labelValues = ["false"]) + # update count on each protocol + for protocol in allProtocols.keys(): + let countOfProtocols = allProtocols.mgetOrPut(protocol, 0) + networkmonitor_peer_type_as_per_protocol.set( + int64(countOfProtocols), labelValues = [protocol] + ) + info "supported protocols in the network", + protocol = protocol, count = countOfProtocols + + # update count on each user-agent + for userAgent in allAgentStrings.keys(): + let countOfUserAgent = allAgentStrings.mgetOrPut(userAgent, 0) + networkmonitor_peer_user_agents.set( + int64(countOfUserAgent), labelValues = [userAgent] + ) + info "user agents participating in the network", + userAgent = userAgent, count = countOfUserAgent + + for country in countries.keys(): + let peerCount = countries.mgetOrPut(country, 0) + networkmonitor_peer_country_count.set(int64(peerCount), labelValues = [country]) + info "number of peers per country", country = country, count = peerCount + +proc populateInfoFromIp( + allPeersRef: CustomPeersTableRef, restClient: RestClientRef +) {.async.} = + for peer in allPeersRef.keys(): + if allPeersRef[peer].country != "" and allPeersRef[peer].city != "": + continue + # TODO: Update also if last update > x + if allPeersRef[peer].ip == "": + continue + # get more info the peers from its ip address + var location: NodeLocation + try: + # IP-API endpoints are now limited to 45 HTTP requests per minute + await sleepAsync(1400.millis) + let response = await restClient.ipToLocation(allPeersRef[peer].ip) + location = response.data + except CatchableError: + warn "could not get location", ip = allPeersRef[peer].ip + continue + allPeersRef[peer].country = location.country + allPeersRef[peer].city = location.city + +# TODO: Split in discovery, connections, and ip2location +# crawls the network discovering peers and trying to connect to them +# metrics are processed and exposed +proc crawlNetwork( + node: WakuNode, + wakuDiscv5: WakuDiscoveryV5, + restClient: RestClientRef, + conf: NetworkMonitorConf, + allPeersRef: CustomPeersTableRef, +) {.async.} = + let crawlInterval = conf.refreshInterval * 1000 + while true: + let startTime = Moment.now() + # discover new random nodes + let discoveredNodes = await wakuDiscv5.findRandomPeers() + + # nodes are nested into bucket, flat it + let flatNodes = wakuDiscv5.protocol.routingTable.buckets.mapIt(it.nodes).flatten() + + # populate metrics related to capabilities as advertised by the ENR (see waku field) + setDiscoveredPeersCapabilities(discoveredNodes) + + # populate cluster metrics as advertised by the ENR + setDiscoveredPeersCluster(flatNodes) + + # tries to connect to all newly discovered nodes + # and populates metrics related to peers we could connect + # note random discovered nodes can be already known + await setConnectedPeersMetrics( + discoveredNodes, node, conf.timeout, restClient, allPeersRef + ) + + updateMetrics(allPeersRef) + + # populate info from ip addresses + await populateInfoFromIp(allPeersRef, restClient) + + let totalNodes = discoveredNodes.len + #let seenNodes = totalNodes + + info "discovered nodes: ", total = totalNodes #, seen = seenNodes + + # Notes: + # we dont run ipMajorityLoop + # we dont run revalidateLoop + let endTime = Moment.now() + let elapsed = (endTime - startTime).nanos + + info "crawl duration", time = elapsed.millis + + await sleepAsync(crawlInterval.millis - elapsed.millis) + +proc retrieveDynamicBootstrapNodes( + dnsDiscoveryUrl: string, dnsAddrsNameServers: seq[IpAddress] +): Future[Result[seq[RemotePeerInfo], string]] {.async.} = + ## Retrieve dynamic bootstrap nodes (DNS discovery) + + if dnsDiscoveryUrl != "": + # DNS discovery + debug "Discovering nodes using Waku DNS discovery", url = dnsDiscoveryUrl + + var nameServers: seq[TransportAddress] + for ip in dnsAddrsNameServers: + nameServers.add(initTAddress(ip, Port(53))) # Assume all servers use port 53 + + let dnsResolver = DnsResolver.new(nameServers) + + proc resolver(domain: string): Future[string] {.async, gcsafe.} = + trace "resolving", domain = domain + let resolved = await dnsResolver.resolveTxt(domain) + if resolved.len > 0: + return resolved[0] # Use only first answer + + var wakuDnsDiscovery = WakuDnsDiscovery.init(dnsDiscoveryUrl, resolver) + if wakuDnsDiscovery.isOk(): + return (await wakuDnsDiscovery.get().findPeers()).mapErr( + proc(e: cstring): string = + $e + ) + else: + warn "Failed to init Waku DNS discovery" + + debug "No method for retrieving dynamic bootstrap nodes specified." + ok(newSeq[RemotePeerInfo]()) # Return an empty seq by default + +proc getBootstrapFromDiscDns( + conf: NetworkMonitorConf +): Future[Result[seq[enr.Record], string]] {.async.} = + try: + let dnsNameServers = @[parseIpAddress("1.1.1.1"), parseIpAddress("1.0.0.1")] + let dynamicBootstrapNodesRes = + await retrieveDynamicBootstrapNodes(conf.dnsDiscoveryUrl, dnsNameServers) + if not dynamicBootstrapNodesRes.isOk(): + error("failed discovering peers from DNS") + let dynamicBootstrapNodes = dynamicBootstrapNodesRes.get() + + # select dynamic bootstrap nodes that have an ENR containing a udp port. + # Discv5 only supports UDP https://github.com/ethereum/devp2p/blob/master/discv5/discv5-theory.md) + var discv5BootstrapEnrs: seq[enr.Record] + for n in dynamicBootstrapNodes: + if n.enr.isSome(): + let + enr = n.enr.get() + tenrRes = enr.toTypedRecord() + if tenrRes.isOk() and ( + tenrRes.get().udp.isSome() or tenrRes.get().udp6.isSome() + ): + discv5BootstrapEnrs.add(enr) + return ok(discv5BootstrapEnrs) + except CatchableError: + error("failed discovering peers from DNS") + +proc initAndStartApp( + conf: NetworkMonitorConf +): Future[Result[(WakuNode, WakuDiscoveryV5), string]] {.async.} = + let bindIp = + try: + parseIpAddress("0.0.0.0") + except CatchableError: + return err("could not start node: " & getCurrentExceptionMsg()) + + let extIp = + try: + parseIpAddress("127.0.0.1") + except CatchableError: + return err("could not start node: " & getCurrentExceptionMsg()) + + let + # some hardcoded parameters + rng = keys.newRng() + key = crypto.PrivateKey.random(Secp256k1, rng[])[] + nodeTcpPort = Port(60000) + nodeUdpPort = Port(9000) + flags = CapabilitiesBitfield.init( + lightpush = false, filter = false, store = false, relay = true + ) + + var builder = EnrBuilder.init(key) + + builder.withIpAddressAndPorts( + ipAddr = some(extIp), tcpPort = some(nodeTcpPort), udpPort = some(nodeUdpPort) + ) + builder.withWakuCapabilities(flags) + + builder.withWakuRelaySharding( + RelayShards(clusterId: conf.clusterId, shardIds: conf.shards) + ).isOkOr: + error "failed to add sharded topics to ENR", error = error + return err("failed to add sharded topics to ENR: " & $error) + + let recordRes = builder.build() + let record = + if recordRes.isErr(): + return err("cannot build record: " & $recordRes.error) + else: + recordRes.get() + + var nodeBuilder = WakuNodeBuilder.init() + + nodeBuilder.withNodeKey(key) + nodeBuilder.withRecord(record) + nodeBuilder.withSwitchConfiguration(maxConnections = some(MaxConnectedPeers)) + + nodeBuilder.withPeerManagerConfig( + maxConnections = MaxConnectedPeers, + relayServiceRatio = "13.33:86.67", + shardAware = true, + ) + let res = nodeBuilder.withNetworkConfigurationDetails(bindIp, nodeTcpPort) + if res.isErr(): + return err("node building error" & $res.error) + + let nodeRes = nodeBuilder.build() + let node = + if nodeRes.isErr(): + return err("node building error" & $res.error) + else: + nodeRes.get() + + var discv5BootstrapEnrsRes = await getBootstrapFromDiscDns(conf) + if discv5BootstrapEnrsRes.isErr(): + error("failed discovering peers from DNS") + var discv5BootstrapEnrs = discv5BootstrapEnrsRes.get() + + # parse enrURIs from the configuration and add the resulting ENRs to the discv5BootstrapEnrs seq + for enrUri in conf.bootstrapNodes: + addBootstrapNode(enrUri, discv5BootstrapEnrs) + + # discv5 + let discv5Conf = WakuDiscoveryV5Config( + discv5Config: none(DiscoveryConfig), + address: bindIp, + port: nodeUdpPort, + privateKey: keys.PrivateKey(key.skkey), + bootstrapRecords: discv5BootstrapEnrs, + autoupdateRecord: false, + ) + + let wakuDiscv5 = WakuDiscoveryV5.new(node.rng, discv5Conf, some(record)) + + try: + wakuDiscv5.protocol.open() + except CatchableError: + return err("could not start node: " & getCurrentExceptionMsg()) + + ok((node, wakuDiscv5)) + +proc startRestApiServer( + conf: NetworkMonitorConf, + allPeersInfo: CustomPeersTableRef, + numMessagesPerContentTopic: ContentTopicMessageTableRef, +): Result[void, string] = + try: + let serverAddress = + initTAddress(conf.metricsRestAddress & ":" & $conf.metricsRestPort) + proc validate(pattern: string, value: string): int = + if pattern.startsWith("{") and pattern.endsWith("}"): 0 else: 1 + + var router = RestRouter.init(validate) + router.installHandler(allPeersInfo, numMessagesPerContentTopic) + var sres = RestServerRef.new(router, serverAddress) + let restServer = sres.get() + restServer.start() + except CatchableError: + error("could not start rest api server") + ok() + +# handles rx of messages over a topic (see subscribe) +# counts the number of messages per content topic +proc subscribeAndHandleMessages( + node: WakuNode, + pubsubTopic: PubsubTopic, + msgPerContentTopic: ContentTopicMessageTableRef, +) = + # handle function + proc handler( + pubsubTopic: PubsubTopic, msg: WakuMessage + ): Future[void] {.async, gcsafe.} = + trace "rx message", pubsubTopic = pubsubTopic, contentTopic = msg.contentTopic + + # If we reach a table limit size, remove c topics with the least messages. + let tableSize = 100 + if msgPerContentTopic.len > (tableSize - 1): + let minIndex = toSeq(msgPerContentTopic.values()).minIndex() + msgPerContentTopic.del(toSeq(msgPerContentTopic.keys())[minIndex]) + + # TODO: Will overflow at some point + # +1 if content topic existed, init to 1 otherwise + if msgPerContentTopic.hasKey(msg.contentTopic): + msgPerContentTopic[msg.contentTopic] += 1 + else: + msgPerContentTopic[msg.contentTopic] = 1 + + node.subscribe((kind: PubsubSub, topic: pubsubTopic), WakuRelayHandler(handler)).isOkOr: + error "failed to subscribe to pubsub topic", pubsubTopic, error + quit(1) + +when isMainModule: + # known issue: confutils.nim(775, 17) Error: can raise an unlisted exception: ref IOError + {.pop.} + let confRes = NetworkMonitorConf.loadConfig() + if confRes.isErr(): + error "could not load cli variables", err = confRes.error + quit(1) + + var conf = confRes.get() + info "cli flags", conf = conf + + if conf.clusterId == 1: + let twnNetworkConf = NetworkConf.TheWakuNetworkConf() + + conf.bootstrapNodes = twnNetworkConf.discv5BootstrapNodes + conf.rlnRelayDynamic = twnNetworkConf.rlnRelayDynamic + conf.rlnRelayEthContractAddress = twnNetworkConf.rlnRelayEthContractAddress + conf.rlnEpochSizeSec = twnNetworkConf.rlnEpochSizeSec + conf.rlnRelayUserMessageLimit = twnNetworkConf.rlnRelayUserMessageLimit + conf.numShardsInNetwork = twnNetworkConf.shardingConf.numShardsInCluster + + if conf.shards.len == 0: + conf.shards = + toSeq(uint16(0) .. uint16(twnNetworkConf.shardingConf.numShardsInCluster - 1)) + + if conf.logLevel != LogLevel.NONE: + setLogLevel(conf.logLevel) + + # list of peers that we have discovered/connected + var allPeersInfo = CustomPeersTableRef() + + # content topic and the number of messages that were received + var msgPerContentTopic = ContentTopicMessageTableRef() + + # start metrics server + if conf.metricsServer: + let res = + startMetricsServer(conf.metricsServerAddress, Port(conf.metricsServerPort)) + if res.isErr(): + error "could not start metrics server", err = res.error + quit(1) + + # start rest server for custom metrics + let res = startRestApiServer(conf, allPeersInfo, msgPerContentTopic) + if res.isErr(): + error "could not start rest api server", err = res.error + quit(1) + + # create a rest client + let clientRest = + RestClientRef.new(url = "http://ip-api.com", connectTimeout = ctime.seconds(2)) + if clientRest.isErr(): + error "could not start rest api client", err = res.error + quit(1) + let restClient = clientRest.get() + + # start waku node + let nodeRes = waitFor initAndStartApp(conf) + if nodeRes.isErr(): + error "could not start node" + quit 1 + + let (node, discv5) = nodeRes.get() + + (waitFor node.mountRelay()).isOkOr: + error "failed to mount waku relay protocol: ", err = error + quit 1 + + waitFor node.mountLibp2pPing() + + var onFatalErrorAction = proc(msg: string) {.gcsafe, closure.} = + ## Action to be taken when an internal error occurs during the node run. + ## e.g. the connection with the database is lost and not recovered. + error "Unrecoverable error occurred", error = msg + quit(QuitFailure) + + if conf.rlnRelay and conf.rlnRelayEthContractAddress != "": + let rlnConf = WakuRlnConfig( + dynamic: conf.rlnRelayDynamic, + credIndex: some(uint(0)), + ethContractAddress: conf.rlnRelayEthContractAddress, + ethClientUrls: conf.ethClientUrls.mapIt(string(it)), + epochSizeSec: conf.rlnEpochSizeSec, + creds: none(RlnRelayCreds), + onFatalErrorAction: onFatalErrorAction, + ) + + try: + waitFor node.mountRlnRelay(rlnConf) + except CatchableError: + error "failed to setup RLN", err = getCurrentExceptionMsg() + quit 1 + + node.mountMetadata(conf.clusterId, conf.shards).isOkOr: + error "failed to mount waku metadata protocol: ", err = error + quit 1 + + for shard in conf.shards: + # Subscribe the node to the shards, to count messages + subscribeAndHandleMessages( + node, $RelayShard(shardId: shard, clusterId: conf.clusterId), msgPerContentTopic + ) + + # spawn the routine that crawls the network + # TODO: split into 3 routines (discovery, connections, ip2location) + asyncSpawn crawlNetwork(node, discv5, restClient, conf, allPeersInfo) + + runForever() diff --git a/apps/networkmonitor/networkmonitor_config.nim b/apps/networkmonitor/networkmonitor_config.nim new file mode 100644 index 0000000..f67fb09 --- /dev/null +++ b/apps/networkmonitor/networkmonitor_config.nim @@ -0,0 +1,190 @@ +import + chronicles, + chronicles/topics_registry, + confutils, + chronos, + std/strutils, + results, + regex + +const git_version* {.strdefine.} = "n/a" + +type EthRpcUrl* = distinct string + +proc `$`*(u: EthRpcUrl): string = + string(u) + +type NetworkMonitorConf* = object + logLevel* {. + desc: "Sets the log level", + defaultValue: LogLevel.INFO, + name: "log-level", + abbr: "l" + .}: LogLevel + + timeout* {. + desc: "Timeout to consider that the connection failed", + defaultValue: chronos.seconds(10), + name: "timeout", + abbr: "t" + .}: chronos.Duration + + bootstrapNodes* {. + desc: "Bootstrap ENR node. Argument may be repeated.", + defaultValue: @[""], + name: "bootstrap-node", + abbr: "b" + .}: seq[string] + + dnsDiscoveryUrl* {. + desc: "URL for DNS node list in format 'enrtree://@'", + defaultValue: "", + name: "dns-discovery-url" + .}: string + + shards* {. + desc: + "Shards index to subscribe to [0..NUM_SHARDS_IN_NETWORK-1]. Argument may be repeated.", + name: "shard" + .}: seq[uint16] + + numShardsInNetwork* {. + desc: "Number of shards in the network", + name: "num-shards-in-network", + defaultValue: 8 + .}: uint32 + + refreshInterval* {. + desc: "How often new peers are discovered and connected to (in seconds)", + defaultValue: 5, + name: "refresh-interval", + abbr: "r" + .}: int + + clusterId* {. + desc: + "Cluster id that the node is running in. Node in a different cluster id is disconnected.", + defaultValue: 1, + name: "cluster-id" + .}: uint16 + + rlnRelay* {. + desc: "Enable spam protection through rln-relay: true|false", + defaultValue: true, + name: "rln-relay" + .}: bool + + rlnRelayDynamic* {. + desc: "Enable waku-rln-relay with on-chain dynamic group management: true|false", + defaultValue: true, + name: "rln-relay-dynamic" + .}: bool + + ethClientUrls* {. + desc: + "HTTP address of an Ethereum testnet client e.g., http://localhost:8540/. Argument may be repeated.", + defaultValue: newSeq[EthRpcUrl](0), + name: "rln-relay-eth-client-address" + .}: seq[EthRpcUrl] + + rlnRelayEthContractAddress* {. + desc: "Address of membership contract on an Ethereum testnet", + defaultValue: "", + name: "rln-relay-eth-contract-address" + .}: string + + rlnEpochSizeSec* {. + desc: + "Epoch size in seconds used to rate limit RLN memberships. Default is 1 second.", + defaultValue: 1, + name: "rln-relay-epoch-sec" + .}: uint64 + + rlnRelayUserMessageLimit* {. + desc: + "Set a user message limit for the rln membership registration. Must be a positive integer. Default is 1.", + defaultValue: 1, + name: "rln-relay-user-message-limit" + .}: uint64 + + ## Prometheus metrics config + metricsServer* {. + desc: "Enable the metrics server: true|false", + defaultValue: true, + name: "metrics-server" + .}: bool + + metricsServerAddress* {. + desc: "Listening address of the metrics server.", + defaultValue: parseIpAddress("127.0.0.1"), + name: "metrics-server-address" + .}: IpAddress + + metricsServerPort* {. + desc: "Listening HTTP port of the metrics server.", + defaultValue: 8008, + name: "metrics-server-port" + .}: uint16 + + ## Custom metrics rest server + metricsRestAddress* {. + desc: "Listening address of the metrics rest server.", + defaultValue: "127.0.0.1", + name: "metrics-rest-address" + .}: string + metricsRestPort* {. + desc: "Listening HTTP port of the metrics rest server.", + defaultValue: 8009, + name: "metrics-rest-port" + .}: uint16 + +proc parseCmdArg*(T: type IpAddress, p: string): T = + try: + result = parseIpAddress(p) + except CatchableError as e: + raise newException(ValueError, "Invalid IP address") + +proc completeCmdArg*(T: type IpAddress, val: string): seq[string] = + return @[] + +proc parseCmdArg*(T: type chronos.Duration, p: string): T = + try: + result = chronos.seconds(parseInt(p)) + except CatchableError as e: + raise newException(ValueError, "Invalid duration value") + +proc completeCmdArg*(T: type chronos.Duration, val: string): seq[string] = + return @[] + +proc completeCmdArg*(T: type EthRpcUrl, val: string): seq[string] = + return @[] + +proc parseCmdArg*(T: type EthRpcUrl, s: string): T = + ## allowed patterns: + ## http://url:port + ## https://url:port + ## http://url:port/path + ## https://url:port/path + ## http://url/with/path + ## http://url:port/path?query + ## https://url:port/path?query + ## disallowed patterns: + ## any valid/invalid ws or wss url + var httpPattern = + re2"^(https?):\/\/((localhost)|([\w_-]+(?:(?:\.[\w_-]+)+)))(:[0-9]{1,5})?([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])*" + var wsPattern = + re2"^(wss?):\/\/((localhost)|([\w_-]+(?:(?:\.[\w_-]+)+)))(:[0-9]{1,5})?([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])*" + if regex.match(s, wsPattern): + raise newException( + ValueError, "Websocket RPC URL is not supported, Please use an HTTP URL" + ) + if not regex.match(s, httpPattern): + raise newException(ValueError, "Invalid HTTP RPC URL") + return EthRpcUrl(s) + +proc loadConfig*(T: type NetworkMonitorConf): Result[T, string] = + try: + let conf = NetworkMonitorConf.load(version = git_version) + ok(conf) + except CatchableError: + err(getCurrentExceptionMsg()) diff --git a/apps/networkmonitor/networkmonitor_metrics.nim b/apps/networkmonitor/networkmonitor_metrics.nim new file mode 100644 index 0000000..dda3e57 --- /dev/null +++ b/apps/networkmonitor/networkmonitor_metrics.nim @@ -0,0 +1,107 @@ +{.push raises: [].} + +import + std/[net, json, tables, sequtils], + chronicles, + chronicles/topics_registry, + chronos, + json_serialization, + metrics, + metrics/chronos_httpserver, + presto/route, + presto/server, + results + +logScope: + topics = "networkmonitor_metrics" + +# On top of our custom metrics, the following are reused from nim-eth +#routing_table_nodes{state=""} +#routing_table_nodes{state="seen"} +#discovery_message_requests_outgoing_total{response=""} +#discovery_message_requests_outgoing_total{response="no_response"} + +declarePublicGauge networkmonitor_peer_type_as_per_enr, + "Number of peers supporting each capability according to the ENR", + labels = ["capability"] + +declarePublicGauge networkmonitor_peer_cluster_as_per_enr, + "Number of peers on each cluster according to the ENR", labels = ["cluster"] + +declarePublicGauge networkmonitor_peer_type_as_per_protocol, + "Number of peers supporting each protocol, after a successful connection) ", + labels = ["protocols"] + +declarePublicGauge networkmonitor_peer_user_agents, + "Number of peers with each user agent", labels = ["user_agent"] + +declarePublicHistogram networkmonitor_peer_ping, + "Histogram tracking ping durations for discovered peers", + buckets = [10.0, 20.0, 50.0, 100.0, 200.0, 300.0, 500.0, 800.0, 1000.0, 2000.0, Inf] + +declarePublicGauge networkmonitor_peer_count, + "Number of discovered peers", labels = ["connected"] + +declarePublicGauge networkmonitor_peer_country_count, + "Number of peers per country", labels = ["country"] + +type + CustomPeerInfo* = object # populated after discovery + lastTimeDiscovered*: int64 + discovered*: int64 + peerId*: string + enr*: string + ip*: string + enrCapabilities*: seq[string] + country*: string + city*: string + maddrs*: seq[string] + + # only after ok connection + lastTimeConnected*: int64 + retries*: int64 + supportedProtocols*: seq[string] + userAgent*: string + lastPingDuration*: Duration + avgPingDuration*: Duration + + # only after a ok/nok connection + connError*: string + + CustomPeerInfoRef* = ref CustomPeerInfo + + # Stores information about all discovered/connected peers + CustomPeersTableRef* = TableRef[string, CustomPeerInfoRef] + + # stores the content topic and the count of rx messages + ContentTopicMessageTableRef* = TableRef[string, int] + +proc installHandler*( + router: var RestRouter, + allPeers: CustomPeersTableRef, + numMessagesPerContentTopic: ContentTopicMessageTableRef, +) = + router.api(MethodGet, "/allpeersinfo") do() -> RestApiResponse: + let values = toSeq(allPeers.values()) + return RestApiResponse.response(values.toJson(), contentType = "application/json") + router.api(MethodGet, "/contenttopics") do() -> RestApiResponse: + # TODO: toJson() includes the hash + return RestApiResponse.response( + $(%numMessagesPerContentTopic), contentType = "application/json" + ) + +proc startMetricsServer*(serverIp: IpAddress, serverPort: Port): Result[void, string] = + info "Starting metrics HTTP server", serverIp, serverPort + + try: + startMetricsHttpServer($serverIp, serverPort) + except Exception as e: + error( + "Failed to start metrics HTTP server", + serverIp = serverIp, + serverPort = serverPort, + msg = e.msg, + ) + + info "Metrics HTTP server started", serverIp, serverPort + ok() diff --git a/apps/networkmonitor/networkmonitor_utils.nim b/apps/networkmonitor/networkmonitor_utils.nim new file mode 100644 index 0000000..0e89c4a --- /dev/null +++ b/apps/networkmonitor/networkmonitor_utils.nim @@ -0,0 +1,53 @@ +{.push raises: [].} + +import + std/json, + results, + chronicles, + chronicles/topics_registry, + chronos, + presto/[client, common] + +type NodeLocation* = object + country*: string + city*: string + lat*: string + long*: string + isp*: string + +proc flatten*[T](a: seq[seq[T]]): seq[T] = + var aFlat = newSeq[T](0) + for subseq in a: + aFlat &= subseq + return aFlat + +proc decodeBytes*( + t: typedesc[NodeLocation], value: openArray[byte], contentType: Opt[ContentTypeData] +): RestResult[NodeLocation] = + var res: string + if len(value) > 0: + res = newString(len(value)) + copyMem(addr res[0], unsafeAddr value[0], len(value)) + try: + let jsonContent = parseJson(res) + if $jsonContent["status"].getStr() != "success": + error "query failed", result = $jsonContent + return err("query failed") + return ok( + NodeLocation( + country: jsonContent["country"].getStr(), + city: jsonContent["city"].getStr(), + lat: $jsonContent["lat"].getFloat(), + long: $jsonContent["lon"].getFloat(), + isp: jsonContent["isp"].getStr(), + ) + ) + except Exception: + return err("failed to get the location: " & getCurrentExceptionMsg()) + +proc encodeString*(value: string): RestResult[string] = + ok(value) + +proc ipToLocation*( + ip: string +): RestResponse[NodeLocation] {.rest, endpoint: "json/{ip}", meth: MethodGet.} diff --git a/apps/networkmonitor/nim.cfg b/apps/networkmonitor/nim.cfg new file mode 100644 index 0000000..2231f2e --- /dev/null +++ b/apps/networkmonitor/nim.cfg @@ -0,0 +1,4 @@ +-d:chronicles_line_numbers +-d:chronicles_runtime_filtering:on +-d:discv5_protocol_id:d5waku +path = "../.." diff --git a/apps/networkmonitor/prometheus.yaml b/apps/networkmonitor/prometheus.yaml new file mode 100644 index 0000000..c7af03f --- /dev/null +++ b/apps/networkmonitor/prometheus.yaml @@ -0,0 +1,9 @@ +global: + scrape_interval: 15s + +scrape_configs: + - job_name: 'prometheus' + scrape_interval: 5s + static_configs: + - targets: ['host.docker.internal:8008'] + metrics_path: '/metrics' \ No newline at end of file diff --git a/apps/sonda/.env.example b/apps/sonda/.env.example new file mode 100644 index 0000000..ea769b3 --- /dev/null +++ b/apps/sonda/.env.example @@ -0,0 +1,44 @@ +# RPC URL for accessing testnet via HTTP. +# e.g. https://linea-sepolia.infura.io/v3/123aa110320f4aec179150fba1e1b1b1 +RLN_RELAY_ETH_CLIENT_ADDRESS= + +# Account of testnet where you have Linea Sepolia ETH that would be staked into RLN contract. +ETH_TESTNET_ACCOUNT= + +# Private key of testnet where you have Linea Sepolia ETH that would be staked into RLN contract. +# Note: make sure you don't use the '0x' prefix. +# e.g. 0116196e9a8abed42dd1a22eb63fa2a5a17b0c27d716b87ded2c54f1bf192a0b +ETH_TESTNET_KEY= + +# Address of the RLN contract on Linea Sepolia. +RLN_CONTRACT_ADDRESS=0xB9cd878C90E49F797B4431fBF4fb333108CB90e6 +# Address of the RLN Membership Token contract on Linea Sepolia used to pay for membership. +TOKEN_CONTRACT_ADDRESS=0x185A0015aC462a0aECb81beCc0497b649a64B9ea + +# Password you would like to use to protect your RLN membership. +RLN_RELAY_CRED_PASSWORD= + +# Advanced. Can be left empty in normal use cases. +NWAKU_IMAGE= +NODEKEY= +DOMAIN= +EXTRA_ARGS= +STORAGE_SIZE= + + +# -------------------- SONDA CONFIG ------------------ +METRICS_PORT=8004 +NODE_REST_ADDRESS="http://nwaku:8645" +CLUSTER_ID=16 +SHARD=32 +# Comma separated list of store nodes to poll +STORE_NODES="/dns4/store-01.do-ams3.shards.test.status.im/tcp/30303/p2p/16Uiu2HAmAUdrQ3uwzuE4Gy4D56hX6uLKEeerJAnhKEHZ3DxF1EfT, +/dns4/store-02.do-ams3.shards.test.status.im/tcp/30303/p2p/16Uiu2HAm9aDJPkhGxc2SFcEACTFdZ91Q5TJjp76qZEhq9iF59x7R, +/dns4/store-01.gc-us-central1-a.shards.test.status.im/tcp/30303/p2p/16Uiu2HAmMELCo218hncCtTvC2Dwbej3rbyHQcR8erXNnKGei7WPZ, +/dns4/store-02.gc-us-central1-a.shards.test.status.im/tcp/30303/p2p/16Uiu2HAmJnVR7ZzFaYvciPVafUXuYGLHPzSUigqAmeNw9nJUVGeM, +/dns4/store-01.ac-cn-hongkong-c.shards.test.status.im/tcp/30303/p2p/16Uiu2HAm2M7xs7cLPc3jamawkEqbr7cUJX11uvY7LxQ6WFUdUKUT, +/dns4/store-02.ac-cn-hongkong-c.shards.test.status.im/tcp/30303/p2p/16Uiu2HAm9CQhsuwPR54q27kNj9iaQVfyRzTGKrhFmr94oD8ujU6P" +# Wait time in seconds between two consecutive queries +QUERY_DELAY=60 +# Consecutive successful store requests to consider a store node healthy +HEALTH_THRESHOLD=5 \ No newline at end of file diff --git a/apps/sonda/.gitignore b/apps/sonda/.gitignore new file mode 100644 index 0000000..f366b94 --- /dev/null +++ b/apps/sonda/.gitignore @@ -0,0 +1,4 @@ +.env +keystore +rln_tree +.env diff --git a/apps/sonda/Dockerfile.sonda b/apps/sonda/Dockerfile.sonda new file mode 100644 index 0000000..0e5a606 --- /dev/null +++ b/apps/sonda/Dockerfile.sonda @@ -0,0 +1,23 @@ +FROM python:3.9.18-alpine3.18 + +ENV METRICS_PORT=8004 +ENV NODE_REST_ADDRESS="http://nwaku:8645" +ENV QUERY_DELAY=60 +ENV STORE_NODES="" +ENV CLUSTER_ID=1 +ENV SHARD=1 +ENV HEALTH_THRESHOLD=5 + +WORKDIR /opt + +COPY sonda.py /opt/sonda.py + +RUN pip install requests argparse prometheus_client + +CMD python -u /opt/sonda.py \ + --metrics-port=$METRICS_PORT \ + --node-rest-address="${NODE_REST_ADDRESS}" \ + --delay-seconds=$QUERY_DELAY \ + --pubsub-topic="/waku/2/rs/${CLUSTER_ID}/${SHARD}" \ + --store-nodes="${STORE_NODES}" \ + --health-threshold=$HEALTH_THRESHOLD diff --git a/apps/sonda/README.md b/apps/sonda/README.md new file mode 100644 index 0000000..459f6fe --- /dev/null +++ b/apps/sonda/README.md @@ -0,0 +1,52 @@ +# Sonda + +Sonda is a tool to monitor store nodes and measure their performance. + +It works by running a `nwaku` node, publishing a message from it every fixed interval and performing a store query to all the store nodes we want to monitor to check they respond with the last message we published. + +## Instructions + +1. Create an `.env` file which will contain the configuration parameters. + You can start by copying `.env.example` and adapting it for your use case + + ``` + cp .env.example .env + ${EDITOR} .env + ``` + + The variables that have to be filled for Sonda are + + ``` + CLUSTER_ID= + SHARD= + # Comma separated list of store nodes to poll + STORE_NODES= + # Wait time in seconds between two consecutive queries + QUERY_DELAY= + # Consecutive successful store requests to consider a store node healthy + HEALTH_THRESHOLD= + ``` + +2. If you want to query nodes in `cluster-id` 1, then you have to follow the steps of registering an RLN membership. Otherwise, you can skip this step. + + For it, you need: + * Ethereum Linea Sepolia WebSocket endpoint. Get one free from [Infura](https://linea-sepolia.infura.io/). + * Ethereum Linea Sepolia account with minimum 0.01ETH. Get some [here](https://docs.metamask.io/developer-tools/faucet/). + * A password to protect your rln membership. + + Fill the `RLN_RELAY_ETH_CLIENT_ADDRESS`, `ETH_TESTNET_KEY` and `RLN_RELAY_CRED_PASSWORD` env variables and run + + ``` + ./register_rln.sh + ``` + +3. Start Sonda by running + + ``` + docker-compose up -d + ``` + +4. Browse to http://localhost:3000/dashboards and monitor the performance + + There's two Grafana dashboards: `nwaku-monitoring` to track the stats of your node that is publishing messages and performing queries, and `sonda-monitoring` to monitor the responses of the store nodes. + diff --git a/apps/sonda/docker-compose.yml b/apps/sonda/docker-compose.yml new file mode 100644 index 0000000..d659442 --- /dev/null +++ b/apps/sonda/docker-compose.yml @@ -0,0 +1,114 @@ + +x-logging: &logging + logging: + driver: json-file + options: + max-size: 1000m + +# Environment variable definitions +x-rln-relay-eth-client-address: &rln_relay_eth_client_address ${RLN_RELAY_ETH_CLIENT_ADDRESS:-} # Add your RLN_RELAY_ETH_CLIENT_ADDRESS after the "-" + +x-rln-environment: &rln_env + RLN_RELAY_CONTRACT_ADDRESS: ${RLN_RELAY_CONTRACT_ADDRESS:-0xB9cd878C90E49F797B4431fBF4fb333108CB90e6} + RLN_RELAY_CRED_PATH: ${RLN_RELAY_CRED_PATH:-} # Optional: Add your RLN_RELAY_CRED_PATH after the "-" + RLN_RELAY_CRED_PASSWORD: ${RLN_RELAY_CRED_PASSWORD:-} # Optional: Add your RLN_RELAY_CRED_PASSWORD after the "-" + +x-sonda-env: &sonda_env + METRICS_PORT: ${METRICS_PORT:-8004} + NODE_REST_ADDRESS: ${NODE_REST_ADDRESS:-"http://nwaku:8645"} + CLUSTER_ID: ${CLUSTER_ID:-1} + SHARD: ${SHARD:-0} + STORE_NODES: ${STORE_NODES:-} + QUERY_DELAY: ${QUERY_DELAY-60} + HEALTH_THRESHOLD: ${HEALTH_THRESHOLD-5} + +# Services definitions +services: + nwaku: + image: ${NWAKU_IMAGE:-harbor.status.im/wakuorg/nwaku:deploy-status-prod} + container_name: nwaku + restart: on-failure + ports: + - 30304:30304/tcp + - 30304:30304/udp + - 9005:9005/udp + - 127.0.0.1:8003:8003 + - 80:80 #Let's Encrypt + - 8000:8000/tcp #WSS + - 127.0.0.1:8645:8645 + <<: + - *logging + environment: + DOMAIN: ${DOMAIN} + NODEKEY: ${NODEKEY} + RLN_RELAY_CRED_PASSWORD: "${RLN_RELAY_CRED_PASSWORD}" + RLN_RELAY_ETH_CLIENT_ADDRESS: *rln_relay_eth_client_address + EXTRA_ARGS: ${EXTRA_ARGS} + STORAGE_SIZE: ${STORAGE_SIZE} + <<: + - *rln_env + - *sonda_env + volumes: + - ./run_node.sh:/opt/run_node.sh:Z + - ${CERTS_DIR:-./certs}:/etc/letsencrypt/:Z + - ./rln_tree:/etc/rln_tree/:Z + - ./keystore:/keystore:Z + entrypoint: sh + command: + - /opt/run_node.sh + networks: + - nwaku-sonda + + sonda: + build: + context: . + dockerfile: Dockerfile.sonda + container_name: sonda + ports: + - 127.0.0.1:${METRICS_PORT}:${METRICS_PORT} + environment: + <<: + - *sonda_env + depends_on: + - nwaku + networks: + - nwaku-sonda + + prometheus: + image: docker.io/prom/prometheus:latest + container_name: prometheus + volumes: + - ./monitoring/prometheus-config.yml:/etc/prometheus/prometheus.yml:Z + command: + - --config.file=/etc/prometheus/prometheus.yml + # ports: + # - 127.0.0.1:9090:9090 + restart: on-failure:5 + depends_on: + - nwaku + networks: + - nwaku-sonda + + grafana: + image: docker.io/grafana/grafana:latest + container_name: grafana + env_file: + - ./monitoring/configuration/grafana-plugins.env + volumes: + - ./monitoring/configuration/grafana.ini:/etc/grafana/grafana.ini:Z + - ./monitoring/configuration/dashboards.yaml:/etc/grafana/provisioning/dashboards/dashboards.yaml:Z + - ./monitoring/configuration/datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml:Z + - ./monitoring/configuration/dashboards:/var/lib/grafana/dashboards/:Z + - ./monitoring/configuration/customizations/custom-logo.svg:/usr/share/grafana/public/img/grafana_icon.svg:Z + - ./monitoring/configuration/customizations/custom-logo.svg:/usr/share/grafana/public/img/grafana_typelogo.svg:Z + - ./monitoring/configuration/customizations/custom-logo.png:/usr/share/grafana/public/img/fav32.png:Z + ports: + - 0.0.0.0:3000:3000 + restart: on-failure:5 + depends_on: + - prometheus + networks: + - nwaku-sonda + +networks: + nwaku-sonda: \ No newline at end of file diff --git a/apps/sonda/monitoring/configuration/customizations/custom-logo.png b/apps/sonda/monitoring/configuration/customizations/custom-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..dcf13b931be20127443409243f18a69329dc3d7e GIT binary patch literal 10938 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 q{LyJ(_S!`{;r~|P_y6SD>yt2q?MdW2>6pg< + + diff --git a/apps/sonda/monitoring/configuration/dashboards.yaml b/apps/sonda/monitoring/configuration/dashboards.yaml new file mode 100644 index 0000000..e59ac96 --- /dev/null +++ b/apps/sonda/monitoring/configuration/dashboards.yaml @@ -0,0 +1,9 @@ +apiVersion: 1 + +providers: +- name: 'Prometheus' + orgId: 1 + folder: '' + type: file + options: + path: /var/lib/grafana/dashboards \ No newline at end of file diff --git a/apps/sonda/monitoring/configuration/dashboards/nwaku-monitoring.json b/apps/sonda/monitoring/configuration/dashboards/nwaku-monitoring.json new file mode 100644 index 0000000..2b024e3 --- /dev/null +++ b/apps/sonda/monitoring/configuration/dashboards/nwaku-monitoring.json @@ -0,0 +1,5303 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": 12485, + "graphTooltip": 0, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 45, + "panels": [], + "title": "Waku Node", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 9, + "x": 0, + "y": 1 + }, + "id": 41, + "options": { + "displayMode": "gradient", + "maxVizHeight": 300, + "minVizHeight": 10, + "minVizWidth": 0, + "namePlacement": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "exemplar": false, + "expr": "rate(waku_histogram_message_size_bucket[1h])/scalar(rate(waku_histogram_message_size_count[1h]))*100", + "format": "heatmap", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Message distrubution %/kBytes (Last Hour)", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "deckbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 9, + "x": 9, + "y": 1 + }, + "id": 38, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(waku_histogram_message_size_sum[1h])/rate(waku_histogram_message_size_count[1h])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Average Msg Size (Last Hour)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "deckbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 9, + "y": 5 + }, + "id": 42, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.75, rate(waku_histogram_message_size_bucket[1h]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "75% Percentile (Last hour)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "deckbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 14, + "y": 5 + }, + "id": 39, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(waku_histogram_message_size_bucket[1h]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "99% Percentile (Last Hour)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 9, + "x": 0, + "y": 9 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "(increase(waku_node_messages_total[1m]))/60", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Messages/second", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "deckbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 9, + "x": 9, + "y": 9 + }, + "id": 43, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.4.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "exemplar": false, + "expr": "waku_histogram_message_size_sum/waku_histogram_message_size_count", + "format": "heatmap", + "instant": false, + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Average msg size (kBytes)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 3, + "x": 0, + "y": 16 + }, + "id": 2, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "builder", + "exemplar": false, + "expr": "waku_version{instance=\"nwaku:8003\"}", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Version", + "transformations": [ + { + "id": "filterFieldsByName", + "options": { + "include": { + "names": [ + "version" + ] + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 3, + "x": 3, + "y": 16 + }, + "id": 22, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "libp2p_autonat_reachability_confidence", + "legendFormat": "{{reachability}}", + "range": true, + "refId": "A" + } + ], + "title": "Reachability", + "transformations": [ + { + "id": "reduce", + "options": { + "includeTimeField": false, + "mode": "reduceFields", + "reducers": [ + "max" + ] + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 3, + "x": 6, + "y": 16 + }, + "id": 32, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "routing_table_nodes{state=\"seen\"}", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Discv5 (Seen Nodes)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 3, + "x": 9, + "y": 16 + }, + "id": 33, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "routing_table_nodes", + "legendFormat": "{{label_name}}", + "range": true, + "refId": "A" + } + ], + "title": "Discv5 (Nodes)", + "transformations": [ + { + "id": "filterFieldsByName", + "options": { + "include": { + "names": [ + "Time", + "{__name__=\"routing_table_nodes\", instance=\"nwaku:8003\", job=\"nwaku\"}" + ] + } + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 3, + "x": 12, + "y": 16 + }, + "id": 25, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "builder", + "expr": "libp2p_peers", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Connected Peers", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 3, + "x": 15, + "y": 16 + }, + "id": 28, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "libp2p_pubsub_topics", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Number Pubsub Topics", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "dateTimeAsIso" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 3, + "x": 0, + "y": 21 + }, + "id": 10, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "process_start_time_seconds{job=\"nwaku\"}*1000", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Start Times (UTC)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 15, + "x": 3, + "y": 21 + }, + "id": 44, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "waku_connected_peers", + "legendFormat": "{{direction}}_{{protocol}}", + "range": true, + "refId": "A" + } + ], + "title": "Connected Peers (Direction/Protocol)", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 3, + "x": 0, + "y": 26 + }, + "id": 36, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "waku_peer_store_size", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Peer Store Size", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 6, + "x": 0, + "y": 31 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.3.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "builder", + "expr": "libp2p_peers", + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A" + } + ], + "title": "Connected Peers", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "binBps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 6, + "x": 6, + "y": 31 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(libp2p_network_bytes_total{direction=\"in\"}[$__rate_interval])", + "legendFormat": "traffic_{{direction}}", + "range": true, + "refId": "A" + } + ], + "title": "libp2p traffic (in)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "binBps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 6, + "x": 12, + "y": 31 + }, + "id": 29, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(libp2p_network_bytes_total{direction=\"out\"}[$__rate_interval])", + "legendFormat": "traffic_{{direction}}", + "range": true, + "refId": "A" + } + ], + "title": "libp2p traffic (out)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 40 + }, + "id": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "nim_gc_heap_instance_occupied_bytes{}", + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A" + } + ], + "title": "Heap allocation", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 40 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "nim_gc_mem_bytes{}", + "hide": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A" + } + ], + "title": "Nim Memory Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 40 + }, + "id": 128, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "waku_rln_number_registered_memberships", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "RLN Registered Memberships", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 48 + }, + "id": 127, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "waku_rln_proof_generation_duration_seconds", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "RLN Proof Generation (seconds)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 48 + }, + "id": 126, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "waku_rln_proof_verification_duration_seconds", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "RLN Proof Verification (seconds)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 48 + }, + "id": 135, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "waku_rln_membership_insertion_duration_seconds", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "RLN Membership Insertion (seconds)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 54 + }, + "id": 134, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "waku_rln_membership_credentials_import_duration_seconds", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "RLN Credentials Import (seconds)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 54 + }, + "id": 137, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "waku_rln_messages_total_total", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "RLN Messages Total", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 54 + }, + "id": 136, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "waku_rln_proof_verification_total_total", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "RLN Proof Verification Total", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 60 + }, + "id": 133, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "waku_rln_invalid_messages_total_total", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "RLN Invalid Messages Total", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 60 + }, + "id": 130, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "waku_rln_spam_messages_total_total", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "RLN Spam Messages Total", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 60 + }, + "id": 138, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "waku_rln_invalid_messages_total_total", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{type}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "RLN Invalid Messages", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "Number of messages currently stored in the database", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 9, + "x": 0, + "y": 66 + }, + "id": 141, + "options": { + "legend": { + "calcs": [ + "last" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "pg_tb_stats_messages{}", + "instant": false, + "legendFormat": "{{ pubsubtopic }}", + "range": true, + "refId": "A" + } + ], + "title": "# messages per shard", + "type": "timeseries" + }, + { + "datasource": { + "type": "postgres", + "uid": "e5d2e0c2-371d-4178-ac71-edc122fb459c" + }, + "description": "Messages in local database per app name, as extracted from the content topic.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [ + { + "options": { + "/waku/2/rs/1/0": { + "index": 0, + "text": "0" + }, + "/waku/2/rs/1/1": { + "index": 1, + "text": "1" + }, + "/waku/2/rs/1/2": { + "index": 2, + "text": "2" + }, + "/waku/2/rs/1/3": { + "index": 3, + "text": "3" + }, + "/waku/2/rs/1/4": { + "index": 4, + "text": "4" + }, + "/waku/2/rs/1/5": { + "index": 5, + "text": "5" + }, + "/waku/2/rs/1/6": { + "index": 6, + "text": "6" + }, + "/waku/2/rs/1/7": { + "index": 7, + "text": "7" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "string" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Number of Messages (sum)" + }, + "properties": [ + { + "id": "unit", + "value": "none" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Payload Size (sum)" + }, + "properties": [ + { + "id": "unit", + "value": "decbytes" + } + ] + } + ] + }, + "gridPos": { + "h": 11, + "w": 9, + "x": 9, + "y": 66 + }, + "id": 144, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "frameIndex": 1, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "e5d2e0c2-371d-4178-ac71-edc122fb459c" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "SELECT REGEXP_REPLACE(contenttopic,'^\\/(.+)\\/(\\d+)\\/(.+)\\/(.+)$','\\1') as \"App name\", COUNT(id), pg_column_size(payload)\nFROM messages\nGROUP BY contenttopic, payload", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [ + { + "name": "pubsubtopic", + "type": "functionParameter" + } + ], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "name": "pubsubtopic", + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "messages" + } + ], + "title": "Stored Message by Content Topic App Name", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "contenttopic": "App name", + "count": "Number of Messages", + "pg_column_size": "Total Payload Size" + } + } + }, + { + "id": "groupBy", + "options": { + "fields": { + "App name": { + "aggregations": [ + "uniqueValues" + ], + "operation": "groupby" + }, + "Number of Messages": { + "aggregations": [ + "sum" + ], + "operation": "aggregate" + }, + "Total Payload Size": { + "aggregations": [ + "sum" + ], + "operation": "aggregate" + }, + "pg_column_size": { + "aggregations": [ + "sum" + ], + "operation": "aggregate" + } + } + } + }, + { + "id": "sortBy", + "options": { + "fields": {}, + "sort": [ + { + "desc": true, + "field": "Number of Messages (sum)" + } + ] + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "Number of messages currently stored in the database", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 9, + "x": 0, + "y": 77 + }, + "id": 146, + "options": { + "legend": { + "calcs": [ + "last" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "exemplar": false, + "expr": "pg_tb_messages_count{}", + "instant": false, + "interval": "", + "legendFormat": "messages", + "range": true, + "refId": "A" + } + ], + "title": "Unique stored messages (Postgres)", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 84 + }, + "id": 46, + "panels": [], + "title": "Postgres", + "type": "row" + }, + { + "colorBackground": false, + "colorValue": false, + "datasource": "Prometheus", + "description": "Source: server_version_num", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 85 + }, + "id": 11, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(50, 168, 82)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "max(pg_settings_server_version_num)", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "PostgreSQL Version", + "type": "stat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "description": "Transactions committed + roolback per minute\n\nSource: pg_stat_database,xact_commit + xact_rollback", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 4, + "y": 85 + }, + "id": 14, + "interval": "", + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum((rate(pg_stat_database_xact_commit{instance=\"$Instance\"}[$Interval])))+sum((rate(pg_stat_database_xact_rollback{instance=\"$Instance\"}[$Interval])))", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "Transaction rate (Postgres)", + "type": "stat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "description": "Statements executed per Minute.\n\nSource: pg_stat_statements.calls", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 8, + "y": 85 + }, + "id": 93, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum((rate(pg_stat_statements_calls{instance=\"$Instance\"}[$Interval])))", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "Query rate (Postgres)", + "type": "stat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "description": "Source: pg_stat_statements.total_time / pg_stat_statements.calls", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "format": "s", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 12, + "y": 85 + }, + "id": 102, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum((delta(pg_stat_statements_total_time_seconds{instance=\"$Instance\"}[$Interval])))/sum((delta(pg_stat_statements_calls{instance=\"$Instance\"}[$Interval])))", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "Average query runtime (Postgres)", + "type": "stat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "decimals": 2, + "description": "Size of all databases in $Instance.\n\nSource: pg_database_size()", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "format": "bytes", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 16, + "y": 85 + }, + "id": 37, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(pg_database_size_bytes{instance=\"$Instance\"})", + "refId": "A" + } + ], + "thresholds": "", + "title": "Total database size (Postgres)", + "type": "stat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "description": "Max Replication lag behind master in seconds\n\nOnly available on a standby system.\n\nSource: pg_last_xact_replay_timestamp\n\nUse: pg_stat_replication for Details.", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "format": "s", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 20, + "y": 85 + }, + "id": 84, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "max(pg_replication_lag{instance=\"$Instance\"})", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "Max Replication Lag (Postgres)", + "type": "stat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "max" + }, + { + "datasource": "Prometheus", + "description": "Shared buffer hits vs reads from disc", + "fieldConfig": { + "defaults": { + "decimals": 2, + "mappings": [ + { + "id": 0, + "op": "=", + "text": "N/A", + "type": 1, + "value": "null" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-red" + }, + { + "color": "semi-dark-yellow", + "value": 80 + }, + { + "color": "semi-dark-green", + "value": 90 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 3, + "x": 0, + "y": 88 + }, + "id": 16, + "links": [], + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "expr": "sum(pg_stat_database_blks_hit{instance=~\"$Instance\"})/(sum(pg_stat_database_blks_hit{instance=~\"$Instance\"})+sum(pg_stat_database_blks_read{instance=~\"$Instance\"}))*100", + "refId": "A" + } + ], + "title": "Shared Buffer Hits (Postgres)", + "type": "gauge" + }, + { + "datasource": "Prometheus", + "description": "Percentage of max_connections used", + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [ + { + "id": 0, + "op": "=", + "text": "N/A", + "type": 1, + "value": "null" + } + ], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + }, + { + "color": "semi-dark-yellow", + "value": 0.75 + }, + { + "color": "semi-dark-red", + "value": 0.9 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 3, + "x": 3, + "y": 88 + }, + "id": 9, + "links": [], + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "expr": "sum(pg_stat_database_numbackends)/max(pg_settings_max_connections)", + "refId": "A" + } + ], + "title": "Connections used (Postgres)", + "type": "gauge" + }, + { + "datasource": "Prometheus", + "description": "Transaction committed vs rollbacked", + "fieldConfig": { + "defaults": { + "decimals": 2, + "mappings": [ + { + "id": 0, + "op": "=", + "text": "N/A", + "type": 1, + "value": "null" + } + ], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-red", + "value": null + }, + { + "color": "#EAB839", + "value": 0.75 + }, + { + "color": "semi-dark-green", + "value": 0.9 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 3, + "x": 6, + "y": 88 + }, + "id": 15, + "links": [], + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "expr": "sum(pg_stat_database_xact_commit{instance=\"$Instance\"})/(sum(pg_stat_database_xact_commit{instance=\"$Instance\"}) + sum(pg_stat_database_xact_rollback{instance=\"$Instance\"}))", + "refId": "A" + } + ], + "title": "Commit Ratio (Postgres)", + "type": "gauge" + }, + { + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "description": "Clients executing Statements.\n\nSource: pg_stat_activity", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 12, + "y": 88 + }, + "id": 23, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(pg_stat_activity_count{state=\"active\",instance=\"$Instance\"})", + "refId": "A" + } + ], + "thresholds": "", + "title": "Active clients (Postgres)", + "type": "stat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "dateTimeAsIso" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 16, + "y": 88 + }, + "id": 125, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "pg_postmaster_start_time_seconds*1000", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Postgres start time", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 51, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 6, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 91 + }, + "id": 142, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "pg_stat_user_tables_n_live_tup{datname=\"postgres\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Live", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "pg_stat_user_tables_n_dead_tup", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Dead", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "Estimated number of rows (Postgres)", + "type": "timeseries" + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "decimals": 0, + "description": "View: pg_stat_activity", + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 95 + }, + "hiddenSeries": false, + "id": 24, + "interval": "$Interval", + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": true, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [ + { + "targetBlank": true, + "title": "PostgreSQL Documentation", + "url": "https://www.postgresql.org/docs/current/monitoring-stats.html" + } + ], + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.2.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (state) (pg_stat_activity_count{instance=\"$Instance\"})", + "legendFormat": "{{state}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Connections by state (stacked) (Postgres)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "logBase": 1, + "show": true + }, + { + "decimals": 0, + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "decimals": 0, + "description": "View: pg_stat_activity", + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 99 + }, + "hiddenSeries": false, + "id": 121, + "interval": "$Interval", + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": true, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [ + { + "targetBlank": true, + "title": "PostgreSQL Documentation", + "url": "https://www.postgresql.org/docs/current/monitoring-stats.html" + } + ], + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.2.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (datname) (pg_stat_activity_count{instance=\"$Instance\"})", + "legendFormat": "{{datname}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Connections by database (stacked) (Postgres)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "logBase": 1, + "show": true + }, + { + "decimals": 0, + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "decimals": 2, + "description": "1 Minute rate of transactions committed or rollback.", + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 104 + }, + "hiddenSeries": false, + "id": 122, + "interval": "", + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.2.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum ((rate(pg_stat_database_xact_commit[$Interval])))", + "interval": "", + "legendFormat": "committed", + "refId": "A" + }, + { + "expr": "sum ((rate(pg_stat_database_xact_rollback[$Interval])))", + "hide": false, + "interval": "", + "legendFormat": "rollback", + "refId": "B" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Transactions (Postgres)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Source: pg_stat_database", + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 108 + }, + "hiddenSeries": false, + "id": 27, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideZero": false, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.2.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum((rate(pg_stat_database_tup_inserted{instance=\"$Instance\"}[$Interval])))", + "interval": "", + "legendFormat": "Inserts", + "refId": "A" + }, + { + "expr": "sum((rate(pg_stat_database_tup_updated{instance=\"$Instance\"}[$Interval])))", + "interval": "", + "legendFormat": "Updates", + "refId": "B" + }, + { + "expr": "sum((rate(pg_stat_database_tup_deleted{instance=\"$Instance\"}[$Interval])))", + "interval": "", + "legendFormat": "Deletes", + "refId": "C" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Tuples inserts/updates/deletes (Postgres)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "* blk_read_time: Time spent reading data file blocks by backends in this database, in milliseconds\n* blk_write_time: Time spent writing data file blocks by backends in this database, in milliseconds\n\ntrack_io_timings needs to be activated", + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 113 + }, + "hiddenSeries": false, + "id": 26, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.2.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum ((rate(pg_stat_database_blk_read_time{instance=\"$Instance\"}[$Interval])))", + "interval": "", + "legendFormat": "blk_read_time", + "refId": "A" + }, + { + "expr": "sum ((rate(pg_stat_database_blk_write_time{instance=\"$Instance\"}[$Interval])))", + "interval": "", + "legendFormat": "blk_read_time", + "refId": "B" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "I/O Read/Write time (Postgres)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Source: pg_stat_database\n\n* tup_fetched: rows needed to satisfy queries\n* tup_returned: rows read/scanned", + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 117 + }, + "hiddenSeries": false, + "id": 111, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideZero": false, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.2.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum((rate(pg_stat_database_tup_fetched{instance=\"$Instance\"}[$Interval])))", + "interval": "", + "legendFormat": "Fetched", + "refId": "A" + }, + { + "expr": "sum((rate(pg_stat_database_tup_returned{instance=\"$Instance\"}[$Interval])))", + "interval": "", + "legendFormat": "Returned", + "refId": "B" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Tuples fetched/returned (Postgres)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "min": "0", + "show": false + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Source: pg_locks", + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 122 + }, + "hiddenSeries": false, + "id": 123, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + { + "title": "PostgreSQL Lock Modes", + "url": "https://www.postgresql.org/docs/12/explicit-locking.html#LOCKING-TABLES" + } + ], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.2.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (mode) (pg_locks_count{instance=\"$Instance\"})", + "legendFormat": "{{mode}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Locks by state (Postgres)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Should be 0 \n\nSource: pg_stat_database\n\nWith log_lock_waits turned on, deadlocks will be logged to the PostgreSQL Logfiles.", + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 126 + }, + "hiddenSeries": false, + "id": 30, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + { + "title": "PostgreSQL Locking", + "url": "https://www.postgresql.org/docs/12/explicit-locking.html" + } + ], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.2.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (datname) ((rate(pg_stat_database_deadlocks{instance=\"$Instance\"}[$Interval])))", + "interval": "", + "legendFormat": "{{datname}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Deadlocks by database (Postgres)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Should be 0. If temporary files are created, it can indicate insufficient work_mem. With log_temp_files the creation of temporary files are logged to the PostgreSQL Logfiles.", + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 131 + }, + "hiddenSeries": false, + "id": 31, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + { + "title": "PostgreSQL Ressources", + "url": "https://www.postgresql.org/docs/current/runtime-config-resource.html" + } + ], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.2.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (datname) ((rate(pg_stat_database_temp_files{instance=\"$Instance\"}[$Interval])))", + "interval": "", + "legendFormat": "{{datname}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Temporary files by database (Postgres)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Lag behind master in seconds.\n\nOnly available on a standby System.", + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 132 + }, + "hiddenSeries": false, + "id": 120, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.2.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "max(pg_replication_lag{instance=\"$Instance\"})", + "instant": false, + "intervalFactor": 1, + "legendFormat": "lag ", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Replication lag (Postgres)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false + } + } + ], + "refresh": "1m", + "revision": 1, + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "postgres-exporter:9187", + "value": "postgres-exporter:9187" + }, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "definition": "label_values({job=\"postgres-exporter\"}, instance)", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "Instance", + "options": [], + "query": "label_values({job=\"postgres-exporter\"}, instance)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "definition": "label_values(datname)", + "hide": 0, + "includeAll": true, + "multi": true, + "name": "Database", + "options": [], + "query": "label_values(datname)", + "refresh": 1, + "regex": "/^(?!template*|postgres).*$/", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "auto": true, + "auto_count": 30, + "auto_min": "10s", + "current": { + "selected": false, + "text": "10m", + "value": "10m" + }, + "hide": 0, + "name": "Interval", + "options": [ + { + "selected": false, + "text": "auto", + "value": "$__auto_interval_Interval" + }, + { + "selected": false, + "text": "30sec", + "value": "30sec" + }, + { + "selected": false, + "text": "1m", + "value": "1m" + }, + { + "selected": true, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + } + ], + "query": "30sec,1m,10m,30m,1h,6h,12h,1d", + "queryValue": "", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "browser", + "title": "nwaku-monitoring", + "uid": "yns_4vFVk", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/apps/sonda/monitoring/configuration/dashboards/sonda-monitoring.json b/apps/sonda/monitoring/configuration/dashboards/sonda-monitoring.json new file mode 100644 index 0000000..1d87f2b --- /dev/null +++ b/apps/sonda/monitoring/configuration/dashboards/sonda-monitoring.json @@ -0,0 +1,1571 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "Sonda messages successfully sent to the network", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "successful_sonda_msgs_total", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Sent Sonda Messages", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "Sonda messages that failed to be sent to the network", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "{__name__=\"failed_sonda_msgs_total\", instance=\"sonda:8004\", job=\"nwaku\"}" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "failed_sonda_msgs_total", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Failed Sonda Messages", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "Sonda messages successfully sent to the network", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "increase(successful_sonda_msgs_total[5m])/5", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "interval": "", + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Sent Sonda Messages Rate per Minute", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "Sonda messages that failed to be sent to the network", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "{instance=\"sonda:8004\", job=\"nwaku\"}" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "increase(failed_sonda_msgs_total[5m]) / 5", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Failed Sonda Messages per Minute", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "Store responses including the latest Sonda message ", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 16 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "successful_store_queries_total{node=~\"^$node$\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{__name__=\"{{__name__}}\" , node=\"{{node}}\"}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Successful Store Responses", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "Store queries with a non-200 response", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "{__name__=\"failed_store_queries_total\" , error=\"504 PEER_DIAL_FAILURE: 16Uiu2HAmAUdrQ3uwzuE4Gy4D56hX6uLKEeerJAnhKEHZ3DxF1EfT\", node=\"/dns4/store-01.do-ams3.shards.test.status.im/tcp/30303/p2p/16Uiu2HAmAUdrQ3uwzuE4Gy4D56hX6uLKEeerJAnhKEHZ3DxF1EfT\"}" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 16 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "failed_store_queries_total{node=~\"^$node$\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{__name__=\"{{__name__}}\" , error=\"{{error}}\", node=\"{{node}}\"}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Failed Store Queries", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "Store responses including the latest Sonda message ", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "{__name__=\"\" , node=\"/dns4/store-01.do-ams3.shards.test.status.im/tcp/30303/p2p/16Uiu2HAmAUdrQ3uwzuE4Gy4D56hX6uLKEeerJAnhKEHZ3DxF1EfT\"}" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 24 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "increase(successful_store_queries_total{node=~\"^$node$\"}[5m]) / 5", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{__name__=\"{{__name__}}\" , node=\"{{node}}\"}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Successful Store Responses per Minute", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "Store queries with a non-200 response", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 24 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "increase(failed_store_queries_total{node=~\"^$node$\"}[5m]) / 5", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{__name__=\"{{__name__}}\" , error=\"{{error}}\", node=\"{{node}}\"}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Failed Store Queries per Minute", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "Store responses that didn't include our latest Sonda message", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "{__name__=\"empty_store_responses_total\" , node=\"/dns4/store-01.do-ams3.shards.test.status.im/tcp/30303/p2p/16Uiu2HAmAUdrQ3uwzuE4Gy4D56hX6uLKEeerJAnhKEHZ3DxF1EfT\"}" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 32 + }, + "id": 5, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "empty_store_responses_total{node=~\"^$node$\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{__name__=\"{{__name__}}\" , node=\"{{node}}\"}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Empty Store Responses", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "Store responses that didn't include our latest Sonda message", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "{__name__=\"\" , node=\"/dns4/store-01.do-ams3.shards.test.status.im/tcp/30303/p2p/16Uiu2HAmAUdrQ3uwzuE4Gy4D56hX6uLKEeerJAnhKEHZ3DxF1EfT\"}" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 32 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "increase(empty_store_responses_total{node=~\"^$node$\"}[5m]) / 5", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{__name__=\"{{__name__}}\" , node=\"{{node}}\"}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Empty Store Responses per Minute", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "Latency of store queries", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "{__name__=\"store_query_latency\" , node=\"/dns4/store-01.do-ams3.shards.test.status.im/tcp/30303/p2p/16Uiu2HAmAUdrQ3uwzuE4Gy4D56hX6uLKEeerJAnhKEHZ3DxF1EfT\"}" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 40 + }, + "id": 7, + "options": { + "bucketOffset": 0, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "store_query_latency{node=~\"^$node$\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{__name__=\"{{__name__}}\" , node=\"{{node}}\"}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Store Query Latency (seconds)", + "type": "histogram" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "Latency of each store query", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "{__name__=\"store_query_latency\" , node=\"/dns4/store-01.do-ams3.shards.test.status.im/tcp/30303/p2p/16Uiu2HAmAUdrQ3uwzuE4Gy4D56hX6uLKEeerJAnhKEHZ3DxF1EfT\"}" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 40 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "store_query_latency{node=~\"^$node$\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{__name__=\"{{__name__}}\" , node=\"{{node}}\"}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Store Query Latency (seconds)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "description": "Node health according to the configured health threshold. 1 means healthy, 0 not.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "stepAfter", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "{__name__=\"node_health\" , node=\"/dns4/store-01.do-ams3.shards.test.status.im/tcp/30303/p2p/16Uiu2HAmAUdrQ3uwzuE4Gy4D56hX6uLKEeerJAnhKEHZ3DxF1EfT\"}" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 48 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "node_health{node=~\"^$node$\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{__name__=\"{{__name__}}\" , node=\"{{node}}\"}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Node health", + "type": "timeseries" + } + ], + "refresh": "", + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": true, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "definition": "label_values(node)", + "hide": 0, + "includeAll": true, + "label": "node", + "multi": false, + "name": "node", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(node)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "sonda-monitoring", + "uid": "cbd1b6c8-63d2-41f3-b57b-a776ec8fa23e", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/apps/sonda/monitoring/configuration/datasources.yaml b/apps/sonda/monitoring/configuration/datasources.yaml new file mode 100644 index 0000000..9f4f51f --- /dev/null +++ b/apps/sonda/monitoring/configuration/datasources.yaml @@ -0,0 +1,11 @@ +apiVersion: 1 + +datasources: + - name: Prometheus + type: prometheus + access: proxy + org_id: 1 + url: http://prometheus:9090 + is_default: true + version: 1 + editable: true \ No newline at end of file diff --git a/apps/sonda/monitoring/configuration/grafana-plugins.env b/apps/sonda/monitoring/configuration/grafana-plugins.env new file mode 100644 index 0000000..2780809 --- /dev/null +++ b/apps/sonda/monitoring/configuration/grafana-plugins.env @@ -0,0 +1,2 @@ +#GF_INSTALL_PLUGINS=grafana-worldmap-panel,grafana-piechart-panel,digrich-bubblechart-panel,yesoreyeram-boomtheme-panel,briangann-gauge-panel,jdbranham-diagram-panel,agenty-flowcharting-panel,citilogics-geoloop-panel,savantly-heatmap-panel,mtanda-histogram-panel,pierosavi-imageit-panel,michaeldmoore-multistat-panel,zuburqan-parity-report-panel,natel-plotly-panel,bessler-pictureit-panel,grafana-polystat-panel,corpglory-progresslist-panel,snuids-radar-panel,fzakaria-simple-config.config.annotations-datasource,vonage-status-panel,snuids-trafficlights-panel,pr0ps-trackmap-panel,alexandra-trackmap-panel,btplc-trend-box-panel +GF_INSTALL_PLUGINS=grafana-worldmap-panel,grafana-piechart-panel,yesoreyeram-boomtheme-panel,briangann-gauge-panel,pierosavi-imageit-panel,bessler-pictureit-panel,vonage-status-panel diff --git a/apps/sonda/monitoring/configuration/grafana.ini b/apps/sonda/monitoring/configuration/grafana.ini new file mode 100644 index 0000000..f237726 --- /dev/null +++ b/apps/sonda/monitoring/configuration/grafana.ini @@ -0,0 +1,51 @@ +instance_name = nwaku dashboard + +;[dashboards.json] +;enabled = true +;path = /home/git/grafana/grafana-dashboards/dashboards + + +#################################### Auth ########################## +[auth] +disable_login_form = false + +#################################### Anonymous Auth ########################## +[auth.anonymous] +# enable anonymous access +enabled = true + +# specify organization name that should be used for unauthenticated users +;org_name = Public + +# specify role for unauthenticated users +org_role = Admin +; org_role = Viewer + +;[security] +;admin_user = ocr +;admin_password = ocr + +;[users] +# disable user signup / registration +;allow_sign_up = false + +# Set to true to automatically assign new users to the default organization (id 1) +;auto_assign_org = true + +# Default role new users will be automatically assigned (if disabled above is set to true) +;auto_assign_org_role = Viewer + +#################################### SMTP / Emailing ########################## +;[smtp] +;enabled = false +;host = localhost:25 +;user = +;password = +;cert_file = +;key_file = +;skip_verify = false +;from_address = admin@grafana.localhost + +;[emails] +;welcome_email_on_sign_up = false + diff --git a/apps/sonda/monitoring/prometheus-config.yml b/apps/sonda/monitoring/prometheus-config.yml new file mode 100644 index 0000000..51e2b50 --- /dev/null +++ b/apps/sonda/monitoring/prometheus-config.yml @@ -0,0 +1,10 @@ +global: + scrape_interval: 15s + evaluation_interval: 15s + external_labels: + monitor: "Monitoring" + +scrape_configs: + - job_name: "nwaku" + static_configs: + - targets: ["nwaku:8003", "sonda:8004"] diff --git a/apps/sonda/register_rln.sh b/apps/sonda/register_rln.sh new file mode 100755 index 0000000..4fb373b --- /dev/null +++ b/apps/sonda/register_rln.sh @@ -0,0 +1,31 @@ +#!/bin/sh + + +if test -f ./keystore/keystore.json; then + echo "keystore/keystore.json already exists. Use it instead of creating a new one." + echo "Exiting" + exit 1 +fi + + +if test -f .env; then + echo "Using .env file" + . $(pwd)/.env +fi + +# TODO: Set nwaku release when ready instead of quay + +if test -n "${ETH_CLIENT_ADDRESS}"; then + echo "ETH_CLIENT_ADDRESS variable was renamed to RLN_RELAY_ETH_CLIENT_ADDRESS" + echo "Please update your .env file" + exit 1 +fi + +docker run -v $(pwd)/keystore:/keystore/:Z harbor.status.im/wakuorg/nwaku:v0.30.1 generateRlnKeystore \ +--rln-relay-eth-client-address=${RLN_RELAY_ETH_CLIENT_ADDRESS} \ +--rln-relay-eth-private-key=${ETH_TESTNET_KEY} \ +--rln-relay-eth-contract-address=0xB9cd878C90E49F797B4431fBF4fb333108CB90e6 \ +--rln-relay-cred-path=/keystore/keystore.json \ +--rln-relay-cred-password="${RLN_RELAY_CRED_PASSWORD}" \ +--rln-relay-user-message-limit=20 \ +--execute diff --git a/apps/sonda/run_node.sh b/apps/sonda/run_node.sh new file mode 100644 index 0000000..e130019 --- /dev/null +++ b/apps/sonda/run_node.sh @@ -0,0 +1,110 @@ +#!/bin/sh + +echo "I am a nwaku node" + +if test -n "${ETH_CLIENT_ADDRESS}" -o ; then + echo "ETH_CLIENT_ADDRESS variable was renamed to RLN_RELAY_ETH_CLIENT_ADDRESS" + echo "Please update your .env file" + exit 1 +fi + +if [ -z "${RLN_RELAY_ETH_CLIENT_ADDRESS}" ] && [ "${CLUSTER_ID}" -eq 1 ]; then + echo "Missing Eth client address, please refer to README.md for detailed instructions" + exit 1 +fi + +if [ "${CLUSTER_ID}" -ne 1 ]; then + echo "CLUSTER_ID is not equal to 1, clearing RLN configurations" + RLN_RELAY_CRED_PATH="" + RLN_RELAY_ETH_CLIENT_ADDRESS="" + RLN_RELAY_CRED_PASSWORD="" +fi + +MY_EXT_IP=$(wget -qO- https://api4.ipify.org) +DNS_WSS_CMD= + +if [ -n "${DOMAIN}" ]; then + + LETSENCRYPT_PATH=/etc/letsencrypt/live/${DOMAIN} + + if ! [ -d "${LETSENCRYPT_PATH}" ]; then + apk add --no-cache certbot + + certbot certonly\ + --non-interactive\ + --agree-tos\ + --no-eff-email\ + --no-redirect\ + --email admin@${DOMAIN}\ + -d ${DOMAIN}\ + --standalone + fi + + if ! [ -e "${LETSENCRYPT_PATH}/privkey.pem" ]; then + echo "The certificate does not exist" + sleep 60 + exit 1 + fi + + WS_SUPPORT="--websocket-support=true" + WSS_SUPPORT="--websocket-secure-support=true" + WSS_KEY="--websocket-secure-key-path=${LETSENCRYPT_PATH}/privkey.pem" + WSS_CERT="--websocket-secure-cert-path=${LETSENCRYPT_PATH}/cert.pem" + DNS4_DOMAIN="--dns4-domain-name=${DOMAIN}" + + DNS_WSS_CMD="${WS_SUPPORT} ${WSS_SUPPORT} ${WSS_CERT} ${WSS_KEY} ${DNS4_DOMAIN}" +fi + +if [ -n "${NODEKEY}" ]; then + NODEKEY=--nodekey=${NODEKEY} +fi + +if [ "${CLUSTER_ID}" -eq 1 ]; then + RLN_RELAY_CRED_PATH=--rln-relay-cred-path=${RLN_RELAY_CRED_PATH:-/keystore/keystore.json} +fi + +if [ -n "${RLN_RELAY_CRED_PASSWORD}" ]; then + RLN_RELAY_CRED_PASSWORD=--rln-relay-cred-password="${RLN_RELAY_CRED_PASSWORD}" +fi + +if [ -n "${RLN_RELAY_ETH_CLIENT_ADDRESS}" ]; then + RLN_RELAY_ETH_CLIENT_ADDRESS=--rln-relay-eth-client-address="${RLN_RELAY_ETH_CLIENT_ADDRESS}" +fi + +# TO DO: configure bootstrap nodes in env + +exec /usr/bin/wakunode\ + --relay=true\ + --filter=false\ + --lightpush=false\ + --keep-alive=true\ + --max-connections=150\ + --cluster-id="${CLUSTER_ID}"\ + --discv5-discovery=true\ + --discv5-udp-port=9005\ + --discv5-enr-auto-update=True\ + --log-level=DEBUG\ + --tcp-port=30304\ + --metrics-server=True\ + --metrics-server-port=8003\ + --metrics-server-address=0.0.0.0\ + --rest=true\ + --rest-admin=true\ + --rest-address=0.0.0.0\ + --rest-port=8645\ + --rest-allow-origin="waku-org.github.io"\ + --rest-allow-origin="localhost:*"\ + --nat=extip:"${MY_EXT_IP}"\ + --store=false\ + --pubsub-topic="/waku/2/rs/${CLUSTER_ID}/${SHARD}"\ + --discv5-bootstrap-node="enr:-QEKuECA0zhRJej2eaOoOPddNcYr7-5NdRwuoLCe2EE4wfEYkAZhFotg6Kkr8K15pMAGyUyt0smHkZCjLeld0BUzogNtAYJpZIJ2NIJpcISnYxMvim11bHRpYWRkcnO4WgAqNiVib290LTAxLmRvLWFtczMuc2hhcmRzLnRlc3Quc3RhdHVzLmltBnZfACw2JWJvb3QtMDEuZG8tYW1zMy5zaGFyZHMudGVzdC5zdGF0dXMuaW0GAbveA4Jyc40AEAUAAQAgAEAAgAEAiXNlY3AyNTZrMaEC3rRtFQSgc24uWewzXaxTY8hDAHB8sgnxr9k8Rjb5GeSDdGNwgnZfg3VkcIIjKIV3YWt1Mg0"\ + --discv5-bootstrap-node="enr:-QEcuEAgXDqrYd_TrpUWtn3zmxZ9XPm7O3GS6lV7aMJJOTsbOAAeQwSd_eoHcCXqVzTUtwTyB4855qtbd8DARnExyqHPAYJpZIJ2NIJpcIQihw1Xim11bHRpYWRkcnO4bAAzNi5ib290LTAxLmdjLXVzLWNlbnRyYWwxLWEuc2hhcmRzLnRlc3Quc3RhdHVzLmltBnZfADU2LmJvb3QtMDEuZ2MtdXMtY2VudHJhbDEtYS5zaGFyZHMudGVzdC5zdGF0dXMuaW0GAbveA4Jyc40AEAUAAQAgAEAAgAEAiXNlY3AyNTZrMaECxjqgDQ0WyRSOilYU32DA5k_XNlDis3m1VdXkK9xM6kODdGNwgnZfg3VkcIIjKIV3YWt1Mg0"\ + --discv5-bootstrap-node="enr:-QEcuEAX6Qk-vVAoJLxR4A_4UVogGhvQrqKW4DFKlf8MA1PmCjgowL-LBtSC9BLjXbb8gf42FdDHGtSjEvvWKD10erxqAYJpZIJ2NIJpcIQI2hdMim11bHRpYWRkcnO4bAAzNi5ib290LTAxLmFjLWNuLWhvbmdrb25nLWMuc2hhcmRzLnRlc3Quc3RhdHVzLmltBnZfADU2LmJvb3QtMDEuYWMtY24taG9uZ2tvbmctYy5zaGFyZHMudGVzdC5zdGF0dXMuaW0GAbveA4Jyc40AEAUAAQAgAEAAgAEAiXNlY3AyNTZrMaEDP7CbRk-YKJwOFFM4Z9ney0GPc7WPJaCwGkpNRyla7mCDdGNwgnZfg3VkcIIjKIV3YWt1Mg0"\ + ${RLN_RELAY_CRED_PATH}\ + ${RLN_RELAY_CRED_PASSWORD}\ + ${RLN_RELAY_TREE_PATH}\ + ${RLN_RELAY_ETH_CLIENT_ADDRESS}\ + ${DNS_WSS_CMD}\ + ${NODEKEY}\ + ${EXTRA_ARGS} + diff --git a/apps/sonda/sonda.py b/apps/sonda/sonda.py new file mode 100644 index 0000000..8b74bd0 --- /dev/null +++ b/apps/sonda/sonda.py @@ -0,0 +1,207 @@ +import requests +import time +import json +import os +import base64 +import sys +import urllib.parse +import requests +import argparse +from datetime import datetime +from prometheus_client import Counter, Gauge, start_http_server + +# Content topic where Sona messages are going to be sent +SONDA_CONTENT_TOPIC = '/sonda/2/polls/proto' + +# Prometheus metrics +successful_sonda_msgs = Counter('successful_sonda_msgs', 'Number of successful Sonda messages sent') +failed_sonda_msgs = Counter('failed_sonda_msgs', 'Number of failed Sonda messages attempts') +successful_store_queries = Counter('successful_store_queries', 'Number of successful store queries', ['node']) +failed_store_queries = Counter('failed_store_queries', 'Number of failed store queries', ['node', 'error']) +empty_store_responses = Counter('empty_store_responses', "Number of store responses without the latest Sonda message", ['node']) +store_query_latency = Gauge('store_query_latency', 'Latency of the last store query in seconds', ['node']) +consecutive_successful_responses = Gauge('consecutive_successful_responses', 'Consecutive successful store responses', ['node']) +node_health = Gauge('node_health', "Binary indicator of a node's health. 1 is healthy, 0 is not", ['node']) + + +# Argparser configuration +parser = argparse.ArgumentParser(description='') +parser.add_argument('-m', '--metrics-port', type=int, default=8004, help='Port to expose prometheus metrics.') +parser.add_argument('-a', '--node-rest-address', type=str, default="http://nwaku:8645", help='Address of the waku node to send messages to.') +parser.add_argument('-p', '--pubsub-topic', type=str, default='/waku/2/rs/1/0', help='PubSub topic.') +parser.add_argument('-d', '--delay-seconds', type=int, default=60, help='Delay in seconds between messages.') +parser.add_argument('-n', '--store-nodes', type=str, required=True, help='Comma separated list of store nodes to query.') +parser.add_argument('-t', '--health-threshold', type=int, default=5, help='Consecutive successful store requests to consider a store node healthy.') +args = parser.parse_args() + + +# Logs message including current UTC time +def log_with_utc(message): + utc_time = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S") + print(f"[{utc_time} UTC] {message}") + + +# Sends Sonda message. Returns True if successful, False otherwise +def send_sonda_msg(rest_address, pubsub_topic, content_topic, timestamp): + message = "Hi, I'm Sonda" + base64_message = base64.b64encode(message.encode('utf-8')).decode('ascii') + body = { + 'payload': base64_message, + 'contentTopic': content_topic, + 'version': 1, + 'timestamp': timestamp + } + + encoded_pubsub_topic = urllib.parse.quote(pubsub_topic, safe='') + url = f'{rest_address}/relay/v1/messages/{encoded_pubsub_topic}' + headers = {'content-type': 'application/json'} + + log_with_utc(f'Sending Sonda message via REST: {url} PubSubTopic: {pubsub_topic}, ContentTopic: {content_topic}, timestamp: {timestamp}') + + try: + start_time = time.time() + response = requests.post(url, json=body, headers=headers, timeout=10) + elapsed_seconds = time.time() - start_time + + log_with_utc(f'Response from {rest_address}: status:{response.status_code} content:{response.text} [{elapsed_seconds:.4f} s.]') + + if response.status_code == 200: + successful_sonda_msgs.inc() + return True + else: + response.raise_for_status() + except requests.RequestException as e: + log_with_utc(f'Error sending request: {e}') + + failed_sonda_msgs.inc() + return False + + +# We return true if both our node and the queried Store node returned a 200 +# If our message isn't found but we did get a store 200 response, this function still returns true +def check_store_response(json_response, store_node, timestamp): + # Check for the store node status code + if json_response.get('statusCode') != 200: + error = f"{json_response.get('statusCode')} {json_response.get('statusDesc')}" + log_with_utc(f'Failed performing store query {error}') + failed_store_queries.labels(node=store_node, error=error).inc() + consecutive_successful_responses.labels(node=store_node).set(0) + + return False + + messages = json_response.get('messages') + # If there's no message in the response, increase counters and return + if not messages: + log_with_utc("No messages in store response") + empty_store_responses.labels(node=store_node).inc() + consecutive_successful_responses.labels(node=store_node).set(0) + return True + + # Search for the Sonda message in the returned messages + for message in messages: + # If message field is missing in current message, continue + if not message.get("message"): + log_with_utc("Could not retrieve message") + continue + + # If a message is found with the same timestamp as sonda message, increase counters and return + if timestamp == message.get('message').get('timestamp'): + log_with_utc(f'Found Sonda message in store response node={store_node}') + successful_store_queries.labels(node=store_node).inc() + consecutive_successful_responses.labels(node=store_node).inc() + return True + + # If our message wasn't found in the returned messages, increase counter and return + empty_store_responses.labels(node=store_node).inc() + consecutive_successful_responses.labels(node=store_node).set(0) + return True + + +def send_store_query(rest_address, store_node, encoded_pubsub_topic, encoded_content_topic, timestamp): + url = f'{rest_address}/store/v3/messages' + params = { + 'peerAddr': urllib.parse.quote(store_node, safe=''), + 'pubsubTopic': encoded_pubsub_topic, + 'contentTopics': encoded_content_topic, + 'includeData': 'true', + 'startTime': timestamp + } + + s_time = time.time() + + try: + log_with_utc(f'Sending store request to {store_node}') + response = requests.get(url, params=params) + except Exception as e: + log_with_utc(f'Error sending request: {e}') + failed_store_queries.labels(node=store_node, error=str(e)).inc() + consecutive_successful_responses.labels(node=store_node).set(0) + return False + + elapsed_seconds = time.time() - s_time + log_with_utc(f'Response from {rest_address}: status:{response.status_code} [{elapsed_seconds:.4f} s.]') + + if response.status_code != 200: + failed_store_queries.labels(node=store_node, error=f'{response.status_code} {response.content}').inc() + consecutive_successful_responses.labels(node=store_node).set(0) + return False + + # Parse REST response into JSON + try: + json_response = response.json() + except Exception as e: + log_with_utc(f'Error parsing response JSON: {e}') + failed_store_queries.labels(node=store_node, error="JSON parse error").inc() + consecutive_successful_responses.labels(node=store_node).set(0) + return False + + # Analyze Store response. Return false if response is incorrect or has an error status + if not check_store_response(json_response, store_node, timestamp): + return False + + store_query_latency.labels(node=store_node).set(elapsed_seconds) + return True + + +def send_store_queries(rest_address, store_nodes, pubsub_topic, content_topic, timestamp): + log_with_utc(f'Sending store queries. nodes = {store_nodes} timestamp = {timestamp}') + encoded_pubsub_topic = urllib.parse.quote(pubsub_topic, safe='') + encoded_content_topic = urllib.parse.quote(content_topic, safe='') + + for node in store_nodes: + send_store_query(rest_address, node, encoded_pubsub_topic, encoded_content_topic, timestamp) + + +def main(): + log_with_utc(f'Running Sonda with args={args}') + + store_nodes = [] + if args.store_nodes is not None: + store_nodes = [s.strip() for s in args.store_nodes.split(",")] + log_with_utc(f'Store nodes to query: {store_nodes}') + + # Start Prometheus HTTP server at port set by the CLI(default 8004) + start_http_server(args.metrics_port) + + while True: + timestamp = time.time_ns() + + # Send Sonda message + res = send_sonda_msg(args.node_rest_address, args.pubsub_topic, SONDA_CONTENT_TOPIC, timestamp) + + log_with_utc(f'sleeping: {args.delay_seconds} seconds') + time.sleep(args.delay_seconds) + + # Only send store query if message was successfully published + if(res): + send_store_queries(args.node_rest_address, store_nodes, args.pubsub_topic, SONDA_CONTENT_TOPIC, timestamp) + + # Update node health metrics + for store_node in store_nodes: + if consecutive_successful_responses.labels(node=store_node)._value.get() >= args.health_threshold: + node_health.labels(node=store_node).set(1) + else: + node_health.labels(node=store_node).set(0) + + +main() diff --git a/apps/wakucanary/README.md b/apps/wakucanary/README.md new file mode 100644 index 0000000..1140823 --- /dev/null +++ b/apps/wakucanary/README.md @@ -0,0 +1,58 @@ +# waku canary tool + +Attempts to dial a peer and asserts it supports a given set of protocols. + +```console +./build/wakucanary --help +Usage: + +wakucanary [OPTIONS]... + +The following options are available: + + -a, --address Multiaddress of the peer node to attempt to dial. + -t, --timeout Timeout to consider that the connection failed [=chronos.seconds(10)]. + -p, --protocol Protocol required to be supported: store,relay,lightpush,filter (can be used + multiple times). + -l, --log-level Sets the log level [=LogLevel.DEBUG]. + -np, --node-port Listening port for waku node [=60000]. + --websocket-secure-key-path Secure websocket key path: '/path/to/key.txt' . + --websocket-secure-cert-path Secure websocket Certificate path: '/path/to/cert.txt' . + -c, --cluster-id Cluster ID of the fleet node to check status [Default=1] + -s, --shard Shards index to subscribe to topics [ Argument may be repeated ] + +``` + +The tool can be built as: + +```console +$ make wakucanary +``` + +And used as follows. A reachable node that supports both `store` and `filter` protocols. + +```console +$ ./build/wakucanary --address=/dns4/node-01.ac-cn-hongkong-c.waku.sandbox.status.im/tcp/30303/p2p/16Uiu2HAmSJvSJphxRdbnigUV5bjRRZFBhTtWFTSyiKaQByCjwmpV --protocol=store --protocol=filter +$ echo $? +0 +``` + +A node that can't be reached. +```console +$ ./build/wakucanary --address=/dns4/node-01.ac-cn-hongkong-c.waku.sandbox.status.im/tcp/1000/p2p/16Uiu2HAmSJvSJphxRdbnigUV5bjRRZFBhTtWFTSyiKaQByCjwmpV --protocol=store --protocol=filter +$ echo $? +1 +``` + +Note that a domain name can also be used. +```console +$ ./build/wakucanary --address=/dns4/node-01.do-ams3.status.test.status.im/tcp/30303/p2p/16Uiu2HAkukebeXjTQ9QDBeNDWuGfbaSg79wkkhK4vPocLgR6QFDf --protocol=store --protocol=filter +$ echo $? +0 +``` + +Websockets are also supported. The websocket port openned by waku canary is calculated as `$(--node-port) + 1000` (e.g. when you set `-np 60000`, the WS port will be `61000`) +```console +$ ./build/wakucanary --address=/ip4/127.0.0.1/tcp/7777/ws/p2p/16Uiu2HAm4ng2DaLPniRoZtMQbLdjYYWnXjrrJkGoXWCoBWAdn1tu --protocol=store --protocol=filter +$ ./build/wakucanary --address=/ip4/127.0.0.1/tcp/7777/wss/p2p/16Uiu2HAmB6JQpewXScGoQ2syqmimbe4GviLxRwfsR8dCpwaGBPSE --protocol=store --websocket-secure-key-path=MyKey.key --websocket-secure-cert-path=MyCertificate.crt +``` diff --git a/apps/wakucanary/certsgenerator.nim b/apps/wakucanary/certsgenerator.nim new file mode 100644 index 0000000..b8a9e9d --- /dev/null +++ b/apps/wakucanary/certsgenerator.nim @@ -0,0 +1,37 @@ +import osproc, os, httpclient, strutils + +proc getPublicIP(): string = + let client = newHttpClient() + try: + let response = client.get("http://api.ipify.org") + return response.body + except Exception as e: + echo "Could not fetch public IP: " & e.msg + return "127.0.0.1" + +# Function to generate a self-signed certificate +proc generateSelfSignedCertificate*(certPath: string, keyPath: string): int = + # Ensure the OpenSSL is installed + if findExe("openssl") == "": + echo "OpenSSL is not installed or not in the PATH." + return 1 + + let publicIP = getPublicIP() + + if publicIP != "127.0.0.1": + echo "Your public IP address is: ", publicIP + + # Command to generate private key and cert + let + cmd = + "openssl req -x509 -newkey rsa:4096 -keyout " & keyPath & " -out " & certPath & + " -sha256 -days 3650 -nodes -subj '/C=XX/ST=StateName/L=CityName/O=CompanyName/OU=CompanySectionName/CN=" & + publicIP & "'" + res = execCmd(cmd) + + if res == 0: + echo "Successfully generated self-signed certificate and key." + else: + echo "Failed to generate certificate and key." + + return res diff --git a/apps/wakucanary/nim.cfg b/apps/wakucanary/nim.cfg new file mode 100644 index 0000000..2231f2e --- /dev/null +++ b/apps/wakucanary/nim.cfg @@ -0,0 +1,4 @@ +-d:chronicles_line_numbers +-d:chronicles_runtime_filtering:on +-d:discv5_protocol_id:d5waku +path = "../.." diff --git a/apps/wakucanary/wakucanary.nim b/apps/wakucanary/wakucanary.nim new file mode 100644 index 0000000..e770028 --- /dev/null +++ b/apps/wakucanary/wakucanary.nim @@ -0,0 +1,300 @@ +import + std/[strutils, sequtils, tables, strformat], + confutils, + chronos, + chronicles/topics_registry, + os +import + libp2p/protocols/ping, + libp2p/crypto/[crypto, secp], + libp2p/nameresolving/dnsresolver, + libp2p/multicodec +import + ./certsgenerator, + waku/[waku_enr, node/peer_manager, waku_core, waku_node, factory/builder] + +# protocols and their tag +const ProtocolsTable = { + "store": "/vac/waku/store/", + "storev3": "/vac/waku/store-query/3", + "relay": "/vac/waku/relay/", + "lightpush": "/vac/waku/lightpush/", + "filter": "/vac/waku/filter-subscribe/2", + "filter-push": "/vac/waku/filter-push/", + "ipfs-id": "/ipfs/id/", + "autonat": "/libp2p/autonat/", + "circuit-relay": "/libp2p/circuit/relay/", + "metadata": "/vac/waku/metadata/", + "rendezvous": "/rendezvous/", + "ipfs-ping": "/ipfs/ping/", + "peer-exchange": "/vac/waku/peer-exchange/", + "mix": "mix/1.0.0", +}.toTable + +const WebSocketPortOffset = 1000 +const CertsDirectory = "./certs" + +# cli flags +type WakuCanaryConf* = object + address* {. + desc: "Multiaddress of the peer node to attempt to dial", + defaultValue: "", + name: "address", + abbr: "a" + .}: string + + timeout* {. + desc: "Timeout to consider that the connection failed", + defaultValue: chronos.seconds(10), + name: "timeout", + abbr: "t" + .}: chronos.Duration + + protocols* {. + desc: + "Protocol required to be supported: store,relay,lightpush,filter (can be used multiple times)", + name: "protocol", + abbr: "p" + .}: seq[string] + + logLevel* {. + desc: "Sets the log level", + defaultValue: LogLevel.INFO, + name: "log-level", + abbr: "l" + .}: LogLevel + + nodePort* {. + desc: "Listening port for waku node", + defaultValue: 60000, + name: "node-port", + abbr: "np" + .}: uint16 + + ## websocket secure config + websocketSecureKeyPath* {. + desc: "Secure websocket key path: '/path/to/key.txt' ", + defaultValue: "", + name: "websocket-secure-key-path" + .}: string + + websocketSecureCertPath* {. + desc: "Secure websocket Certificate path: '/path/to/cert.txt' ", + defaultValue: "", + name: "websocket-secure-cert-path" + .}: string + + ping* {. + desc: "Ping the peer node to measure latency", defaultValue: true, name: "ping" + .}: bool + + shards* {. + desc: + "Shards index to subscribe to [0..NUM_SHARDS_IN_NETWORK-1]. Argument may be repeated.", + defaultValue: @[], + name: "shard", + abbr: "s" + .}: seq[uint16] + + clusterId* {. + desc: + "Cluster id that the node is running in. Node in a different cluster id is disconnected.", + defaultValue: 1, + name: "cluster-id", + abbr: "c" + .}: uint16 + +proc parseCmdArg*(T: type chronos.Duration, p: string): T = + try: + result = chronos.seconds(parseInt(p)) + except CatchableError: + raise newException(ValueError, "Invalid timeout value") + +proc completeCmdArg*(T: type chronos.Duration, val: string): seq[string] = + return @[] + +proc areProtocolsSupported( + toValidateProtocols: seq[string], nodeProtocols: seq[string] +): bool = + ## Checks if all toValidateProtocols are contained in nodeProtocols. + ## nodeProtocols contains the full list of protocols currently informed by the node under analysis. + ## toValidateProtocols contains the protocols, without version number, that we want to check if they are supported by the node. + var numOfSupportedProt: int = 0 + + for rawProtocol in toValidateProtocols: + let protocolTag = ProtocolsTable[rawProtocol] + debug "Checking if protocol is supported", expected_protocol_tag = protocolTag + + var protocolSupported = false + for nodeProtocol in nodeProtocols: + if nodeProtocol.startsWith(protocolTag): + info "The node supports the protocol", supported_protocol = nodeProtocol + numOfSupportedProt += 1 + protocolSupported = true + break + + if not protocolSupported: + error "The node does not support the protocol", expected_protocol = protocolTag + + if numOfSupportedProt == toValidateProtocols.len: + return true + + return false + +proc pingNode( + node: WakuNode, peerInfo: RemotePeerInfo +): Future[void] {.async, gcsafe.} = + try: + let conn = await node.switch.dial(peerInfo.peerId, peerInfo.addrs, PingCodec) + let pingDelay = await node.libp2pPing.ping(conn) + info "Peer response time (ms)", peerId = peerInfo.peerId, ping = pingDelay.millis + except CatchableError: + var msg = getCurrentExceptionMsg() + if msg == "Future operation cancelled!": + msg = "timedout" + error "Failed to ping the peer", peer = peerInfo, err = msg + +proc main(rng: ref HmacDrbgContext): Future[int] {.async.} = + let conf: WakuCanaryConf = WakuCanaryConf.load() + + # create dns resolver + let + nameServers = + @[ + initTAddress(parseIpAddress("1.1.1.1"), Port(53)), + initTAddress(parseIpAddress("1.0.0.1"), Port(53)), + ] + resolver: DnsResolver = DnsResolver.new(nameServers) + + if conf.logLevel != LogLevel.NONE: + setLogLevel(conf.logLevel) + + # ensure input protocols are valid + for p in conf.protocols: + if p notin ProtocolsTable: + error "invalid protocol", protocol = p, valid = ProtocolsTable + raise newException(ConfigurationError, "Invalid cli flag values" & p) + + info "Cli flags", + address = conf.address, + timeout = conf.timeout, + protocols = conf.protocols, + logLevel = conf.logLevel + + let peerRes = parsePeerInfo(conf.address) + if peerRes.isErr(): + error "Couldn't parse 'conf.address'", error = peerRes.error + quit(QuitFailure) + + let peer = peerRes.value + + let + nodeKey = crypto.PrivateKey.random(Secp256k1, rng[])[] + bindIp = parseIpAddress("0.0.0.0") + wsBindPort = Port(conf.nodePort + WebSocketPortOffset) + nodeTcpPort = Port(conf.nodePort) + isWs = peer.addrs[0].contains(multiCodec("ws")).get() + isWss = peer.addrs[0].contains(multiCodec("wss")).get() + keyPath = + if conf.websocketSecureKeyPath.len > 0: + conf.websocketSecureKeyPath + else: + CertsDirectory & "/key.pem" + certPath = + if conf.websocketSecureCertPath.len > 0: + conf.websocketSecureCertPath + else: + CertsDirectory & "/cert.pem" + + var builder = WakuNodeBuilder.init() + builder.withNodeKey(nodeKey) + + let netConfig = NetConfig.init( + bindIp = bindIp, + bindPort = nodeTcpPort, + wsBindPort = some(wsBindPort), + wsEnabled = isWs, + wssEnabled = isWss, + ) + + var enrBuilder = EnrBuilder.init(nodeKey) + + enrBuilder.withWakuRelaySharding( + RelayShards(clusterId: conf.clusterId, shardIds: conf.shards) + ).isOkOr: + error "could not initialize ENR with shards", error + quit(QuitFailure) + + let recordRes = enrBuilder.build() + let record = + if recordRes.isErr(): + error "failed to create enr record", error = recordRes.error + quit(QuitFailure) + else: + recordRes.get() + + if isWss and + (conf.websocketSecureKeyPath.len == 0 or conf.websocketSecureCertPath.len == 0): + info "WebSocket Secure requires key and certificate. Generating them" + if not dirExists(CertsDirectory): + createDir(CertsDirectory) + if generateSelfSignedCertificate(certPath, keyPath) != 0: + error "Error generating key and certificate" + quit(QuitFailure) + + builder.withRecord(record) + builder.withNetworkConfiguration(netConfig.tryGet()) + builder.withSwitchConfiguration( + secureKey = some(keyPath), secureCert = some(certPath), nameResolver = resolver + ) + + let node = builder.build().tryGet() + + if conf.ping: + try: + await mountLibp2pPing(node) + except CatchableError: + error "failed to mount libp2p ping protocol: " & getCurrentExceptionMsg() + quit(QuitFailure) + + node.mountMetadata(conf.clusterId, conf.shards).isOkOr: + error "failed to mount metadata protocol", error + quit(QuitFailure) + + await node.start() + + var pingFut: Future[bool] + if conf.ping: + pingFut = pingNode(node, peer).withTimeout(conf.timeout) + + let timedOut = not await node.connectToNodes(@[peer]).withTimeout(conf.timeout) + if timedOut: + error "Timedout after", timeout = conf.timeout + quit(QuitFailure) + + let lp2pPeerStore = node.switch.peerStore + let conStatus = node.peerManager.switch.peerStore[ConnectionBook][peer.peerId] + + if conf.ping: + discard await pingFut + + if conStatus in [Connected, CanConnect]: + let nodeProtocols = lp2pPeerStore[ProtoBook][peer.peerId] + + if not areProtocolsSupported(conf.protocols, nodeProtocols): + error "Not all protocols are supported", + expected = conf.protocols, supported = nodeProtocols + quit(QuitFailure) + elif conStatus == CannotConnect: + error "Could not connect", peerId = peer.peerId + quit(QuitFailure) + return 0 + +when isMainModule: + let rng = crypto.newRng() + let status = waitFor main(rng) + if status == 0: + info "The node is reachable and supports all specified protocols" + else: + error "The node has some problems (see logs)" + quit status diff --git a/apps/wakunode2/nim.cfg b/apps/wakunode2/nim.cfg new file mode 100644 index 0000000..a6fab9c --- /dev/null +++ b/apps/wakunode2/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/apps/wakunode2/wakunode2.nim b/apps/wakunode2/wakunode2.nim new file mode 100644 index 0000000..ac6b38a --- /dev/null +++ b/apps/wakunode2/wakunode2.nim @@ -0,0 +1,102 @@ +{.push raises: [].} + +import + std/[options, strutils, sequtils, net], + chronicles, + chronos, + metrics, + libbacktrace, + system/ansi_c, + libp2p/crypto/crypto +import + ../../tools/[rln_keystore_generator/rln_keystore_generator, confutils/cli_args], + waku/[ + common/logging, + factory/waku, + node/health_monitor, + waku_api/rest/builder as rest_server_builder, + waku_core/message/default_values, + ] + +logScope: + topics = "wakunode 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: " & waku.git_version + + var wakuNodeConf = WakuNodeConf.load(version = versionString).valueOr: + error "failure while loading the configuration", error = error + quit(QuitFailure) + + ## Also called within Waku.new. The call to startRestServerEssentials needs the following line + logging.setupLog(wakuNodeConf.logLevel, wakuNodeConf.logFormat) + + case wakuNodeConf.cmd + of generateRlnKeystore: + let conf = wakuNodeConf.toKeystoreGeneratorConf() + doRlnKeystoreGenerator(conf) + of noCommand: + let conf = wakuNodeConf.toWakuConf().valueOr: + error "Waku configuration failed", error = error + quit(QuitFailure) + + var waku = (waitFor Waku.new(conf)).valueOr: + error "Waku initialization failed", error = error + quit(QuitFailure) + + (waitFor startWaku(addr waku)).isOkOr: + error "Starting waku failed", error = error + quit(QuitFailure) + + debug "Setting up shutdown hooks" + proc asyncStopper(waku: Waku) {.async: (raises: [Exception]).} = + await waku.stop() + 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(waku) + + setControlCHook(handleCtrlC) + + # Handle SIGTERM + when defined(posix): + proc handleSigterm(signal: cint) {.noconv.} = + notice "Shutting down after receiving SIGTERM" + asyncSpawn asyncStopper(waku) + + 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", stacktrace = getBacktrace() + + # Not available in -d:release mode + writeStackTrace() + + waitFor waku.stop() + quit(QuitFailure) + + c_signal(ansi_c.SIGSEGV, handleSigsegv) + + info "Node setup complete" + + runForever() diff --git a/ci/Jenkinsfile.lpt b/ci/Jenkinsfile.lpt new file mode 100644 index 0000000..c81a21b --- /dev/null +++ b/ci/Jenkinsfile.lpt @@ -0,0 +1,95 @@ +#!/usr/bin/env groovy +library 'status-jenkins-lib@v1.8.17' + +pipeline { + agent { label 'linux' } + + options { + timestamps() + timeout(time: 20, unit: 'MINUTES') + disableRestartFromStage() + buildDiscarder(logRotator( + numToKeepStr: '10', + daysToKeepStr: '30', + )) + } + + parameters { + string( + name: 'IMAGE_TAG', + description: 'Name of Docker tag to push. Optional Parameter.', + defaultValue: 'latest' + ) + string( + name: 'IMAGE_NAME', + description: 'Name of Docker image to push.', + defaultValue: params.IMAGE_NAME ?: 'wakuorg/liteprotocoltester', + ) + string( + name: 'DOCKER_CRED', + description: 'Name of Docker Registry credential.', + defaultValue: params.DOCKER_CRED ?: 'harbor-telemetry-robot', + ) + string( + name: 'DOCKER_REGISTRY', + description: 'URL of the Docker Registry', + defaultValue: params.DOCKER_REGISTRY ?: 'harbor.status.im' + ) + string( + name: 'NIMFLAGS', + description: 'Flags for Nim compilation.', + defaultValue: params.NIMFLAGS ?: [ + '--colors:off', + '-d:disableMarchNative', + '-d:chronicles_colors:none', + '-d:insecure', + ].join(' ') + ) + choice( + name: "LOWEST_LOG_LEVEL_ALLOWED", + choices: ['TRACE', 'DEGUG', 'INFO', 'NOTICE', 'WARN', 'ERROR', 'FATAL'], + description: "Defines the log level, which will be available at runtime (Chronicles log level)" + ) + } + + stages { + stage('Build') { + steps { script { + image = docker.build( + "${DOCKER_REGISTRY}/${params.IMAGE_NAME}:${params.IMAGE_TAG ?: env.GIT_COMMIT.take(8)}", + "--label=commit='${git.commit()}' " + + "--label=version='${git.describe('--tags')}' " + + "--build-arg=MAKE_TARGET='liteprotocoltester' " + + "--build-arg=NIMFLAGS='${params.NIMFLAGS}' " + + "--build-arg=LOG_LEVEL='${params.LOWEST_LOG_LEVEL_ALLOWED}' " + + "--target ${params.IMAGE_TAG == 'deploy' ? 'deployment_lpt' : 'standalone_lpt'} " + + "--file=apps/liteprotocoltester/Dockerfile.liteprotocoltester.compile " + + " ." + ) + } } + } + + stage('Check') { + steps { script { + image.inside('--entrypoint=""') { c -> + sh '/usr/bin/liteprotocoltester --version' + } + } } + } + + stage('Push') { + when { expression { params.IMAGE_TAG != '' } } + steps { script { + withDockerRegistry([ + credentialsId: params.DOCKER_CRED, url: "https://${DOCKER_REGISTRY}" + ]) { + image.push(params.IMAGE_TAG) + } + } } + } + } // stages + + post { + cleanup { cleanWs() } + } // post +} // pipeline diff --git a/ci/Jenkinsfile.prs b/ci/Jenkinsfile.prs new file mode 100644 index 0000000..2aa5654 --- /dev/null +++ b/ci/Jenkinsfile.prs @@ -0,0 +1,137 @@ +#!/usr/bin/env groovy + +library 'status-jenkins-lib@v1.6.0' + +pipeline { + agent { label "${getAgentLabel()} && x86_64" } + + parameters { + string( + name: 'NIMFLAGS', + description: 'Flags for Nim compilation.', + defaultValue: params.NIMFLAGS ?: [ + '--colors:off', + '-d:insecure', + '-d:disableMarchNative', + '--parallelBuild:6', + '-d:postgres', + ].join(' ') + ) + string( + name: 'LOG_LEVEL', + description: 'Build logging level. (DEBUG, TRACE)', + defaultValue: params.LOG_LEVEL ?: 'DEBUG' + ) + string( + name: 'VERBOSITY', + description: 'Makefile verbosity level.(0-2)', + defaultValue: params.VERBOSITY ?: '1' + ) + string( + name: 'MAKEFLAGS', + description: 'Makefile flags.', + defaultValue: params.MAKEFLAGS ?: '-j6' + ) + } + + options { + timestamps() + disableRestartFromStage() + /* Prevent Jenkins jobs from running forever */ + timeout(time: 30, unit: 'MINUTES') + /* Limit builds retained. */ + buildDiscarder(logRotator( + numToKeepStr: '3', + daysToKeepStr: '30', + artifactNumToKeepStr: '1', + )) + } + + environment { + TARGET = getAgentLabel() + } + + stages { + stage('Deps') { steps { script { + /* Avoid checking multiple times. */ + v2changed = versionWasChanged('v2') + /* TODO: Re-add caching of Nim compiler. */ + nix.shell("make ${params.MAKEFLAGS} V=${params.VERBOSITY} update", pure: false) + nix.shell("make ${params.MAKEFLAGS} V=${params.VERBOSITY} deps", pure: false) + } } } + + stage('Binaries') { + parallel { + stage('V2') { + when { expression { v2changed } } + steps { script { + nix.shell("make ${params.MAKEFLAGS} NIMFLAGS=\"${params.NIMFLAGS}\" V=${params.VERBOSITY} all") + } } + } + } + } + + stage('Run Tests') { + parallel { + stage('V2') { + when { expression { v2changed } } + steps { script { + nix.shell("make ${params.MAKEFLAGS} NIMFLAGS=\"${params.NIMFLAGS}\" V=${params.VERBOSITY} test") + } } + } + } + } + + stage('Upload') { + when { expression { v2changed } } + steps { script { + def out = genOutputFilename() + sh "mv build/wakunode2 ${out}" + env.PKG_URL = s3.uploadArtifact(out) + jenkins.setBuildDesc(Waku: env.PKG_URL) + } } + } + } // stages + post { + success { script { github.notifyPR(true) } } + failure { script { github.notifyPR(false) } } + always { cleanWs() } + } // post +} // pipeline + + +/* This allows us to use one Jenkinsfile and run + * jobs on different platforms based on job name. */ +def getAgentLabel() { + if (params.AGENT_LABEL) { + return params.AGENT_LABEL + } + def tokens = env.JOB_NAME.split('/') + for (platform in ['linux', 'macos', 'windows']) { + if (tokens.contains(platform)) { return platform } + } + throw new Exception('No agent provided or found in job path!') +} + +def genOutputFilename() { + return [ + "wakunode2", utils.timestamp(), utils.gitCommit(), getAgentLabel() + ].join('-') + (env.NODE_NAME.startsWith('windows') ? '.exe' : '.bin') +} + +def versionWasChanged(version) { + def changes = sh( + script: "git diff --name-only origin/${env.CHANGE_TARGET}", + returnStdout: true + ) + if (changes =~ "(?m)^(Makefile|waku.nimble|config.nims|vendor|ci|shell.nix).*") { + return true + } + if (version == 'v2' && changes =~ "(?m)^(apps|tools)/.*") { + return true + } + if (changes =~ "(?m)^(waku|tests|examples)/(${version}|common)/.*") { + return true + } + return false +} diff --git a/ci/Jenkinsfile.release b/ci/Jenkinsfile.release new file mode 100644 index 0000000..4a0cd0d --- /dev/null +++ b/ci/Jenkinsfile.release @@ -0,0 +1,146 @@ +#!/usr/bin/env groovy +library 'status-jenkins-lib@v1.8.17' + +pipeline { + agent { label 'linux' } + + options { + timestamps() + disableRestartFromStage() + timeout(time: 20, unit: 'MINUTES') + buildDiscarder(logRotator( + numToKeepStr: '10', + daysToKeepStr: '30', + )) + } + + parameters { + string( + name: 'MAKE_TARGET', + description: 'Makefile target to build. Optional Parameter.', + defaultValue: params.MAKE_TARGET ?: 'wakunode2', + ) + string( + name: 'IMAGE_TAG', + description: 'Name of Docker tag to push. Optional Parameter.', + defaultValue: getDefaultImageTag() + ) + string( + name: 'IMAGE_NAME', + description: 'Name of Docker image to push.', + defaultValue: params.IMAGE_NAME ?: 'harbor.status.im/wakuorg/nwaku', + ) + string( + name: 'DOCKER_CRED', + description: 'Name of Docker Registry credential.', + defaultValue: params.DOCKER_CRED ?: 'harbor-wakuorg-robot', + ) + string( + name: 'DOCKER_REGISTRY_URL', + description: 'URL of the Docker Registry', + defaultValue: params.DOCKER_REGISTRY_URL ?: 'https://harbor.status.im' + ) + string( + name: 'NIMFLAGS', + description: 'Flags for Nim compilation.', + defaultValue: params.NIMFLAGS ?: [ + '--colors:off', + '-d:disableMarchNative', + '-d:chronicles_colors:none', + '-d:insecure', + ].join(' ') + ) + choice( + name: "LOWEST_LOG_LEVEL_ALLOWED", + choices: ['TRACE', 'DEGUG', 'INFO', 'NOTICE', 'WARN', 'ERROR', 'FATAL'], + description: "Defines the log level, which will be available at runtime (Chronicles log level)", + ) + booleanParam( + name: 'DEBUG', + description: 'Enable debug features', + defaultValue: false + ) + booleanParam( + name: 'HEAPTRACK', + description: 'Enable heaptrack build', + defaultValue: false + ) + } + + stages { + stage('Build') { + steps { script { + if (params.HEAPTRACK) { + echo 'Building with heaptrack support' + image = docker.build( + "${params.IMAGE_NAME}:${params.IMAGE_TAG ?: env.GIT_COMMIT.take(8)}", + "--label=build='${env.BUILD_URL}' " + + "--label=commit='${git.commit()}' " + + "--label=version='${git.describe('--tags')}' " + + "--build-arg=MAKE_TARGET='${params.MAKE_TARGET}' " + + "--build-arg=NIMFLAGS='${params.NIMFLAGS} -d:postgres -d:heaptracker ' " + + "--build-arg=LOG_LEVEL='${params.LOWEST_LOG_LEVEL_ALLOWED}' " + + "--build-arg=DEBUG='${params.DEBUG ? "1" : "0"} ' " + + "--build-arg=NIM_COMMIT='NIM_COMMIT=heaptrack_support_v2.0.12' " + + "--target='debug-with-heaptrack' ." + ) + } else { + image = docker.build( + "${params.IMAGE_NAME}:${params.IMAGE_TAG ?: env.GIT_COMMIT.take(8)}", + "--label=build='${env.BUILD_URL}' " + + "--label=commit='${git.commit()}' " + + "--label=version='${git.describe('--tags')}' " + + "--build-arg=MAKE_TARGET='${params.MAKE_TARGET}' " + + "--build-arg=NIMFLAGS='${params.NIMFLAGS} -d:postgres ' " + + "--build-arg=LOG_LEVEL='${params.LOWEST_LOG_LEVEL_ALLOWED}' " + + "--build-arg=DEBUG='${params.DEBUG ? "1" : "0"} ' " + + "--target='prod' ." + ) + } + } } + } + + stage('Check') { + steps { script { + image.inside('--entrypoint=""') { c -> + sh '/usr/bin/wakunode --version' + } + } } + } + + stage('Push') { + when { expression { params.IMAGE_TAG != '' } } + steps { script { + withDockerRegistry([ + credentialsId: params.DOCKER_CRED, url: params.DOCKER_REGISTRY_URL + ]) { + image.push() + /* If Git ref is a tag push it as Docker tag too. */ + if (params.GIT_REF ==~ /v\d+\.\d+\.\d+.*/) { + image.push(params.GIT_REF) + image.push('latest-release') + } + } + } } + } + } // stages + + post { + success { script { + discord.send( + header: '**Nim-Waku deployment successful!**', + cred: 'discord-waku-deployments-webhook', + descPrefix: "Image: [`${IMAGE_NAME}:${IMAGE_TAG}`](https://hub.docker.com/r/${IMAGE_NAME}/tags?name=${IMAGE_TAG})" + ) + } } + always { sh 'docker image prune -f' } + } // post +} // pipeline + +def getDefaultImageTag() { + switch (env.JOB_BASE_NAME) { + case 'docker-latest': return 'latest' + case 'docker-release': return 'stable' + default: return env.JOB_BASE_NAME + } +} diff --git a/config.nims b/config.nims new file mode 100644 index 0000000..f74fe18 --- /dev/null +++ b/config.nims @@ -0,0 +1,127 @@ +import os + +if defined(release): + switch("nimcache", "nimcache/release/$projectName") +else: + switch("nimcache", "nimcache/debug/$projectName") + +if defined(windows): + switch("passL", "rln.lib") + switch("define", "postgres=false") + + # Automatically add all vendor subdirectories + for dir in walkDir("./vendor"): + if dir.kind == pcDir: + switch("path", dir.path) + switch("path", dir.path / "src") + + # disable timestamps in Windows PE headers - https://wiki.debian.org/ReproducibleBuilds/TimestampsInPEBinaries + switch("passL", "-Wl,--no-insert-timestamp") + # increase stack size + switch("passL", "-Wl,--stack,8388608") + # https://github.com/nim-lang/Nim/issues/4057 + --tlsEmulation: + off + if defined(i386): + # set the IMAGE_FILE_LARGE_ADDRESS_AWARE flag so we can use PAE, if enabled, and access more than 2 GiB of RAM + switch("passL", "-Wl,--large-address-aware") + + # The dynamic Chronicles output currently prevents us from using colors on Windows + # because these require direct manipulations of the stdout File object. + switch("define", "chronicles_colors=off") + +# https://github.com/status-im/nimbus-eth2/blob/stable/docs/cpu_features.md#ssse3-supplemental-sse3 +# suggests that SHA256 hashing with SSSE3 is 20% faster than without SSSE3, so +# given its near-ubiquity in the x86 installed base, it renders a distribution +# build more viable on an overall broader range of hardware. +# +if defined(disableMarchNative): + if defined(i386) or defined(amd64): + if defined(macosx): + # macOS Catalina is EOL as of 2022-09 + # https://support.apple.com/kb/sp833 + # "macOS Big Sur - Technical Specifications" lists current oldest + # supported models: MacBook (2015 or later), MacBook Air (2013 or later), + # MacBook Pro (Late 2013 or later), Mac mini (2014 or later), iMac (2014 + # or later), iMac Pro (2017 or later), Mac Pro (2013 or later). + # + # These all have Haswell or newer CPUs. + # + # This ensures AVX2, AES-NI, PCLMUL, BMI1, and BMI2 instruction set support. + switch("passC", "-march=haswell -mtune=generic") + switch("passL", "-march=haswell -mtune=generic") + else: + if defined(marchOptimized): + # https://github.com/status-im/nimbus-eth2/blob/stable/docs/cpu_features.md#bmi2--adx + switch("passC", "-march=broadwell -mtune=generic") + switch("passL", "-march=broadwell -mtune=generic") + else: + switch("passC", "-mssse3") + switch("passL", "-mssse3") +elif defined(macosx) and defined(arm64): + # Apple's Clang can't handle "-march=native" on M1: https://github.com/status-im/nimbus-eth2/issues/2758 + switch("passC", "-mcpu=apple-m1") + switch("passL", "-mcpu=apple-m1") +else: + if not defined(android): + switch("passC", "-march=native") + switch("passL", "-march=native") + if defined(windows): + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65782 + # ("-fno-asynchronous-unwind-tables" breaks Nim's exception raising, sometimes) + switch("passC", "-mno-avx512f") + switch("passL", "-mno-avx512f") + +--threads: + on +--opt: + speed +--excessiveStackTrace: + on +# enable metric collection +--define: + metrics +# for heap-usage-by-instance-type metrics and object base-type strings +--define: + nimTypeNames + +switch("define", "withoutPCRE") + +# the default open files limit is too low on macOS (512), breaking the +# "--debugger:native" build. It can be increased with `ulimit -n 1024`. +if not defined(macosx) and not defined(android): + # add debugging symbols and original files and line numbers + --debugger: + native + if not (defined(windows) and defined(i386)) and not defined(disable_libbacktrace): + # light-weight stack traces using libbacktrace and libunwind + --define: + nimStackTraceOverride + switch("import", "libbacktrace") + +--define: + nimOldCaseObjects + # https://github.com/status-im/nim-confutils/issues/9 + +# `switch("warning[CaseTransition]", "off")` fails with "Error: invalid command line option: '--warning[CaseTransition]'" +switch("warning", "CaseTransition:off") + +# The compiler doth protest too much, methinks, about all these cases where it can't +# do its (N)RVO pass: https://github.com/nim-lang/RFCs/issues/230 +switch("warning", "ObservableStores:off") + +# Too many false positives for "Warning: method has lock level , but another method has 0 [LockLevel]" +switch("warning", "LockLevel:off") + +if defined(android): + var clang = getEnv("ANDROID_COMPILER") + var ndk_home = getEnv("ANDROID_TOOLCHAIN_DIR") + var sysroot = ndk_home & "/sysroot" + var cincludes = sysroot & "/usr/include/" & getEnv("ANDROID_ARCH") + + switch("clang.path", ndk_home & "/bin") + switch("clang.exe", clang) + switch("clang.linkerexe", clang) + switch("passC", "--sysroot=" & sysRoot) + switch("passL", "--sysroot=" & sysRoot) + switch("cincludes", sysRoot & "/usr/include/") diff --git a/docker/binaries/Dockerfile.bn.amd64 b/docker/binaries/Dockerfile.bn.amd64 new file mode 100644 index 0000000..7fba7ce --- /dev/null +++ b/docker/binaries/Dockerfile.bn.amd64 @@ -0,0 +1,31 @@ +# Dockerfile to build a distributable container image from pre-existing binaries +FROM debian:bookworm-slim AS prod + +ARG MAKE_TARGET=wakunode2 + +LABEL maintainer="vaclav@status.im" +LABEL source="https://github.com/waku-org/nwaku" +LABEL description="Wakunode: Waku client" +LABEL commit="unknown" + +# DevP2P, LibP2P, and JSON RPC ports +EXPOSE 30303 60000 8545 + +# Referenced in the binary +RUN apt-get update &&\ + apt-get install -y libpq-dev curl iproute2 wget dnsutils &&\ + apt-get clean && rm -rf /var/lib/apt/lists/* + +# Copy to separate location to accomodate different MAKE_TARGET values +ADD ./build/$MAKE_TARGET /usr/local/bin/ + +# Copy migration scripts for DB upgrades +ADD ./migrations/ /app/migrations/ + +# Symlink the correct wakunode binary +RUN ln -sv /usr/local/bin/$MAKE_TARGET /usr/bin/wakunode + +ENTRYPOINT ["/usr/bin/wakunode"] + +# By default just show help if called without arguments +CMD ["--help"] diff --git a/docker/binaries/Dockerfile.bn.local b/docker/binaries/Dockerfile.bn.local new file mode 100644 index 0000000..79445d1 --- /dev/null +++ b/docker/binaries/Dockerfile.bn.local @@ -0,0 +1,63 @@ +# Dockerfile to build a distributable container image from pre-existing binaries +# FROM debian:stable-slim AS prod +FROM ubuntu:24.04 AS prod + +ARG MAKE_TARGET=wakunode2 + +LABEL maintainer="vaclav@status.im" +LABEL source="https://github.com/waku-org/nwaku" +LABEL description="Wakunode: Waku client" +LABEL commit="unknown" + +# DevP2P, LibP2P, and JSON RPC ports +EXPOSE 30303 60000 8545 + +# Referenced in the binary +RUN apt-get update &&\ + apt-get install -y libpcre3 libpq-dev curl iproute2 wget jq dnsutils &&\ + apt-get clean && rm -rf /var/lib/apt/lists/* + +# Fix for 'Error loading shared library libpcre.so.3: No such file or directory' +RUN ln -s /usr/lib/libpcre.so /usr/lib/libpcre.so.3 + +# Copy to separate location to accomodate different MAKE_TARGET values +ADD ./build/$MAKE_TARGET /usr/local/bin/ + +# Copy migration scripts for DB upgrades +ADD ./migrations/ /app/migrations/ + +# Symlink the correct wakunode binary +RUN ln -sv /usr/local/bin/$MAKE_TARGET /usr/bin/wakunode + +ENTRYPOINT ["/usr/bin/wakunode"] + +# By default just show help if called without arguments +CMD ["--help"] + +# Build debug tools: heaptrack +FROM ubuntu:24.04 AS heaptrack-build + +RUN apt update +RUN apt install -y gdb git g++ make cmake zlib1g-dev libboost-all-dev libunwind-dev +RUN git clone https://github.com/KDE/heaptrack.git /heaptrack + +WORKDIR /heaptrack/build +# going to a commit that builds properly. We will revisit this for new releases +RUN git reset --hard f9cc35ebbdde92a292fe3870fe011ad2874da0ca +RUN cmake -DCMAKE_BUILD_TYPE=Release .. +RUN make -j$(nproc) + + +# Debug image +FROM prod AS debug-with-heaptrack + +RUN apt update +RUN apt install -y gdb libunwind8 + +# Add heaptrack +COPY --from=heaptrack-build /heaptrack/build/ /heaptrack/build/ + +ENV LD_LIBRARY_PATH=/heaptrack/build/lib/heaptrack/ +RUN ln -s /heaptrack/build/bin/heaptrack /usr/local/bin/heaptrack + +ENTRYPOINT ["/heaptrack/build/bin/heaptrack", "/usr/bin/wakunode"] diff --git a/docs/api/node.md b/docs/api/node.md new file mode 100644 index 0000000..ab1580f --- /dev/null +++ b/docs/api/node.md @@ -0,0 +1,94 @@ +# Waku APIs + +## Nim API + +The Nim Waku API consist of a set of methods operating on the Waku Node object. +Some of them have different arity depending on what privacy/bandwidth trade-off +the consumer wants to make. These methods are: + +1. **Init** - create a node. +2. **Start** - start a created node. +3. **Subscribe** - to a topic or a specific content filter. +4. **Unsubscribe** - to a topic or a specific content filter. +5. **Publish** - to a topic, or a topic and a specific content filter. +6. **Query** - for historical messages. +7. **Info** - to get information about the node. +8. **Resume** - to retrieve and persist the message history since the node's last online time. + +```Nim +proc init*(T: type WakuNode, nodeKey: crypto.PrivateKey, + bindIp: ValidIpAddress, bindPort: Port, + extIp = none[ValidIpAddress](), extPort = none[Port]()): T = + ## Creates a Waku Node. + ## + ## Status: Implemented. + +proc start*(node: WakuNode) {.async.} = + ## Starts a created Waku Node. + ## + ## Status: Implemented. + +proc subscribe*(node: WakuNode, topic: Topic, handler: TopicHandler) = + ## Subscribes to a PubSub topic. Triggers handler when receiving messages on + ## this topic. TopicHandler is a method that takes a topic and some data. + ## + ## NOTE The data field SHOULD be decoded as a WakuMessage. + ## Status: Implemented. + +proc subscribe*(node: WakuNode, request: FilterRequest, handler: ContentFilterHandler) {.async, gcsafe.} = + ## Registers for messages that match a specific filter. Triggers the handler whenever a message is received. + ## FilterHandler is a method that takes a MessagePush. + ## + ## Status: Implemented. + +proc unsubscribe*(node: WakuNode, topic: Topic, handler: TopicHandler) = + ## Unsubscribes a handler from a PubSub topic. + ## + ## Status: Implemented. + +proc unsubscribeAll*(node: WakuNode, topic: Topic) = + ## Unsubscribes all handlers registered on a specific PubSub topic. + ## + ## Status: Implemented. + +proc unsubscribe*(w: WakuNode, contentFilter: ContentFilter) = + ## Unsubscribe from a content filter. + ## + ## Status: Not yet implemented. + ## TODO Implement. + +proc publish*(node: WakuNode, topic: Topic, message: WakuMessage) = + ## Publish a `WakuMessage` to a PubSub topic. `WakuMessage` should contain a + ## `contentTopic` field for light node functionality. This field may be also + ## be omitted. + ## + ## Status: Implemented. + +proc query*(w: WakuNode, query: HistoryQuery, handler: QueryHandlerFunc) {.async, gcsafe.} = + ## Queries known nodes for historical messages. Triggers the handler whenever a response is received. + ## QueryHandlerFunc is a method that takes a HistoryResponse. + ## + ## Status: Implemented. + +proc info*(node: WakuNode): WakuInfo = + ## Returns information about the Node, such as what multiaddress it can be reached at. + ## + ## Status: Implemented. + ## + +proc resume*(node: WakuNode, peerList: Option[seq[PeerInfo]]) = + ## Retrieves and persists the history of waku messages published on the default waku pubsub topic since the last time the waku node has been online. + ## It requires the waku node to have the store protocol mounted in the full mode (i.e., persisting messages). + ## `peerList` indicates the list of peers to query from. + ## The history is fetched from all available peers in this list and then consolidated into one deduplicated list. + ## If no peerList is passed, the history is fetched from one of the known peers. + ## It retrieves the history successfully given that the dialed peer has been online during the queried time window. + ## + ## Status: Implemented. + ## +``` + + +## REST API + +[Here](./rest-api.md) you can find more details on the Node HTTP REST API. diff --git a/docs/api/rest-api.md b/docs/api/rest-api.md new file mode 100644 index 0000000..eeb90ab --- /dev/null +++ b/docs/api/rest-api.md @@ -0,0 +1,43 @@ +## HTTP REST API + +The HTTP REST API consists of a set of methods operating on the Waku Node remotely over HTTP. + +This API is divided in different _namespaces_ which group a set of resources: + +| Namespace | Description | +------------|-------------- +| `/debug` | Information about a Waku v2 node. | +| `/relay` | Control of the relaying of messages. See [11/WAKU2-RELAY](https://rfc.vac.dev/spec/11/) RFC | +| `/store` | Retrieve the message history. See [13/WAKU2-STORE](https://rfc.vac.dev/spec/13/) RFC | +| `/filter` | Control of the content filtering. See [12/WAKU2-FILTER](https://rfc.vac.dev/spec/12/) RFC | +| `/admin` | Privileged access to the internal operations of the node. | +| `/private` | Provides functionality to encrypt/decrypt `WakuMessage` payloads using either symmetric or asymmetric cryptography. This allows backwards compatibility with Waku v1 nodes. | + + +### API Specification + +The HTTP REST API has been designed following the OpenAPI 3.0.3 standard specification format. +The OpenAPI specification files can be found in the [Waku Node REST API Reference](https://waku-org.github.io/waku-rest-api/) repository. + +You can also use [hosted OpenAPI UI](https://waku-org.github.io/waku-rest-api/) to explore and execute the calls locally. + +Check the [OpenAPI Tools](https://openapi.tools/) site for the right tool for you (e.g. REST API client generator) + +A particular OpenAPI spec can be easily imported into [Postman](https://www.postman.com/downloads/) + 1. Open Postman. + 2. Click on File -> Import... + 2. Load the openapi.yaml of interest, stored in your computer. + 3. Then, requests can be made from within the 'Collections' section. + + +### Usage example + +#### [`get_waku_v2_debug_v1_info`](https://rfc.vac.dev/spec/16/#get_waku_v2_debug_v1_info) + +```bash +curl http://localhost:8645/debug/v1/info -s | jq +``` + + +### Node configuration +Find details [here](https://github.com/waku-org/nwaku/tree/master/docs/operators/how-to/configure-rest-api.md) diff --git a/docs/benchmarks/cspell.json b/docs/benchmarks/cspell.json new file mode 100644 index 0000000..8227630 --- /dev/null +++ b/docs/benchmarks/cspell.json @@ -0,0 +1,20 @@ +{ "words": + [ + "pubsubtopic", + "jmeter", + "analyzed", + "queryc", + "wakudev", + "statusim", + "queryc", + "wakudev", + "statusim", + "chronos", + "libpqis", + "Conn", + "messageindex", + "storedat", + "pubsubtopic", + "wakudev" + ] +} diff --git a/docs/benchmarks/imgs/digram_multiple_nodes_one_database.png b/docs/benchmarks/imgs/digram_multiple_nodes_one_database.png new file mode 100644 index 0000000000000000000000000000000000000000..e26f392cbc5beeb0a3e6d6ec0d48dbc004c6dc5d GIT binary patch literal 206077 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%0An?m2VE5=B9d-D%T6mW?iu# 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 HdC30&Yz5x> literal 0 HcmV?d00001 diff --git a/docs/benchmarks/imgs/insert-time-dist-2.png b/docs/benchmarks/imgs/insert-time-dist-2.png new file mode 100644 index 0000000000000000000000000000000000000000..a5af6a361a32f7ef0bd52669d523cd766a2e2a5d GIT binary patch literal 24921 zcmeFZbyQrz)+Y*qK=2SG5G({waCZ_Q5Zr>hHty~T1b4T_-Q6`v;{t9DiWwsf5imX{UBKz)M>2M32C@kLY-4i1?L4i28{ z1=3>;;xI7x>BB)-;_HjY;`zcT=q;3E&^LCZo{1Cu z5)SSyoP_A7udZo_%O0Lzr`sMLRN17lQMyz5wB7uSu|d2ii!O)>@8)_OUCGz-}Qy1pXtX$p|inY zEGWtTMkdb)Svzm9U9Vifn2a65)IG}TW*0KNt|eVX&pTdX|9gSF>S$kq`}Z2`rfNDm zx_AFxbnd3`JHfkkWl719f2Rmi{r_j8ETl>nkR(j-68~FQ=2G6D=Ka%y zCN&QGMhqAUNQpycnE&X=@(8&$H5Ib|XL(&8)RMa15+a(v^4o_@&jBCR{1!@MFYJcy$!qtgL1sddvk_F$1}4z@rxAcY83!vu;qG6Ob#$UmJXQjxsb@q zt4}MIWUEt=^Jf0u)G&U5_+km{|?$~&k1T({@Hu~_g!2nYRu!1udYv&TPg998j-l->b zAIuoP_5 z=S> ze8qP4jY^uoD#6&TuC0TFaq4Jpu>G@C5)VZ%Mn!_ogj49#UeQ8L5pk~B|L~}x;tP4k z`BaUaugBI~=MGGeU+0Sw_ZHMt^-|R+UgCeX(uC+PL}!*J+eb8nGG7^z-F4PzXo-Fg z6`#M`DR6`M<*31#i+f{s90@2?8G z3E$|<8j8=!4Jyp%b6*|nJS(J@d7KwI> z#R_i~o2yan!x?y3Z!ESn%HXF-s|B1-k3y^@HSSIcANI5soXkfz=_V3i22&gES6@_@ zq^x=gI7UorNPQmnC{=HZ_zB)OmE_G4VTi-Uope^Hff_L+{OaoYaV4TfnO3bQ;T}aM zQ?wRNw&SQxy2DvpXJtKX^bqAXOiKD`2vXL1Q!-l!YoMY}Nf&0X!!@Ze*vh#41qWW- zAMivSTFYYD6YbF0cZdBk9NOc=6FCI@**ui5*#i$J6flX4e-N^W-mZO-Y}Tp>trh@} z`RCbGdxoG83|Dt-SDQ|<;2pa+Px~M4Z?i6Zb zKlB^uPViexv7ZgPkO4%(gE#r`Yivi2V%~My-@PQW8a4_qu*$DlN%!GB3LGwm&?lw% z7hTh)&hn2SJ-E@k>G2L^F?{vBc{6suErZDge}%(k$P)VC#Y=&d^4pP)Z*^e3!N&@i zVSfK)J?-bu7B)0vO-2pn_bl!%X4NgrL-n`U$$%a`VoOVScc!xZ%Ex8zHab)x;9&A$ zSQo2F0K6zO6tbhnnkSTDqt#o};S&xFGagqO;%i5spagnQ*HvC`DYrK6z4T1(wz>Bp zq2esOr3?)#sJ_~DWJ1DaO`hK{pO32x>A?ND+rrj=r_ZZ=YS}src6#r^L)hURK30+3dzm;wGpaHepj%-ysqkA3 zvm{+(wB$L%k*-W~H%ZrZE2Kr)lKa<0uMGnBq`Ga3P|JOq#7s-zi|c*i1Sa6dJ&Pb5 zcxIKF7Dy#$%zPQ}=2SH z(Sg(PgD=+5+v{&T1D*yf4h3Ovc?&n*t)ch@*C+GHPxbmA?vhH%3Tv%LrFWEMx409; zjjk84CXuL)-dd=hE(+}^rk=kg9NNK|9pO{W#@Rq=NTy?OdEbx?ZB^j+7uOxt-#W+V zwB+t7iyY2&Go+p;U7ALTV&8E7i8k}7C*lY(SpZ~m%+4n%$8whJ1aR&()aa9Bs6K0j zmzmHFqPIPIX?-#v{xbLx2m7~#9lnf^-&$hMQ{jw9Q=3-nK}_2i2NUp7AF<+KL!lac6~t(w|)-;ls4MXqFfAY@=@z*tq_@I9T0L(=mz3B6zRU{agxlgL$L z

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 K}~G% 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 C509Au literal 0 HcmV?d00001 diff --git a/docs/benchmarks/imgs/insert-time-dist-3.png b/docs/benchmarks/imgs/insert-time-dist-3.png new file mode 100644 index 0000000000000000000000000000000000000000..34980c751bcc005c08607043f81313cf50835bc7 GIT binary patch literal 24443 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 literal 0 HcmV?d00001 diff --git a/docs/benchmarks/imgs/insert-time-dist-4.png b/docs/benchmarks/imgs/insert-time-dist-4.png new file mode 100644 index 0000000000000000000000000000000000000000..7287c82f5b642da3070df9892dee87425f5981cc GIT binary patch literal 23470 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

&nXMgSg~o+ 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 literal 0 HcmV?d00001 diff --git a/docs/benchmarks/imgs/insert-time-dist-5.png b/docs/benchmarks/imgs/insert-time-dist-5.png new file mode 100644 index 0000000000000000000000000000000000000000..8e976309062dd50f7dae8fbfdcab62445555e071 GIT binary patch literal 25031 zcmeFZWmKHawk}G726wj*++Bi&U?DgJcN*6~;|(+xT!K3!c!FCu?ykYLA$V|iJ0#z? z_Fn7UGsa!#j(x|KvFitPzs#zd^1QQV&8kV5ijph_Dk&-)92|z+J1I3dIAlgRxMu<= zNKa3Wxe4)~ejxzg%6&k2YThVjp-P(j1zz(BMP#1A z!@*I*$w^6k@W|MMf%Fr$G9Mqch(p#w$pa!8adA|;Ua89Ql9u*lC`8Huq6-XQ`)O{w zZmoQ<9yzz4*V+_wdNQaqs(36Y$QWBn3SZ(4juaAk$V6mdtN0tl z^&&y?&3kVVZxORP%Y$7Y?9!Dh`xZ#$fP#+N>=*hk4b9`s1zzf(TbEDK8z!26ZtS_w z^Z%t&T_kG4KNHZbax<%h{|m|B|6vfGFS&?!3cl#5C>_QsZ0die>@pC_JkKbtQ86#J zaTnV7{MVr4s+e;o{?00Iur+se$T2}s0j0kfyg|wxiZoYaUNc=^}&yj*g%%SD`jY00YoYX2;=l)en&`+uQuA|YV>tN-70 zUFILY;QtHBzd6VaTrL>f{~=2h7Rf@QfDnwdV)<)3_%CI>b60uzqwBICqKNN1&63I& z`lq)xP4|+pnzBSv@9l6Gp!;@f%eN(=r$Ij(bQ-gY$g%mJ4an4cMjUelm*= zuUOGs9GCpkdb2n^r+6Jm&o~1TcYbJR(ak$LxG$$Kq2La_cGp16My?EBZkQ-nT;ygpxqz`tt(V+k ztXB?MpmRmdk*2x>>Vn6g1WOOpVVAgC)mB{_t~cGKX7|Ae7PszT9^DPD4CF_99@|F~ zXDZ^`-*z3hWenL%a$^eFlZg^Cns`{e>7CIz_Ym=)aV%|)IZ^(tTc_9ucf@=r_F}Qw ze%s{;8^AN+IXPQ71-mQg1{s>5{OtWj_YCfJQyV5GT7EYjzK$Kcy_iPGY>O{j*e>qe zl^kl)k9yYI4VID&C!zKl9aKg(_V(3ZL&!*#zqEws9#%Vp+-i#U@#zYcRmV$TLaThW z&Prc~7iNJ|&3OWt=BvZb)A=iR&#*UHL8(Tf&YsJh(FOzM54Lm>J#Cd7(8_y95Yust zUfG(M3u`l3m|{9c5OGa-W2*u&rgY{?h8uJL+VS9FM(i zhR~9w!8A*}S%dkjr6@h^vpW`6y}MD?tDRmu(W&E|v`Yg4?jB&T0uO=FA#Lulaez}r zDzz

L)t<&5VvyN*)O$PXoTtRLOr_y^v|op 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

)Ag0sNtIfY&){liT?40ax9vLjb(1hAqS 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 literal 0 HcmV?d00001 diff --git a/docs/benchmarks/imgs/insert-time-dist-postgres-2.png b/docs/benchmarks/imgs/insert-time-dist-postgres-2.png new file mode 100644 index 0000000000000000000000000000000000000000..b515c5beb6ecaf8dd09f0bc6506e2c607624d9e6 GIT binary patch literal 20367 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 literal 0 HcmV?d00001 diff --git a/docs/benchmarks/imgs/insert-time-dist-postgres-3.png b/docs/benchmarks/imgs/insert-time-dist-postgres-3.png new file mode 100644 index 0000000000000000000000000000000000000000..553157209dbd30b7e605784222b8a67353b47442 GIT binary patch literal 19415 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 O2|R!CFQjj-{_r1bO^>Yr literal 0 HcmV?d00001 diff --git a/docs/benchmarks/imgs/jmeter-results.png b/docs/benchmarks/imgs/jmeter-results.png new file mode 100644 index 0000000000000000000000000000000000000000..451c6620c9a2b731003e342de6649720e317e0a3 GIT binary patch literal 16031 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 z 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⪚ zTh?P*e9>gA3mktt;JqU~ZzCR6M6&litJw2eEw9S`{51vg^a{t$YFpBGW`JY)KVZP$)!7 zenu9>puBV+i+|_9z}(#4eW1lW-|nrs*QR66#a|FZw>Y7LqzAnjXaw5@TA+o$KU=o; zt87bJuTQhj91vgQ=pM3*fa>9I`7XJK_~{t;&a%XBl|PCVkWQ``+52c40Y(9(8jrv} zN!Q~w4I`t9ep#B~AZHDMZa~5BxO0nHDC?>!)psbGR?uXuX%q!K+mcTkbPe{5xDrY9 z;u1*$$P$nK^qC`Zc%k~SwExzfXAI{=XlDz^9K3xqYNnASS?VMcviZYN{UgDMwRB=^ z+05}%L%S6E9@)ZrtQ8{^W=BQC#-QF~C>E1+u!$5%V_5&T*qJw&F3Y(CZxsJ4iJlW z?b>z8z=2vFO0B`~Fu39JPst53pZedmpMJu)NPI5?=#?6OdhZfkEA9>jI%AqUZw)X` zSSu$k3ttud|LAXB!#ZQ=TEAoOJ-5{4vEr2J*l$i`W{!~0_8+Zz3%`^$%KY)Cc2 zb$OCtkHjlFRJTO2Sd#Zy_z2O(qkEuWg8-9h>|gnsyPtLwh_QuIpJLapN-fLiE5k;i zte#a{^n$I7%lw?JF>z5_GkAALt2(XWa*(6p=XUxq&nl*#In!P=A#fxiPF4lIN=XxL zgiJ9@qVAX@Ukf(jC6!9DD(HH3c_{GPB{@~K=;I=6V0Z%e!!05Wg+`F*bg%`!`y;`B z@c5r?1whNt>)^j{`3H7AEYrQs!+IsJ!mOgNtH=;&rj9Vwqkr>zqTpSB8q_PdzZmxQ7e=ytf1Ee9wI8H=W+Bxqf>G&Z1`Fp88V? zQLQ#Al82H_XPoPIbjb_67^g1ebuUQ@h?Ua?WVT1dr{CcS)i)jm%H1|bY+4m@Vq5P^!wCP9D5Y? zr0b{LJlt7cZk_W&ymI`KU!Gh`i0X0=2p`@*#ieT>?j`z>Dxru+P(_ z(Wx)z@taa(t<8BZ5@1fQW{oz^GHiLg_9vDOuI98NynYaTka&>E;Io7b%TpZMc; zu32+BDl=~`w34f#syG8no+^O-(4pxD_DUEkL8X>&5N8b-6tl&3hAn$E*OQ#IOG$3)(f4K0L~O zxeFv~`dw903y=tUx+R0}e*b)G?QXK{gI_;={PXMbk|s3QLXH3A_YQlj3%o7i`0L(# z2O`30shxbYn=bZr-`k4RM#_IOi3u?@ZZ^TmBHnO+qchcr2frX8C9aefdI3N7&P-#p zsk+x5@J18tm03zkSm9Kev+mEe!^Ywc^;{g~^lMD(a)@`E9V3ocWzx`@W=cxNL3;CE zyNhyM)tj?Y?k$q_nSgG=hN1p!T4YPeq}rR<|5sj^n~slBJN5P10k`J<3aAIimkmWE zbZk({p{P}6d0jSX;49ZOfUx$F`fLf~krPEYc7_Q=1|H=(Ud6S*-f6v7ScT`1XduPn)fL}6N#NjF3B@6OpEbmgBENBUv z`!Y{J17>fvZ?SHmK28-?O&} z42M#0o08_|H8yA5FP<*P3XjNT2z>85w8LvIEjOsE+3Ic8K3F=p-#Z=o08_Ua|2%jf zx5{k*Rvpa_wY}#Jjr+e#Ebq!NNSZ3c4f#e!#c)GLhkCnFqcV$f5mb>Vnof-Kc&=jl zqvpk4Hb}hb=lrdge_n?V>9|UKJajhCmk)x~o?-%cgKhvZb-8CXvTql(=Ik~$PHAgk z6rh@X`5bOyi4;zO$dv07>Uwm%pl>oZSZ5ab<7=Wrjrev@7ov#@Kj1zIu|75`__9@Z z@E28qi0EX(k7jj}%0OXihiPis@g)A*<_v|kX+JlCX1WMMBuCk}*Lm#+r-m+-;d<8g z&|3(aq}`*^_MKoHzUuAeN+1tKoV=bEWZy4zC|sTBEg|y?P|l(5I`9VtlbecB3TTiO&1P(mC^wIe z7^E3hpl@ir80zWh3`c>4l*JMc+|SM~u3X9G(^=e4G>=j}c9x|0|4Bg%UNJ+XpK?Z7 zU#X$Ysk;jzV|n)pZ*swDq}9HXTY&vl$8PGcYIxR*h2_g>Rt^z&j>8E11!SZBP0It$ z-BBgsQ@5RHhO6YSX-uTFpuTI2PufolxXR;~`<`}V|EOM9HlN5x3%&4^1A{6Nu&o>L z-(;QU#+Alp(S?aETR-CFE||~^4HH7aaH)^kuul|(ZO2nw^p zku#!;xehLL>;%q^VrnYZq$n7s1($jKHFuceOAne&3mATl^7hc$V_z3p;`Wf7M@6>4 z&^@N_4}Q*0wh^)19o1o+o>0L$&5oQ!6To1a;^TfArsfIH^O(ZTCQ(k_?`01aHbel= zDMn}YIl5Q1f@Y7k(}NgSJx{2yWuLlsF2iiPQVi&GB-nlvZ@S&C=m=NSQ|@BzdH(>Y z4^#Do%Zsc0X<$;eiHp+iwp2XobEH~bKT0pE^Z{+1vOnNdYTEgh21FP1kvssmuhG*Z zYf&W$1xNgzNe51zQFjw7>gLz@cI-Ghz?v75XkosZ7{RQOTiO9yEA!lYv$d9H$s@n| zlKGBRD+314GY=ixr24WNTA5;Er1bQ<`CGO@pEUFH?VMs^mfi+nwv(rF&6b3cVOsXw zV1RRhXH(pEt~I1&=T)24c&1i?bWJQ?*@k zME7V~lFyCFq?e~}`@QON_-Jq8y4q75bKKdJ4<|L5Tb$G?W**DAEdJz&1?c3HSfWx{ z^PWe#Lb!8~?3bx6E~_w?g?}VKIq43oJnap!8rc=UT{c>>|LwZkrYmsr6LzUbkYs7U z3ErFk_ky1DY^2)J4S1eovuOUiWps1aD-MPX(3j7#lmYt16&ssPD3Mn1VroRrw<8Ap z3+(7}sCU%)C8`ePgt^qLRCBgGo0K&YI9fGrBljK0@&8psD96nK3?i)DumMfooQMvb zUjVfgJcP^SwpigBv4}HT`E)WQV{1Vd#ZuWX(@I*Z~6Y+KV58MwU8{3Y-eHU3g%N}pqUpJ}>PgFVxH_^VJay}-MzCHIo z+>=gEJ?FB@1QcSP&!5*F9u$2L;tinCiAC-78dt zD2v`zk4;x@q@-I^Up`%41ZxXI^>}Xrx`3=ew@|!8{qh_QijRjG9wUfJYjPOvL^v zt!t#JBgwsSeFzn+Z(4uK;YI4`FZ5G?i#3 zhjR{us)=n=i;jwUha!?I<<^GJ*j+481H5c=wpTxHj=Wp0YoxLGfGsY--e&@mi1#{&?cF!&a9= z3?MA?Kl%madQKoxBH(wOA{KJ@MTl6*!i2FB*)~TgJGORT+)TB3-BK!hS-l$FdNDda zYG^E^+7LgwsfAHnS_Zc7A61lS)^*S}D}DtSt2aqGsFEesp`wjZ~LK9Mr!2#RUXF zJgiaAVEQk*^T*tRn!!qr#57y6ylkPm#p<{@5OtzpPQGc)*FOWPby_kk`)_1JjW5l* zf@+&-mCCnfz9Ya+reptOqdX3jA+B?>kzc6OOdRH2S)Nm6bI8(`_fA5dPlrAwrE zXlZk)-AO(EB?+gdgR@&o9Q#MI7J5Yf${Dz*+JUHdCfH25`}wx%$NOBL&rntL8FbJ> zP1{Y-0v*~dsEDJL{m9O#)lni+diG?-aPoUOMVKV=^gr(S-X5Gtaq#$eHn{IAkl`T2 zf>78Z<2FK4kU7-Ta}3`1iruDqo0t{DE{gdo7Yp!P{q)=dRd)17)=l z<$%r*MbiRV;gr&+WlY0(`&iGNz3*V>FL%@56?_fM%At}~nU^!~CbrGU;Nn^L%$|t3 z14}k%SoLXqZoUx&sqP$2+^3|gX!-_*Nfzqc4{nYxF~mv5bJ6u9;todK9>`LH90GU3 zRRNG9{)WC=>$3`VbSF6(y@&dyo3ET~26Nr%Xx;d_Fd4ik4>^{jEMpA_Zx*yvj8!P0 zSuDu+p=;n!2AvXr`BH5SW&~@dvB(-)c*4 ztxlY6Gx;(pI1SmA1hUQDfH*xG>(;NP?EPJrt66wYPGNV4COEmTW#B#=aTv$`Sn{pXucistx*VcH5azIwAO{U!!x$iBc z7uzGx%lxTS`we)ZxSS5=_dI=pP_jyTC;Rmi&?b8L&(3Ynf!_Pp?}gvzEzpl|wiNb7 zb$6%*sqtU86$qCTIlBy=^=%jU9G=AkLn_tQrlOqmH*tNw?UHjegePZKvL>QkpsiWg zEf`|0+cXef-N`&1MGq~vYs}yBy(AJawQHK$ut|`XTta>Eg-a9N4wpvOcE)9Ct*y9C zokSUI7d7|BSFmqvOUb0pXMNf30@os-DM=rwon>bc$n+=}n%Vne$dTo6E>$cM;EZTg zb|FmdqPF#e^AXWs4CYLjIBE-{dnFU%6(X5R^XF~5?zUC7teY%);W}lo3F#Q_ZdR6u zmXDA(T~kJ(ZtNnq^^s%_^}o>P)N9QViV_LD_GE%NozC$rGBfhD%UG*Qlec^GF@p-w z4BBrrtEL5!OVZsvh!~1;0vQGDKKyi_yl+XMN0)TN4X-mFTb?%zxDpMT5e*u9udNPs zk>docKB_ufHM;Ml%}f`Ne>HPZr3gUYYR^T+y?ehpxei8Ns={EdKgA*k_bB=!BO~eA zpQVZc)RibLOIiXK4+SR8czFq^0DYQBM^*>bwA6pGFHw`GL~j3L(`0~m3nQSf0!OvU z%_%nHzf{{?bF>-bwpJBcl+M`H2lA)h#J8-M<=!|JB~I5N{MQjKq(c}~FFq*1<>Uq)00a@D+= z0o>4NQARCTl@jYmXN2q2`C4B_5!bgiW#4|Y47#T|8$P&8;ZB6-- zXA7yFAw|~SXCFj78I{Tivc2dPsP1c+@`xm2OW{IF42*7>?8MMYqnw+Gi!XMh$p2Q$ zv?nxUY2%DShGcZkmXNj;gV!8=<>bsR23D0t+l`Et(%QkUfg)74Ua2lTZoBI274Hs{ zXbCmK@}+y|0IG!Jt`9BI?KvXaVds5KHFH|R{UsHOKKOT5;$~A%3HKdn$%_)2{?iq;d{#15; z*2A9b+AsuPEZaQNE`A2lq-B{|^p_4F3I=J;lR<1|VQg&i%36T`g*aSAq=p)1`c!dQ z493~fmboq|#+juhXRXea#5x~GChK!?7)h=BNV%uNvO-*5UkxUlq*SV?KR&J9m3i%r zn1JR@12aO4LEz#|b;Lo$%_QC}z!-rVBi3Rd`MMJWsHsrB#p`J)20J!Yb>eg4+EjfskW`_ zammHHLe%BXo-x+Q&l}#dleX%;T(nn50S+7Jd=<`W9m7OTFdL*@1+nnVCG9(w%S9d^_Ocm`h1f5M z6}V&vs+Noq#1bMBrl(!RLa1X}G&d8OvesKBaGET`L!JCt5Xi-hC7TCJ2Xx}in)6uq z34C48%7Oc(J)s+$`NmV6C87dcBDXT|Kz$rd;R!nE?y(c-~iBTgtYrP)U#j9_34fq5an0G5Z>24j>ofK3G=-Vvf-YG)t zcrZ>#$KEbJyT1o;)qYbl5~jTJbnM3h65ASG*jdZguW+P=Nm(S1F4e=r1n)*M@LrZjXgkgc?b$k_f#7<_YqL=}@({Qsc8r1TZjj1s7e~7Tm_q@# z+ODygB_H6nwrjb1t4{)yY0?m+%J$Visw#KOg&P{HKIyMFX5}Y~L&YBh$9jyTfI6QQ zRQeNk3S^RMy5lG69?}^G@vKl)?EJ7B$foLdWdjJK{6}{-mlL|1{kVbr?b891!FI;` z93Xx*8d}&-T`(fg(8uup9g$Uop{{H)*L@^&A>)Q}Ur^gR4^R|5qn$c-DxS$@=yK9- z8%A3B+dYq8rqu0hk#T4UPbSJ}*Zi(psxf&urzh?)Qr=2#Uy}zo2?Evo{jOVk*EEk5 z(qneyaEd7vceajA>V!qH*C^XhytTLt`+8M4AhNbw_$-63Pe` zKo>~j?&{!h1`^;MGD@&CL4jBto9PX8qy@|CD-Ji(DY13GBa zP2mXU4sh(BD$7ES&yyRg)-fDp)&C}P!?$>7x<0-!d1VvHR|L~4BcuQ#i(dxcK7@;s z@qzR4#L~eza)wTYoD3B$M0VHv$|a7y8sfH78E|6BjKFut4tO zP`q>$_PLF0o8|Z+UUbpvB%iFT3f%^AiuXRIV*`PM)PLP^(iMl$KqpvmhL71Nz8t++ zhY5Kf&g-#{6V6LT?B`Th*fx+$jy=LQFCUYH@{eUR zr7OZ(e~%>{$4~ypZs-n5_6no2aD|SF;!NAo)4hIuH1*lMWNg7BT4_XGBg|%1imh}4H$S^Cp&Gw1l`#EHdhC}sInI|nm zpkg>R$Vu?b&0W#dD#>e2ea_^mZTxREFI%35z|0Kg6)_`AyZ1?SJH^f6308OmC- zb;<{d=5wncMgO!l|3xFY2npUNTv*73UZG_R2ia1J8Uy4>7;ijOs)*(MjiIpozu15k zEe#09jy+P7We}{aB|NQ-e7S?PEyJ1A=rh)WI)BK!V0n3O2>TH^d0lEUf&URgU!cS8 z5X5MxPfN!&EUbqqEdpc}I=hn&)ifA}L7{zR$MksM60!WL>VMcvAF+#`-~Iuq#XAnY zX0>rd#~qbTJPF*+wKKK3$}rTqIFHm@%k;k!(X^(bhpUbm4M=~(PR`l^!Hkm{AC>BU z_aSB;;`fw-BIPp#i8n;)3HXZt{&yGYLVy2!HN8$8g){g-z4EZ`ro{88qC;S{x#7@7 zqk%j|F6GKG>SbTUxzu*Wq zeG6imvuo9(F-N4pURQhizKr@XTIRne6xt)$5HG3zGcZOiMPYgEE!xvYKc!fe(?5Mz3$ z7&$G?xza*KqC?z1_-qX+za|3DdWdA)V3Koxh~!}Zcbf*quIahzI|V8mwl+0%OB2Yd zaQ06{Y8sO-WK;d$)6!amZD`zC+`b7BI;!c=+L~xL_S#c_NV4$^+5V}h*;Ri7lES!8 zO4B4+X#d{fy^i;7h>q8Fb8#9#xZjaqw^3pIE|NPNw2jg@#2vQ|wencbJMYxP4j zhJV(xON6MYv|eW@b@OLXWyaxU)z43@sCs?6P2hyeqyMyoin9^#j>aR;eEfIQz`hq% zZGclBduiNbx(VS5TKgMlvs8pBqY0#XWVT<)A98v(ePl6{^izx`+Lm|;r;Te~;MI89@&_85;e5a zi(@R?C{p10#V3k)<)sa24xE<{q;GOrZ35b?YO*5?m+y9MKiaiCB<7%E z#-U=vw;wjNh4y7@gyfF$ft&UZv8&C-zv-Gc+lkfN5`1dUtSMA`%5UtFxa4c*dzs!$X4*r0Nyn0G{%kEpdv&_T zDPaTZ^5P3I6`s-dflXNlhD#LS`AAF~Yu!jKU!Q#; zN*SKn)#T-=p>Xh1{xWY%wus)bG(%YPhX_ciQUb>%P-Zsopr%9D=dvi4BH9re8;v3`-ZM(HKIfhD6b_lfWw%gQE z*#wIkl*L|i_8f;I)VCGbjlJr583*wR)I~xEC{x@#2&Su2+|7+pi%oUd54y--6dy09 zabwP93if<-hwmlXZ^~$qk*roE>Zc#e4i>WVOW}j!C?3>PaneVU!{(DB1?V4CT|600swJKPT>~6X;*1Xz?9BCK*=Fo8Xmi{7uTcm-SoRZ;fFI3c#TdE30 zy|(eG7WEa$XjG~&a@P8~ihV)Nnju`fDjs#XPTU4Y;&@XX2~MROa$*bX#8qILhTZAz zxpTN$g<8CJs7Ug=t-Lyh53X24kzEqPzQJQNj@~tTi;hak_80>z+~*&MT}O$P{rOKc z878=pkg#cI7O7#X9n5qCfCu&o- z#)yUeViF)Qwptx%8qx?3S?-M{$$Wwvg2-8KdN8-_e@pwWIXuJ|>-z0{4tC&m5iJeI zs^&mC2}6=kzi>PQgGx$zFOuPp@xF8M)n9D3O=*6xP+@P%5f!tcy<~}$9ZV%-|HUe` zq}HvDogF93ag1vvJ*_=qQz|1$Ru7&M#>gqx2z zDb4=jyihvR*N%7QseIK*a&JQ+(e1S*u&pXru-@A3LbtPyui|Jmy-#yKM;E*+&W#_N z%7|`TW-l6*cdSG$-pyW@R6iauI6re$00MJb=TcWEE24aCnNXk2Q%){YH`B<*L|T|p zt#qKpz=APiS^2cv{_Js#Bg(_X3Fitm%?bQIOKJd|MI33=j0)-CSG|Uz`ltHP6fr&U?q0xeL+!ZI7;lPob2auk zg~`u&lzG~!r3(p>wu_ai!uH@SA+>ATQUkeV=hA*wCIm&cP|2#|8}@SZ?B7e~(wWPH zvceJJP;ni$AK7X35~ze9KN>gJNm67~O-7jS+H!tKvc$Ag$_`wt&ELcc`WhR-F}s?? z(Bj)Npr!A?gZe&&Z@B>LApa}d8Xx+mGe>E{$afy_cMc;(HnJ;M$RHd*UtKv58zbck~ zTml2+tYy)Nj?G_}f;n#^KO(7!owlC63CgM2TeZm?%T!#BR-e3h{IQ+qd5erCM;11G zx}rf?P=D+ifj2nM>&w_VC=ajod*bOI zC!E~IwlY=2%I=B3j!T~={evbW`-DOz;V1;(R-p0b!J>g`KT_50#`H~{Ei|`7i_>w$ z^9DoV{w^!47)sSX`pp+Kuv{!=F09jZq;5xodMAp~b^LquY}Ek#^u_;4)F}ecVbJb1 zm@E^Rz!4t~7BgTR;v3f}w+@(~x`pv!Ki>e6@zwfK{CvUK z5bHUIL68_|7{s#D{5y?%VC76i?Ucg&kaq3MX? zmvWy3`G>yrjooTBY>3+o<0+GkUFl3QKYSU*V0?nUw%zsL2k&Mfb`fzEydI?Rgt+!nUSjjD?fp`T?G~ zAe8|aMxC@!esz%>*8HS(%5Zge?E6d+ux@3Oij3E-f`Q>3G0z|hB@Gj800HxtPi%VK zb8OL|+!~s*Kb#ubV2xD2ldtOP1nL3qBrno_t{to)>C!(Rnpo%=Sre!)W;_0JRxPc& zej>{45V2t1>tQqU>Q}HU>SpMu3U>9mQhzxxnx9%qg)&N#>rL_v_so7^v;LuB(IYlx zG}D@Fn90qr;8U{SZs6h>CP?2I$`q-b&RF@i-s8rCD?uhR4T2okP&qxT4Bweb~ua*tX%K{z8a8V zetp5X0AxYxL#mZV@ls@9g3|a8_SXJXkHfp}W}K2w+Kv<)!nUo0lkYPfL$%7yKMw_c z$ZrjolkiT~#05p`^jL z9FOWpZY^K%A^YJN5eP#W25a22G-L~o6QpO}cPBviG3xCar*nI7rC!KEzNN9oDq!_L zI1fP}x%FlfYIi$Hgr?2+QnFu28`>(7p+hxkCDS>#_Ra^K?nf z1n%QTabIahd&{DuB8G~?3F&O;K%tJ9K8#}_iU-nio1=|cYb}-H62kx_7O~TVr$2`4 zE2t}i}q}ig7%zF<{&Gew)v8!a`z+<#COv@e%o@E`w@2I<~+U$vCnRG z`Pf(1_s`1AL^39^JiwUkU7~ip>9OR;x6?nM=8-|Y;v%IdI^^^ve~7DDrUqlnsFlMr z{zT@uM=@Mg|1@`+0}`jm&1(5$IKNq{DYiF$3lu~OPC)>Q0A$vrdK(zFao-b<#VW(o?27qM!zEn$*W^mk||G96ySKF)M?hJ zTa8`f3@oT(4XH^55o$#jGTr@k3jMW)vsc{Xm(g5m?D%0Ml?)SA>vWA&a!PWLlBl`} zmJcF7i4?3B65S=>8hVZUeD1HEtXEAyV485C7EEc9lf`+@wed$0))p5wIG)hA5nF%_ z2D&!akz#TF<0$ar&n4rZP{h{-Cp<|26(uQT~(l=3&eFGlSYoRFE z<)Gxhj_bm1Zp`odXfn}Gs*z-y{xB@$EY*b~vBGQenNY)fk!bC{J$gdV4YiNBXS8jm zj9!D5z`(O9*!Qy1Nnt~cu6jvjd9`IQ)v)K5m-dS-Emf;tdm z`u~yjl|gN`-_sRJ@fLRr9s(4n(Bkgyt|eG;heC08m*Se>Zp9snI}~>>Ztwm4X8xbv z8D zH%@Iv%tX$7xhmomUu}+T+BN?KNp%}>;VwLNTSKyY%oK_6zGQPON^1Of3u!jDzhK;5 z$)I|lqxlh5ijA>wM9%iD-)KZF_h`lb>dIkT<0 z`Q)&a(gkiW3F1sI7ov5%4qz7h^~vtHN-Uwj)HzDk1EOks4Le4aOFpx5{dYFr%OX7b zyegX&yC)k*`&aKa1 z40>HOpnLE_yoAU}l|#?30*U7$!*@AR)FVE0@bxz#liyYM>=8!ZJf@8-%U(V(1e%j= zin~3!#WZk)43ykmi(U7IiPC>F4y2-f=%G-Ag>p`=dNwGfFe|gn4bsA_>doJ2YQ`>1 z6tS}wUi>wtpjP4&_e*Dy?(ysKAh%Al~Ebp*p;c_Kf1(rIvvh!=aDz4?Rq-3 zT%D?dBUOzd(Y13ND3QU%%c+DttTMa>>Q<)6q=FU0tSW@c;#dJTM}WCqhtJq*cU0=p zIdEb7m58UXEnd}IiC&_^kT_WxRh-bJAZPgqSlf7^IYipy$G3Sti#?Kvi^CO#O2@KZ z>*1QV+<|-*yzCdvEEqcKKeuTY+!Bhcir5V-l}k2tlfAJ-8aAnL>q(G-_27zLP*h_S z%N|uBerns~mtbSUIEK^twK~2?$Pz(h7nOwAY?$(l#JuY4aRW@!PU;6jUVoDj8@&>lK^9#cXZQ9=r3eDLZe~f*pIvY84ez(HQZYLE3vxVtlNy`522q8a zR?KgHN% zg$cDCWy{udK<4pOLTQrPauf#;4yq#Vcr`#+HNiTKoT zM1@nUsU7RSoK=Y&7yRlW(zn1()dSYEP&Y5MCOPda)J*yr@9$7` z&pxW3Gj}El&*ze;I=D^usW(^9Rznj9vBTitfA}l^z`*1FzErUcXjTj2s1u^(#q+1s z@u}6C%^YCGjY%1)0i(*R0L*?9-3^@hVRiGcE})fek0QtSH{FMlabVD@b`9QO%Hom_ zaj{`7vFc)0N-{F;>z7u-3o!dF9`_d*fh^^$5N0K+DyGksOEU6O|JdYAnk*O*z*GuV zp+x?OtmPkq#_^)gnd$(u6gb@aSP$kF5lYwA11)Q^i*|ut9880gb(?nOBZCFhE@D!E z)awtvrCU`vtq&Lz$(iWkvmGXw>6h_7C^XqtRQMR6a;(nu~NJD}vRXNT{GdqO5P9+JtC>5QN3z#u6Rx~dd z32W%p%uot^-NOcctQEp*f+CciS(A7qd#r)nr!3i;Y$zgJ_&QP0qOa>)m2srF;FQhy z*JL^E=|~NUocSf2nu7jZ_|rF>SfH$=c(o?5Em0yf8Zq!`50UID@7pCfpIs`wdeRy- z*qXx;#$>0LJgZp)2E&g_c`%|$&FSd}4rl9~y2RBA%*9QA_x(99o(ljeU&IU#rUW+c zk2F(GIwabW#oqpdw@eR&mZQy(xa z8)5h8o@8V1LOaswJ$f_Wu4nFW-xrNr&`adPu``Htw3=<^Y8<#(B1^Q?mut68_T5r13y+u&tupHtrxOf` z+nizHF2yBh)5EN*&$QSJES{=hjMCj*R@u;Bg^Cp-4NW6VBH$VY{T}thZ-~^yH}ms( z@d%r*v+kB<;5Md~?Oi|#oyTF|eB626re;mMT{KKkD)hx#MQthj)QNcn-dXk{FK=+S zvk#$aaaItD`+58pkDYNfa<)k<6dsTw(z-66I<;xkez$EF#Kw8jy3H? zcxHU6VA|~GqSqeR`FH<(iz|-{IrP@S@$B4ix3<>evwx538%94n?z=v`v`a(nN>N; zJiHO33$~wA$L>x*YQT9BMZG)cC#H+)xr8!tMfv(2(Wcz4PEQmJQ<| zD8PDpW%T%;V20r|%e0zM`nWGdf!+`~aLOyn!K786S@NH&_Oyk@ZQq<~(gi=FCwfHM z*o&Jjal2Cj3)$)Jb2Qz`#_l;`YI)}7-p~HM`XmBIQ-Xzp7ArZrwQ@E0d5jW2f?@n{ zvIpUh>Sa)$W4E1FgMPt;m-}IC9E+Zm32E!kjaR<{l;%>i5+(1|cwNot$2gfpNpY>9 z6hTeOIf`)$t0o>7l%(Y&mI(fA4ab+)FLSHrnDK`Z;{#CI0ssa$rmSSb(OSX9)QsBccEqkk}!Q!JH4@xt6@;g#w_ zyTt?AO6B( zk!O8t*i*@x|K|nZpPp@R;M}YxCGnhe+57w_RGs|`LSA0f!-<8#U*KShapBQh6IO_R z-ySSdkCKrGlK$hcAI|PzA4-lY&+2po$=Tm zLu+5g`bwHBXyH~AHGb;NKi1m#1A^-8%$RXBc{OHFWg0J>P|2-!7NPa^eY51h-sS%f zH@}-n?QHcTG1BDtd+x=4B6lkqx|2}XP0Y+|cT{sF$3~bJc_G;0ysRlHsrlPbNTsbIC<=U@> z#(2U80tSzA*Wx=}-FnWp-mmRNOf|2Ld>iJ%!*rJWNR(+Ap5uc(j8)pK_`8tZtja_% zCK02FPUicL@(*dbT4(BBs~&r~u8Wa^SGZyqrlLW_(nB#;qhO?VC`_s_P?&3GrvKeB zBH`lvpARSwuBJunU~yBz)f;y3LVhnP)6lAcw`ZoFj+_SOHK5A*K0naZUuzyMLb)!Y zaS%P_Tx>Z1!%$^4V|y{s{zpdiM1ywfSQ~nOkWjj`-o;j1Adyzmm>mfk3N92*AMboY z@Y7$>n&wmY>#B8va9&aBY3KC7)@U-I&Q*wc31H}CN zfnM47-}mFheEV8DFAq;|;xA_QiuH_K zd^Xcz`ZK9n@n^wa*2h&yqK~F;Q8w}I9yN2eaKZ}AvoGFxJ0UPmThZnvzm@H%9Kg=z zKUu79?#ET-zsY8~teaYSyjj!M&x;^gB&IP0d%dWJ7>jNE%$95lG^jUoJh{V?sIcB$ zY1nqVU+!~PfVmwpg#KJ`2WYstV%1l|E}7B`)LT;}Gc?NPm@7$xnHiXP`)Q)pLd~-% zV4&2Tt#?@M+<$TOgEidz@s+`^wl*Qciw%*pAq6=&OpGgz_oUi z49Q;4siPj9WsWb=I^ET6GM>Vmlgxj*?eb}VP6W{@q@xuK<7AO-E{75&8P)LEIfxCP z`MHMQJk2~{Avg!xeXVn0|94az$Q=Ad9=Y1U{F^~Sfm!%=YxF^!u$1)0J)gJe7O(GP zJ7eql4$;dQw@g+>+vQrSY3+Qk!rIEwW;Y)?UOA*0dI8MoM*;2O(M}{>TyI8`VaUmX z$%D@c4zX)BACyZNP)Hh(vu=%b-ybBL*3As8(eJw0YdAPcE)02x9!0V=&vv&U0YB?t zIqgo4xTshwt;>aY*tDT+y)$|v`3rJ)cyeTbF7 zt^Ri;Q#+SO#op%X`E!n%5zc7@R>ZAh_$X`FBok=i4^g<11ZSSLphvOU&+pal6=F4% zP)3c0E!5zi)07$cY zER1LSuntWb44~?UsF90>bUu!~ei?3TwZTr(F-pIFf)>LqYY|>Cgh8@^?Spsu zZ^4HBQcab&_T|E%UQ#cS&JJ=dZ#Z4A;_#@v&jJ||+ zlem9qIp(as+nuxnj5imsJTVJ}U6WgLo zJA-e-r%vyl_^9d!h&Vfz4&wh5h3N`!TOB4FgpNTj{p3w zLN`<=T~I%uZkxyM7W7*vUM@C^k;6)zednVsHSA^`A>rIB7Cns=Xf}5^sw=mvu&ikao%gJyxGEMdY&4@T@?xlt^Gh=VaHV} zQ%a6aJT0lP)YaJJli#s=jk1(hSpHLP295&D@t3XA?Mp9Wq->xP~ zouHOJF`PTjlbTS7+|7puGD=qzj3HMmD9J*3Z*vf|RUhc@|HogPJd$gvR9dBNKZYDA z1Bg0B3`>~^fuI?Rlx`c^5dnH?!++J;$|jwv#ZH^&NE5g?BtL zwT>P<4!YRv2aK*`uFwo3HZ#E?gI49m228b41yDWEWa9@Ar4lvvx#?Gw0uM&aRQW|5 zu-xQloZ4cm3nH=nLa82|#02DY2RYhRfv(uY5vt`mLz-nY<#qDBsnrY;FfVKKEerOhf-2(6MUgK$6 zLay(PVrm7rVs~y;<)-+DK}&}?t6hs|4>aRtjCvemU2qV7{?Bo)UCw?>Gv!C&#h520 zXUrLZaFg~jTkH}LXsN74t~|d5cBzIQU4ZD(VuguqYlu4g{CN-)T$-A!t_03r)XuSK zQJL5Dn)-p-Xa9rU4&#fQ{prN>PrZLZ;0V2H2KmGkw&pMC(*jSt>jIapB`mU2 zAY}7K%JLsR-E4HF&B24r=BM*NJ^}BGO*Ey!b@HmZ0QFe9F@}(uAB%w|0?DmBoXJBihfaQf(||8p$#~Ep>w` z+<6up63FE9P`G=yKNl8i%4KGd?BGR7H??9^m4d$s#EgxM!A934lSIk#E6fO1+Ga#c zJa-ZK>IvwbL&UkWRAz^XfZD-Dt*nLoo%XTTTup?ojTS)!VgPg}UBya&Da@luo@YTf zL98aW-X**Y6Jw$HYNvP3DHPZ@lYka?6z+**_LY>jsk-Mlk`+v7v&a|DSs%^fqhcMl zR6ju8{^_`=RdG91fxM{oFAZuR5a;!+*hIo5B_kE-*PaicEl`4rq@7L&9d1rLf^PU9 zUH-Gk!QYHAh^F$@^{{7q#;&^_{d(D9rXK8@UW#7@WK}Av*Eo!VcAAeE+l;seX6Odp zVMP|cNj^47_+z)440p&@X8$#wKid%b8nhpWmT#2za{p^*oRN+7j=9>p<`VtwK=o)6bLM{F&iP%O zsKw&WWNo&z41P*>gVX@Z(#akrvGNzL$|kdTw{VfDqvZY7bTi9xt;+TPdcESi0qPOw z(2cCOnW8mDwhwa;=XYlC*485|$^X!fS_)dW8X0UO`}UqFusz2#X2=0OFYr|@Q+g5q z!yAAX9-41pjwhAIl;aGSG|d(T^w~$#*egXnc<$EW0RQPtm~#+v-y29)OVtn*5E*qP zF!wKq5xfE0Qmswn3pRs>m@Yu4_maOXyO;O3%eV#)`tqE$N*ptX3G}?a8w8oJ=xVqp zr-LyU49gqOjxE`i;^B+;!Aj?K#&rO9Dq!#dI*d}lh}+lheAk?qni?Qg1%hi-LE@oD zY6&}KB<_EkoWuFSmuhG;)C8zVb#8#qOWguk_9cLAsnTD|k(Aex6O!=6)_pqPIpuqu zd-(gc@rU)CXneQJ^)i7LHiq1xmA_xx#F?a{RQN`X>sGw?u7EYf`c<9XBGf=SZjTRvw^_k2*N~FOn(v5^vE?IT}y(z`M*3x3f2IbybUF#_lk2t5 zL>DvVp#Ur8m9c@WI8!wnOMJ=?D{CPWD-)_x>bU7On?A{n$nULdn|oF%f0|CauruVi z%aN*?%h|-?<=_dkl2swUx0y4pQjaGFOHI^kV`^0l(}#)X=Y%*R$@crRVF3+VAl8w% zxo9C4muCavi9dtJMQP2mox~p&xP4im1&^tUim65cs_~_H6U9WL<@4+|3S`HN%wNGa z#;1C^5H`{A#wQ)%azTIXdejrn0Inacf zx|$%53<$*@s0Wt;jH$7bEgmg`&2+O|xf8=V}wX z5dEaPgV^gksj?g#)%I&SYzD&3EO9TvPh{Wbf7m{L?RY96Ds>yAynSSzV5*}-JxM0$~$ zOr(IDz_Vez(&V?Pg^1x9HjpKkfuC>YQ`!?K9G2}JTzT^KWdNn)-0o?*fa1yTOEOEv z{qyI{EXl}NBXY62!TF5zn1!$3SR0mGcko%hJ$A6Hj&-~|w>_?|q1$imU$0eEE1Fbe z?G~;uUAKDHkc26mUlsL;n>v^D>GDhRs_vH1Ig<%6Bf(uZM@BSL^L01JT(4sHF);U} zs;Dhy=O5s~y^LJm-u%2&;HjyKBgb4gvgb~Jc1QhC%A{_howo>05#rs(+RLq7MIsoB z9~rMuE$+$qC(oZ)>XW$=we@7*W^ub&P<&&1!~kHNqow4M>n!tsyLVdO=-sh1D7yOD zP*I6mxYJx>1}ubM~G(ABq@IE6A^cWrJpH3AA0#q+l!~ixj zMlJ9HQ9uPa;$cU7jOabIwVK3+r`>L^ZG|$;pwSwZa#8_wVCD1W<%Z@D=%zO*$oJgK z&+q37B#WgI)}Q{A#xjU@O(=<#W$zBOj{H>izSs2ZsBsdQP1VL&s9d{jfGG|V2{R;O zO5Gf+6GJMfj+X7xH__TR1l*y!9qdw{@U|u=EM-TXkn{h|@~k@*!#udLFfqtiELqjj z+ThvR@&)=@=}YfNz2>vhd6!>?Z53iWbbHul$=M;@c;GGD3b4cBy1o%=MoSfxO=W_+ z)*M~xKQS*d4Lp%pPjFOodpoXhL3?EhruhQBX)+`C&fI7Q{<#yp%JRC{*uTFj zjZ$YPXslaeqFtD^Xr`{r9TZ&>UEQJ^1_`i{T>^iJqU zB2-S95(`hdaspYP8y)1JlRdbVJHR_bw0mlrn3Z~V*_@6p?n3CbPX3M&F!zT@_G7qu z_4QlXm0o7<`rFp+ALWh+HY`-e;BIM1luBW!maZPueix*VBbl+HH*A?Lw-q;4oS*8` zp7xJ|9s>kr-1LCQG!5Pbn~H{)ZMrr-UfG!NA|<3u4e&uYBoa^{O}O>Y0$tT%wIY;P z)Ku^zlDrN*^*tg5#JGF3K5da&lGLGEJvk)k3@Zg4bx2au`VY8tnTtv}sf{abE^M}3 z?T4`z=m87{z2z4gx-&@qdSB+-z9w#S$Ml;LL=z2SBW%#pOxhdb@~vs61(0%mfj~jj z2IIq_?GA&W#3YtY&AJQ-x~11X!#EyNYbGtH21(ecY?&YEKSnlB%adbwX^C~g^M3atmge})0=3> zn}g`y9{`i%nx)Xu2uaqc0W#dWyn0(ESxGvGL!vrJxwyg@*8fh7%+yOw+%yLg`|XH5 zi0B;-EWI)($l1XPn0tw3@x+alUMUMfsHnTl@wJ=u z(R3G~Xk54iYy`y%_wY~ufVj6`={7fd`FO1Hlt7$b&$+#rwA~-2v&?HF{Rrw*hA}XT{XYV7~0Jh_Y)m zn#VAB36htFEAjc*%ZYh`X)jVul){C@XtAmrt2d}JactjkI@{3B&Qva5vy%0$Q0PZK zh6RnYG`SltNfvzteb0=f(y>pDAqR|e@i zYNCrCT|a4suyy?PR!?{S=}%-lZabin)-kcS{pu+*$RfUpM=kes2ZLH_5D)DLrj&8_s7P(cD?Zo;x`Tcr&i)EOh^$rKfhXrX=yZ4wdj`4BtlgbcHPD+1|t++Zt*>Fz*zm`?=)L=^Ymv4c;@BiPB?ax zH@q%39}Hz;opx|Fmm{fFS?gCX|I7 z>Sn02B|V`hFJw&NuF{4zh}NY3@W;i^-=B>7fAr4UhUdJFPjtuC!)Ue|1wdrTD{?Xs zY_f*8IR_}7roofT_c9N~$(#z5Lv>pL>N{4{({J*2nLe<>w+?%%H|}40D8p4$Fb~pt zq$hUqK46^wakqyI;6F2TJ*;YNc9~4!Sbz~Akq3z5PD|D9I~C(>%^6!vH;4;lx}XWt z?Rbf6B?g#TwyN9+wlIjI@d$^Wy&y#iFtXku?X@~~WI(|Gy;t94g| z?Zy|fUgbB+q$%n(>ZqCd0a+h6^`|nh36en|a4^?OYoCJP!^ensDUYip669`Ubr()Z z`2h7xP5NI~BVmIhSIAB|X4$W&)A;xgLYy;mPaw+g>~nE|H(I7PFn8}RfW*;D@zL@$ zfbzZRqfdp}1$0_flGa+ko#3y450@0L?RkH8wEOhQKo34zHdU_?A|I=xCCr1F%90)JNj1D_pS_%=_ zKdfxz*_L4Mab{M7SA1LCw~%KYG_S(%`4QC9&X4{(kIQU-@QX~` z!qXC41$>nMb4~(n z3ddQXFPh_p@TGw9R2spbYaw58hbN!v_ZSl`U|skYRLN(r0mXY7JrbCX3}{$1m!k(TH;+etDbd-j;OAx&f zyfgJ2m?U`f3tDM6KtWi89B9pvhw0QlN`Y%vpJ+8ID;Zn~VT=jkVrS^AYQYVg_RuT- zq&H*v^Vj!91g)9MXGIFKPMfll(Fnfa45tKl7($_m5FrLKs*;#ZMM#81K;#Y(_g$#2 zHiSQPfj$`Wk27RKJuo{D?ccn+4R@1whmW3%CpXq>foatxnlhnB@ol24!0jk()!&-T_xjRb6bBZ<+;pM zZ0V`Pt~|oz`d&Pz?3B-be;x~f{L4M z>K3AKob-xtgxU z&-e)GJ`Z0rA5Htk$b4#>uvwcvn!088baZ@ZPhT2L-K`L4Iog{W(tM`qsJ%jCi5^NY zpbUTNWr+NyxxD0h%y>SXdc7cZD8x|w_@trcasT9X)xq%C;=1#hd);xSpPQ)AmX!*=z2V``B*l&RGeHiJnui~KupY!=TmUgLHJJEH2Pz!IElKUa50P2Yw{<>VDm0XHdJrF3Xo zHB|9;F1OWr%V|ZW?vHKUyXLU>rdrD_+#b(o-G)0oU;I+Y^K9$u{zr@1#AnZ8K(*)+ z(Ad6Lre{AMFA;h>ZKNf9TL00YDaCH4q{*vOVBt##SS9o^O*HL_0O2^glRrEvUk+^h z@+YZ>ktQ{ViI#PQmVH%u| zj*b~$7(GMIwe@Mz&^J-<=e4JODF4q3fIEKvD3g1+CGFG9W~@uHVB}!iHQpT^=J`f! z{TYX<$Tj^{FaJdG_*!q{_y z3?A2Gztg7HF(=M_?F9H(FhWJxNFY;~U8L?iJ=U|}^eu~OI&q4PJbfzxWHl6`3E4)V zLmpp zWJ%%Q+fUc9Q1tedx;*`fVmLion=R^JH37Q-z>WVGm7K*bLvq!vc&z;x@#oXATI6ei z<<|bc-U3u%L_Sv*(2SNN*YE*pwS}6bW+HR>5x@(&PrOe7bZa^WQ+OImZ6}{$-;qXK zZtz0h1WydV&iaCh<0(gsvtp{kbr-jVN85UH!p3%XS0Ujxyk3S6e=I&5-&1M@^cmy- znu2IN)X%98&lKx}V@^k+fX#i`8PaHnKr)HhBWhAGZ#=qaRJ8{tCVfz?qJ&%3evIu( zo3V7%f9s!savQiOMK^Z48Bt zEZ7Su)M{FcG7X|RrA9*d0nfS==b)d%O!^HT%3^|*@B;mqUa{zO5g}G$DFtzctn|k%1qfI*E^Sqj7hY}d zyx4_ajqR^kQ$9i~B!w7d1+OjZ3t<7PWeaApI=+Y@)k!THu$6D#S}v_mEB z5{-DMtC4g$JoB@^VKhzu&ho*^@5y%1B{OmG9L6* zG+*)Qx*j6Rr{X_wa9aDv$%s#{e1LirZ=zDHeQR?oMKh%ijFV@Cy7JMT{nbLipt6$r zoFU+w&!cynu2{$qT%1gbTAIfBLKy2f%zr>c#yBtARkkxiJ6p^B2tzIO8TxqEWCm{yPOjUA7t>)mcZLcpqeZuTu z(lR4}9gE8LIrNrbP+(YRJSO4C(;1KP0<8L?G#_kkyux?BH>PO@J}R*WUUnI-7zXR% zYf4dH_GkRiH-wiyX@U+BJ-nJPtV?+PxsCWCmE=IGW;Qxs0$- zLeA+iJMJIsj;k8I=f9Pm;N#65N3$Q&?(Sf>?)>68NykSNM5M0$LUn6Dxb)4r{%QxvIkX2i3h*- zF8%|4EcNYx0W||7i2O-=BEFu7!}?F+{lp0Jl8}ZhneUl<)R*t&us2?HW=2~?p#vTz z^3=G{^sloR{N!HGn_{_?#A-IHI>zWIK;=L9%u_?Rv+{B{tPR;Q#Zx!+;2j~?#zgL7 z_N<&UE}+kwL4!J{+E7W=FV8y8c-35~3e2Tp^Uhm*-_ZR5kiFBIKc_Fi6H%XlA5Zpo zQ60+zv1PZZ8JDqPTB^8>9LFX`V&-lV>`@@H8g5llULJeq-!?6W%dK^N0*|AU&6}Ql zBNev;xHLfxr6iO38^h6ocmLTykLJQq=!lcxb0{J;`;n>yi};=7*Csk#!^vr)O_1(h zpor(PMN<<4fer`QoQ~yNjt{qg@hYN#V`Wo@a>KN>#YDw>+eN17?WbB?+0WaW%6x)7 zw5;YsP|S8bN;hY|s}A^uM0@f(&~ZO4*Lkmgc%!E!K&5>BfHe4@KX2?p2J`;t?5# z+eI(M%f9!h=gtY=K}H9Joo%{ZlOeNGb3`TrZ9l@tIW(4XMFpZ+93p#e6$np>_{t^Z zELQMI&9rjP!N%UIlzTA`*Z()#t9m-m89$Z3uN2`!S;o^d1GIrAi?F9*tCpy=HmI6M6dMl5sYamr?W8jkt(gi2XAXX$i*X-D=Vv8#Y8Ls zrk13OYMB84%I{N7^oiSeV)=@@IAvJdr9J5wR@OEpL@jtJNds428;!Td+ocqYI{581 z;rxirHeHmcV(|mXX3S$83Ffcq=cx7D=QAqbzcn`TnN$BM+no!8`Yl_$m+B2_39VtxI;Kr`>EI#UK2~5 zv$KY?TAc?Y?8H`TK5LvphU~AQ3H$E|zYoLJXlo>6ZkiY)1eL(DISRxtXF%FT_j}Fo zU?W2II2#BHbnwk^W5G$1X>*xJnRms|S1J${d(vq%zLmN;(~8I;NP_nz)|Lc!OH;J zR3a^fS_7zod#OI01jez{2wFL(0-x}dFA`?G`fe)OO)8-peQ>(kLe#kV3#zd5(89ry z7G;cU2<<35P(vkKtnh@WYhU8H68pXSqlk<*i*(!eWZF=Hco5^)P<5jA~bp$M$Wz$vn&)Kyz4rG?d454rVt*x5b9uk`YpHKbA_ zh&34+abkt8c`HD1dO8hlb|C02VQfo8(X&vWBV)JQUx~7T+2r$E75&`rM;Sruvgk5U z6c+yYj)U<#@!*4-Oi?rao)^y(1hSH6G=AWB5*_y{!9hUaDQu(TWe4JOfKR`J@2Zi* z-!fwKM@*FenIWknK5V}@Bw&Fly~A&ofEeRbLx8C1<(uG6eO!l3Q1a}@zp3w1)Ofnf zwU%xwf|h$y?aBHvz#&EMXu)&e570V0^bwNOf9xhBo@H7zR75$OnCJR^6Y09Bp4v@B zG)j%sNHuHcm=XN>VO`>ss`2vMTSinl2u$yZfUTy-q*9_=?x7Z)TVW|j*>nm>1BtjhP&h=TaLiGlQl1rFdy+1r7N<99TReGQ-Hp-|U~WMH-j9 zQm~Nft5tW6w-ZR#oQ?TBhZUMVf^y4mFx@F%38VcW;Hg2c{%9Bo-&A?+_1H<&SM=t# zucLgtw$A5my-t9-xBIBR{AphCp>@HxMXm@`%IqtjB?R2Q&`#zRZU zgThY{^mj1VG`l}xZo(W_8s@h!6|QrSG0S>pM24;<;_h>~Y$+4idZS5x`|>;;6fn0q6@0A&=~WPT-eNmu-YA!UjWd0pxHhp)DEhrHft}mYDI+W$7}C>micpCbKZQ4x-NO&v*}i z;%8!IPX0FT>(tzzt#=21AfJ1$uD^aKWt-_>*I*PI^(sb=kX}1%;MJc*u1e@mIS0`v zwQyM@6+2#(URi0e_KjMt@z(@OSZD;2y_`6V)3l_Y$5chf9BH+rzDN(1j#MW#vs+WO ztt;EMKV8$dUqW9=PZflq@qT_!r||BKU7*~s;J1;7r9}}XDkH+v3K59X+zv|c`-}{I zA;8uG7I`!i6P1cmM=@*-nWLXXCVjm+XkEJqahL=Vyrw&xP!`qhp*EB^HfatoN7%5n znne^6%MC$o&Xhv_p0st zQ`NuF(s!lR=|MIC&?&tQtA6t8S6!~GQGfkQ^U|D(jNB$y^*T;Ej|vRs+^}ppJwcq6 z##td8?o$b-$Nb>8kZuwXtHb2>O|cg`ShX`+(CQx65=rr)SkBNsQY2d|k_efwn43X7 zIQ^P44AuHl9Ig|@^*I4M_gvC~3l$^xmlr)Cz( z7hG!><5)=(!9r|>o41&_36-82mLCK3vXkXl%S2>GQ>FHc>ws;ku@S-7R*g@;!k#=y zhP6v*h9}W)G{FoQl;p^)#zIIf$YSb$3>S{`N4)f^Q_{I6Dz z*1Q6RLwN6g{3*`81E+oN^`E-#vwd*`Sixu}L6 zz76Eo8w$QP5!PY2XrjWrrh$6##)%Z9bC_sE<(yH10 z&Y8vMi2tnwmE&z+Lxs&4S51%6FNI#oj^_0pOTOt5$V`DA^_sUe>9Bj)dvbaG%jN-6 zp(?r}BiKk-o)c-~-4Dc)F_hg6C3NGJrfW{ZEaU9aKk?=r!+IriFFfWsl%?M!<&M72 zzJ2wPjZ*S%v}WpHhBiR8*ydW3ug9c(kCFM)F8ae|Is#=DX@5<}jb1d&+)lk)+OONe zFPE+i*tVpISHaZ6X+XO-dN7c@z*;`Wh!l&c|43eOB-^g_UbG7_3a#Xib0IUIA>Q2J zJ3?XFfVb~Ii++BWE0f8^C3RlEL`0D8bRt#u3CC~?-q_@ZEB*7YNVfEPr$PZ7>T}&2 zk11L0_u_qVK!V4cqq$z``opfwG$J@MN{pK`m4b}5(j(``2^9urQz}Ra%ouWoQVc2A z2tYA<+Y1)b5bhn6P*_N6P4DClf~PD0nm&su$uum9c`yI(?_|xCtXzwXV_i@_h+zL$ z2%2Jmo1L%j%{}dR^Njw)rpRy)%_>1p(6I7qq#RrWbJaE3pAUl*v(*DTz{cpJ_gzH$ z&F{hkiyxR_1t`RJ&wHqEPCmmah`1_!qoXvK5x=}^TAi~YsZoVv=EIeRc>a_bxeR{R zQqF`CHiTzczg^KncXl)=p*8N#O}ADSsp=A%@_R3k*>%an_YS#6<_n^StD@LCBgp&q zze_Os@aMw2Fvd%g=X-M3@i#DR9QFrH!}@?;lwl9AW31@5uSDvj=!9Zs#J5cxHFnO7 zI5o)V?#a*z4~*Y-u-A; zoA@1Gf%vNwp+f(!5Cc`KspHDok?YTI(BCij(0LQ`8f;C?&F_X4QKx!4HXG~)IRgdG z0VB%;!hsaH7V&JuE{S!ly@uV?h%m13j9Mh|A7*@9s{UaE4h0ZntnUy>Sbdu4@exCK z1`dt+61D?oig6|d?WZ>?Raw~fNMd64i_1geg>eDHX)`6iYX%3K^U`XOWQYCPtmAsB z-yn5fv5&YVEbtfBr(;^i$>9y*9#j#1WgWt)vQ^&S3kln972y!0LOf|{@eBPNb`oK> zIf&y!IA^Y`pf1uR{uSE!^MMmm&fC9|IWbp4>x%95TTlf6e1s=GJfj{-@reTMNQu-^ zr3AuQT&|gl-mp1!F3c$<%sEETrCC3?j<3w5M39xMb8|1myn(5?-2LS9M9;dMtQzOkk4V&62ubvun`Bb0|VQXDUh>gOmen zmXwj-ZWD>I8U4NehF#RZ@VB${G;@5I)>)MXTK3sd>aAL=$8_egWZwiPZW&DxjL+nk zBJK4~obzh7TfYBlMie~4HoCw$8P|&1R1haLvk6+KCKe{yQ{8TE`ib$?5BE&;Y0(NA z1)iP(j539yjU(sWCd;?4awt@6dUch&A~OEf7Z@YrX_O47;TF%d&X%wL@`HwRT7k@e zJ>T!Nul}P~LwlTNQOxi*YQv3>wh9(=dOha$knJN7dLH^}h|^y(X1-UT07Yds*k88S z+sMCvGy9+I@{PIEm**0;W_Cof2U9|-C!z~nuAROv$iwVnYdG?mwQ7Sf^UV3sHpS|b z3vwVQ3!Sv>ug#Mg)KPJI!3$28)BQK^ z6A(Xs^1XRzSsQ03VAst|E;01n4pu|zkE{l$2BUuC|6vNH}bIfL`R z`VkXqJ(yOfWJ&RHbIClqPK2#A2d*gkj?Vmzq1Esl^Jfe)JmJ@G*~3XL%>1|Ch}p?6 zVTzgN2*=71)jQiYm747HO{KWITgGeX6B`?KleN(8(uq)LH#$E*vFy;nNW6VKz4Q53fK&^H|U_rDFwY*c9jQSNErT z3v3JqI+#i@y0rO>^eLpvKr!Yu1pEVU}E zjXD_6zP?-riL>Do)FRlM`f^uZElg1x+WP;9dh4jD!tH-}=0F3B~1>L&trv{`+Mj~ zx-7KKL*q@3T4RQ>{`k=BNc+^(qL1d{NTJze6V1ny1oo+kNQim%cja;-_R1ieFErXl zbp%YXB3F|LlpPd0lE|)h(YiKwhdk)_b}A?~Hh54j;X>2b%>0gJL;a#oF7@k`%)FWA zz+|Qa);r54sbr`y6s1g2qn>NjbY2$S(1}p+WLBURxlbu!l?H%pgADOiox3zF`{C~t z4N{T!!Y!Ze3$;_NbV%cCZ)`+yd)Uaon=IABe{KABI0FIZkEHW0)k4#8Cen&2xWOgU zavm(JIL;i+6J?NEp;9vrvq6xndCtQ}C4MZ2EJII7`SXSIPVP2_1*iJgbQ`C?n}|!3 z-%B88QwEXb4yO~%A(=}8&z(KohyaJ=?aD>Ik%cC_&(Xzwq`?^?X`qO;Q|1Yp71$w0=X_Fnn-k3qO7P& zx|ZPibPJLs&=M1V6bG$pOFM53R4R(VUSBXdyEL(_IkQvk4e?hyqn0nkFgb}N0-V)* z(}L|gS~+U%Y#Uuw)d5}AvQMBi|i7?q~V;OHA) zwXCWYh_s*^|DI${R78vdyO?9yWM8Fd023-JaLU;8J*gI>vimFppyZ>ZQH(;9N3Ph| zvQT}Uhu-=#`xZWPJt#g=g&#Jk2(*sh%`p>^W5SLPU(FjH_ifgK4`(q*wls;K_wb#8 zjX|ho_PBe*PT?%#RZ&dpNBnRNg$}1*O1iV2qGkheSYj!k*^qSRwsD$d)_a@L z=sTfMJZ30q))T`(F~5nIz&+r$>Jz zKo4}`HU$^-CWzxa84T!S36>|U5ws+~>|mWq`n!-1AtR}t1V)S>2o1+lGvA&PB!6v; zwoivEgCE0m>dR59Vq%<4<8&NyiOMDwOC+EI( zB}VomCd{*MjfNJ_CeIHa6gu3x#y|H4;MFm{W5T_z>A8pqBDKlPKOJ34U8frO-Ge_} zFJLLJ`%?tdW=}}&zP&>cacPX8^J_lm)yf+v@mfp5<>~(;k=s;{$5ir?esGyKzWCD^ zSxskcPljOR^qO1%eIuBXxZ+?j8!JPLU)*X1Sm`yY)LmX<0C(>@Lu%(e!NNmTtWTVqdJ5!AT&d zj%2!J=4DyemS-FsFV;$@J_j4&X_kAs;Z=2&CPwjA%rp~I6#j7gP6zH;KxBWbad!Fb zx~TBuwekSo7@93CV;p=Kbz|qSG%}2P{wF$Is}xe1QD)aGX8b5*VLcx?t0qTg@JvFk z5=9D@MxEA62W`~{EdcY_N90ws(F+x5QR4-gl2lRH8yRc&;5uQH?x-af0t6@ zfveW{z+%w(RP8j&;L66p+tzcsjw9gPfFFZnQd!F0N`17nN)fTwU7V|eyuqI1VySMr zLsjCcmyOef<453oT}psHI#i%t(*qg*7?$$6zEGO6+3hgAYc-wcIo%u-6Rqyp zU54yzao)0k>{LvMt90$MFy6)3V?Ys^>VL`}MjBNp_>PAxta1Sa`;f=Had~%V2LleE}N}JoU4o+=oD zc5KM_sz#qPG!p!>TK!|*164?bO$usuT%R*_;jzYey{Tvz25FdNbd*BA>rl*z`cI~w zbm63E!W}U4j>%tcFF`lDjc2~nEVk2`Olohm4#YMq2(5WJ6FhOritNRkuhZu?5ORhI zs)GhUlgF56f}7h7$6oTn(cbkoba74Xn!dfgHzYB;9m_HpC&W6fbh;>h?jGF>N0rQ+ zPt(P(m?{_;rOj7dsy@RvRC~Dv-%!ocAy_xVQ?|nj0DK05AeKyJrK;g{ZUY}3RlA=j6 zQ5Z8w&-pxZhwyHnz&!5|${x1t)yHl~f$a()z(|LQC-?DgZTP+s&kGGAT5>FvO#UEKzLmME@tbfzXhUcCss1=UGSAuIBgDCxz-h?x@TM!3OmEh<{Rq_{>Q^`>=GCx z4Xn~V2su$21H-I_8`qg}C5L-G2?d#y;8BLIthAt9wD=Jjyfty38q;$1j08TcL{>54 zA>*t#rKlJ$)e;I$;3xlAmx{@m&7qW;e>$5Zg$um0q=tiOLqBi!2 z%NEZnCfXBl21L5jHti@zoB1u>_;JvIx?%lv-b9ehdMRDYO;D4Lg)&GN7p4K(q#Z?- z{Zb~S`URsl!;l-i`qaF}8u!&BRm7Q(#i)l%h~0SC%`RhP-xPH}iaWj(*i=w4hs4n* zgMUSWw(^0r;ICu5S9$w)D%3E<>na(n?%KckP57aQfIGFMjf4pEl1w&bu`jL-xV&PY-{ z+S<~`c?2z4 zFVtl$9obV-IIm@tvLImgkx${I)0fkNd;ET&kJXTO(W0V4n{&pp#>#uPqv-UoaS=i~@wx zRBhC7Vmi}_+ZkrM$d=Y&Nhx78%@_mmw|-F$LX{deip#5yrK!(|^anjUz4#5x?8wB0 zXqi$x;KB*G)VcE6M&7k~H)Jmyf2NzPNYeTDuV8Or@X^NfR%c1cKf3jJbsZF$)7m$2 z42L!9Hl=QJ#qt`|peiDErLn;P2FagiK~EWVs#Jxxyi=o5-lZSmsmB1Ua9v4B(?)4v zH<+U4u=KKU4$;-RV1$JzZ+V8D)8+SvET$`G_$8%yPv3J~ELEhbEpA~o z8FNSi0DZE;J9wFS;KJAoHXge8Az>>BGPw;nrZqNgAF>0Qk~M zm+%F7xQvRtqUS}Fd-~1-E3I*HImUu}!CGlbI>CpwzVk#xX7G@GvRT_8U(#N9*b@PC zlwj6!W-a#{XWKC&92Q13@G|?kGxfBv&RzL4f&I2Z*XZ=8wSVQvSbd&6OIzi2xBaP~ z(cRAL;2>x9eQ<%fO;IA$fKz?eZJYsP!=u>FC_YhL1L76_Rz&N|FK|pc*rWn~$%~IN zjhQt@CL>HK0Zj7ld?r;dsu-I~gHcbb^Ub9ffJ3%Y0ZXn!S+Yvrf<~hwOm|X;*rxS#q69nh8KRZR{6y#_efomoD7Egu3 zx$Ul$M6<4XaI?cuNpq$?&#R;!TP8eFs>zs^@8m;=E(Mt$i|IQ(G&N zcd&edRG3X-KE4A`neUCUadU0-mE`cdFS8H@hAZTa(S~`0Z@7gYC zt7cgX@xCUULjoUtTg=Q8MhYmW+y=XjPEoOU`cNaZ(h1(^lgznCBusT|lC;Jx<}9a1KD%W`*tj>aO- zK#39ef@VLjX|rU^!|tLjY6xm#5CiDD74(>o8~lbStM118quNgm{P3`?``oT&JXOD2 z%f}}l<<5i9CBEA}JlycGbXWxS)TMuicH(ehrL5w;ArKv)}j~9pl!kQ~UEdguMt?B1E zBZ$~mPZ)KpF`5D3Azd`8eqENOsMFXCVTwhz{c_%U12)uCMZRmH%QV9tKC|36{_kIA z%2%te+Gc$?zdcx)%Xa)-+8>%n-~I@0sF#Zar+BlnPB5V317eUZpqkxmbUR@4E=QRL zvWF)JF-rv=Ik=e>Mo*ZG1Ir2({&Q{Y?my#Wq%*yFJ9opFom%lWkSV^4z@7yhcBj_} z(w6Wp%Z5b*p<2s%<4?|hx3Ebb(I`w*81FQPjt6F2ST#fg{-?IJQj4dtJeSSRVw}jZ z>_KfN7t$!Z%rmDoZoX=Rg_49FMg9#?qbhGZ*+s0G|cl)VDOA#e=+@P|)ZvYGVN4 z57;S>VoWzQUpgE}!`5C#naJK{r-eo7Vgi5p?{1zS3y6m%NietF^{$^j4;o?C5L0LZ zlC-2AWYflAssGU)?eX#tnWy@ zi-z5Y{@oHKIn#uB6Io%CWWL(dF-diRo;AN+=FgQ3Q|^5zcxha!W4;v9&fFuJ9B)U- z;@6~>toXq@?2BQnL5m!1x6`Ol&$Lq|?)C17d;lY=q)Mo&klwTa9L?uLdeC!FT%`HB zEvzFu?soKADNEh%0=mmlf(rpq60222qP!d4p+B4wQ`lRWr%U^&jR44DZ)fN5hc#EZ zd2rOo3Fj8OUTdQsxWIS@j_f--UFm1lmxRHlw#XwK!f+NOWj_2YSZbGAl zYMCV9jTb+jxujhub{LaMk7@2SspGrNUC&;A%jI=lmn3jmm195fPNq-{L#urVDi;~* zIvLEk=$Qc|v-!f?_fw!bopPe`{5f_#{j-U=KM=^9e$p@b#M$=(sg`8JrP3rbDqDo0*TX87=c;a>ph{qJvCJt@Y1w9mU z*NtwDB5CDIeQ0TD#<>t&8nn+In{NI#KuoeRk+Uda9&uT6Iw;u!T1s#o91II$mdRd$ z_k4qXsmsYZaND{&tDXB_?h=#4j}Gva3%|gd1CUyOZ`a-Mgtlbw15!H1n+a}Z^8350 zO31G-ILY+o>_Wn`tF~Rj6gW)}!0>Dj=w{M@$$MY{y#u z3SO`@XRV6OFhgK1755YeQb;t0>-UMVW>&^r=CIl<`1qP|p+U088g)GyrNI@edA*iV zcwn3_1O*Y76K*b;AMzD0hXgWvk)IaF(WH^CZ%sdCSp-BvrrF&(A9X0-=A-TWB2J1{ zYHXaQAz8dW^C4krvp@W;|HGtlBI)XWLGn51%F>6T9l|%5u%>*k(H4)%h~A z-2MB)nNqXRPj+i0oB?_>3?(wz2Ph21?6RfPtgudKyUa(rGC6+4b$whuwHfQ#a@FZrlb>2q?K<$^|xFoe@?`6SHNHt}kE8%u?ek#^40R)@0c0 zEH`Se+SXX7)`(0oc9MciP^qC8wTWojrINxk?2>7jV zyYm~+8Xc28hnagphZ%xr=enGI#I1^Q4wBi4WbNQ@_GsCB6KFN~e@)a9>lR!U#;m3r zC(d*1uE|lk945+m-*_zQX)3G8)}0D5^A5axAIqgeV-eYMFP(rwjB|e~!6Ca|F`}dD zhFj^#k8If1@*}6XEse23xTeC}@VOnV`Ao5g)oeDWaartfw+G4Q!~!>v8CBujhE6;P zlEEa)G?C=)TAIjU8Vs$?Ri2LE^>$cgRj$5qbNjGxY)Ac12XcHvtS3m@AekTPn`3+< zNY6avl;2%_6-F9fdm&ijc^g+=v6W$?ymE}~7H#9ZSHUp~0{^E{dL4}kDK9#i_gLL7 z4vS{M0RqS9xEO&1@|aw%0C#^In}?!#l6JyS?_%=N0ZW>FA4# zQ=aKIY3;Z=w#K>)c%LtgoPXlwag{`^JE1U@l7uS}6_yUI&p-yAba-!Av|m3gOnAwN zYQQBd2uc9m4I)MS?HM@LYFPhW;OwNoyXh_NLeWonq}J4pW`hG!)Ak^-gS8KHjmwG9c(gR6;|Lh`pI-Wo%Lq`>tI_UPU{q zROs_I?XJtfDx8TAVrjL4kfDw(?ppb0`>IK3z{Z@1tui4Ce74Nd(9iN9Qnmip+lPSx z@ZEn>JAe;F#v8j6rcTFK8*Va*2gI*rM!sOwptGf+G%LpBG3p>|xnW%PRD@L&SmM=K zq?@@kU@GM$OaVEHRM_`@gAqsM;W(~*Pb|e%5OhHqt1_vN&{N9h1x=ae_8bN5B!6xu z*=$uFHf32&3*8D3d5>PpO#U6?Bw%j-kj!Zp;1jHB+#ui&vop|$o?#UDB#-vv{V4Q?+iNlBMb8M1Ac6G}!wM8(%LD|#Hx0YE# zK_6+t4&EseNMmq#9vsWgQBSL@MS=q6uVU&i)-)8Za>IG>n_KI0!aq9!*<2cnyliiRgq5IPH4yVp7^=)?z2xW@cuF1Qr_(qJP*Pg^BNIKK3 zT0f@Fu8~5F<<#{$6u)pE`Q{Ppy4^NLd)SzYdnAqp`S3eVttoSpBg0@~+8-+lKeao5 zKb4?!G-!e4O=c=jO#I+&WI_Wx4=$89rbLZj2qO-WP+LnZ4!-?D)L7`HMz?{p!=tcD_PrLo+WMpLpaOQsQh%r==@EB=N45eHO-#JbmjmvB5QuuMaEUJKbs zFrL$2Ipw?Bn39x1kb|1C0fxoZ+9>Etg>T@F==ov}To5UcAzYs=+ra!DjR@@7CPqU- zU$;9k{Q3b`24Sc1G!TV`!d*Gqu1Kk|A;!SU2q=|W@2Zp%BMmrFXzwWg72+-lH&?S% zjdP57CB}Mufyi(~JynOLCATR*3KrH?RGZ9`jI^uW&@h0zEBjqOwQf{yU=Qb?2d8Sn z#oX6CUUXGf^f9D*LFLc@;3Q>jY0+j}rqGU^aN#&%5w#Y;e9p1ZU}53x@Z;Qj2QT@5 z<=#YcvsGT@3wqMx>fL9~rn~@uQpYb0iwP_Y?sBkdXE1@5w#Kfe#WP6urT%a7=3wHI$uKW@=ySpV)* z7Ws+l8XP`y3_(@W&s}IFbOws9L;jRXcva3R>d*#i46xItR({Hxonl$D+7K0ci4c=i zdjo;>I~jbW zz(79eIUfrNV|}=-o}=foJMQY^&$Eu%x-0`0Z7b~@z)jja)8D~x8a)~rOOPmmL54jO zv+b&&D^WAm1uRwU0x`x#lrL}mKC*dsZN*2Y!>%jTv8aVD>wQ%GkY!3weB5(Ql1w(l z5n3|BoNQk`N8P1Ax?zq`+BS)(*AhhxM@%s{_%VE@e{Ln#? zr`E5|;79;?;hP%dBg~17UiynwurbJhumMNU&6h2k21R%vO#5dU>-+q&^-f)f(1Ql6 z#iykr4tIWc(I`mMtP_COEj*8ZK9^eaKP}J6a0q>usaD0@Gi!(jCi0Psul1ITj3j)j z66zfM?LmTmTo8ZiAba`*jqKZJ8ccKhYa*0^hIwLjZfA@E1`cKZN@;&o?!BGwodtFb zVjt3=+cbOTHtf+N;7kIVgh&6GeoOly%5Y>+>48w( zpxb_8gzAQSs!apNCS)w$3t_CM%2o?Ifmm1phtq|AirvXE9`P*avzn6f%DjyFcbH!cT*48x*A$i zS~~&XRCzH`TDwSsL(=*^$;+10cAYiH$yrLX8c$}VJI<31lC38P7y~S|O3SMM%tf4U z_ignWkcy`ECL|GEH+El_#^u?dPQrhK;e_ zDjXU;a#B-urTF~54PynU`=4i217E5*tfExQEtkzLX|VzMeY!n;e{?fQ1JE02b8Z zY>i1i*-sToOsqV<{MytZA5+hLX9-|~8&(&*&t=TALgr?UT<~Qu<&d*B{A8h@7#TR( z5Y8xziF6!0rkZrbp7>F4q0FtyK~I_;g0 z_q+QE|H|MKfyGO^;5o2JLSxy83mhRi(r#l7RoHBggkSNcz(b$AoHmS=W+;;88Iv|a z68q(P^S=`*ZSA4&Q^*p>y1fp3ey;R^9;|;PUSe~B!B1UoOlb%##56oq=kr}fYV13B z>h1O<;!}bY&zY5dJ)z()uM>S^+D?(N{hd$HUx-IcO<`d7wsAjqUO+L6SA9>_My0;` zhh>wdB)9?_&n)Qx1n6Y)MJiXO7et(51S?!_G%St@d@De7@x&{z#SzC;gd~iP>~YV- z94nh5i5OcLpXgGq-j=6#%gGGLK$VQVdrQ)5R~Q}ZM~UWuUnS635g=M62>iTz!PrR? zDDg6dS7A|>19;)I1P?n2zj>Z(j>^pvi(J^ zyM;cEVBu@DAc3X5dQBs#aA*8RvdK`#h8ua|bLzk_(dz}(bx%?tqNr%!{WiShp#1BU z^kdKKo%NrmLea3E%i!FjHn`{eeXQVD^{a=FTY^6w^5St}VUly(A@_f&244gB;vNgt z198M}U$D+T@BUx7U928&HgA75@;4$Am`pVsD_F!iRVqi#HJB^@Z69`XA??&4%f5(O zkGn*U>du)j=#4t(aI+4*0RPZ#X7HHihOSJw2VSqLieY1#A4nq|82}>2fy|d$TDZnp zKd#qgx9WXs72z%G`A)Ba>IjJWN!>N)ZOXH!GTA$SWCop6f5LC~;10@DeZ=Nl)JZ|l z>%o7(o?*MA334Nj0h59 zL;wW+7&4o_?^V^>c;AsMM0{5IajZmP@wOpwf&9%oG+xW#Byv$Y9m~Ot&DADpDf4 z9Rw{}UXz*yp8D#CE>U&uqokdHeQnmK09I<*Y%uAPC^TCt*592Li1fO7RkG9~Pi-DC z^Fpn3B5JdkzaUC}9P5^ zx+vcE@+PifAsQfn?c4%`*{J%n3IU4kvJ#pF{!H4K$?fhrI z+LOWUAZ-b*>ivlZ=lo7=`WQ%_UxZN$?BEaB(TGB|U6+2sp*|npv%QsL#L-gW{8L2~ z+L8k=r~=>HZPdudurYDnXl(D_q3g~!d+0GEaHrcq#(ne*H|9S^{RJjY6+m0V?*1y~ z%}TEh-RYe^;eu-cmB}J%w1Bn8f@P8ys&n?U-j=Si#P~pi6;I@P0*q|#%oc?@`dK6? zIT#_lg&<-`jG$TSYx?G6Hznl)c7oYR;QS(Z^gHY*7NzCs-+lRx!$-n9eWPB=<~h*v3%9E z{hLQ1(PZ)Y;xEod(8Kz5vgwoTpNiK%<{LprMsC}E;(>KBXa9{%K6a`Jh<@3h_S@R3 z9ry}Rg5W3azl>cB&ff3y9lmL$8RYh$esg+88El91>S!zGMf&>p{l%EGgXV(=Ux0~2 zt~qGnX-rcik%_nN^4E&Cd9VAB-?ZDbO-hw6iVlXts4n@+7$GP~5N;ojd^R3QL^nG{ z=6tkLcwb{VESnxWB!*#PR~G?JsZx!ElyvuO3HULGK6{5kMBH>nfi^!G;WJHm-;wup zY;|taIg4cwd~hx5X7f}U0X1RR*kOlGnZldw^mDoDxqPXrFEqsSGzQRdLWiXfD-%f@ z7>pR@Kj1~7aEYh=TVM7veXlhifh6Dx_2zczK+Tiau!{}KSg znBR4Q!Kt~?0DeFQ(m-r#y z$wILifK_uRGCO+HwdqW_oPCyR8Gx_a9xazjAPB5AEmsaDIQhhb>>K=7q*7=1jQlEL zK6lZvXQ*2W2gNH`^<9p&uR(io#vYxix%YI#yU$=!tJO()OJ-+>{=Hdbw3w9#k0UGR zQix-9e4g)^8^TFx7?x<>#z)YKUEouplzN88sXmqF<~`h0lW1qVkeCr>IM zG_61%hn{O-wS2tb2;x6~z*T!7cQB)$Gq=g!o7Oj5b_cgbW3vAc%?yM{FH1Pa5G0e^ z;~M3{o>Mpjic;iGy$6qz7 zU`(nK#9cfUMpqaF+oEAauG1OC9=>vIU1uOBCh)o01O|-4v`pc%_|3ANeejTt3Y zdLvr%RnczS^f3eb5!toGC>PC%5!LdsEIegoo22IV!6uudo6b7)Hqu*|tEJI<3?#{A zq)W*Y7mkW?q0X-_Z1!`@sbH@3>77@RzXR8kHMa8~7#|njy};1Y^230JcR7N0E-XE6BuqR_%P+4ylM!&NtH&* zAS$g59DS7fOj>8>ZsWhol{kPdhIU%j>2(>p7Rffg-=Ol@r>{@|hQ3Lx&dTd~VII&v zf~AJ0F5fs254gm11)?{s3<)^M)&bd$)W^Yd*q` zXvE@vJZVpf+r;dl(A|s%Xx6o9f}YlV?Ch)dYUgOSaF64cZ?21|GF>lG5NyA+AAJH` zoFN*o&A-!WxtOt8%55Dsbu7~f(43HNFBt@Sc*}RbzYch&**v`S5J7Z%=iFcnIG`V_ z`@)BXf**kSG2M!6YGq&QXj3;=Q$|s>=R2g|v>mDK=YBMiMw-@m+REE%$JI~CcE>VX3?fWM1aVKP z;H>5^HZ9of873p+a(+WR5yEyjr=Eo0=9vIOjOrpI*BH2UPicI*CUd;E9Mj%hHj{mMXgH$?El;%@UY! zo*UEwvS^Dfp5{JADvsZ;W46bI*C&R8mzak2*Uek$%jVaMG5^OEbXGFm4z_o~Mfzo* zzLR*Qmsdf4b6u#}4A8TFH<-e1}wB8&gyo5^GF0M~vl{ zKt-?eEwJ#fy9ZA)eSL?9NB>=*I8kZv(<3Kg^1EFqfjTIx9s+BMFBVv*G}}HZ|0KRx zz8)rNr%omae{mjRxb(rzsSd;PpQ9(*lUOXbRoOsc#Hc`)Mn3&$gsL1zfEftVXY!qU zupw#5$95x%%h4cB5p+R&Gvt8^7D7(X+Hzj%**d=WB`|P z6Sd3Bz)t%yY)Q#r{`$bESEUNJ`F6fs6Agp@;NX3D(DapI)_8}rV|sUkfHKoo@K+~f z+^V(Zz^yN#>@i?Vb8MJ-IiuIJ#F$p0P2Z#EKUA`*vO9In<4t490E3Ci=3_|kF74y% z%Z&#JBnc_jtMMzKRm6>ifItvb*y?npscl(g9GEnBWJGD~(dt`%11Uy)#4;Dks-FLM zj1ofATWoPMzQswB6R%`J@K5o9Htt3S_=be>Gw`THVRS)j;^Oe{Wj$G_uMYpMzVim+ zg~wZjt9q&rJA+~v&(A!8S7Qf>21)1GC?p){83)T%P!4R4d7hC?C$#NvjyQCSC;-lv zA+O9?YS+qla_mto`{%{*%q@GZT(Rq-yceQ!#YqOR61KsB>!u=44$vuRMn=4vmME2r z`t39fh;_0b(0?0yr7x0nIK9a3(-10{L2PBwZZTBUWcRt6e=pWsY?l1%ohRhQ|5zr0U9 z+3T;l?cso}2lnTI)VUyvP^!~iO9yOgs6KI}i0 z7u+bueCC{|G)B$L{Gj@6vYnD29u-)ww*B{G#wM)&VsvYla6aS9@ zgPCphM%F3-C`4vsa=^rwFm$dv?hRGhH2t5mx2}!qWKv}$%}p^tk2d$Vb#1!cGK11^LSJy`sa3m z^2N^%>$SHvCglCvi1^#n-NMv+MkRA{Qs&|c{+Ll-6rpn|zN4T-RE*6{oFCmO$LEIs zg64dgh@dnp6mbE4DQ2~Kj)n0S(|af{o`TMzwsG5RvTohhUPEck}6W=8oX_z5saOSD(Je!%V|gw=#1*B~lJ^#fy!M z*N6y5T=heh<@p>*8ZHUU$eqa~C7X ztY1T3h!ab3iY9m8d>+w43Zpp1^TM(}wo)VNy9%v?v;GejM9hnKSADS@&0Va>4b-V= z*ZCft&;GdYC4JfxGiTAfjSQ;y3h;E{{V1EPFnKiO`C6c{QJ_eDLSslM8nXgDeq@AD z@iqD*hpcWf@mdWHt{!&6!61Tl>7MLoOCjXKXlh`~7na{S@28p?vYMJHr`N;8J5cC9 zWd3K}=P$Bz-vMS`(1EpjEfPrN<%cOSz5LhQ9@%!_VK>D<5*d~v7#sY%oJ@U`dFbR8 zW(>A@;-yTa6v+PsPI_9YYzLyl^Ry6vQ{b_e4gZf zM<@smve5e4=mS1ZgdP|g3yCvV6+Jn9#zDX-RCPVR)Pjj@xAG9+9HYVG7eUZj#ycP# ziog=SJv04nhXX_j9`7B7Fy6O$A>&xee{t6=M@DLNLL28tMJ2!lZqp`3=aEi`MFKER zfPbcb9rbsQS02e_pjbMhq=4BcZC?|{!D5O2Tjl_u?K>Vl;HO_h@7V%+QbdF*D}mIh z2e8U^{oxn!V3)(QSlxUsX{Q7l4#^M6wl9f>EwBtYcI;D8A2GWQ{(4aq1ltVFW|^#Q z=`%!vR_U~tmEeO&Fyy0i_+s_b1wQXP{wc>NK3;UQiyk?4eFjGWQmV+aJLq-arDRQ1Zrv5zUuTEtWZc{KZ8)~1?Sv{#Y zf%!{6OiD1Yhihy2rMr}pAps$8{^3tx^oIc@x%JqU{D9%G%c~u1i!yoh$tH`$YO)VT z)UfZdWzr7t)Dh=GPJvA#(`WdYQVS0@%oDx;rzm(D$X?H$CBa{5fXm)a<|?J?6eX?n(hITecbnBcc>x!qM_V4jN3YNO4$~a`1MP`YMd&tS zV^Y*H%oSM}l~Z0%ho6Q9UWl0TygP+(={xOVzldj!)LS>&F}$n_3`K3?$b_SPI`Y_9 zAS(`$kxbcHc|qv^V_|LXNz>T)=ki(2s#6Hl1I>U((Uzvsd%kpB==OFurPl(%YICsu zWSm$2finpRNEmv2-&_?wz54P?9Q+u1Bv3-x}X0sLTM*jW000!`Eht7KoTy)~2@xcJLAbEfxop2RQ;5i=UH(LwJcwSZDA=>2T8wEo7Y1T*r9lsz>DQav-6$UK6y4D$4 zJOnp)CNPkLLa)i^8Fq^;2s)j+6FhT0#i8)9Yw;u`m&NP0RXaqMBgpARERShcqXrE% zeop?&kOEHy>@MjT;}Ls8AZn>8298Xs&t~R9;aj^_-gBVmqtBiF`h#&%jmg+SWQnL> z|D!6B51TB02A;JZw^)g*pT2pZjZ2`o@$s_n-rqJd@lJ}ilPRx}AA6s=>Cwhd!!&gE z=KDpEdg2f6brP?%0>aP5-{#L3}qG`(63KE)8%{cacs-BGKuvVlqw`gy5 z9Kl2Fpy2e~Ly`_Wu|CS__2rhdGw5xg_g|8D4;cMx);c59Ci}bU47B^rMh~M09Lm2p z?(`=(djwC$?UohU3?31sP_ecO4$d{5R-fpT(>~}oH(Z$DJ{(HpIuWqC&gD&CXTI)i z=#aE4gWHyJ+I&n4Tuj~Ek77j%e}90~w|jxXnXG-6g4z3l19~^ALS$*n`Yn1;9yQxq zMGQ3S9-Qu z92-0iZs-kjjC|)TFGrkxu7b9ogL}6S>y7*22hrY&jH$moralJNd3t)@3{i#TdAtqu z>yafyhKCK4pvJD1THakN9sb*KnDr}@%9TzV_d+UBAyf0_s|Y6x_dq4bMJ7txlWPKf ztz^uYomQ)}<2wQIPi{XUvu%n|Xf9QGg1UVNv%7zVmdo*nHM4D8o)#Z-7?P(lsZ{8{ z;X21iMg)|-q}auF$nmga)l7XAjMI!glw+Y%F6+g)qiZmFqDds5_d8D9xPk8ZTx#3 zkj@=ZnQg|Mu1%G9f78WLSv1a27%Zfcx-6ru`tqB9M8w_3VRB|LOQ{%fdnNl!OLS2n z#i;=sI{C|!j5Ts8g%R62SsIIzlz=$=bDXK;OUU$H}{t`pgZ(Fhw&sw zwlXwqEhm%Yh-82*X!YH1I-p`kw-} z_o)|p`ELh$Utm*Uzjn%4e*OC#d#S!4UY^04#;%XG9mG7wKkJYulvYyq)tGcIsHbkl`_f3UK1azNA# zry{qe!3iPHE-!FYFWDg@E02uouS*Td%XMToiyo%seU?-qH}WBvgP8+2vIXJ~8{ToO z*#A9lj3aG!QQyYgC(I(*cEHVKmOe8-S=kCt<$pGlutMlrbHka} z@ZRUY4>yob1&DUDPh6eH96^B{`eb z%KEduRaVyp3-x}-_wr;jy3|OkNhKfgd%t|R&=gazTf24az;vi7!-Mk@)y1qS-3bir zko=dlrLH0@inc3#T(P$TEIb{?w+~JF5zKfVj{M*!!M6< z8Dz2M(>FOma}$&uxy)0;iWBh8aNavF6cg{${Z1Ebf!pRL`XjORKKtPRsmWA1DLLq!>n@4GSaF2s8c)SL(sOC)n@`^;Wzfsh2qhVV=Q^qb8u zcpk_2mrxT%OZ!^oG@`HC7g0*77xRol7lH{~q8cP7;rr>H@U`uI_hrs>LIf#o%@I>{ z<66vk&#}C0B!b`nnV3&hbWw?LW0s9-UA@Mc+SsHU3{BPV+{&wPB4|L_gFk|6(awP# zBo%vW#b?j>vp2(UU`?MtVi~EAx>{eGin~mFP%%i*>6)8>KFKqb$@aDZbk@ zA3J&I0%hDvBt=Y!m`!#6Oh;6q`-5ny_&AR>U_P)M6U*a8GkerfGF4>x(jkXMt+vQO zMG2}Y*)Lly@s(|_D9M>ys6hz9HWNDSL+PHi;cSu=$?H=jRdBB;^=I`2j4bHxUOJ(B z_3d6}u+Jh`D%+yZ^?T}a2tTO>j$4sZf-7&i)PShiI+NW+##Q*5d-A1&e!FFh0@;Zp zQSz4bA(!^?!eP--m8z7{i=nHZR5)5qTRDige$-qs+u8?4iD8_~O-j%F>)9$VGQL+U zDFQbfvu?-^&hBJpQ*_F@Yk$4n9J|;%S9(zm?yvzKpSjqA!n;{5ut?@6Se~6quH^E6 zM@=r6#&Lq>AJwK;l@KvrjeB0CthIRQu{Rjh{3a6JW3$FHb8$CQpX%yT`vMWvEOfcv zygVU$yHedv_rF~|9&Z+fv0F>kX?v?dLCH#G{Sz9B(*U+r6)W&l5zc7QS5>ER;E7xw zis(-IMIU9$nvmS4eQWtd=-3`?)T*POj*VCtQG01)0wOOe$^pCT;Qno>{D#%ZX_-`E*3`5o{f36 z){7UYALTOdUQ)g6RcO|J7hL#<@e%$bZwB|X^BRtvoR6DZ2)=-|Z2k?0j_$u`1uYXk1*_~Dmh`lx=bSBanK!I`!+L|Wimudk zu4rZu`N+$3qFh#b&3Y0=Clc=)(LeQ3u2|-0#Q?|N;yL^0iA-x|LAJ+&o;Wwx;mjb6 z+_TZ=+|G28t|*c?|NOMYQ8g?*aVTmG5x1GG)!S>#ZT-1ZNVzHWt0J>)3nM3%7v>0G zUvws-Wm(5K=)F$aA}2CShMtJB_Ol1xx`%dhiD#$CyO+!I9R^kk3k=LFPdg=h(j=1_ z1SnYqscf%wg7Q=|mtQ?8A*$pmnHwt<&A#US)h8way$JU!Bt0M!9<-BAt5D$=6~w2g zjS!*iYt>8DvAQOyzh{d{#9sc0kdqKEKSEDe?#;{I%y=|dZp)^nQEUkmth1z}9yBi; zG3v*y4BYdvM!3(BWz8_W-pKQx7T~_fno>t&cnbP{nQXmd!wi!jtC&&hyqBVE&4~fg z;jd-8=$?-l+E*fBPUSWUIag4e88}ta$oXhC^*#iueW`r=eZOTlg$CrXP;Hoy92nKj zT#V>9Vf0T81Zi|x&Fy0;cXEvxJEssOlGt9&e}tx9M@F?2WDj0tqEy{d8EeR;_t^%x zc_y(PNuOES%j+3|8@B4A@@{NhJ~|jHeSH0ITa~W8OpyO$$`St~0+SXVX=3`-*porR z*82ma+;y%2<6D+@IYUDEJ1(#ygGrDJ22X%i!}tBg%~#C_kd+vZP_n4zb7r{=^gy#O z80qnlFTW;n*^-P_*eAhtu$8_)CWDSllr{zu3;jzxP4-Y@n^{Jmg}wVxu_F3B;a$g4 zf|h}a&hD;b<>uJ+-#FA5buG9mN{7JAML~(vo72vnM1n`l0}Bp_iRNa1@|$$>1@#g) z{Qo71-DX>41r$+Hr3{SCgc$t$M<8~uNA5a;6y3-KKAe>(GA5$Td4KXZH*dW-(NfrC4GOwTGE(JA->mN&xREOJqqtm z=B?z}?^!QQR{!!@f-e8}q>jpiD_);WCD%#tV}^xeF=NJ>2nmv%erCQ1pCyp2;EY&p zFH0tRkCLN-T27Ugr%2lq!+`uY88MzSjx)qlt=d z%T5Yk7|W#*go!t>{9xs7vXL%}mhyIeD{A21-&R=lRmVmtJJ&Xwbk31Jm|At)J+~}5 zSt)fT)twh`je*g}4d(1|cp+U!b{k!hkcM72q$D8+U_!ySCk1$FuR?<`MWTqH=ZzyZ zLIYh#t7L6(XbfN28jn3)r}01$>9dP9MHpX(?TrOP_=>MbsN-Cmp^j9+lv^k+<>S94 z&(lX=W9o~MX76~^J?=$INw7O(!`6FHL!Zwx5hRZ<2Te2XJ9;f`<+c& zPm_L}*Y^h!fe}^U3U3CEe?{~eoeg{5k~ANxlP~#}xcdT?*kcv(&HdCmfdBA^`+XA01O9J^aKX zIjO-2rjTUdp=7|57Q>SLLAU7!=H60*RX)fI;rOsqnh>9Z%%%u65l+u*$;uqj;Z(WN zOz2UEqK6%?#`?y8R?w1By!U%1v9mdv%Y}k*aJ0cz>klkfm1X4vg{Vq!r$!X`UU6Mx~m3lpr+PK=SJKh33iUeUdssJdTr)rG204uSM1io(1W<* zWdV&)X%5v8iI9r|a#^X~e5aXJph)*a@5EV!+F9P#B|AjPUK>5~?}H3%&{YrF<~cmZ zZluLj3l=Xz;;GI6c3qK_eMT~o+=eg96`REvNMrDdf7IIbWF4m3~+W(aXmcT#VkBjanG5|+WUTY0ai{CNGaZ4a$1Hm*cvo=`X)a4L+AubG+f#Ggj zI+jwq)K-odPZ8y6beQH+gq%- zk^vWa7f(XRt1B){;>NL{yqu!rUZ46~#pKr!gb%R^t%d-&sk2M9jUjz{YtZq7YFW9BrGl zC@ZwNNGKG)Y&*a=Dz)J@4`*z?6<<5J{m7D#!#Y~X$+sMfrta%enVnml0;`ohx7G3bO7pdNCAlTVyUGCQPp-JhZM*lYeP;9}jjBSr zzk!we_AG6+O14q_U2kru%Wr#-Wrd*JVRRd47?2;c?8a4~U{ja4d26whY` z+mH7luW^U{04QEg;!~%X@SiE-`*rt81yfRSyyZNd?+-#5wx0|Uq34pSB^CW? zR}i6${A_aa((b};m5{-6GeoN3$YHZ#FaKDe`el>}I4EGtlxzP<;q^lb--p}0p4Vwq zS8XL@f*F&WoM%zDFBj&nw5ZB_LV9$SG)iB{ierW5v2$(sWN?ih?Z#<40HL9x=lJHE zKi8PED@jLjwqWh-(@%yCGTy#>Xz=bk%;F^TTT&w}d>joAu8QvJ8_?yDHqybhRLsg! zFke~}8t}+$AL>0tUHKt_b8&cqKR0~!&-yUZFtiE}&iPonJF0l!>xY!w(GL_9Hs1Uq zfVz<2SyH<$mv|AX8uT^>ttJcwV$ zbeE>h;-n}uD>uL6dRd(z$b3{Hl;ggi5lYCcBnabWSg2IB*syX;Z9dcP51NYAA1*l< zzZP#gQ9HLidx%ja-C@H+mmV&OATjb zG0iF5u2#;%?}aJ(pRZIky96u1OFxhA)Zfm`(BOOgTI<-?ek=4-=p?LZMW2wC;)S2r zr!|IVPwNDwIAeQf%qW7#->TvzqT2LJ&Y-;W3pdZwj0`V6tAUg3LxVT9)DZ_SP8dj@ zP`~ga92-{OU+$IQQSMjf*5YZg<9JL_tnw0-Y&!F(HwKwmbqYIf{MJ2yN?e*9?LeNA z=4`gav{i0O%Y@!kq~(x3V-g6(N+Eticc~Gbxi__k2n;%PY;+iO`&oabZrw<@AtFp! zYB$G#=}oMyzrfXJq`z8(SkYHDZ7%R+a1_Yij$3ihckajRe0xN3!*D-Y8Yir|-dIt6 za{Bl=)$^)>rrizNca^oP38q2|`monsNogbn`MpygZ0Y&;7Elo5MVbLC>qbk_mxa|u zFK87oPfvf&kS6oH2JAr!>F?L3x(f?TY(Q*ySgiNeDzoO8ZY=mL^!gCWRUGK(6SNh; z!8Z}@6U+7Zq;y0LUSIY>E884cJ$BJ-YHUorQvjQ0+mUUoxlU*tlc3nSv8nw1grHdL z=jWj%w>JfwtDTZLG_R)jT$%wU#az#Qj@lB%vGCv|Ptw(%Twg^}H4yPELL_HLGGF$Q zzEsh$-Nl%D;669f_xo_vQZTKA+EEm-8`F0}Y&O>z)6D$fVKB{{UVF2^?bMv^YEk#O z!y_-^Z%z^-a-7u;8q&N>nOzax0fEqOI&ZpG3;%R3avCS@8N@hrJtl6J^E^ja%Kddg z#t_jj#!V_Y7<@R&lWCn0YZMho?On9+W1Z{pNcieU2EGDQl?|FFSr!fy&4iScW(0f#9R4Zz`U-PSu2Z?HwO3^%vz zlqga)gm~>Z$Ox&slfFMy!V6NPyb&2K1kz}IY)VQ@rPfV2(#u^DRRg8lw@n8EYKsBou`yedK?;-x1N;-m=Y9ES=r5UYZI>hug+!Gu&DvD#}X~OXvd7 zeu3irpM$Ztrzz)&H>E3aZWz9Cc;Ae8qDWpLSecrpn~3p90^S`RbX9jF>iAc>%d(Nb zmFcxN9lF)A3*H#hlUjaSMil8~=}O8jB?iV8iR2Z%VCWV_Q+#34GxD*@eybVudWkDv zf?K_IZXu6u?xuh%u035%#;0TqEWcnEsG|{&%fQ8>j5+G6mG6F1J>*fqBSW9OI<)3z zIvN{0@!ehUO7ir#8}Puy;-_$dCuVmeFAj()ci*=+14%6oYaz+JxlF9AHyr*E!(6#2IvG@SUjf>IHX= zQY)n>neR3iklwZIMEiBh!IYY0_*WU z5S%RmZZ(0$;9{-&)=@(~y(ez%ptQR9E60X16xv0gT0u`TS;Oi%JOi`R{h8Rs5qI#; z<5-q(pWBofG7CV#d(o``n0&Vtdh(*gipcvWX7ceTveB@%t({Qy{s$AN~AYl1oD} zx9g9MAHOArGsCWxA3XB=#piNsO4C30V|Yoc(6RTYRlus?Gq-}(TqfOH&26bh!HNY3 zAhZx9X|PC?sVFdn9o?L0Hy~4lTrx8Lr2iOY@o#S8baC7}N8fS1QgZ3HW8F`g;JAE& z8J~`PS(7Z#^^jb!kHOOck>%#fqE>!Zm&@FTvR5xOhgh;4YhaaX8Wlg{K6_8-5H3Qi zHRn-)$o)2NVE*ND>)3HYhV51<{@M{n4e>&u;j?kUaGK+^YW8pZE7-xPOfLsV9{C9;yQRgb>452$DnFLv;K3bAu#+V9PeO;94Bt!@ z)u4R)vRTekoLzS3{C5tltY5cv9ra`L8!Bd8hH-+gEmqo@h^=RiXt)yN%HMzXgUDCg z^jeH2ax_LK!J^>N55DP`8I*&DI43pALbZ8F93&w9b{*YSiX@FML*KG<#k(zCT`Z1t zMSJz=GGel%|7e?eqokGpmj{iW{PP9{0vm5@HvkN+)45lu|4#RQXDJMlrRV_o_~mK~ z2E-V^`+$QhM&@neH%F6neB0yO&hK03n~lap4qp`VE2D->%VMk$B=E)*XG-fpe0N@| zFIBE_qDu@fvcqTMC=w$OOWIWjBSM-6X#+o-KhGdwLa|Fx+E&(Ufg~46yg}6x0hM{< zhK)g_R?fhuieXjbpQRfrs*F2?$5QlyYrA$bj#H(2D?Yy$^#xvPdi zN}exo>ext3Ef1Qdp%_|!$Kxy}TH;xq&XL9TdqQt$D#6&s;Si+7`h_aJ%&+7b1q9=S zJ!)<3cLf?y0JV;diB0XlC~o9NE}tXHr<5yL8*%%T&CAs2b;>R9%2PGCqBOnga9?6r zUtDk73y5YT*CiB!2 z0Z*f^^*1AdD+fh{ObA}ju?;uqvC*-;_HKqJZR$tcw@$p%28#=IsRb+FBF8*687=Wu3Tw;*a!>q_Utu$=+zy7$RBK zsTcZVQU`TDfEl@4A8vE;ru<}YnJ_R0$9Lw)RrL)Une6OSA|qsC!yFvTXULq-?g8N> zPb_iIDa7w#DF4l%nC1ZDRnMp@MLE(JYmA2Lge2?zz4wfUfy5KiGRuZGUwyjp-r{cI zPFPeU^oW~nxGjvt4dBn88$?5xjSgAk&^VfIQjTq{!=(x|NEG5M9(`P?(>L~JBcjE?29`+zXT?!p7k4>X z??qdoVOZQaJhy#7DmXxNcv+!#*FNCJy>TsUaW4U3AAidx-uT!Jre8oyKU3%8kqPkUtO$G#0kkXUbyNW)z zZ^sV_XcxHjKh&qHD8uxcVVp@1K7^u&iLhYfkEBP+j=f1N8CpJa!4ec|X$+t1rfPO$ zjyGzjYg|03(i)ZqjP${;^q@6{v9Pg<*V~>jbA($Y(x!5GiwSD^&@PcS?P7iRUq&%Y@_$G#8TR7bFpkGaPHgc?lVqXgDv}6GC6L0?g7A> z=4>59N^WeO`Jz+?flJmnlf-G6QNv3#HNGCa&-)@Yq)@ingtluX>GZUL^tR6Ce#aL{ zDJC_=v`;$c+yj_BmTB&JMX@Bh(yzTKB5bejfADSo;tf2Kd#)rBX;C~UWk?Nh>qYfJ z+CZrqW;c3~BLyq#dp>m*^GmnJCi6Mn@+5tjmXz^w{-f9{`l*i33K`Dg0SeFKQ{&<> zV?Bu946%}Ru3BJoj4U&I3Uo)waz$v4gp>aH4TZ9zcN*NJ$+GV)8GmW8m!5e|Dc_>& zzlTkRcis`<2c@+hmmX5&{{r&|7pj_t=&I=H823!lwfuTw2ixvZG)$Y?V&SX=$r#f# z^behkOy#lh79IR1O(@3{tC8TwktXv-s}c8}nr}Z;x@93$_;aK<*0IZ-xOAWx6G-Iy z86v`AM{ucTrj(>N4BWJw5)*rf)g+JsA4pQD=iMJ~;m3yAO5@CsU(Ql@y4v%)@xpy* zm;_vCe;GG#%%_|hz&U^1AbEV>q^T0;)!@pT9In$~ia2ApG49=WJHeZWTnt|Ws&V)K%?J=qqTxodU~i;4HnL>;vlC!uH} ziZGt!TtrLT=CJenm72N|U7-Ur>DNh%2voL(s!(|I;@XL)b8?BGQ1`hZ5Z==m@7Y1rgGp7F#mdrf99-A=zJp(I#`;pS{(~L!Ilsm5@>A+%TQJ=jl zknR78<_P5@j6V04t+(bI6PoR+?9RR)suF6exWf@i6o`}7BAAB!;kjgXT&uH>)}Mq> zR|o>}+tUr4CCkUS!}Pro=`mKcm_-G3;j@4|Rjb_kB)zwK%86yLR#>@SCU-#X>1W&( zpn~JgC!mxi@3S^kp-PFes-M?!#rVX)l&PmYNRYWYS_r_UC?lK2h_ESig!D3z6g6N# z@)YGQ`ZgP%!x)q~fC#rHBtW*Ld{YU(lQfOpsy|HgfO*S6NgwD2R?}7#&K%2tB-NZ5 z@AJ#pI{J$FADcJ3WIM<;)d#BFPyk%T7}4N50aN2~(rcK|sFaS0amE3L99R1foaZQZ zz;8HaVG%REk4J!ht`3#DZq!p2kkAO&%07Q+6h}Ag>{!M%md+VP#Y><%_$s0pft(hQSlEKDU)9KC940Thmkv^{~Q2 z_dZ!-x;iRx9UCXMAnb!4R|G%5m~g34ukRF*l%@KpoutCEW|yoXAqt$MFdc~X)}qAc zJ8YV;Z*xlmbU;sGxOSu$b=ZlGD?*XU4idCSD55>?79nO!J~jH6F}0l8l;U?FvG%G{ zV06e7;`~|d7yknT8xYy4n)+DN^*M)gB|dR2eAON}O4CuUw;kHCTqq%HY>#m?pQ7RcU+ai8Bt4W@Zd71 zg6OtKMof>;qzuC6V)k>_JY)?QN8G@`dO$9N$-+%f>R1@;POtF zF`(k?D-1<=x^nL$tY&iyD^xdRNT@c&OwJGoixLm6K&+ULTAX>m9Gnpxg@QZ zjRX+a{^2aPJYQ1_$`(s|wtQ+!qX6PXhBKxUwc5HmdlSSb9?N|p_6#AFx@7EX_PH)a ze~1}hR+8UM+mEYQNo#~iR>Db1wF20+qBL>iTI8H3-B|u)8?&P<^b4D2kl5^?(XwM$ zO)3syz9a>a22s%}8!u;^FzV(4tU)JI#t>U{c+}r;=#Vm*lMlKRnCK{@ix|2|ulU~c z|HWA5E^S0T`%?aFI8NgwhZ8v&Uwr2#>pB1!#wEOy&1qQ~zX}9+4?I~3_S!M6vB8JD zRH)YRVh}*W2wdjl`%M!sj}n-N0;`sLVW)K#hK*w9GAHcQvISPn4u|B^X4{O6H{yG5 zuU9YN=ixJu;W-fq2qdj#+b8_>{8NIvA_OvNL5m21+y;y|Jn3K$+a36BQc$RBLGNJr z*4Q3f+>jc;|J5%fY+02)GEyvPR?%hDunjC1cK^^`0l-AUCyHc(QJVcJ2vUIU)f7xw zcTVvAy;J;MDvO362fqeIjWEN5&)cXyxRtUZ+|2aT7aQEfc=Vvf9=PaSu|_PW7-g|M zhgoaca7mbt==(3uuVlQiRS|LJ^MIczy`aR0q7URNW^ndVTS^$zAma57 z_-t$4WJs{9YIG;)f@){CtL25XcbgnIq%Rvyz`ky)v`_Kx;Q_fB;9ZG>bX0Px%C4~T zP_PvdhE=3-;@N8ZWbHHoBj#z%T7s&|rI&P87L#g4>IMp3WSN7f>pqU-8c{+WONQP? z%W|@?B^-BRLT@iG+|OzEq1hVev`jT=BaMnAg6>0-QKVSwif#-oGs%`35fz7vl;H6o zuBOGPphMsCMwW!0w`&wqY&@8flDw8lRwhn-_`|!PHiK6U7m2?2Dq1!QRZpuDD=+Qj zC9mafe{=_?GHxUWh&@g+DqOFrmZUX1_6N)X*l#rv6!7v3gdUL2N%i-HNWI-M8#(Xp zk?F`a)Iv14GmN|!TM&~a3lElFyC~*BR{8*vBI~3!hqo@gF>t6Av6B1n8Dg9XNVxvG z(6WiU{dO`p5_Y?&(HE{B2y8c37HwsL!)&OG@3mv){wQJb=*pSvH)*GOm)6hxY%X=M5rRir^C>+dszHG?W^FxJ9yg!Rw9uB)p-Q_$M88PC$YdSM zfj|ssXpIzI_zHPXYo$C6o4L+K5F$PXsCin$NFzTEo4vQAmS{DO!##0z5Bv~#_?73wwCQvBvY^PMzG7{QX5FXl(uxU@;0a-bRjA0@h zHdl@B8`~Z$M|m&p3bxH3;uBjk{zzQbE9b<6lfppv8RU;AgTGWBu`il7cw|uKt`d;l zVl$_!tlU@Ur&-YCkXtVOM)7u8e(H22&;O;01%b7|rxuCpE1BhJCL?CB8{S`i-DlF4 z0H2cd2Hf@1k9A?RLXUe|i%;|HRQ92w4hLb27(fW|N6Pa9?0-D+tyB%R?h;2K7eCH?T0-c zZ^($I@1Pxn2*c904bOa8a?M9@t?~Vv=@8yn`AHhW#@AsIiz|h1N2sb|S4S z?6vP|&o9atbMEd0AJdR6dg?>a0RFo;g@V%?u8s_ptSR@UCmtSC*g)=LR9~MGZ7zrL zN}TdQf{dEWD@U60!ZWonfzgk^G8y^XC@4t+RYNR|+B1Nxs}(TjEk&^BFr%5eOgD;{ zP)Z19qk!khNQaF9#IdO7%B-fVk)>TB34Dr>a%LM0`WEx)@lEjIR&zn-R`uqwY*Kb? z=VXA2uv*lwP8b`DLa4c(>uBL;Ei8@Qi_yzIfC5c@HY>d3A*;Ae3wY49A?vaC(K`TN zO(mPM0MG5WTAX=8B*+y8*XGMWQrj4yoa=T>ruO2e8V5GfGq@NzQpW**2_zs~=ziJu zwh*HYBD{oXlcQHs1CqVq=)eFeWG!i|>4HOI!)6nswrgLD@BNs1*%(4fO!${UYWBkN zkLFgJZ4OY@E0>mc^Mp6w1Lr(P`!uYwi(BPFm&EJu?@c-b-HQ?XzEzrRregr{VKLOr7^k-Am)i( zkmx2yJH@J^0%Xg6MdNedo)dgQfC>W0ySbRI^42N>bI#^7c$`B6*2w>%=o~y+W9yt@ zfA+n6t0iKr}D?O@5f7w7d(>$iO2x8*bq4k@suwh8aA$0YsFqD!VmngRI5 z-Jaw&hFJaQ3=^nDL7I}1m{$X`rfgF#rJbC6`VCBWzT#RI>mm_ybI2|&Kn9py0=Y)k zwG-x{cW@=CB^u|c20=uGN^-!vvuSQ5?Q zmdr)CrB>0ADo;MYK*Nx)IjP&%|QSh}+4v-ukG$`9FoKL*n~iI8&X zZD3ezOttNI)b}dYH`=-D1?Dn~fw^Y&XPyPrC;+~_D@`<6=et)<#oV9%ElFT7VSG88 zJpOQgd*GV)@}_s^SCiU}Rd1LWG4Zz@Z`+Up78OJQ{CVK+u0C1w?yVLKbY+Bxx>A17 zaHY*`v$)j)(p@&n_ulkXp!?`X5m?yuQe6r{#Q@4{$3o6`o4*IAthI+XHeKBoPfc>4 zs4xS_Bfw_1sf$7@?RJ7k$agFPXNBDCIGeg!rc#`6^N<}J; zCf^HQoxg%WUO=vvc6T&k%<0JSgJbc}^2!AzjkTdroKOuHTZb}l;5i1nOEm{nx7Urm z&mP5vKe0M+_g{A@%{E{OzLoe2bRc%>d}A&@{j~~VTE(8mBR|4**B`Fu32%2~G0azz z|H-(Dg@81xsRLuQ5Ql+Ftr2k5you6Y&wad|xrQe^xo3*=3@fpm>2yd_#?gVQ=zS-D4iIQz*9C;tu!*q=;BN&#ux*;@rPq? zTs`-1)=l_m6(D7RC68)qki9@-p!#i0>DET5gLa2a7{{w|>HljdkJp!GWyYKY`2E1J-#HhNskn`bq^|FjX(zpngH1riS=d?kmh)4f-s%;n( z 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 N%Bnsod~EdY{{ajduqyxn literal 0 HcmV?d00001 diff --git a/docs/benchmarks/imgs/query-time-dist-3.png b/docs/benchmarks/imgs/query-time-dist-3.png new file mode 100644 index 0000000000000000000000000000000000000000..078e3ee8a2c464b0225d6eb9e1c837c6571d9224 GIT binary patch literal 59575 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�|Y(XL`pue!NH$LjQsp5{z_|VP-O;L8>13xCwt zbAapB(T3A|U(OW#g8_Lmq4W>3kxiR+ptE&v1vewwO8Oi(u3bBQO7Cc-cD=sRfk36q zYbrN}&Vv`*2{rC0C1!;#Gtshzvvf&S;{G4gW;`~!x}jIFlWb!Q+SI_6L!fxsCS63m zeZi|#X-iE+CuCW-nM2~J=bL9&EptQnQtVOL{jCj{q1I0#19?)kybvfkES3Xmd|H;X z9MX*LNYeDOR~rOXeq5MO{K${li6LFrxmCx68qF)L<4>dpTqbVgKk-XBa}oz641Xy0 zwi0tY&H$IHkf2igk%(uAMw^T!iQJ#SDLKVJ-+9A+dxR*UT;d7QIj^JAz!oIa=MJ(& zf(-B=@QQY5e9z&#!FyJE!v$*#OXJz#W57I-UEhi6N_@DNi%tGvVTP#Xd#nxK4u}&p zHm)i16fND)x*qbe#Kkd<f;m4IFBC4%?7`Oz#`m;Kws^e{H8`{MMGZE%^!U(;=Y0 za3HaY6H!N$Q-0O@H^$lNOhq3=;;7pUYJ0ucv0(&G^bZj>L)TME$o7EXm2FmYWo16# zNqWcDn~&-Y55|~YhIeQz4<~R0Zlj4Ea)kp@JxJ4Xko5cNTjQ1itB_m8-=v*?ywp6w zHu>E{(-Ff4V=h&*oSGDGCc{u3dybM}F%ykQkA{@m@gz287&Q@1mCg~^ zTShsp^J8ly=yC@dt3+L$5X>H%0PQ9vx|n4+i}61$+&QMT+N%mxT|NM*>kFrsh4$3k zWRbk&pd4OpBxm(;o3II+{#tFpnrg)F0WNLC(ZA0N+7!*|O7P%4^-PVd%Pdy zA_NT(>0WcU2iOwh|J-(@ZM5|zK=l1Nzf@v=j)ucLV$p90N=#5( zHgfC#lKkHNyepSJQ43*dLJrIMZc-CY2SP>p1+dla3`eBZ67h$i``gQ2PlV~X>9}aj z7JNH7xE?Y9s>;hFzvL!@4HN5Ukuh-armykymPCeLJ?^oaSbpKCT6& z-dWiCYl5|)KSRy+JPSq*yT6||cLbGG_T6fStl0&NvuO%haBmM=$+ zk+Xsx84Ts0;~3#HcnpLLZM8Q#xop&2OcDlKQMU((rJxQL_qQbrYB_CvUJ>n$K$Nf{ z(86qvexgG?`_i!|)sAUJ57S^=PUY#qyEa3(hL)D*VSJOCoP5up#e_}988-x1*2Lf{^BxGL+I$)R z=v^mwDiO`w)YBm3bQKGhYiKh+4>SX-`m`Fh=`gU<>Xls8LafD^e6l=s&ck!DUE{J- z1t4(fD>~N$?q(2Uu|e#+B-)$q+Z;sg#G23QLzNHCO445kKhYs$;T!P$;Oc%mlZ;al zeD%pYc+{9Io_tW-`H`F8nHsTsw|7O3JC9NJ1HxWb8#vZz_RVmR%E#AD^y3n5CZadr ze!&YXv17}&$yBCXVSI-3rASfaM|&vlr9Xy75^ugff0!`0+x1aMbK?yPmTNCQ@uYuk z6jFN{cpiwC`L-+Z1Osp(7?0}w<57knJrf|%f)t$0zUOKbx_$@$R{cs@-6Su$Q~g)ml*Dep)~OC0!y65iNm5kJ zd$0;&m;>n$iJaxv%q<@nW?R<5Te2W2CO#1=E>$}pc>DgRP=DElQi=dr!}l)t7wjXO9|O3w%K4J6XMw+Rl%IAIay zQ?}1XrdcyP5b!QOZl&FM44AF5*KmQbTZH9G-pSf>05jsy_ku3 zvh6~#)^fkWDW+#3?e1=A@&2l?@I|ks!12jFLy?vce`$!ZD{@JqT2m!5&6d3(j4Wft zP=#*Cq%ek9`R0W%(^6Z=_)lzhlJw`o1JnT`6HerBu2}?Gg*b!X^uMolV8PL)DV-2# z%i|?0fAaF3>!sy*ol<)MmCxhltv!WUblm>lOh{3J1y+J%HYyfnpjga#`v3^H;|>Jxt=`GFUPBkQ=wd)w!ZM*$ zsuG4DzPPO1B3+JT_czvZ+9l5@CTl6`vbI&TGjkUPwHvp*(D-xLy@%b8z*W2F7F zKDg=el_X;SJFGW(fX(T+%N_*|Pvb804jX=tbR zb!jhlXqMMu4q|95m8foKuQcy#kV*zEd?>MDQU6Or1p zx;0>w0xxr9OeL2zl6evI47XwA5cJy~rJlkk1t9wv(&4O{ZSI|uqBx!A@GYmz`4oiS zNXCcVHnHy;&6!Jnc2ouY#EkY6*eL)jmhhgq-7jNj%A|ooXL~JCdquuUIY{ z-kH6G8%ZV@b4pePp&~bPTlNb-66#Jit38))Hb{ZPIwv;v3vv)lg=N)m-?-q(`AKGe zXiKk~x5utM12{181>6%hx(sFh-oJVl{~j_TLQpQkT_;PIb6G#-JO$&qf*hkSN1D5A z{lbA&#Fv{4Cluh_xASuy6!D7Gu;w_&j``nb0OeK$Qh1#RUvt)3h-PS3Tb|%CsPun4 zdZ81@AX=@5-`Qn8o{T*SMS1(ZX*wT?gx2r}kC0=X(G!}_RhUdBmJ6__; z1gxaZ_%SzbW3op$J90Y)W(+rhrX}b1`Zd``}!mUO# zt`mVhUs)JkG;{^a9^EXK>Z1rwdu6jX&itHAr`tt`G|Hx-kdBv~Hnfc*Y)Z?NfrAM* z6DQ9k(HmW#15u{^zSHDrEjz9%MxD97Lglg_e_hzq+LO@mB3-0SrM%4c%6S2kNaOOZ z_oi3L`ResCNmUZkV{P^E&cHzNp6Dl&y#smjI0bJf`AB^T`hBW^875GtpE5^xfUla^ zPa65qpeMOimO!3N&Jv4Br>-uD2p-jNXWyG-?wdVmm#eK$#%D3K`)p(Qomyppr21Xi zWZdxc@;%svaI}NoDR-qKD11*1&{MvPTfUqzuw?{FJDg_-o!ErDG#%Bl&v7)4O)iz=^0F5q#mGoca zJWe!ig`a|X1&4g{j|b*tPM$?p?7-^imD;#M9GuwlcB6uA(Y9J{D!p*U9gz9orS;Fg zEuIBsOG90~%d1|v-bP#9T=pPhmn^>NNdG+KvoAlLosVtN3tW86a9s2_z&pO_cX0jz z?*Wzu7gMB*qqgXvjuQ&A7qdl4o;DI;U? z!jwgBD}U8(KJX)p57m6zdfWZ9QxN@y}PKEk&I00uH6!DMGK_L-}rIOe@cr~AU+{R%*E5=@^i(-J~NF?{xOd-ysr z5wAB8dpeHM1Ou&B7h{f0x#H5j{wU%l!M!WyQXppt#}ao&8P=ikaPH@paSH+?NB7st z2caZSBu(E{X=XptONoG`5r>VGK9bXJbOo$*Jdnab1>7@yqv6q26tb_^y9u!cglC^J?BaWw_wBODS|M`B>vN?v2 zrPsUcx80?nMVD7vTG`>td1?Mz))hI4%I0R6EUd3QWNiEVHk*|K^6Pq^yzfjXO6I<9 ztAxNJldFvt^KjL=4KIfM52`r_cf_pB;Hjn(jN*!lZ3rVl{RJn9IYtR4^Jr`a0LHlz zW7JRiSR3VlB8A>~KlI16lW(qSd`2S6d332~T3+B5?yQKqN zxJV-5DENEjV~+ga$}QHJ)Ya8FoYnlv%#j2CCgp6qO0m>)k{C=K9N4B%O7-sC{=U{L znx^>pyWhQYav}FGQel{N7o2~_VM}oGzs%YFbGUT>d#S$vXRBq6+>itt?D4=%Lygj8 zRBf?4lM=TbHTgPUvZ79Eqo-7LF>Q?&76VS%@ zX>I0`ra<`Z0L!)a9K$s0oR_J{(Hp&4MmDBdap2m@vC3l*b?}&!x+Ak?7f_GsRfWUR zw=5(VIs*@!lz=*{y;fl?UwCVZW_&F9V1II1eKrx{XghZ zCB>JMLmj@pi(CQ%OG-;^gJMqpLD1mg2{S+^st3Dik{1y1jeSseIkf%R=kdkI5*w>{2#NFNlm2+r1SUbQ&~A`>d_ zO3lQ2RoBFGpg)xgU1-4Ik9AafADQW_d=-$PxuXY zI{@FToos#8kFv@~gLuk7bys}Nzxw6H*;-G?>sr5sa=t1R-S?X5ph=W}eha{d8z__t z6$$@5AC?|=`pjg4e=1_C z)t=FTN-++!A?am98b`9dLSDkUe^$(%o*}e&vAuoFLboDR1j7JGd>+EmcnrWW-EA~< zzt4|a&-I)uM4^gH>QAbXae-wKx~y$c(=2$ZwY9Tl!`}D?dI*?VVQy4cT8y3e&t5)= zmBt=7vCHdUwX<*B5K9qVY>AztYpA6g4X+`KF`I0D*1ye*j{?D-vJ=J2x!*2p&M^$H z@MrD0LFIZL?hB$a7sIlbN|^)N4ef&}&L2mZDjsjCqf!@BvcolcTPd4tQOzE01o9l4 zK0Y9d6|A@VF0c{N_}y$p-LFUy@qsw@c;e^M9A5eEq6jZzlCQmEvJ^v!$1pT z>%3ZZh84E&FnlyKfI(wYM2}O)iH|nCmF!ok1^_mznR%M$p6(_;G4AEdnAY=RbBkII zxm?a4Zx28;x43+djuJySbJ?NKR~wVXw>o!Ri?0aJD*D^uX(E ztj$sXw3}6xWJtq78zpi^-=e~nf6eoUTSH#AT?MyRx6qynkxstE5 zzfoo{dr+4&-|dcSyTe90`BXw5Bep``)t4BnBj`nbQc+6dGf<#ETatK08CWrUGLgga zuq)CDu2|#10`yh9YbExOeST}!s{GDmg-(g6zmaRI{92m*gtd~!VW7Z#CX#Kda7=#; zYPNi}DxEg(5;42E1qE`LOalg`>E1a z$UArBg926YOe63YCr9Z{`m&Pu>m1Hip{RbMe{Yzsxf^*P>*TFf7rw<7V`;WxL zI+sr}UaarBDI=p5RoMruc|m=ydqMWvTElBK4_Rt25i68vnkH*S2mqYP@B!B!b8oH-8{_U8FylEzfMN!^4(@F10@YaeO`0|L?GdOmgMui_ ztj2maWP4hCnPu~(zs2rzHx1#jvA-htxm!}qUheSN?T}=B|#`k(zeH1B+ z^R&V&PrF7Kp+JXnpSlD&I?3*`YkRaylb?Mxy7M_mF6R32Jr5~o%(E2Ky5yF(W=QJj zBXnh?*mAUPS0?o$pe)f_yYS>=>XW%8_jbN4uvOz|-!h%k&Bwa3F4_8iqibUTGGb`A zXU1#5io3;6nEc`0gk{9#sSI+m)947!L3$hj}@fz zJ5!^lWh;yTwNJYpw)NuI)c7GaefyZ$vaTy5>MaIx(!6g62d|8k@xPVxJhqNr`5xG; zXWIJ<^Sa$F-EyAw2=Iw(%2^<;AR>hs44pzFbfC5@OT$apZW^S+8p9J~>kgh`)`aPO zb4SsjQiGgkayCP^DNs(?$bLNGj36cr4h`e^GR<4eX~`VACX{ypb7r=4P+#;M+R5+2 zHhb?uK3FJX;sY(BiDPNma|SABU3GXIEVP-e*HZaB|NpepmwopDS3fCR_ zv`5M9(D_={4UCRNY#!1*4ZEmvJJ?Cks7=VqC`HT6kyL0FO#Q7vO7q|X!RR0AmAUHNrMuJpZOd=5;=Wimy2R!~et9 z9-CjNSwy&mm1MuOu^unuH1d>s%GArs4cnlxc~bkxxxek4&2)G2u+PPXs5unSU5Ya3Bex=^5JO zr&!_TJQP~8cc|kMSY^X6+{0;A1MVKg^$ip`A?3*zR&UtoPY%s~MH5Z{6vc!uKJPv@ z%;lr3&r%}fTHrYx{wmh1X392tYvIZv^KO_*%z3>Z$FL#tG@6jh-kjctl-i>cn|&x4 z@xYYyL(Qc!Rm?~S>e!9VcOgkSc8MLT(eFHH0o)*KD>0`BC~{{%aa6hwvDUEz|qR2(@o(^-2?pNxSA_eyZ}uC`E80zrvc z#J}D?>3XZus7)J_Sd!wrJne6|tg6`glP4VXIjwBoy23U)2LFV4GvwkcT=23#tXA~? zCv4XEZhkge>A47}C4TLOC(`^m__n^wW>3erd1SYn zH90&~>@Tsf;t}}x{~}Xwrs}VV{f*3zAvn1P!Ozxen(Yt`p1KQR+YlE0+>yqbetGD5 z$F)*oM;5=YS(&Ud7c|5FL&$?E?*aT)W+s$5&_b9pJEcEJ1;Lj20qkL)?a931iab`* z5`|^>${ZXWgzFXn@ziAB?bK*6=v7{_V>Z(JxxM&yM zgpPTpFdB~&+_~Y~M<4U#;`{D$o%H@mmT}Y;P?)uHoW#rxA@egd&v0zPXQOF{lrc1A z&WMqK)-Y%NFAo4e!Hr||8uK@E#F@D94AXilaJ1^f&9-m|3Xu5XH%H!Bc6mu(kpCX>-Kwo{Z-WZl~n`(cB!ZTv1hIKu!aM*R@PGe6(jwo*bkiJ zrqnk8FZ>XMT%1?SLp#Iwh(!Dq%dabns_pH<-Z%CtqkQzUloE?!^(Peq4x@8q-DX;T2%?EHYl=?-)zhj@>`p`)!BEz)emM@`J@A z>%Rcntd6{eEpls<)K+H-PS5nMjqNJ2XKuUEZ1oKV;)M>f}A4v6QhG%@15Vm6*z z%7|?lO`>+=F3~1g02aUntZM&5E443r)J901M->V(!$g1z{VlD8O{(*`IdDh1_)4Ht zdQLvBx$?NcQT|*(^ydh<1m|Zl#4bD$IHkY&$hlzjYC8ciM8*5QCwt;yY4n%xf!%s$ zxsAOrk{_?wgUJqXshP#aE0&Rzie2uyM+(I(WUS)yrSDFpWw2(UH#?NGhKl`V-Ri&S z1{?O;8$hrE8BXYv5FvDLd zf$liOB`%}9;V;_#o}huG6W>00dY&l~;o@bEz5g^wETHi&LmrP~K^YGfbHsErf3ry> zHM1ktPllUG7`0>MJX0v~FrDW4b2CzvyjzCRq@fHBIv(<`=?*Mi=1SymbFy8Ysrqpr zlD5u1T5=^J?Nr0jw^F zJGu>$ORW}_&wSi^{W4f0rNaDOAJw<~v#53z8~4@{QDRp`%Oz-523*@Ny;F`B=g1)h z)Mj>Hwsl0pe+Jt*X!P~_NFPzUaHRtIH%r7z_u>|B=?L# z6U>9-6<$T?I(V}=8oi+(bLr3I=Zslbh5>xSc0F9QnC6#H@uVEodn0D_JrY5sM+e$F zjK7r@S$F!>2KM%lICPPDzs6zt!yBW#pA&#i~OO)uNj0$;k!@02C`lk^J zc7mt-$jk4@M~ZJ56MnwAXnCM06K}So?z})E-M#S&NxeGh3Kz#Kyh`%&IT)rD2L1TR zpM5x_0q`Q1YJM|ScvSun&>!DI$sle;oAv04YUD%rmeco3#N`X0Jo$5qqRo_F^Qn4ppUJY!CF}LaRbK3jn{;n(lM5z>$fJX*2s_Sb#BL78K8Mg@ zCt?bTrRc&e@q#~nFPpaAAdjQ(14G$O(zQBWyB}Wp$x?k+I`;#xk5<~`Y6LUAQ z#Crg?Hr#}LWVH0vqu=lnVugR*Go25b6D%=a>t{f%o1x}>DVpR^I7@j6{DU|qxOza z7(#jUgGmL~s=IpQ5=fxWg8b`w~v!hWmsm-Qkyox5{+v0WfHyxn0S z#l#vv)CYdkqNm&0WR(2lI8kOZ=OZ}h^^H9b{O{;3I0=nPG|$`(OoOG4=Dh21=kQ+IQfb>cq8pDsCjKf zxvqOcu3D6v6KV#0algLg7!2bBeQ~sn+*9r~A~p4Ch~6<61mPWhmN zPPP(8A-XP4HX8Y+0gK_bg`{5mhCfzX@)v&tnv4T&vD5+j1cXL2zzX>+`L=vY+T)gw=PH*!F1}&S z`fcxRF5;l6xiF;#;a2xiq{;0hV(-nMZ$^}~epzWt;(z=R7IL&_d~EzTa3_Nz{LjE$ z`Jceu%GI4Lo5tULF7x%iuHD_wH z`;x}ZoZps@KsC;2Mq5+kd#bN>+ATIlR3*#Rh8z28Roc>ER zbM9{lo>$AwwvQt}zcA^y_#E=Jg^#w) zcN{yC$z;o{vAE!Sd*l-)=jVL`mZp0-;9btl9 zPPTcv)-|l##@4$KZ;G_x5CN%YBWGTY!DAtEQj2PE*pq{J=4*F&gX?4JTjBglE-$;# z(6dlaL;srUTrv}S%9Vgj3in2Lf@i=t>zF^{HMO*v`4+SKk9t1Cq&y3 zUP_~9fqO7JQt0=1*y;{J1KxU;b8a7GBk-dx-Ty%-e-QHD_gDRS{3omPzqKvv-_`z4 zZE*YdO8$E#;ZpJcVjJZDm#Ad?5xjgKChf7}^9bNIXQ+zOL~iHyM07+A#Be2+Ijz&_j&zf$G~*L-1ajw(#Gf{zL?~yrJo<+Od2+zlcLF=2Cs0KA4rBPi`K(|5 z@7?d;p;Urs|AKyE(=k5z7eo}iN%t=RK`Jiu*}ouT)CAza00i_mt}p)ueWaFq_w--T zzdJ+t_cH#QK>pw3vlM9w|9^f9@P`Zk&EWq(60h{`>z_{5_CM#26VlGTjcQO|~CcBiGn7-EP}Y3)(UC-$c3gKT7YkiFvFJn8Y;@ z9A4OgNWWFQgdJhRFqA_|+CobHD?rW^;^2o-e-nD+^epI3jB|EA`6iTM|6n2d{YrXoYw0|WkV;QGuN|B8Q&QlTCU1jcagK<-<4VDJ$kJfE}5xvsm5qfU~l;RfDzO1)eXc+=)52XI6KP&zxfZY1;I$;*Bpd#xnsIH7k2KW&S{9~w2#ZK1$9QR4xE;Q+nru|52 z1Tgrksv9BKxKhjJ?{)r(L<9tM*Z-urbHU)uw;Y}J>F1vehh+~735y$hrhL-UJh#jX2Q-t)&Zi2_h~6hvbZ(5-?(VrO z$J8kl#oC@MT)$#1J85I>0wzAVC%5^kM6nW*YQP?lTk8w-mA`8da4lt*(yMTcZgOd+ z>Fs-*Y9aYr$QI}d5fC|Pttr|>oINZ~`#ShtFt_T6W7i!9QNqydeIhN}YZY}ige$iN zodf0@jTZP_v!@?kD?&`PDm9z8nCBX%6$_aM<~B$3sk2rpeFL&JTMiC)=3z zD}OKtEXf4yVMSW3te-ry)4ZbZ`~+X-c~9^yIyo#az3b+qx>E3#c9YW-+C@Xy2UdFRoW{BB1UmGae@} zY}h18ys=dJ*zPE0Hz98xk$oMQY)`p42ytS>3%q>Fc3m{Z{dj4*1z0tU3+uK%_9DMY zS2!OS(6Eh4{U)vGx;e@{$FI>)H~53ucl%Z+;`*yZ%uI~J7*Fl0O_-}Lft|E`9$i14 z4Y01{El7N^JeJ)_yg|PRz0`{ehUR|FnNe=!T(%!wF!0zq!zXg`I`HM;$%Uw1Zi_|I z^Gi%tHnqAygfg*#()P|BLJ^u=VD_%Z1leK z5POQn7X(%-gy^{X^T<;=xLWH>6;;0*noO|LI_Qk(p1*LpIZM2+Q7~8*O3`;k_IuBaBu0R^)PO_`=-IKL=2fW+Z{$!ETu}hleUllkcK792 z^%45DaFhPF(53?y&2~ODuTI0m7Pan|`A@eh@moRhWVFJKQ&PduNhk$C z&{%64E(M7ixb!lys&6kAp_3d&D zO2605aQui0v<_l;?KCrpL@%Uilqc0br14;AbJN8PXUi5F|0W91{U^Rw{jc}E2O56H zA+G$IeL_42z^;W95TgcAoJC_zMbW*y&9L{v;eE%kOmv3O)|r*AEPB$&cH&vL939&u5p za!N~Maeo*kR%&yo{yo-kwpD>$d)nsHtV7(F*e5wn|^L+5kNgjRl)>A^faFDz9$O)|tRl z0wIS5hV^6Sh>8*5{WV6Z?Oq^AVh3it37$P1VlA7Z*#Ts|54j91>c?M%YK9^7ntr{l z|GLq8)xw&%4G%2pK>E>aeeFsPD<3qYQ(9JD_-A8Y*S8ULg$|VB&Kqf#%&Sz$njXzR z6Cu2<$$?s>Q3+wT$D8%VPzJ2;^9@3>3Ur$n3eX;Fbrp|mt_+uRR`BLkoE>h5x(9q( zCD)8Rm>8!#ug%yWnI68gv}3W}Omp9_b08XSy!%2eOdCoEKhX=@_CLb~O9IhZbzCgV z7wT~8dz@!n=IxA(XsqK?ypdA63Qhl$lQ1-8Tn!9Qib>;b8Jd_7ZOwEjMJ zB4(ZF;P1L1aW$yt+S2$Y%-`Y)!)&T`!`}9;%Sq$FqepG3O#!r?kR-6V&zsxJ*r%#i z5nyO#QLCO27-p*8dP`1j_lP-xn!);bqz;9NrZxLLM1cn@wMv}}q@<^2nu~6z zM|~8=tH=kF47A5=thU0H>IF6ut~tZ2Ez#R$aZ~t$3jWO}szz#6Mykn}%TylP@IChNmVK zt*7j;%qOzmCadDNCla^@x&M_3fMm4v4dHR6umi8?P5+T&yz6-K(fhKp3Weh8Xdjf3I#G2^nHjx z1LC1u;eU?SRL`HB9NnT2U_6-gcFUKM@igdQU0^EHSB~DFWIYz*&8lL0ReG;9=LXBF zffl-?i;Bu%$iAAN;bEcae052vw&m^79I?Dy&^a}iPQG(H)DpB|74XzRj9Ya&V~C{v zl=0P~YHlt+-#~nP`IlvevOzI~zF+Ul|Yb&r(C#jT9@x`ljKbAazLA$4v@~MN?X9*+N zc*;dRYmLh7M14?_3=_*v4b3ee|6Ni9#fwSKiP=CgMs5+K>Gyn)} zdl^Qowrqz#s*UcwLU8CGty1YFWu4tr-dshpD?%RO;6PEj%Q0_$#zIqLdxn_jv1^p0 z>f2-5swph<;^+k)B?E7J#&;0dNh_pC6^Xbcz1cM-n2PSX#Ofbu-hT19!o?gY4lZ1K<%n|1nK z%3@sFrzyM1d715!ZJR0`eTaKyJ$XS(&|><3u=kcxZFXI|D5XdXEwsg5ife)5+Tu{$ zHMDqecW9x77A+c_77HXuafjkgkOm9x?jGcXKF_)qge3QpDc8E@ zoam);CsUSBKlCh+ zWj&xr0qPDh56VrSa=I-1R^C`chaR>2Tbt>jxjNcw{75~4dRqg zg)Ks}6wBrfylg+OhSg@9q)SM6ie-{fmgzxRXg6m?p~C^7FwB4{enn#5!zh{P=9e@~ z#dB+2l0_Z9y3n2nDXxPY86HiJ#FJkgi40~w&k;9j5QbW#Vd&CGg6?u9=oiwACmT0Y0?c?C=eYzKjUZTafn`$2$c892#$LO zM4(}clw#NHby<-V^Rr#Wwr_s{>cCT~JZ~rm$s0^C;ST|$cF!mEpZL!cH`Y^R>3tsk zM`_P&?X=2w?lPe%?WK(?ld<%QM>}pT0V+O%-NanNO*DEVOQT@k8iy+WLfY-j{wTW{&7FeH)PUhNC%T9<_-2p91beB zNdt(qJjA1b0l*%l%eoyYoN9JpYs;w;bgKTB|}N^oJyDi?zncSlR0Po7QsV`_HDxGV0lWyFtr(S(Ou1G8}IaXzW zLu!hE>|Xiqw4Z8|^Y&!cR_^m0LJum(LXSjsl%?T#XVwp7cQ6C~@I7YMPEMO&mR@2s z0heus1=>!~ZbMD4W}4fzUVA|dkm1UI{><`H1y?yd96k3Dxxf$-Xb{mUj!D;@k_%l( zX%>&_{CMv0hU5F8kHNu^RuhhUCSGFonKp3joTR_mzATfSMeq1hsp--mG2cH|uycvM z4U1&U9YN2ExS4{TdH}plqT4+lc7LBpZme&MAuv8Jk!a=jy1^o%Dfm-{uUzFY$VQZ< zJi0>`C?;Aw|LlG>BQsv+dvy3W1`j4qdEPDvEvQA|ozDwR424~68ocB+h6l={66Q%la4p@J_i>zVR(4(de*gp=2BPOu~E z#f*hHRNX+OdgC&syJS{cGbDpR3AgeVwsn%AZGxVoMS@+!2LH?nfy6fX7>xvEWUBAe zwyQC;>irA%!RSJb!_tz>R|I@Vm0OQXo4G5N}t3s{29`X?^rw)(&B1Eua>)4>I^`FTWJ`ASN@ z_m0dC6NY;;UBFJB+H+tvJK^fiMyqk7LXJ}us)}e&PZzIUk;BLTZ0I}W%#dV2iXD&* z0=a<$TYv|!&RdkP=regox8JZkG5>Up6!~Xu3Mb|L+GYLY9;^arL+z!Xkj?xHTv{!F zdumabXDquf%>O=CdXu1=)zdzl*wPwkd?P?q1$aw^R46&p8`3LMj7y(B?srYGw%D!< zizo8)i?gy42iL_WvQ3+qJ1_d_Hu$AM=+`&vobuUtxKzL4ulGo_7X`F%*itOC=d;+I z`c5$$F)C)hM4UjcFf9EAmB+d|Sv{Bh#m}QGgy#|Y0aVs2GWi=R>m)s%{uR|!0_-AO zs%0)N;Z3vo&WgZdyW9IV3abT@@KZAb6$S68J~ap(q!cyrWjTY{hX>XS8S#;uRr)&p4 zSD`lBZ`g*-?SszTZaE0vbuS7!KIwg2a_?e)Sq4I{3FUY(C{W}jT*kSlj?aeoVd?g1 zKZ3F&_pN$QE6#N!ISg=HVma3R`Wx{Y^)~v!f-L7zN>!B!(2XX{K9d#odcP1n{+Q7d zCkvGRt%%%lIQ&fWSC>WVc2j%>`t#b(RePxTb#RHR0!kM@<;{px`_zs1l|(ufkG0V` z@@wynLi9wbpV^NOqo9l*qA{M9XBhM6=uM_8&Q3Xa-DXyBz!k2yF$ni*J^#4D$7qO* zlU2?{=||GYQbMn|sg!%djtakr>OCg4@lZc%piS(pE8v_{J=g14OQ4lEmJ< z#twTBl^I)Nt6{~;rVQOXyy8-;J8IrjPw6g(MD4-V1a_lIJbco&H#nT4#;O zhpA{)DvsvV^#%Re&Vk@2l=(NL63Lju@jq4Dv7Er!(dY4H11vL{034v@05A-On^(Q7 zL35_nIv7*t1D`R;aj3(ay>ibdE>32SNCyhl8q`VdZqT$A*OYm~(`OLPoEYwc64HK| zTPDAe^Xhin(+;lw0N|6TUMn+9-^khRK-H}PK*0hkkVG+^=~;v}|5(X-vyUbwBXh0` z?sVXZ!Lmp2_K|x^gdST^)>zCu;R@=1tktTl1vW*XN8#qOTvg>AOY4i^OOVxbEyZuuS+##{L;x9FenmG#R@p%-zB?vmBz&Ri``rF;_{kpZ?4A!@O=H~I;lCuES7JR@j2lbL}7 z+%GZo6j6yl&PsN3Lxj^K73Mx2?c~y>Imf&EW1kmNF9@XZ-u+Ydbe8_NhI#;!L`BY$ zZvRybMf0coe_38NUTgM#L&BZjGS~Sxy*u;6v3U;j?^}$RgiS3*#Z{za?GWSNGVRRQ z+W&{jYmLYKbsyghEH@XFzDsj$iuijGDZ{@PVU;O^xJ>rx|2B^GyyS0v_v4$LB%`nb z|2yo72GaX)KE7#NPmC`v23hc?L~-HXe?_uP`1d^NDC$Q+;@f{n zLXC)syG#K0U77s?IyB|BWO|&{Q~r-19=SaqFK8iCr@n9LpH~Paxa$9C$=Ic$l%$<= z@v6-k+Sb-%a^Kf)Gx)TxB5K6i5zxHu)vt7aWpms0T_QdnK z9Vn#HhZ^s@o`5OJRPTF!=Krp}D4f))d9HIqFaN!+?5vr`{d|4Lx>s@y&IA1#!o602 zYp+T{FV}5%hct;wQ@|{xpmy*o#AbraQf+7VBO<@fPD!WHHs=O=ZfmqDqy8W=-WZD!SUq59X~KR-&Un1GZQ$@E!kUW^(y2|_T%ma)3s^tI$CU=$h^W6HDcmr`j}Yd z@#ApZc*6MHjste(ZpO&iUN`M9=dqopd{^(xGM7{)egfQI3Yh1Fd#wRed*}I$MJl1%PkC$& zg*th^%ideiTm46!-`{k!Ty*58z))&454Rso^xfBMs5~z);$ih%E$JO+c=#fL%Q_?V z7OJ5NlL`ni_y#cg;m4f_wNcA)O!w9V-VS>1dN6L5$;T7@2L6@v_OXMBQM5KB9}W@i z>M{;=n7P16F`OO!&QtGZ@AsRGIH!Y0xA3e0GGyZB^AL50D;?vUVNN!vT<6!lCJ0&1 z{e0L&9pIk}6}w0_*sK_>Ci&ega?Xl;P{-h1viZLR_;7RR4n>n2Fj?7-RDM$R<%ihc ze3+U5L41BR)9=xVdp8*AAld%VE9PUUq}gl0)j+)(#**suz{sof(}oyMrS#b8QoZYY z>lKVs|3)XRa#6{_nQEi48*SO=OQ(nFL|9-p_+jdQwURpV?S24CRHL=eXJ*#Yo< z{59C$IkCMq7cy+a)xO5w>c9NLY`f#2*YVoKL@v4KP={_Hqrjm!5GQ z*DbiPzGQ=VqK?VWnkl%(-ac7VwY_@TTYfz^q8qBARmsAqHP(f&I23|ATh!nHf|PZv z5ntv|*!0gc0s^#05{j^y4B@W7q`uJ9HqJS3P9iX;Ma9*|z+jeadr+zhtE>H>hW5w@ z&MED&YJKB;QzJe#l}lUKggQn8LP>Vz6k9Dq>qKK_HJkYof1+jpcMQXr_|){l+c-Q& zR-HcsKIC354N2k+M&FH$8Sr{{GfMQZ}Dk=DDnhEeq zt5BdRwX{6Gxj}g+pf|kU{jDrbb?JVg_To_|P-0p4#N4Dt(MY`AYjs=Ae3T!l3Y}r@ zui69%_Fob;5a%(lD5>fYt+RS5TN;&D5EvOr3g0E+3^8q&_3~V8%uiRVbp)gs9_fd_ zxEo@t0BgXJ)rCKP$vma5VB$oSq!$t^^7PGVKxF;O6Ayuwr3h`vMC@{up%9-UL8!w7 zb)eKe@|O^^@mP?QsX1!jMiQ{itc;&@YY~bM6nDLB&_2j{3W^6Wny>%mAs}`=wp%CVn(Dk$ zQkzFi{737WvUZJlfQIF+XhgqCWmBcGoVP2Z(R9$EnU>a}$$1ljJO z9(~AqX-n!;YPHa**S4Qb$N-9(C+dZ(7I|llvEVlR^kxb=I)iWR#v*5nBh?~jgle80 zA)FKm^RG3?#+EGV^h=w*K(#GYK{wwBJMrD1i}-0(XREs)#0Es*{Q0)mJV_~IW&#k8 zMyJ0BRrHxFDu3AO#>j#a$t(3M|J7VWJMB|u@Vm0d;ev|fskvn}bsjtT2=|Su&I;nMPD720IaxHu?j+SPu#|t*(>!!81H{)Nd77vW%-eqwWi z!u7N-NmF>4xF?ox{`{CyK1$ZnIwyabfmUpW|kpZcaVmQ)fSu%#YQ$*yJ>)M$X6 zm@CWfHl0QH0Y2a)TzN30rgOG0?0RieAweDsu`WlY{jCcJ!oQU%4*3S0*mm1-@n>xc zZ-l2Eey5k1`BC+S5fbxGV;th)>+k(VV0GOV;ZpH}rhk0d-0$M!=huT*{$HwZjWWZd z8}bnA+nwv{?6>}P0>v;myR1j~;J~=s@e)IwP8IxT@I%$YDno>>CA-)9-4#3$(WBTHR08?t!fLI%)@wjvjl}FIw{6@;v zW(_(sDx3wC+bXY*XKyAcNXSD5zB7fG+z z$Eb-srpTGJsSu;lgIqz3AobcF7oXj?Njs;mp;q&K)2CX#5zKiTb?hg`(>DCOL-EUb zVoiR)$Tf+y;*|CP5IdV^CA}eqj@HC;=`(6Iw!r9S%ClyipvE`Ip-!9pfF?@5ym`Vk zww7Ge@oy=HywI?xWBlX$W!$DlVw;6ftpKPjPg$SqDi85r@V@~$p;a3q7?hQ%~6!ZaLwZ41xROLce26xsCpGg#}r zfN^`Tb~WSmURkCk<)mYx>bYg_ph_i+0-Ra)pk+T*&H;sqO0txCL4K_>H-0w6ZMZ4Y zvdVBpckED!zn0+(d~-4^5g3}~|H&n@(A=e}NnA`#?D>x+GH6!5^{6;#e} zaC9o(73<)g@&q=;NnbRMk2agv452Vn*6A3jDeQ97Gj|G*?Tf zewb6;u-SujiwnMQ+5K@hjoW(dx<$xInfAjOUa%Ukq!Y9h$K(&W>g%gMy`IeHj5Aaf zUDb>$dTy$>aZdv_7#L8-x^)T-_9qIWw*}-4nAh|NTE}I#vuTTR$Z1G3t|J>x=RT49 zX#a%Z*YvuUn8q0pjE)le`GRyCwTC^GH4~w0<57KgebP$)6^3EcEv*5+q@vr7*!3i@ z!qw{Qd+Ga&<4|%etuf(r^l2NoY6Pg^Z2B3PH%aE#c)MEXWXnxi)H`ciGUkc6tBSbq z6rACC6^=~IhB6qSik5jI8RE-o;?o(dI`3P#;MGb;31?Hx z#%iBG#*s8Akp}0k;j_apq6lZnthG9lNjFiuIDoMXHHOBT1Cbnq)KobI1sc27Sef6a zkReV0+HOe$Lesk>*J@oP9w9obbwDAGULs`JLgzYw^~x1kPi;82MguCVnMNsIm%k zgJeW)@t##mc{NlBdhDn2QeLq*@oIJsIM~;t*}AQz<)S)u75;=PZN%Cv>yV336BvHl3Xc z5P^P<%UbcG>*;*X;dI?JTXaWu9^C=oy5{fXLMu{ugtS_|Wx5UzRMSM)Q^J>R(H zR=R#Creq>Cs6boiRD5r{-ahAO!RzAb*zrp~BUq1sj3&}SHUq4RWxA)# zRmY`(nmN-Z+;qm1p!&#v1=2r#ozFl3|p#?~Pe!qERaNb+fv2HeQ%KmIB z8a4FaQERDj@ghcr5VhRWZZOLTQ0q904L;1a$(;xh5eF>qsmAi_0$B>}{i@|HAe7wJ z>}7eHenEi3`MaMoEo51YNKk|S-m_l#isr?xt>Nn%D&e_(f$`oO8!(ZpGq{KKY%4WHCS zhyAK#7X9&|Yhr-@&vr}3tFcDP!Bg{D)0)j2(8u1ubQLy7veiFqz=B5Hfd-opXCyB0v-w42zbuqG|ChV8YFYx!Qd z+At_fLFa0sFY%5l?ChdeWOUa>Sun*?VEf8)?|L^v;)FUU&5}piu_mqKK81qy#qMzk z1AJS-Bj?>?x7T)+%H0q)1YWLD%+`Sm=!5lu#!|7WPQaumx7OGNtJ0HFy^$6R_PeMW zZDU=!i9v}`9ezZ@ad947QPSSvz@cwfj&kO4T{tQbE8_{-*M3|d9sU9uU=MKxnIeH-A=%iVv_ z(+@*FY8hm*>#n}2G<^zY+;)yg6=`nB*Ql9EqD2(nb~|TEPC$Rcv%eap>usqsPjy8m zomwfrCzhQTm*rXS*QsPxtLtC4yBzZU5|ai&%3oc{fK@X*m7nKW93M}mJfsVJTb@0X z#I}!J$2L=M;)j=>P+vEC=vsQ>mKGZGtB)R>4z9~%M@e|N$t;ErNh>DzjesC`%fz>W zR*yZ2OLx(w;sdjqPWqP4*g_orOUsgm7cT{jx>&gS=r4WHZO@r~>MOmRz8Gd}R&E@+ z@b(s`zGNnf2cnjGJj-{#3VZ9>S zvWuBYR1!0>$u7{X9u1#-CiccW<1j>4#fC7P#acgZFN;r&A4zWcO&LC8u??r$^6cL& z)Enu?R2t|XZ*#JSZ23`WZ@Uz3c}KZ>rDoo&f!RuUwo5kgS>$1tU=_|**Bc!uL4nf1V>9;;ec}6(HYEC3${daKwgYBZ@msGm+RNH zZsR#5H+zV5z1gf(R&h+*Ymx`v(yDz~-92A8q=YXT)-VMKE5kC%H-A}I?q#L8GalF$ z|7p0>D8?q4T^V~Y8 zYGbV6*J6qlqnZ{F&f{)KGecpa zc3m3VbevgJXT0n70)N73`P@=3Q^ZnBYH_*+_{@H)=myL|er^_b&y$hX^TngaZf{lI z7lu?cYMwU$@G5`TP>O@VLK-sOb6x3#^kY@%IlouSQ;V`(GP=a z&YW1)rvOE%2i{4j-B*6M=2QLsiFdbTvao7)QM*qsjM%knfpy`&z7he-UrdqjOTyKn z#vh_;s6$EcOUClVA2R@1P~7@9{^iYTFdU*L**VVW-t9 z?H>}n!77>NtGlqy`*g!_1`4De>fR;k-qykr*!osocf9+d*(b`&JYeifA(#44 zYK{9qT=tU&X_#1QZUpx6Y7h7BS+p3Hef?Y1_v`V$*T`p zONxriT`?LLbxKqsT^Zh}0lpIQ=V~KAttsJ_i=i&o0+)=fI@EG}aE(3!F%|-6KdkQJ zp7OCcq&E2G5Sy~7uSGPVKeCtpjj9kjm_Q^9j}wmYjI%1dQFHzHiPzO4fqcuiS@sc+ z#WV86e4Xub3(o%7o72AUK}qlJyX013LO*AUjCc3v$3TZ?>?5oJ0;DW@S21k;lOBWGQ1B=(+dFydY=0` z-DvgGXYz>Da)G^1zb7Z;PMc6@=d-4!k-IfTjFx6=^6`ro8K+gpCZle4`@PWm@8)|) zm(_m?9RTD1R?nfe`Ty^U`~Q5mpT#re^}1wGQ^dz-Z-d^@Zg4-sxWWANqlNa_3CVBo zNYRUkX7r$8wFUgE$JerePm&wVf}w$msuH|{CQi5ZY1J(zMb=3Y%<;Ycm*RFZxs;MU zIwR3{8PUhL223u^q$Gxh~0ORaTR_@^Q^`IL?hp9>}BZ1vN1c0D&$#61P37R3= zkh}k>V~pTibkZ0X?4S|7za77k{M53+et>7`~)G^lYYkss9hOzcSbt1hVo6? zr}Tx4Fol6|LY%fY#052->^(?_x5>w{3aahp=NZn?}PG?VpNWN^zvjG^spGa+2HKl z(8%x=sMr2tYH11GFxBYyF*-RpdD*X5HMdiv^yCz2zmJ16IxYY2BmLVX;_GUUV$^N( zP3^GMMOlPeKcv9{#9Q7 z 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 literal 0 HcmV?d00001 diff --git a/docs/benchmarks/imgs/query-time-dist-5.png b/docs/benchmarks/imgs/query-time-dist-5.png new file mode 100644 index 0000000000000000000000000000000000000000..484545e05ae1d668d307f47d20c990785c017672 GIT binary patch literal 99981 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%0Ds--3nVQqVH)m?d&l^x0 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 z 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 LtDnm{r-UW|5wrR{ literal 0 HcmV?d00001 diff --git a/docs/benchmarks/imgs/query-time-dist-postgres-2.png b/docs/benchmarks/imgs/query-time-dist-postgres-2.png new file mode 100644 index 0000000000000000000000000000000000000000..3f7033fe22b055bad4412894c08cbdf38569708d GIT binary patch literal 20119 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 literal 0 HcmV?d00001 diff --git a/docs/benchmarks/imgs/query-time-dist-postgres-3.png b/docs/benchmarks/imgs/query-time-dist-postgres-3.png new file mode 100644 index 0000000000000000000000000000000000000000..2816a8da1a415719d52b88a433e9bce76d5b4160 GIT binary patch literal 17039 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 literal 0 HcmV?d00001 diff --git a/docs/benchmarks/imgs/query-time-dist-postgres.png b/docs/benchmarks/imgs/query-time-dist-postgres.png new file mode 100644 index 0000000000000000000000000000000000000000..034ca241bb1f10c394e5b9bce2a4eb69bad3e940 GIT binary patch literal 15791 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 If1SJjUk+ZYQUCw| literal 0 HcmV?d00001 diff --git a/docs/benchmarks/imgs/topology-only-store-protocol.png b/docs/benchmarks/imgs/topology-only-store-protocol.png new file mode 100644 index 0000000000000000000000000000000000000000..7ef28c1d91b70ba2e1883c466a1c93bee56246ec GIT binary patch literal 116756 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 |U46Zou(e2DUvE6^!2Di1l$dGm?Y+Y$*c?;K zrKIxf>W->t>czTq@$m5>gZnvNP@H&1NAn75+k#1Vy>RJf5wg)gm(;smT8a}pMI{X5 zre|knI4Sfj?>GN>X>mauc7>S0IHo2P-0)r$1NT^2rJnK#n^I_pZ^JYl<-_cgZE|wk zf!Nj*XwW@hw;hei>&=`?_6Q!Ja*dIV@LukxSa5DZL1;+Gqf1Liyg%LEOu1+E4wxC7yk`$U&b5V& zV!LYb-!XYug#guk9b8d_do3DNRr zg{rUWfzU2Ofb29o_9u!(xUtOC*;stLlvzRL=Lu$5Nf*jAkZhZo#m;M4;?06D4KT>D zA)LMJ86qHnjPLXFhzt97`iKPIwW%&gzn{~f{qz;j^|2Zt=+6Ym2sOfC9+MJxGf{Ip zSbzHsOu~qz*gbXPV9=VtR9M{H(o!LlS+RAs?%&IAHZVj8D2oR?dr_UZ=IG(%!c!8I5VR73 z>Zr!$fO+|Q~ZLl81p$B7aidVvGTm|9b{c;GypBrj@Z#gHpX-LRKsBo`cd~cS&7L%n^;=XC3jQX}AHH zBktd~4^DTk$B)O@Ujj=CcyS7BpkreRkEE^_N$Y{@fM9X({Bak_{5w(<8dt@|nQSmr zW?V5+BI4>*@V6AcHcFr5PE1awLe;ZyikRQLY10umrcC9V-pk9#R-{n?uHagqy%W90XBn-5wdE)g;0gz8tB^|va$k^(8Y-TV^`&^~<6tnZow{SuLUkzW#@0pS-iNv^>-~xz^^Dt|X z$V)cgu;*{h-?0Y^4R9U7!1l6`0i3CJYEt9dgGwOvI6+aem8dShY|skdS-tjc$nqhk zp>dNiV8S^EJZWxv8lc0Fp1AK#vE4s|9(t*!UcbH{p$&4H(>bxj7I$PQKg7Qv;vMy0 z&;hMy!E4&92KR~sj8bA`Yimo?Ik*X$ZPyyqi|EwHSqiR^lzGjn+PG?YS6En(p&rJ? zj$oV?q<131!k}{C9ia%$P6=$E+7Hvi;=09GZ{DDbpI%e*17#}9Ud~4$0YUWO>tV=K z)8`)JLx&K1cVLJdeiNqk-u!uqNJao^pb%vZ6C?RBit5jKGw3p*dZSw-hf*Vl7$ z!ktVu?s9AvM`lIqR?{mh70B{gU?7Qv`v{^2JG;C>@6ePNat;7G{&N#argKK@yFEQT zFoFy~4RkrpG}=iktG$$x(o)21xch7p5ICeAzz|D`jDjD^D>)gN4v>T(Gk#XO^IOiNM}BaIfd~t;b?fT`Xbv%^tAwK=)z$+O z7x%M-V84y` zfKP$+6kZAdIbeAQQZzI^zDqy9f}IU2l)RGC(An)}%`7k>kb zg5eJzkO;#*rX#1h@2dh?-%Wj0@I#^H-Lvvbvp7d5CNQMMA8`e_6ucra>jrcQDwXO~ z)GqyIHZIQyp8!z;=}tp~14fC1okb3Ohvu(=c%BEHNYlY8A+7rV++%WMiW5L6;T^@Xw*Cq8m^5GBA(nE16!hsVY$9ox7s{qikAsso@9mZNx( z?$@cH@A;rbyC|G73kZ~X?k%!<3bU}XI}juA^bhDop~ zj(Ey9*vtP}X!uVrD8O9Xjlr;A$u9r-!6?IbOQdtXvQL_t52%swXOGT4?IKOvp#K3< CW#5nh literal 0 HcmV?d00001 diff --git a/docs/benchmarks/imgs/using-jmeter.png b/docs/benchmarks/imgs/using-jmeter.png new file mode 100644 index 0000000000000000000000000000000000000000..73918de75c1a0d369f49337607a99c2316982977 GIT binary patch literal 73641 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�!_EDW})8D_Ndeel?2CXba?e=rF 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 literal 0 HcmV?d00001 diff --git a/docs/benchmarks/postgres-adoption.md b/docs/benchmarks/postgres-adoption.md new file mode 100644 index 0000000..89fba19 --- /dev/null +++ b/docs/benchmarks/postgres-adoption.md @@ -0,0 +1,239 @@ +--- +title: PostgreSQL +description: Document that describes why Nim-Waku started to use Postgres and shows some benchmark and comparison results. +--- + +## Introduction + +The *Nim Waku Node*, *nwaku*, has the capability of archiving messages until a certain limit (e.g. 30 days) so that other nodes can synchronize their message history throughout the *Store* protocol. + +The *nwaku* originally used *SQLite* to archive messages but this has an impact on the node. *Nwaku* is single-threaded and therefore, any *SQLite* operation impacts the performance of other protocols, like *Relay.* + +Therefore, the *Postgres* adoption is needed to enhance that. + +[https://github.com/waku-org/nwaku/issues/1888](https://github.com/waku-org/nwaku/issues/1888) + +## How to connect the *nwaku* to *Postgres* + +Simply pass the next parameter to *nwaku* + +```bash +--store-message-db-url="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/postgres +``` + +Notice that this only makes sense if the _nwaku_ has the _Store_ protocol mounted +```bash +--store=true +``` + +(start the _nwaku_ node with `--help` parameter for more _Store_ options) + +## Examples of *nwaku* using *Postgres* + +[https://github.com/waku-org/nwaku-compose](https://github.com/waku-org/nwaku-compose) + +[https://github.com/waku-org/test-waku-query](https://github.com/waku-org/test-waku-query) + +## Stress tests + +The following repository was created as a tool to stress and compare performance between *nwaku*+*Postgres* and *nwaku*+*SQLite*: + +[https://github.com/waku-org/test-waku-query](https://github.com/waku-org/test-waku-query) + +### Insert test results + +#### Maximum insert throughput + +**Scenario** + +- 1 node subscribed to pubsubtopic ‘x’ and the *Store* protocol mounted. +- ‘n’ nodes connected to the “store” node, and publishing messages simultaneously to pubsubtopic ‘x’. +- All nodes running locally in a *Dell Latitude 7640*. +- Each published message is fixed, 1.4 KB: [publish_one_client.sh](https://github.com/waku-org/test-waku-query/blob/master/sh/publish_one_client.sh) +- The next script is used to simulate multiple nodes publishing messages: [publish_multiple_clients.sh](https://github.com/waku-org/test-waku-query/blob/fe7061a21eb14395e723402face755c826077aec/sh/publish_multiple_clients.sh) + +**Sought goal** + +Find out the maximum number of concurrent inserts that both *SQLite* and *Postgres* could support, and check whether _Postgres_ behaves better than _SQLite_ or not. + +**Conclusion** + +Messages are lost after a certain threshold, and this message loss is due to limitations in the *Relay* protocol (GossipSub - libp2p.) + +For example, if we set 30 nodes publishing 300 messages simultaneously, then 8997 rows were stored and not the expected 9000, in both *SQLite* and *Postgres* databases. + +The reason why few messages were lost is because the message rate was higher than the *relay* protocol can support, and therefore a few messages were not stored. In this example, the test took 38.8’’, and therefore, the node was receiving 232 msgs/sec, which is much more than the normal rate a node will work with, which is ~10 msgs/sec (rate extracted from Grafana’s stats for the *status.prod* fleet.) + +As a conclusion, the bottleneck is within the *Relay* protocol itself and not the underlying databases. Or, in other words, both *SQLite* and *Postgres* can support the maximum insert rate a Waku node will operate within normal conditions. + +### Query test results (jmeter) + +In this case, we are comparing *Store* performance by means of Rest service. + +**Scenario** + +- node_a: one _nwaku_ node with *Store* and connected to *Postgres.* +- node_b: one _nwaku_ node with *Store* and using *SQLite*. +- Both *Postgres* and *SQLite* contain +1 million rows. +- node_c: one _nwaku_ node with *REST* enabled and acting as a *Store client* for node_a. +- node_d: one _nwaku_ node with *REST* enabled and acting as a *Store client* for node_b. +- With _jmeter_, 10 users make *REST* *Store* requests concurrently to each of the “rest” nodes (node_c and node_d.) +- All _nwaku_ nodes running statusteam/nim-waku:v0.19.0 + +[This](https://github.com/waku-org/test-waku-query/blob/master/docker/jmeter/http_store_requests.jmx) is the _jmeter_ project used. + +![Using jmeter](imgs/using-jmeter.png) + +*Results* + +With this, the *node_b* brings a higher throughput than the *node_a* and that indicates that the node that uses SQLite performs better. The following shows the measures taken by _jmeter_ with regard to the REST requests. + +![jmeter results](imgs/jmeter-results.png) + +### Query test results (only Store protocol) + +In this test suite, only the Store protocol is being analyzed, i.e. without REST. For that, a go-waku node is used, which acts as *Store* client. On the other hand, we have another go-waku app that publishes random *Relay* messages periodically. Therefore, this can be considered a more realistic approach. + +The following diagram shows the topology used: + +![Topology](imgs/topology-only-store-protocol.png) + +For that, the next apps were used: + +1. [Waku-publisher.](https://github.com/alrevuelta/waku-publisher/tree/9fb206c14a17dd37d20a9120022e86475ce0503f) This app can publish Relay messages with different numbers of clients +2. [Waku-store-query-generator](https://github.com/Ivansete-status/waku-store-query-generator/tree/19e6455537b6d44199cf0c8558480af5c6788b0d). This app is based on the Waku-publisher but in this case, it can spawn concurrent go-waku Store clients. + +That topology is defined in [this](https://github.com/waku-org/test-waku-query/blob/7090cd125e739306357575730d0e54665c279670/docker/docker-compose-manual-binaries.yml) docker-compose file. + +Notice that the two `nwaku` nodes run the very same version, which is compiled locally. + +#### Comparing archive SQLite & Postgres performance in [nwaku-b6dd6899](https://github.com/waku-org/nwaku/tree/b6dd6899030ee628813dfd60ad1ad024345e7b41) + +The next results were obtained by running the docker-compose-manual-binaries.yml from [test-waku-query-c078075](https://github.com/waku-org/test-waku-query/tree/c07807597faa781ae6c8c32eefdf48ecac03a7ba) in the sandbox machine (metal-01.he-eu-hel1.misc.wakudev.status.im.) + +**Scenario 1** + +**Store rate:** 1 user generating 1 store-req/sec. + +**Relay rate:** 1 user generating 10msg/sec, 10KB each. + +In this case, we can see that the SQLite performance is better regarding the store requests. + +![Insert time distribution](imgs/insert-time-dist.png) + +![Query time distribution](imgs/query-time-dist.png) + +The following graph shows how the *SQLite* node has blocking periods whereas the *Postgres* always gives a steady rate. + +![Num queries per minute](imgs/num-queries-per-minute.png) + +**Scenario 2** + +**Store rate:** 10 users generating 1 store-req/sec. + +**Relay rate:** 1 user generating 10msg/sec, 10KB each. + +In this case, is more evident that the *SQLite* performs better. + +![Insert time distribution](imgs/insert-time-dist-2.png) + +![Query time distribution](imgs/query-time-dist-2.png) + +**Scenario 3** + +**Store rate:** 25 users generating 1 store-req/sec. + +**Relay rate:** 1 user generating 10msg/sec, 10KB each. + +In this case, the performance is similar regarding the timings. The store rate is bigger in *SQLite* and *Postgres* keeps the same level as in scenario 2. + +![Insert time distribution](imgs/insert-time-dist-3.png) + +![Query time distribution](imgs/query-time-dist-3.png) + +#### Comparing archive SQLite & Postgres performance in [nwaku-b452ed8](https://github.com/waku-org/nwaku/tree/b452ed865466a33b7f5b87fa937a8471b28e466e) + +This nwaku commit is after a few **Postgres** optimizations were applied. + +The next results were obtained by running the docker-compose-manual-binaries.yml from [test-waku-query-c078075](https://github.com/waku-org/test-waku-query/tree/c07807597faa781ae6c8c32eefdf48ecac03a7ba) in the sandbox machine (metal-01.he-eu-hel1.misc.wakudev.status.im.) + +**Scenario 1** + +**Store rate** 1 user generating 1 store-req/sec. Notice that the current Store query used generates pagination which provokes more subsequent queries than the 1 req/sec that would be expected without pagination. + +**Relay rate:** 1 user generating 10msg/sec, 10KB each. + +![Insert time distribution](imgs/insert-time-dist-4.png) + +![Query time distribution](imgs/query-time-dist-4.png) + +It cannot be appreciated but the average *****Store***** time was 11ms. + +**Scenario 2** + +**Store rate:** 10 users generating 1 store-req/sec. Notice that the current Store query used generates pagination which provokes more subsequent queries than the 10 req/sec that would be expected without pagination. + +**Relay rate:** 1 user generating 10msg/sec, 10KB each. + +![Insert time distribution](imgs/insert-time-dist-5.png) + +![Query time distribution](imgs/query-time-dist-5.png) + +**Scenario 3** + +**Store rate:** 25 users generating 1 store-req/sec. Notice that the current Store query used generates pagination which provokes more subsequent queries than the 25 req/sec that would be expected without pagination. + +**Relay rate:** 1 user generating 10msg/sec, 10KB each. + +![Insert time distribution](imgs/insert-time-dist-6.png) + +![Query time distribution](imgs/query-time-dist-6.png) + +#### Conclusions + +After comparing both systems, *SQLite* performs much better than *Postgres* However, a benefit of using *Postgres* is that it performs asynchronous operations, and therefore doesn’t consume CPU time that would be better invested in *Relay* for example. + +Remember that _nwaku_ is single-threaded and *chronos* performs orchestration among a bunch of async tasks, and therefore it is not a good practice to block the whole _nwaku_ process in a query, as happens with *SQLite* + +After applying a few *Postgres* enhancements, it can be noticed that the use of concurrent *Store* queries doesn’t go below the 250ms barrier. The reason for that is that most of the time is being consumed in [this point](https://github.com/waku-org/nwaku/blob/6da1aeec5370bb1c116509e770178cca2662b69c/waku/common/databases/db_postgres/dbconn.nim#L124). The `libpqisBusy()` function indicates that the connection is still busy even the queries finished. + +Notice that we usually have a rate below 1100 req/minute in _status.prod_ fleet (checked November 7, 2023.) + +----------------------------- + +### Multiple nodes & one single database + +This study aims to look for possible issues when having only one single database while several Waku nodes insert or retrieve data from it. +The following diagram shows the scenery used for such analysis. + +![digram_multiple_nodes_one_database](imgs/digram_multiple_nodes_one_database.png) + +There are three nim-waku nodes that are connected to the same database and all of them are trying to write messages to the same _PostgreSQL_ instance. With that, it is very common to see errors like: +``` +ERR 2023-11-27 13:18:07.575+00:00 failed to insert message topics="waku archive" tid=2921 file=archive.nim:111 err="error in runStmt: error in dbConnQueryPrepared calling waitQueryToFinish: error in query: ERROR: duplicate key value violates unique constraint \"messageindex\"\nDETAIL: Key (storedat, id, pubsubtopic)=(1701091087417938405, 479c95bbf74222417abf76c7f9c480a6790e454374dc4f59bbb15ca183ce1abd, /waku/2/default-waku/proto) already exists.\n +``` + +The `db-postgres-hammer` is aimed to stress the database from the `select` point of view. It performs `N` concurrent `select` queries with a certain rate. + +#### Results + +The following results were obtained by using the sandbox machine (metal-01.he-eu-hel1.misc.wakudev) and running nim-waku nodes from https://github.com/waku-org/nwaku/tree/b452ed865466a33b7f5b87fa937a8471b28e466e and using the `test-waku-query` project from https://github.com/waku-org/test-waku-query/tree/fef29cea182cc744c7940abc6c96d38a68739356 + +The following shows the results + +1. Two `nwaku-postgres-additional` inserting messages plus 50 `db-postgres-hammer` making 10 `selects` per second. + +![Insert time distribution Postgres](imgs/insert-time-dist-postgres.png) + +![Query time distribution Postgres](imgs/query-time-dist-postgres.png) + +2. Five `nwaku-postgres-additional` inserting messages plus 50 `db-postgres-hammer` making 10 `selects` per second. +![Insert time distribution Postgres](imgs/insert-time-dist-postgres-2.png) +![Query time distribution Postgres](imgs/query-time-dist-postgres-2.png) + +In this case, the insert time gets more spread because the insert operations are shared amongst five more nodes. The _Store_ query time remains the same on average. + +3. Five `nwaku-postgres-additional` inserting messages plus 100 `db-postgres-hammer` making 10 `selects` per second. +This case is similar to 2. but stressing more the database. +![Insert time distribution Postgres](imgs/insert-time-dist-postgres-3.png) +![Query time distribution Postgres](imgs/query-time-dist-postgres-3.png) diff --git a/docs/benchmarks/test-results-summary.md b/docs/benchmarks/test-results-summary.md new file mode 100644 index 0000000..b5786bf --- /dev/null +++ b/docs/benchmarks/test-results-summary.md @@ -0,0 +1,90 @@ +--- +title: Performance Benchmarks and Test Reports +--- + + +## Introduction +This page summarises key performance metrics for nwaku and provides links to detailed test reports. + +> ## TL;DR +> +> - Average Waku bandwidth usage: ~**10 KB/s** (minus discv5 Discovery) for 1KB message size and message injection rate of 1msg/s. +Confirmed for topologies of up to 2000 Relay nodes. +> - Average time for a message to propagate to 100% of nodes: **0.4s** for topologies of up to 2000 Relay nodes. +> - Average per-node bandwidth usage of the discv5 protocol: **8 KB/s** for incoming traffic and **7.4 KB/s** for outgoing traffic, + in a network with 100 continuously online nodes. +> - Future improvements: A messaging API is currently in development to streamline interactions with the Waku protocol suite. +Once completed, it will enable benchmarking at the messaging API level, allowing applications to more easily compare their +own performance results. + + +## Insights + +### Relay Bandwidth Usage: nwaku v0.34.0 +The average per-node `libp2p` bandwidth usage in a 1000-node Relay network with 1KB messages at varying injection rates. + + +| Message Injection Rate | Average libp2p incoming bandwidth (KB/s) | Average libp2p outgoing bandwidth (KB/s) | +|------------------------|------------------------------------------|------------------------------------------| +| 1 msg/s | ~10.1 | ~10.3 | +| 1 msg/10s | ~1.8 | ~1.9 | + +### Message Propagation Latency: nwaku v0.34.0-rc1 +The message propagation latency is measured as the total time for a message to reach all nodes. +We compare the latency in different network configurations for the following simulation parameters: +- Total messages published: 600 +- Message size: 1KB +- Message injection rate: 1msg/s + +The different network configurations tested are: +- Relay Config: 1000 nodes with relay enabled +- Mixed Config: 210 nodes, consisting of bootstrap nodes, filter clients and servers, lightpush clients and servers, store nodes +- Non-persistent Relay Config: 500 persistent relay nodes, 10 store nodes and 100 non-persistent relay nodes + +Click on a specific config to see the detailed test report. + +| Config | Average Message Propagation Latency (s) | Max Message Propagation Latency (s)| +|------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------|------------------------------------| +| [Relay](https://www.notion.so/Waku-regression-testing-v0-34-1618f96fb65c803bb7bad6ecd6bafff9) (1000 nodes) | 0.05 | 1.6 | +| [Mixed](https://www.notion.so/Mixed-environment-analysis-1688f96fb65c809eb235c59b97d6e15b) (210 nodes) | 0.0125 | 0.007 | +| [Non-persistent Relay](https://www.notion.so/High-Churn-Relay-Store-Reliability-16c8f96fb65c8008bacaf5e86881160c) (510 nodes)| 0.0125 | 0.25 | + +### Discv5 Bandwidth Usage: nwaku v0.34.0 +The average bandwidth usage of discv5 for a network of 100 nodes and message injection rate of 0 or 1msg/s. +The measurements are based on a stable network where all nodes have already connected to peers to form a healthy mesh. + +|Message size |Average discv5 incoming bandwidth (KB/s)|Average discv5 outgoing bandwidth (KB/s)| +|-------------------- |----------------------------------------|----------------------------------------| +| no message injection| 7.88 | 6.70 | +| 1KB | 8.04 | 7.40 | +| 10KB | 8.03 | 7.45 | + +## Testing +### DST +The VAC DST team performs regression testing on all new **nwaku** releases, comparing performance with previous versions. +They simulate large Waku networks with a variety of network and protocol configurations that are representative of real-world usage. + +**Test Reports**: [DST Reports](https://www.notion.so/DST-Reports-1228f96fb65c80729cd1d98a7496fe6f) + + +### QA +The VAC QA team performs interoperability tests for **nwaku** and **go-waku** using the latest main branch builds. +These tests run daily and verify protocol functionality by targeting specific features of each protocol. + +**Test Reports**: [QA Reports](https://discord.com/channels/1110799176264056863/1196933819614363678) + +### nwaku +The **nwaku** team follows a structured release procedure for all release candidates. +This involves deploying RCs to `status.staging` fleet for validation and performing sanity checks. + +**Release Process**: [nwaku Release Procedure](https://github.com/waku-org/nwaku/blob/master/.github/ISSUE_TEMPLATE/prepare_release.md) + + +### Research +The Waku Research team conducts a variety of benchmarking, performance testing, proof-of-concept validations and debugging efforts. +They also maintain a Waku simulator designed for small-scale, single-purpose, on-demand testing. + + +**Test Reports**: [Waku Research Reports](https://www.notion.so/Miscellaneous-2c02516248db4a28ba8cb2797a40d1bb) + +**Waku Simulator**: [Waku Simulator Book](https://waku-org.github.io/waku-simulator/) diff --git a/docs/contributors/README.md b/docs/contributors/README.md new file mode 100644 index 0000000..9f76cd7 --- /dev/null +++ b/docs/contributors/README.md @@ -0,0 +1,11 @@ +# Contributors + +This folder contains documentation that is primarily useful for contributors. Some links and +resources here might require privileged access. + +Example resources: + +- How to do releases +- Viewing and modifying metrics dashboard +- Continuous integration process +- How to view Status cluster logs diff --git a/docs/contributors/cluster-logs.md b/docs/contributors/cluster-logs.md new file mode 100644 index 0000000..3e21c83 --- /dev/null +++ b/docs/contributors/cluster-logs.md @@ -0,0 +1,11 @@ +# Cluster node logs + +These can be found in [Kibana](https://kibana.infra.status.im/goto/a3793b50-489d-11ed-a791-f14ad382fa11). + +Login with Github. For access issues, contact devops. + +Modify search field and time window as appropriate. + +Notice that there are two clusters, test and production. There is also a Waku v1 cluster. + + diff --git a/docs/contributors/continuous-integration.md b/docs/contributors/continuous-integration.md new file mode 100644 index 0000000..1c5fa56 --- /dev/null +++ b/docs/contributors/continuous-integration.md @@ -0,0 +1,32 @@ +# Description + +This document describes the continuous integration setup for `nim-waku`. + +# Details + +The CI setup exists on the Status.im Jenkins instance: + +https://ci.infra.status.im/job/nim-waku/ + +It currently consists of four jobs: + +* [manual](https://ci.infra.status.im/job/nim-waku/job/manual/) - For manually executing builds using parameters. +* [deploy-waku-test](https://ci.infra.status.im/job/nim-waku/job/deploy-waku-test/) - Builds every new commit in `master` and deploys to `waku.test` fleet. +* [deploy-waku-sandbox](https://ci.infra.status.im/job/nim-waku/job/deploy-waku-sandbox/) - Currently has no automatic trigger, and deploys to `waku.sandbox` fleet. + +# Configuration + +The main configuration file is [`Jenkinsfile.release`](../../ci/Jenkinsfile.release) in the `ci` folder. + +Key part is the definition of five `parameters`: + +* `MAKE_TARGET` - Which `Makefile` target is built. +* `IMAGE_TAG` - Tag of the Docker image to push. +* `IMAGE_NAME` - Name of the Docker image to push. +* `NIMFLAGS` - Nim compilation parameters. +* `GIT_REF` - Git reference to build from (branch, tag, commit...) + +The use of `?:` [Elvis operator](http://groovy-lang.org/operators.html#_elvis_operator) plays a key role in allowing parameters to be changed for each defined job in Jenkins without it being overridden by the `Jenkinsfile` defaults after every job run. +```groovy +defaultValue: params.IMAGE_TAG ?: 'deploy-waku-test', +``` diff --git a/docs/contributors/git-submodules.md b/docs/contributors/git-submodules.md new file mode 100644 index 0000000..52336e2 --- /dev/null +++ b/docs/contributors/git-submodules.md @@ -0,0 +1,10 @@ +# Submodules + +We use Git submodules in the `vendor` directory to track internal Nim +dependencies. We want to update submodules all at once to avoid issues. + +``` +git submodule foreach --recursive git submodule update --init +git submodule update --remote +``` + diff --git a/docs/contributors/nph.md b/docs/contributors/nph.md new file mode 100644 index 0000000..91f4149 --- /dev/null +++ b/docs/contributors/nph.md @@ -0,0 +1,34 @@ + +## nph - An opinionated Nim formatter +This prettifier tool is used to format the nwaku code base. + +### VSCode Extension +https://marketplace.visualstudio.com/items?itemName=arnetheduck.vscode-nph + +### GitHub +https://github.com/arnetheduck/nph + +Make sure you use a binary from the following release: +https://github.com/arnetheduck/nph/releases/tag/v0.5.1 + +```bash +$ nph --version +v0.5.1-0-gde5cd48 +``` + +### Installation and configuration +1. Ask the [nwaku team](https://discord.com/channels/1110799176264056863/1111541184490393691) about the required `nph` version. +2. Download the desired release from _GitHub_ and place the binary in the PATH env var. +3. Add the following content into `~/.config/Code/User/settings.json`: + +``` +{ + "[nim]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "arnetheduck.vscode-nph" + }, +} +``` + +With that, every time a Nim file is saved, it will be formatted automatically. + diff --git a/docs/contributors/release-process.md b/docs/contributors/release-process.md new file mode 100644 index 0000000..c0fb12d --- /dev/null +++ b/docs/contributors/release-process.md @@ -0,0 +1,119 @@ +# Release Process + +How to do releases. + +For more context, see https://trunkbaseddevelopment.com/branch-for-release/ + +## How to do releases + +### Before release + +Ensure all items in this list are ticked: +- [ ] All issues under the corresponding release [milestone](https://github.com/waku-org/nwaku/milestones) has been closed or, after consultation, deferred to a next release. +- [ ] All submodules are up to date. + > **IMPORTANT:** Updating submodules requires a PR (and very often several "fixes" to maintain compatibility with the changes in submodules). That PR process must be done and merged a couple of days before the release. + > In case the submodules update has a low effort and/or risk for the release, follow the ["Update submodules"](./git-submodules.md) instructions. + > If the effort or risk is too high, consider postponing the submodules upgrade for the subsequent release or delaying the current release until the submodules updates are included in the release candidate. +- [ ] The [js-waku CI tests](https://github.com/waku-org/js-waku/actions/workflows/ci.yml) pass against the release candidate (i.e. nwaku latest `master`). + > **NOTE:** This serves as a basic regression test against typical clients of nwaku. + > The specific job that needs to pass is named `node_with_nwaku_master`. + +### Performing the release + +1. Checkout a release branch from master + + ``` + git checkout -b release/v0.1.0 + ``` + +1. Update `CHANGELOG.md` and ensure it is up to date. Use the helper Make target to get PR based release-notes/changelog update. + + ``` + make release-notes + ``` + +1. Create a release-candidate tag with the same name as release and `-rc.N` suffix a few days before the official release and push it + + ``` + git tag -as v0.1.0-rc.0 -m "Initial release." + git push origin v0.1.0-rc.0 + ``` + + This will trigger a [workflow](../../.github/workflows/pre-release.yml) which will build RC artifacts and create and publish a Github release + +1. Open a PR from the release branch for others to review the included changes and the release-notes + +1. In case additional changes are needed, create a new RC tag + + Make sure the new tag is associated + with CHANGELOG update. + + ``` + # Make changes, rebase and create new tag + # Squash to one commit and make a nice commit message + git rebase -i origin/master + git tag -as v0.1.0-rc.1 -m "Initial release." + git push origin v0.1.0-rc.1 + ``` + +1. Validate the release. For the release validation process, please refer to the following [guide](https://www.notion.so/Release-Process-61234f335b904cd0943a5033ed8f42b4#47af557e7f9744c68fdbe5240bf93ca9) + +1. Once the release-candidate has been validated, create a final release tag and push it. +We also need to merge release branch back to master as a final step. + + ``` + git checkout release/v0.1.0 + git tag -as v0.1.0 -m "Initial release." + git push origin v0.1.0 + git switch master + git pull + git merge release/v0.1.0 + ``` + +1. Create a [Github release](https://github.com/waku-org/nwaku/releases) from the release tag. + + * Add binaries produced by the ["Upload Release Asset"](https://github.com/waku-org/nwaku/actions/workflows/release-assets.yml) workflow. Where possible, test the binaries before uploading to the release. + +### After the release + +1. Announce the release on Twitter, Discord and other channels. +2. Deploy the release image to [Dockerhub](https://hub.docker.com/r/wakuorg/nwaku) by triggering [the manual Jenkins deployment job](https://ci.infra.status.im/job/nim-waku/job/docker-manual/). + > Ensure the following build parameters are set: + > - `MAKE_TARGET`: `wakunode2` + > - `IMAGE_TAG`: the release tag (e.g. `v0.16.0`) + > - `IMAGE_NAME`: `wakuorg/nwaku` + > - `NIMFLAGS`: `--colors:off -d:disableMarchNative -d:chronicles_colors:none -d:postgres` + > - `GIT_REF` the release tag (e.g. `v0.16.0`) +3. Update the default nwaku image in [nwaku-compose](https://github.com/waku-org/nwaku-compose/blob/master/docker-compose.yml) +4. Deploy the release to appropriate fleets: + - Inform clients + > **NOTE:** known clients are currently using some version of js-waku, go-waku, nwaku or waku-rs. + > Clients are reachable via the corresponding channels on the Vac Discord server. + > It should be enough to inform clients on the `#nwaku` and `#announce` channels on Discord. + > Informal conversations with specific repo maintainers are often part of this process. + - Check if nwaku configuration parameters changed. If so [update fleet configuration](https://www.notion.so/Fleet-Ownership-7532aad8896d46599abac3c274189741?pvs=4#d2d2f0fe4b3c429fbd860a1d64f89a64) in [infra-nim-waku](https://github.com/status-im/infra-nim-waku) + - Deploy release to the `waku.sandbox` fleet from [Jenkins](https://ci.infra.status.im/job/nim-waku/job/deploy-waku-sandbox/). + - Ensure that nodes successfully start up and monitor health using [Grafana](https://grafana.infra.status.im/d/qrp_ZCTGz/nim-waku-v2?orgId=1) and [Kibana](https://kibana.infra.status.im/goto/a7728e70-eb26-11ec-81d1-210eb3022c76). + - If necessary, revert by deploying the previous release. Download logs and open a bug report issue. +5. Submit a PR to merge the release branch back to `master`. Make sure you use the option `Merge pull request (Create a merge commit)` to perform such merge. + +### Performing a patch release + +1. Cherry-pick the relevant commits from master to the release branch + + ``` + git cherry-pick + ``` + +2. Create a release-candidate tag with the same name as release and `-rc.N` suffix + +3. Update `CHANGELOG.md`. From the release branch, use the helper Make target after having cherry-picked the commits. + + ``` + make release-notes + ``` + Create a new branch and raise a PR with the changelog updates to master. + +4. Once the release-candidate has been validated and changelog PR got merged, cherry-pick the changelog update from master to the release branch. Create a final release tag and push it. + +5. Create a [Github release](https://github.com/waku-org/nwaku/releases) from the release tag and follow the same post-release process as usual. diff --git a/docs/contributors/waku-fleets.md b/docs/contributors/waku-fleets.md new file mode 100644 index 0000000..659d855 --- /dev/null +++ b/docs/contributors/waku-fleets.md @@ -0,0 +1,107 @@ +# Waku fleet: management & monitoring + +## Background + +Status currently maintains two fleets for `nwaku` nodes, +the `waku.test` fleet and the `waku.sandbox` (sandbox) fleet. +They'll be referred to as `test` and `sandbox` in this document. +Status fleet nodes and addresses can be viewed [here](https://fleets.status.im/). + +### Fleet overview + +At the time of writing this, each fleet consists of three waku nodes, +with a [websockify](https://github.com/novnc/websockify) WebSocket-to-TCP bridge for each node. +Waku peers can choose to connect either directly to a node's TCP endpoint +or the bridged WebSocket depending on their own supported transports. +The `sandbox` fleet also has a deployed [`chat2bridge`](https://github.com/waku-org/nwaku/blob/master/docs/tutorial/chat2.md#bridge-messages-between-chat2-and-matterbridge), +which serves as a bridge between the [Waku toy-chat](https://rfc.vac.dev/spec/22/) and Matterbridge. +The `chat2bridge` is currently deployed to the `node-01.do-ams3` datacentre +and configured to bridge toy-chat messages to the `#waku channel` on the Vac Discord Server. + +### Fleet deployment rationale + +The `test` fleet is automatically updated after every commit to the `nwaku` repository `master` branch and is therefore the most up to date representation of Waku development. +It is suitable for testing new features before they're rolled out to the (more) stable `sandbox` fleet. + +In general only the latest release of `nwaku` is deployed to the `sandbox` fleet. +It requires manual updating and should therefore be more stable than `test`. +See the [section on Jenkins](#jenkins-for-deployment) below for more on the deployment process. + +### Related repos + +The [`infra-docs` repo](https://github.com/status-im/infra-docs) contains the most comprehensive overview of Status infrastructure. +This is a private repository. +Feel free to contact someone in the team to request access. + +The [`infra-nim-waku` repo](https://github.com/status-im/infra-nim-waku) contains the infrastructure definitions for Waku nodes implemented in Nim. + +## Monitoring and management + +The rest of this document highlights some infra services of specific interest to Waku fleet monitoring and management: + +1. [Consul](https://consul.infra.status.im/ui/do-ams3/services?filter=nim-waku) to view the health status of Waku nodes. +2. [Kibana](https://kibana.infra.status.im/app/discover#/) to view and filter logs. +3. [Grafana](https://grafana.infra.status.im/d/qrp_ZCTGz/nim-waku-v2) to view and filter metrics. +4. [Jenkins](https://ci.infra.status.im/job/nim-waku/) to configure and deploy new builds to the fleets. + +### 1. [Consul](https://consul.infra.status.im/ui/do-ams3/services?filter=nim-waku) for health checks + +Consul provides a useful high-level view of the health of the `nwaku` fleets. +It aggregates the result of various monitoring checks +and shows the health status for the node itself, the RPC API, exposed WebSocket and metrics. +The datacentre can be changed in the upper left-hand corner. + +### 2. [Kibana](https://kibana.infra.status.im/app/discover#/) for logs + +Kibana is a powerful visualisation tool for Elasticsearch data. +For Waku fleets it can be used to retrieve, filter and view the logs for all deployed services. +For example, to view the latest logs for `sandbox`, +Kibana can be opened in "Discover" mode with an [active filter for `fleet: waku.sandbox`](https://kibana.infra.status.im/goto/c0434f60-ca82-11ee-aaa4-85391103106b). + +### 3. [Grafana](https://grafana.infra.status.im/d/qrp_ZCTGz/nim-waku-v2?orgId=1&refresh=5m) for metrics + +The `Nim-Waku` Grafana dashboard displays live and historical metrics for Waku nodes. +The default view includes metrics from both fleets, +though it's possible to filter by `Hostname`, `Fleet name` or `Data Center`. +The time range can also be configured - +by default the latest metrics will be shown. + +The dashboard itself includes an _"At a glance"_ summary +with an overview of the latest connected peers, total messages, CPU usage, reported errors, etc. +The _"General"_ collection contains a more in-depth look at node, libp2p and performance-related metrics. +This is followed by separate panel collections showing _per-protocol_ metrics. + +A copy of the `Nim-Waku` fleets dashboard is maintained in the [`nwaku` repo](https://github.com/waku-org/nwaku/blob/master/metrics/waku-fleet-dashboard.json). +From time to time certain Prometheus queries may fail, +often when the underlying metrics are renamed. +Please report any broken panels via our Discord channels or by [creating an issue in `nwaku`](https://github.com/waku-org/nwaku/issues/new). + +### 4. [Jenkins](https://ci.status.im/job/nim-waku/) for deployment + +The [`nim-waku` jobs](https://ci.infra.status.im/job/nim-waku/) on Jenkins are configured to deploy `nwaku` builds to the fleets. +1. [`deploy-waku-test`](https://ci.infra.status.im/job/nim-waku/job/deploy-waku-test/) is triggered automatically after every commit to the `nwaku` `master` branch. +2. [`deploy-waku-sandbox`](https://ci.infra.status.im/job/nim-waku/job/deploy-waku-sandbox/) must be triggered manually. Usually this job is only built after a tagged release in `nwaku`. + +Each job can be manually triggered using the _"Build with Parameters"_ option. +Options under _"Configure"_ include the build triggers, build target and branches to build. +These should only be changed with care. + +See [Continuous Integration docs](https://github.com/waku-org/nwaku/blob/master/docs/contributors/continuous-integration.md) for more. + +## Quick links + + 1. [`chat2bridge`](https://github.com/waku-org/nwaku/blob/master/docs/tutorial/chat2.md#bridge-messages-between-chat2-and-matterbridge) + 2. [Consul for do-ams3](https://consul.infra.status.im/ui/do-ams3/services?filter=nim-waku) + 3. [Consul for ac-cn-hongkong-c](https://consul.infra.status.im/ui/ac-cn-hongkong-c/services?filter=nim-waku) + 4. [Consul for gc-us-central1-a](https://consul.infra.status.im/ui/gc-us-central1-a/services?filter=nim-waku) + 5. [Grafana Nim-Waku dashboard](https://grafana.infra.status.im/d/qrp_ZCTGz/nim-waku-v2?orgId=1&refresh=5m) + 6. [`infra-docs` repo](https://github.com/status-im/infra-docs) + 7. [`infra-waku` repo](https://github.com/status-im/infra-waku) + 8. [Jenkins jobs for `nim-waku`](https://ci.infra.status.im/job/nim-waku/) + 9. [Jenkins deploy-waku-sandbox manual trigger](https://ci.infra.status.im/job/nim-waku/job/deploy-waku-sandbox/build) + 10. [Jenkins deploy-waku-test manual trigger](https://ci.infra.status.im/job/nim-waku/job/deploy-waku-test/build) + 11. [Kibana logs for `sandbox`](https://kibana.infra.status.im/goto/c0434f60-ca82-11ee-aaa4-85391103106b) + 12. [Kibana logs for `test`](https://kibana.infra.status.im/goto/7cd22f20-ca83-11ee-aaa4-85391103106b) + 13. [Status fleets](https://fleets.status.im/) + 14. [Status fleets - Table](https://fleets.waku.org) + 15. [Websockify](https://github.com/novnc/websockify) diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 0000000..40a189c --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,34 @@ +# FAQ + +## How do I see what address a node is listening for? + +Grep for "Listening on". It should be printed at INFO level at the beginning. E.g. from Kibana: + +`Oct 7, 2020 @ 23:17:00.383INF 2020-10-07 23:17:00.375+00:00 Listening on topics="wakunode" tid=1 file=wakunode2.nim:140 full=/ip4/0.0.0.0/tcp/60000/p2p/16Uiu2HAkzHaTP5JsUwfR9NR8Rj9HC24puS6ocaU8wze4QrXr9iXp` + +## How do I find out node addresses at the test cluster? + +The easiest way is to use `jq` and query the fleets registry that Status operates: + +``` +curl -s https://fleets.status.im | jq '.fleets["waku.test"]' + +# Output +{ + "tcp/p2p/waku": { + "node-01.do-ams3.waku.test": "/dns4/node-01.do-ams3.waku.test.status.im/tcp/30303/p2p/16Uiu2HAkykgaECHswi3YKJ5dMLbq2kPVCo89fcyTd38UcQD6ej5W", + "node-01.gc-us-central1-a.waku.test": "/dns4/node-01.gc-us-central1-a.waku.test.status.im/tcp/30303/p2p/16Uiu2HAmDCp8XJ9z1ev18zuv8NHekAsjNyezAvmMfFEJkiharitG", + "node-01.ac-cn-hongkong-c.waku.test": "/dns4/node-01.ac-cn-hongkong-c.waku.test.status.im/tcp/30303/p2p/16Uiu2HAkzHaTP5JsUwfR9NR8Rj9HC24puS6ocaU8wze4QrXr9iXp" + }, + "enr/p2p/waku": { + "node-01.do-ams3.waku.test": "enr:-QESuEC1p_s3xJzAC_XlOuuNrhVUETmfhbm1wxRGis0f7DlqGSw2FM-p2Ugl_r25UHQJ3f1rIRrpzxJXSMaJe4yk1XFSAYJpZIJ2NIJpcISygI2rim11bHRpYWRkcnO4XAArNiZub2RlLTAxLmRvLWFtczMud2FrdS50ZXN0LnN0YXR1c2ltLm5ldAZ2XwAtNiZub2RlLTAxLmRvLWFtczMud2FrdS50ZXN0LnN0YXR1c2ltLm5ldAYfQN4DgnJzkwABCAAAAAEAAgADAAQABQAGAAeJc2VjcDI1NmsxoQJATXRSRSUyTw_QLB6H_U3oziVQgNRgrXpK7wp2AMyNxYN0Y3CCdl-DdWRwgiMohXdha3UyDw", + "node-01.gc-us-central1-a.waku.test": "enr:-QEkuECnZ3IbVAgkOzv-QLnKC4dRKAPRY80m1-R7G8jZ7yfT3ipEfBrhKN7ARcQgQ-vg-h40AQzyvAkPYlHPaFKk6u9uAYJpZIJ2NIJpcIQiEAFDim11bHRpYWRkcnO4bgA0Ni9ub2RlLTAxLmdjLXVzLWNlbnRyYWwxLWEud2FrdS50ZXN0LnN0YXR1c2ltLm5ldAZ2XwA2Ni9ub2RlLTAxLmdjLXVzLWNlbnRyYWwxLWEud2FrdS50ZXN0LnN0YXR1c2ltLm5ldAYfQN4DgnJzkwABCAAAAAEAAgADAAQABQAGAAeJc2VjcDI1NmsxoQMIJwesBVgUiBCi8yiXGx7RWylBQkYm1U9dvEy-neLG2YN0Y3CCdl-DdWRwgiMohXdha3UyDw", + "node-01.ac-cn-hongkong-c.waku.test": "enr:-QEkuEDzQyIAhs-CgBHIrJqtBv3EY1uP1Psrc-y8yJKsmxW7dh3DNcq2ergMUWSFVcJNlfcgBeVsFPkgd_QopRIiCV2pAYJpZIJ2NIJpcIQI2ttrim11bHRpYWRkcnO4bgA0Ni9ub2RlLTAxLmFjLWNuLWhvbmdrb25nLWMud2FrdS50ZXN0LnN0YXR1c2ltLm5ldAZ2XwA2Ni9ub2RlLTAxLmFjLWNuLWhvbmdrb25nLWMud2FrdS50ZXN0LnN0YXR1c2ltLm5ldAYfQN4DgnJzkwABCAAAAAEAAgADAAQABQAGAAeJc2VjcDI1NmsxoQJIN4qwz3v4r2Q8Bv8zZD0eqBcKw6bdLvdkV7-JLjqIj4N0Y3CCdl-DdWRwgiMohXdha3UyDw" + }, + "wss/p2p/waku": { + "node-01.do-ams3.waku.test": "/dns4/node-01.do-ams3.waku.test.status.im/tcp/8000/wss/p2p/16Uiu2HAkykgaECHswi3YKJ5dMLbq2kPVCo89fcyTd38UcQD6ej5W", + "node-01.gc-us-central1-a.waku.test": "/dns4/node-01.gc-us-central1-a.waku.test.status.im/tcp/8000/wss/p2p/16Uiu2HAmDCp8XJ9z1ev18zuv8NHekAsjNyezAvmMfFEJkiharitG", + "node-01.ac-cn-hongkong-c.waku.test": "/dns4/node-01.ac-cn-hongkong-c.waku.test.status.im/tcp/8000/wss/p2p/16Uiu2HAkzHaTP5JsUwfR9NR8Rj9HC24puS6ocaU8wze4QrXr9iXp" + } +} +``` diff --git a/docs/operators/README.md b/docs/operators/README.md new file mode 100644 index 0000000..5850977 --- /dev/null +++ b/docs/operators/README.md @@ -0,0 +1,35 @@ +# The nwaku guide for operators + +*If you're eager to get started, check out our [quickstart guide](./quickstart.md) for typical configurations or [step-by-step overview](./overview.md) for newcomers.* + +Nwaku is a client implementation in Nim of the [Waku v2 family of protocols](https://rfc.vac.dev/spec/10/) for peer-to-peer communication. +The protocols are designed to be secure, privacy-preserving, censorship-resistant and able to run in resource restricted environments. +Moreover, we've taken a modular approach so that node operators can choose which protocols they want to support +based on their own motivations and availability of resources. +We call this concept ["adaptive nodes"](https://rfc.vac.dev/spec/30/), +implying that a Waku v2 network can consist of heterogeneous nodes contributing at different levels to the network. + +Nwaku (formerly `nim-waku`) aims to be a lightweight and robust Waku v2 client. +It serves as the reference implementation for researchers, +who extend the client in parallel to spec development. +As such, it is first in line to support innovative and new Waku v2 protocols, +but configurable enough to serve the adaptive needs of various operators. +We are also developing a set of operator-focused tools to monitor and maintain a running nwaku node. + +This guide provides step-by-step tutorials covering how to build and configure your own nwaku node, +connect to an existing Waku v2 network +and use existing tools for monitoring and maintaining a running node. + +## Helpful resources + + + +## Getting in touch or reporting an issue + +For an inquiry, or if you would like to propose new features, feel free to [open a general issue](https://github.com/waku-org/nwaku/issues/new/). + +For bug reports, please [tag your issue with the `bug` label](https://github.com/waku-org/nwaku/issues/new/). + +If you believe the reported issue requires critical attention, please [use the `critical` label](https://github.com/waku-org/nwaku/issues/new?labels=critical,bug) to assist with triaging. + +To get help, or participate in the conversation, join the [Vac Discord](https://discord.gg/KNj3ctuZvZ) server. diff --git a/docs/operators/docker-quickstart.md b/docs/operators/docker-quickstart.md new file mode 100644 index 0000000..0907772 --- /dev/null +++ b/docs/operators/docker-quickstart.md @@ -0,0 +1,79 @@ +# Quickstart: running nwaku in a Docker container + +This guide explains how to run a nwaku node in a Docker container. + +## Prerequisites + +Make sure you have Docker installed. +Installation instructions for different platforms can be found in the [Docker docs](https://docs.docker.com/engine/install/). + +For example, to use Docker's convenience script for installation: + +```bash +curl -fsSL https://get.docker.com -o get-docker.sh +sudo sh get-docker.sh +``` + +## Step 1: Get Docker image + +Nwaku Docker images are published to the Docker Hub public registry under [`wakuorg/nwaku`](https://hub.docker.com/r/wakuorg/nwaku). +For specific releases the published images are tagged with the release version, e.g. [`wakuorg/nwaku:v0.20.0`](https://hub.docker.com/layers/wakuorg/nwaku/v0.20.0/images/sha256-9976ac2dc536fae49b21f7b77618aa6f0efb59c694e7b3181e54c08be0c4f089?context=explore). +Images are also published for each commit to the `master` branch in the [nwaku repo](https://github.com/status-im/nwaku/commits/master) +and tagged with the corresponding commit hash. +See [`wakuorg/nwaku`](https://hub.docker.com/r/wakuorg/nwaku/tags) on Docker Hub for a full list of available tags. + +To pull the image of your choice, use + +```bash +docker pull wakuorg/nwaku:v0.20.0 # or, whichever tag you prefer in the format wakuorg/nwaku:[tag] +``` + +You can also build the Docker image locally using + +```bash +git clone --recurse-submodules https://github.com/waku-org/nwaku +cd nwaku +docker build -t wakuorg/nwaku:latest . +``` + +## Step 2: Run + +To run nwaku in a new Docker container, +use the following command: + +```bash +docker run [OPTIONS] IMAGE [ARG...] +``` + +where `OPTIONS` are your selected Docker options, +`IMAGE` the image and tag you pulled from the registry or built in Step 1 +and `ARG...` the list of nwaku arguments for your [chosen nwaku configuration](./how-to/configure.md). + +For Docker options we recommend explicit port mappings (`-p`) at least +for your exposed libp2p listening ports +and any discovery ports (e.g. the Waku discv5 port) that must be reachable from outside the host. + +As an example, consider the following command to run nwaku in a Docker container with the most typical configuration: + +```bash +docker run -i -t -p 60000:60000 -p 9000:9000/udp wakuorg/nwaku:v0.20.0 \ + --dns-discovery:true \ + --dns-discovery-url:enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im \ + --discv5-discovery \ + --nat:extip:[yourpublicip] # or, if you are behind a nat: --nat=any +``` + +This runs nwaku in a new container from the `wakuorg/nwaku:v0.20.0` image, +connects to `wakuv.sandbox` as bootstrap fleet and +enables [Waku Discovery v5](https://rfc.vac.dev/spec/33/) for ambient peer discovery, +while mapping the default libp2p listening port (`60000`) +and default discv5 UDP port (`9000`) to the host. + +> **Tip:** The `docker run` command will pull the specified image from Docker Hub if it's not yet available locally, +so it's possible to skip Step 1 and pull the image from your configured registry automatically when running. + +If you've used the `-i` and `-t` Docker options when running the new container, +the `run` command would have allocated an interactive terminal +where you'll see the `stdout` logs from the running nwaku process. +To detach gracefully from the running container, +use `Ctrl-P` followed by `Ctrl-Q`. diff --git a/docs/operators/droplet-quickstart.md b/docs/operators/droplet-quickstart.md new file mode 100644 index 0000000..070cf6d --- /dev/null +++ b/docs/operators/droplet-quickstart.md @@ -0,0 +1,305 @@ +# Quickstart for running nwaku on a DigitalOcean Droplet + +This guide explains how to run a nwaku node on a +DigitalOcean Droplet. We enable the following protocols - + +1. Relay +2. Store +3. DNS Discovery +4. Discv5 + +A Droplet is a simple virtual machine that runs in DigitalOcean's datacenters. + +Note that Droplets do cost money, the size described in the guide costs approximately $12 a month. + +The guide makes heavy use of the `doctl` cli to make it as UI agnostic as possible. +There are similar steps to accomplish the same through DigitalOcean's cloud console, accessible [here](https://cloud.digitalocean.com/) + +## Prerequisites + +1. A DigitalOcean account. Upon signing up, you have $100 worth of credits to use. + + + +## 1. Get the `doctl` binary + +Follow this [guide](https://docs.digitalocean.com/reference/doctl/how-to/install/) to install, +and configure the `doctl` cli, which will help with setting up the Droplet. + +> Note: It is not required to set up the droplet that is mentioned in the `doctl` cli guide + +## 2. Set up SSH credentials + +Run the following command - +```bash +export DROPLET_SSH_KEY_PATH=~/.ssh/id_nwaku_droplet +ssh-keygen -f $DROPLET_SSH_KEY_PATH +``` + +Press `enter` twice, i.e do NOT set a passphrase. + +Run the following command - +```bash +export DROPLET_SSH_PUBLIC_KEY=$(cat "$DROPLET_SSH_KEY_PATH".pub) +``` + +*Alternatively*, if you would like to supply your own credentials, make sure that the public key is in the `DROPLET_SSH_PUBLIC_KEY` env variable. + + +Lastly, add the ssh key to your DigitalOcean account - +```bash +doctl compute ssh-key create nwaku-key --public-key="$DROPLET_SSH_PUBLIC_KEY" +``` + +## 3. Select the region closest to you + +Run the following command to get the list of available +regions - + +```bash +doctl compute region list | grep true +``` + +You should get an output similar to this - + +```bash +nyc1 New York 1 true +sgp1 Singapore 1 true +lon1 London 1 true +nyc3 New York 3 true +ams3 Amsterdam 3 true +fra1 Frankfurt 1 true +tor1 Toronto 1 true +blr1 Bangalore 1 true +sfo3 San Francisco 3 true +``` +Choose the region closest to you, and run the following command - + +```bash +export DROPLET_REGION= +``` + +For example, if you live in NYC - +```bash +export DROPLET_REGION=nyc1 +``` + +Note that it is *optional* to choose the datacenter closest to you. This is merely done for operational efficiency. + +## 4. Select the OS distribution + +Run the following command to get the list of distributions - + +```bash +doctl compute image list-distribution +``` + +You should get an output similar to this - + +```bash +ID Name Type Distribution Slug Public Min Disk +78547182 1.5.8 x64 snapshot RancherOS rancheros true 15 +106433672 7 x64 snapshot CentOS centos-7-x64 true 9 +106434098 9 Stream x64 snapshot CentOS centos-stream-9-x64 true 10 +106434191 8 Stream x64 snapshot CentOS centos-stream-8-x64 true 10 +... +``` + +Choose the distribution you are most comfortable with, and then run the following command + +```bash +export DROPLET_IMAGE= +``` + +For example, if you chose Debian 11 x64 - + +```bash +export DROPLET_IMAGE=debian-11-x64 +``` + +## 5. Select the size of the Droplet + +Run the following command to get the list of Droplet sizes for the previously selected region - + +```bash +doctl compute size list +``` + +You should get an output similar to this - +```bash +Slug Description Memory VCPUs Disk Price Monthly Price Hourly +s-1vcpu-512mb-10gb Basic 512 1 10 4.00 0.005950 +s-1vcpu-1gb Basic 1024 1 25 6.00 0.008930 +s-1vcpu-1gb-amd Basic AMD 1024 1 25 7.00 0.010420 +s-1vcpu-1gb-intel Basic Intel 1024 1 25 7.00 0.010420 +s-1vcpu-2gb Basic 2048 1 50 12.00 0.017860 +s-1vcpu-2gb-amd Basic AMD 2048 1 50 14.00 0.020830 +s-1vcpu-2gb-intel Basic Intel 2048 1 50 14.00 0.020830 +s-2vcpu-2gb Legacy Basic 2048 2 60 18.00 0.026790 +... +``` + +> Note: To compile the nwaku binary, a minimum of 2GB of RAM is required. You may choose a smaller Droplet, however, you would have to supply the binary in an alternate manner, i.e via the official release on Github, or compiling it on another machine and copying it over. Currently, we only supply binaries for macOS and Ubuntu. + +Choose the Droplet size that you are most comfortable with, and then run the following command - + +```bash +export DROPLET_SIZE= +``` + +For example, `s-1vcpu-2gb` is more than capable to handle the protocols we mentioned above - + +```bash +export DROPLET_SIZE=s-1vcpu-2gb +``` + +## 6. Create the Droplet + +Run the following command to create the droplet - + +> Note: Droplet names must be valid hostnames, i.e they must only contain alphanumeric characters and hyphens (-) + +```bash +export DROPLET_NAME= +export DROPLET_ID=$(doctl compute droplet create --region=$DROPLET_REGION --image=$DROPLET_IMAGE --size=$DROPLET_SIZE --enable-monitoring --format=ID --wait $DROPLET_NAME | sed -n '2 p') +``` + +For example, to create a droplet named `nwaku` - + +```bash +export DROPLET_NAME=nwaku +export DROPLET_ID=$(doctl compute droplet create --region=$DROPLET_REGION --image=$DROPLET_IMAGE --size=$DROPLET_SIZE --enable-monitoring --format=ID --wait $DROPLET_NAME | sed -n '2 p') +``` + +## 7. Create a Domain and attach it to the droplet (OPTIONAL) + +Follow this [guide](https://docs.digitalocean.com/products/networking/dns/how-to/add-domains/) to create a domain, and add it to the droplet appropriately. + +## 8. SSH into the Droplet + +You can get the following details in the email that DigitalOcean sends upon successful creation of the Droplet - + +1. username +2. password +3. public ipv4 address + +Since the public key we previously generated was automatically added to the authorized_keys list, we can run the following command to ssh into the Droplet - + +```bash +export DROPLET_USERNAME= +export DROPLET_IP= +ssh -i $DROPLET_SSH_KEY_PATH $DROPLET_USERNAME@$DROPLET_IP +``` + +For example, if the username was `root`, and the ipv4 address was `0.0.0.0`, + +```bash +export USERNAME=root +export IP=0.0.0.0 +ssh -i $DROPLET_SSH_KEY_PATH $DROPLET_USERNAME@$DROPLET_IP +``` + +Enter the password received in the email. + +## 9. Build nwaku + +To build `nwaku`, follow this [guide](./how-to/build.md) + +OR + +To fetch the latest release from Github, navigate to https://github.com/status-im/nwaku/releases and download the latest tarball for your distribution. + +This [guide](https://www.itprotoday.com/development-techniques-and-management/how-install-targz-file-ubuntu-linux) describes how to install a tarball for your distribution. + +OR + +Run the following script to copy over the wakunode2 binary (from the host machine) - + +```bash +scp -i $DROPLET_SSH_KEY_PATH ./build/wakunode2 $DROPLET_USERNAME@$DROPLET_IP:~/wakunode2 +``` + +## 10. Set up a terminal multiplexer of choice + +You may decide to use either `screen` or `tmux` to be able to reattach to the process +after closing the ssh connection. + +Installation instructions for - +1. [screen](https://linuxhint.com/screen-linux/) +2. [tmux](https://linuxhint.com/install-tmux-ubuntu/) + +## 10. Run nwaku + +First, start the `screen` or `tmux` session by following the instructions of the terminal multiplexer chosen previously - +1. [screen](https://linuxize.com/post/how-to-use-linux-screen/#starting-linux-screen) +2. [tmux](https://linuxize.com/post/getting-started-with-tmux/#starting-your-first-tmux-session) + +Run the following command to run `nwaku` - + +*Note the path to the wakunode2 binary* + +a. Add the parent directory of the wakunode2 binary to your environment: + + If you built it locally and copied it via scp - + + ```bash + export WAKUNODE_DIR="$pwd" + ``` + + OR + + If you compiled it on the Droplet - + + ```bash + export WAKUNODE_DIR="$pwd"/build + ``` + +b. Choose the fleet you wish to connect your node to: + - waku sandbox: enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im + - waku test: enrtree://AOGYWMBYOUIMOENHXCHILPKY3ZRFEULMFI4DOM442QSZ73TT2A7VI@test.waku.nodes.status.im + + ```bash + export WAKU_FLEET= + ``` + + +c. Run `nwaku`: + + If you set up a domain previously - + + ```bash + export DOMAIN_NAME= + $WAKUNODE_DIR/wakunode2 \ + --store:true \ + --persist-messages \ + --dns-discovery \ + --dns-discovery-url:"$WAKU_FLEET" \ + --dns4-domain-name:"$DOMAIN_NAME" \ + --discv5-discovery:true + ``` + + OR + + If you did not set up a domain - + + ```bash + $WAKUNODE_DIR/wakunode2 \ + --store:true \ + --persist-messages \ + --dns-discovery \ + --dns-discovery-url:"$WAKU_FLEET" \ + --discv5-discovery:true + ``` + +You now have nwaku running! You can verify this by observing the logs. The logs should show that the node completed 7 steps of setup, and is actively discovering other nodes. + +You may now detach from stdout, by following instructions according to the terminal multiplexer chosen previously - +1. [screen](https://linuxize.com/post/how-to-use-linux-screen/#detach-from-linux-screen-session) +2. [tmux](https://linuxize.com/post/getting-started-with-tmux/#starting-your-first-tmux-session) + +To re-attach and observe the logs at a later date, follow these instructions - +1. [screen](https://linuxize.com/post/how-to-use-linux-screen/#reattach-to-a-linux-screen) +2. [tmux](https://linuxize.com/post/getting-started-with-tmux/#re-attaching-to-tmux-session) + +For alternative configurations, refer to this [guide](./how-to/configure.md) + diff --git a/docs/operators/how-to/build.md b/docs/operators/how-to/build.md new file mode 100644 index 0000000..473547c --- /dev/null +++ b/docs/operators/how-to/build.md @@ -0,0 +1,59 @@ +# Build nwaku + +Nwaku can be built on Linux and macOS. +Windows support is experimental. + +## Installing dependencies + +Cloning and building nwaku requires the usual developer tools, +such as a C compiler, Make, Bash and Git. + +### Linux + +On common Linux distributions the dependencies can be installed with + +```sh +# Debian and Ubuntu +sudo apt-get install build-essential git + +# Fedora +dnf install @development-tools + +# Archlinux, using an AUR manager +yourAURmanager -S base-devel +``` + +### macOS + +Assuming you use [Homebrew](https://brew.sh/) to manage packages + +```sh +brew install cmake +``` + +## Building nwaku + +### 1. Clone the nwaku repository + +```sh +git clone https://github.com/status-im/nwaku +cd nwaku +``` + +### 2. Make the `wakunode2` target + +```sh +# The first `make` invocation will update all Git submodules. +# You'll run `make update` after each `git pull`, in the future, to keep those submodules up to date. +make wakunode2 +``` + +This will create a `wakunode2` binary in the `./build/` directory. + +> **Note:** Building `wakunode2` requires 2GB of RAM. +The build will fail on systems not fulfilling this requirement. + +> Setting up a `wakunode2` on the smallest [digital ocean](https://docs.digitalocean.com/products/droplets/how-to/) droplet, you can either +> * compile on a stronger droplet featuring the same CPU architecture and downgrade after compiling, or +> * activate swap on the smallest droplet, or +> * use Docker. diff --git a/docs/operators/how-to/configure-dns-disc.md b/docs/operators/how-to/configure-dns-disc.md new file mode 100644 index 0000000..f003c61 --- /dev/null +++ b/docs/operators/how-to/configure-dns-disc.md @@ -0,0 +1,27 @@ +# Use DNS discovery to connect to existing nodes + +> **Note:** This page describes using DNS to discover other peers +and is unrelated to the [domain name configuration](./configure-domain.md) for your nwaku node. + +A node can discover other nodes to connect to using [DNS-based discovery](../../tutorial/dns-disc.md). +The following command line options are available: + +``` +--dns-discovery Enable DNS Discovery +--dns-discovery-url URL for DNS node list in format 'enrtree://@' +``` + +- `--dns-discovery` is used to enable DNS discovery on the node. +Waku DNS discovery is disabled by default. +- `--dns-discovery-url` is mandatory if DNS discovery is enabled. +It contains the URL for the node list. +The URL must be in the format `enrtree://@` where `` is the fully qualified domain name and `` is the base32 encoding of the compressed 32-byte public key that signed the list at that location. + +A node will attempt connection to all discovered nodes. + +This can be used, for example, to connect to one of the existing fleets. +Current URLs for the published fleet lists: +- production fleet: `enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im` +- test fleet: `enrtree://AOGYWMBYOUIMOENHXCHILPKY3ZRFEULMFI4DOM442QSZ73TT2A7VI@test.waku.nodes.status.im` + +See the [separate tutorial](../../tutorial/dns-disc.md) for a complete guide to DNS discovery. diff --git a/docs/operators/how-to/configure-domain.md b/docs/operators/how-to/configure-domain.md new file mode 100644 index 0000000..226da4b --- /dev/null +++ b/docs/operators/how-to/configure-domain.md @@ -0,0 +1,16 @@ +# Configure a domain name + +> **Note:** This page describes configuring a domain name that resolves to your node's IP +and is unrelated to [DNS discovery](./configure-dns-disc.md), +by which a node may discover the listening addresses of other peers using DNS. + +It is possible to configure an IPv4 DNS domain name that resolves to the node's public IPv4 address. + +```shell +wakunode2 --dns4-domain-name=mynode.example.com +``` + +This allows for the node's publicly announced `multiaddrs` to use the `/dns4` scheme. +In addition, nodes with domain name and [secure websocket configured](./configure-websocket.md), +will generate a discoverable ENR containing the `/wss` multiaddr with `/dns4` domain name. +This is necessary to verify domain certificates when connecting to this node over secure websocket. \ No newline at end of file diff --git a/docs/operators/how-to/configure-key.md b/docs/operators/how-to/configure-key.md new file mode 100644 index 0000000..8da84f9 --- /dev/null +++ b/docs/operators/how-to/configure-key.md @@ -0,0 +1,54 @@ +# Generate and configure a node key + +By default a node will generate a new, random key pair each time it boots, +resulting in a different public libp2p `multiaddrs` after each restart. + +To maintain consistent addressing across restarts, +it is possible to configure the node with a previously generated private key using the `--nodekey` option. + +```shell +wakunode2 --nodekey=<64_char_hex> +``` + +This option takes a [Secp256k1](https://en.bitcoin.it/wiki/Secp256k1) private key in 64 char hexstring format. + +To generate such a key on Linux systems, +use the openssl `rand` command to generate a pseudo-random 32 byte hexstring. + +```sh +openssl rand -hex 32 +``` + +Example output: + +```sh +$ openssl rand -hex 32 +6a29e767c96a2a380bb66b9a6ffcd6eb54049e14d796a1d866307b8beb7aee58 +``` + +where the key `6a29e767c96a2a380bb66b9a6ffcd6eb54049e14d796a1d866307b8beb7aee58` can be used as `nodekey`. + +To create a reusable keyfile on Linux using `openssl`, +use the `ecparam` command coupled with some standard utilities +whenever you want to extract the 32 byte private key in hex format. + +```sh +# Generate keyfile +openssl ecparam -genkey -name secp256k1 -out my_private_key.pem +# Extract 32 byte private key +openssl ec -in my_private_key.pem -outform DER | tail -c +8 | head -c 32| xxd -p -c 32 +``` + +Example output: + +```sh +read EC key +writing EC key +0c687bb8a7984c770b566eae08520c67f53d302f24b8d4e5e47cc479a1e1ce23 +``` + +where the key `0c687bb8a7984c770b566eae08520c67f53d302f24b8d4e5e47cc479a1e1ce23` can be used as `nodekey`. + +```sh +wakunode2 --nodekey=0c687bb8a7984c770b566eae08520c67f53d302f24b8d4e5e47cc479a1e1ce23 +``` diff --git a/docs/operators/how-to/configure-rest-api.md b/docs/operators/how-to/configure-rest-api.md new file mode 100644 index 0000000..3fe070a --- /dev/null +++ b/docs/operators/how-to/configure-rest-api.md @@ -0,0 +1,23 @@ + +# Configure a REST API node + +A subset of the node configuration can be used to modify the behaviour of the HTTP REST API. + +These are the relevant command line options: + +| CLI option | Description | Default value | +|------------|-------------|---------------| +|`--rest` | Enable Waku REST HTTP server. | `false` | +|`--rest-address` | Listening address of the REST HTTP server. | `127.0.0.1` | +|`--rest-port` | Listening port of the REST HTTP server. | `8645` | +|`--rest-relay-cache-capacity` | Capacity of the Relay REST API message cache. | `30` | +|`--rest-admin` | Enable access to REST HTTP Admin API. | `false` | +|`--rest-private` | Enable access to REST HTTP Private API. | `false` | + +Note that these command line options have their counterpart option in the node configuration file. + +Example: + +```shell +wakunode2 --rest=true +``` diff --git a/docs/operators/how-to/configure-store-v0.12.0.md b/docs/operators/how-to/configure-store-v0.12.0.md new file mode 100644 index 0000000..237c7fc --- /dev/null +++ b/docs/operators/how-to/configure-store-v0.12.0.md @@ -0,0 +1,56 @@ +# Configure store protocol (versions prior to v0.13.0) + +Store protocol is enabled by default on a nwaku node. +This is controlled by the `--store` CLI option. + +```sh +# Disable store protocol on startup +./build/wakunode2 --store:false +``` + +Note that this only mounts the `store` protocol, +meaning your node will indicate to other peers that it supports `store`. +It does not yet allow your node to either retrieve historical messages as a client +or store and serve historical messages itself. + +## Configuring a store client + +Ensure that `store` is enabled (this is `true` by default) and provide at least one store service node address with the `--storenode` CLI option. + +See the following example, using the peer at `/dns4/node-01.ac-cn-hongkong-c.waku.test.status.im/tcp/30303/p2p/16Uiu2HAkzHaTP5JsUwfR9NR8Rj9HC24puS6ocaU8wze4QrXr9iXp` as store service node. + +```sh +./build/wakunode2 \ + --store:true \ + --storenode:/dns4/node-01.ac-cn-hongkong-c.waku.test.status.im/tcp/30303/p2p/16Uiu2HAkzHaTP5JsUwfR9NR8Rj9HC24puS6ocaU8wze4QrXr9iXp +``` + +Your node can now send queries to retrieve historical messages +from the configured store service node. +One way to trigger such queries is asking your node for historical messages using the [Waku v2 JSON RPC API](https://rfc.vac.dev/spec/16/). + +## Configuring a store service node + +To store historical messages on your node which can be served to store clients the `--persist-messages` CLI option must be enabled. +By default a node would store up to the latest `50 000` messages. +This is configurable using the `--store-capacity` option. +A node that has a `--db-path` set will backup historical messages to a local database at the DB path +and persist these messages even after a restart. + +```sh +./build/wakunode2 \ + --store:true \ + --persist-messages:true \ + --db-path:/mnt/nwaku/data/db1/ \ + --store-capacity:150000 +``` + +### How much resources should I allocate? + +Currently store service nodes use an in-memory key-value store as primary storage with the disk-based database only used for backups. +Most Waku messages average a size of 1KB - 2KB, +implying a minimum memory requirement of at least ~250MB +for a medium capacity store of 100k messages. +Note, however, that the allowable maximum size for Waku messages is up to 1MB. +We are working on a disk-only and hybrid store to lower the memory requirement. +It will soon also be possible to configure store capacity on maximum store size or number of days' history to keep. diff --git a/docs/operators/how-to/configure-store.md b/docs/operators/how-to/configure-store.md new file mode 100644 index 0000000..ffa39cf --- /dev/null +++ b/docs/operators/how-to/configure-store.md @@ -0,0 +1,58 @@ +# Configure store protocol + +> :information_source: This instructions apply to nwaku version v0.13.0+. For versions prior to v0.13.0, check [this page](./configure-store-v0.12.0.md). + +The waku store protocol is disabled by default the nwaku node. +This is controlled by the `--store` option. To enable waku store protocol on startup, specify explicitly the `--store` option set to `true`: + +```shell +wakunode2 --store=true +``` + +This option controls the mounting of the Waku Store protocol, meaning that your node will indicate to other peers that it supports the Waku store protocol. + +## Configuring the node as a waku store client + +Provide at least one store service node address with the `--storenode` option. This option is independent of the `--store` option i.e., one node can act as a waku store client without mounting the Waku Store protocol. + +For example, to use the peer at `/dns4/node-01.ac-cn-hongkong-c.waku.test.status.im/tcp/30303/p2p/16Uiu2HAkzHaTP5JsUwfR9NR8Rj9HC24puS6ocaU8wze4QrXr9iXp` as the waku store service node: + +```shell +wakunode2 \ + --storenode=/dns4/node-01.ac-cn-hongkong-c.waku.test.status.im/tcp/30303/p2p/16Uiu2HAkzHaTP5JsUwfR9NR8Rj9HC24puS6ocaU8wze4QrXr9iXp +``` + +Your node can now send queries to retrieve historical messages +from the configured store service node. One way to trigger such queries is asking your node for historical messages using the [Waku v2 JSON RPC API](https://rfc.vac.dev/spec/16/). + +## Configuring the node as a store service node + +If the waku store node is enabled (the `--store` option is set to `true`) the node will store historical messages and will be able to serve those messages to the waku store clients. + +There is a set of configuration options to customize the waku store protocol's message store. These are the most relevant: + +* `--store-message-retention-policy`: This option controls the retention policy i.e., how long certain messages will be persisted. Three different retention policies are supported: + + The time retention policy,`time:` (e.g., `time:14400`) + + The capacity retention policy,`capacity:` (e.g, `capacity:25000`) + + The size retention policy,`size:` (e.g, `size:25Gb`) + + To disable the retention policy, explicitly, set this option to `""`, an empty string. +* `--store-message-db-url`: The message store database url option controls the message storage engine. This option follows the [_SQLAlchemy_ database URL format](https://docs.sqlalchemy.org/en/14/core/engines.html#database-urls). + + + SQLite engine: The only database engine supported by the nwaku node. The database URL has this shape: `sqlite://`. If the `` is not an absolute path (preceded by a `/` character), the file will be created in the current working directory. The SQLite engine also supports to select a non-persistent in-memory database by setting the `` to `:memory:`. + + In the case you don't want to use a persistent message store; set the `--store-message-db-url` to an empty string, `""`. This will instruct the node to use the fallback in-memory message store. + +By default the node message store will be configured with a time retention policy set to `14400` seconds (4 hours). Additionally, by default, the node message store will use the SQLite database engine to store historical messages in order to persist these between restarts. + +> :warning: Note the 3 slashes, `///`, after the SQLite database URL schema. The third slash indicates that it is an absolute path: `/mnt/nwaku/data/db1/store.sqlite3` + +```shell +wakunode2 \ + --store=true \ + --store-message-db-url=sqlite:///mnt/nwaku/data/db1/store.sqlite3 \ + --store-message-retention-policy=capacity:150000 +``` + +### How much resources should I allocate? + +Currently store service nodes use, by default, a message store backed by an in-disk SQLite database. Most Waku messages average a size of 1KB - 2KB, implying a minimum memory requirement of at least ~250MB +for a typical store capacity of 100k messages. Note, however, that the allowable maximum size for Waku messages is up to 1MB. diff --git a/docs/operators/how-to/configure-websocket.md b/docs/operators/how-to/configure-websocket.md new file mode 100644 index 0000000..4f1c461 --- /dev/null +++ b/docs/operators/how-to/configure-websocket.md @@ -0,0 +1,35 @@ +# Configure websocket transport + +Websocket is currently the only Waku transport supported by browser nodes using [js-waku](https://github.com/status-im/js-waku). +Setting up websocket enables your node to directly serve browser peers. + +A valid certificate is necessary to serve browser nodes, +you can use [`letsencrypt`](https://letsencrypt.org/): + +```shell +sudo letsencrypt -d +``` + +You will need the `privkey.pem` and `fullchain.pem` files. + +To enable secure websocket, pass the generated files to `wakunode2`: +Note, the default port for websocket is 8000. + +```shell +wakunode2 --websocket-secure-support=true --websocket-secure-key-path="/privkey.pem" --websocket-secure-cert-path="/fullchain.pem" +``` + +## Self-signed certificates + +Self-signed certificates are not recommended for production setups because: + +- Browsers do not accept self-signed certificates +- Browsers do not display an error when rejecting a certificate for websocket. + +However, they can be used for local testing purposes: + +```shell +mkdir -p ./ssl_dir/ +openssl req -x509 -newkey rsa:4096 -keyout ./ssl_dir/key.pem -out ./ssl_dir/cert.pem -sha256 -nodes +wakunode2 --websocket-secure-support=true --websocket-secure-key-path="./ssl_dir/key.pem" --websocket-secure-cert-path="./ssl_dir/cert.pem" +``` \ No newline at end of file diff --git a/docs/operators/how-to/configure.md b/docs/operators/how-to/configure.md new file mode 100644 index 0000000..f052b22 --- /dev/null +++ b/docs/operators/how-to/configure.md @@ -0,0 +1,136 @@ +# Configure a nwaku node + +Nwaku can be configured to serve the adaptive needs of different operators. + +> :bulb: **Tip:** The recommended configuration method is through environment variables. + +## Node configuration methods + +One node can be configured using a combination of the following methods: + +1. Command line options and flags +2. Environment variables +3. Configuration file (currently, only TOML format is supported) +4. Default value + +Note the precedence order, each configuration mechanism overrides the configuration set by one below (e.g., _command line options_ override the configuration set by the _environment variables_ and by the _configuration file_). + +### Command line options/flags + +The main mechanism to configure the node is via command line options. Any configuration option provided via the command line will override any other configuration mechanism. + +> :warning: nwaku is under heavy development. It is likely that configuration will change from one version to another. +> +> If after an upgrade, the node refuses to start, check if any of the command line configuration options provided to the node have been changed or removed. +> +> To overcome this issue, we recommend to configure the node via environment variables. + +The configuration options should be provided after the binary name as follows: + +```shell +wakunode2 --tcp-port=65000 +``` + +In the case of using docker to run you node you should provide the commandline options after the image name as follows: + +```shell +docker run wakuorg/nwaku --tcp-port=65000 +``` + +Run `wakunode2 --help` to get a comprehensive list of configuration options (and its default values): + +```shell +$ wakunode2 --help +Usage: + +wakunode2 [OPTIONS]... + +The following options are available: + + --config-file Loads configuration from a TOML file (cmd-line parameters take precedence). + --log-level Sets the log level. [=LogLevel.INFO]. + --version prints the version [=false]. + +<...> +``` + +Check the configuration tutorials for specific configuration use cases. + +### Environment variables + +The node can also be configured via environment variables. + +> :information_source: Support for configuring the node via environment variables was added in v0.13.0 + +The environment variable name should be prefixed by the app's name, in this case `WAKUNODE2_` followed by the commandline option in [screaming snake case](https://en.wiktionary.org/wiki/screaming_snake_case). + +For example, to set the `--tcp-port` configuration we should call `wakunode2` binary as follows: + +```shell +WAKUNODE2_TCP_PORT=65000 wakunode2 +``` + +In the case of using docker to run you node you should start the node using the `-e` command options: + +```shell +docker run -e "WAKUNODE2_TCP_PORT=65000" wakuorg/nwaku +``` + +This is the second configuration method in order of precedence. Any command line configuration option will override the configuration +provided via environment variables. + +### Configuration file + +The third configuration mechanism in order of precedence is the configuration via a TOML file. The previous mechanisms take precedence over this mechanism as explained above. + +The configuration file follows the [TOML](https://toml.io/en/) format: + +```toml +log-level = "DEBUG" +tcp-port = 65000 +``` + +The path to the TOML file can be specified using one of the previous configuration mechanisms: + +* By passing the `--config-file` command line option: + ```shell + wakunode2 --config-file= + ``` +* By passing the path via environment variables: + ```shell + WAKUNODE2_CONFIG_FILE= wakunode2 + ``` + +### Configuration default values + +As usual, if no configuration option is specified by any of the previous mechanisms, the default configuration will be used. + +The default configuration value is listed in the `wakunode2 --help` output: + +```shell +$ wakunode2 --help +Usage: + +wakunode2 [OPTIONS]... + +The following options are available: + + --config-file Loads configuration from a TOML file (cmd-line parameters take precedence). + --log-level Sets the log level. [=LogLevel.INFO]. + --version prints the version [=false].--tcp-port TCP listening port. [=60000]. + --websocket-port WebSocket listening port. [=8000]. +<...> +``` + +## Configuration use cases + +This is an index of tutorials explaining how to configure your nwaku node for different use cases. + +1. [Connect to other peers](./connect.md) +2. [Configure a domain name](./configure-domain.md) +3. [Use DNS discovery to connect to existing nodes](./configure-dns-disc.md) +4. [Configure store protocol and message store](./configure-store.md) +5. [Generate and configure a node key](./configure-key.md) +6. [Configure websocket transport](./configure-websocket.md) +7. [Run nwaku with rate limiting enabled](./run-with-rln.md) +8. [Configure a REST API node](./configure-rest-api.md) diff --git a/docs/operators/how-to/connect.md b/docs/operators/how-to/connect.md new file mode 100644 index 0000000..b375401 --- /dev/null +++ b/docs/operators/how-to/connect.md @@ -0,0 +1,60 @@ +# Connect to other peers + +*Note that this tutorial describes how to **configure** a node to connect to other peers before running the node. +For connecting a running node to existing peers, +see the [WAKU REST API reference](https://waku-org.github.io/waku-rest-api/#post-/admin/v1/peers).* + +There are currently three options. +Note that each of these options can be used in combination with any of the other two. +In other words, it is possible to configure a node to connect +to a static list of peers and +to discover such peer lists using DNS discovery and +discover and connect to random peers using discovery v5 with a bootstrap node. + +## Option 1: Configure peers statically + +Static peers can be provided to a nwaku node on startup using the `--staticnode` CLI parameter. +The `--staticnode` option can be repeated for each peer you want to connect to on startup. + +```sh +./build/wakunode2 \ + --staticnode: \ + --staticnode: +``` + +As an example, consider a nwaku node that connects to two known peers +on the same local host (with IP `0.0.0.0`) +with TCP ports `60002` and `60003`, +and peer IDs `16Uiu2HAkzjwwgEAXfeGNMKFPSpc6vGBRqCdTLG5q3Gmk2v4pQw7H` and `16Uiu2HAmFBA7LGtwY5WVVikdmXVo3cKLqkmvVtuDu63fe8safeQJ` respectively. + +```sh +./build/wakunode2 \ + --staticnode:/ip4/0.0.0.0/tcp/60002/p2p/16Uiu2HAkzjwwgEAXfeGNMKFPSpc6vGBRqCdTLG5q3Gmk2v4pQw7H \ + --staticnode:/ip4/0.0.0.0/tcp/60003/p2p/16Uiu2HAmFBA7LGtwY5WVVikdmXVo3cKLqkmvVtuDu63fe8safeQJ +``` + +## Option 2: Discover peers using DNS discovery + +A node can discover other nodes to connect to using DNS-based discovery. +For a quickstart guide on how to configure DNS discovery, +see [this tutorial](./configure-dns-disc.md). +There is also a [more comprehensive tutorial](../../tutorial/dns-disc.md) for advanced users. + +## Option 3: Discover peers using Waku Discovery v5 + + + +Enable Discovery v5 using the `--discv5-discovery` option. + +It is possible to configure bootstrap entries for the Discovery v5 routing table +using the `--discv5-bootstrap-node` option repeatedly. + +```sh +./build/wakunode2 \ + --discv5-discovery:true \ + --discv5-bootstrap-node: \ + --discv5-bootstrap-node: +``` + +Note that if Discovery v5 is enabled and used in conjunction with DNS-based discovery, +the nwaku node will attempt to bootstrap the Discovery v5 routing table with ENRs extracted from the peers discovered via DNS. diff --git a/docs/operators/how-to/monitor.md b/docs/operators/how-to/monitor.md new file mode 100644 index 0000000..8ef3f06 --- /dev/null +++ b/docs/operators/how-to/monitor.md @@ -0,0 +1,111 @@ +# Monitor nwaku using Prometheus and Grafana + +## Prerequisites + +1. A running nwaku instance with HTTP metrics server enabled (i.e. with `--metrics-server:true`) +2. [Prometheus](https://prometheus.io/) and [Grafana](https://grafana.com/) installed + +### Installing Prometheus + +Prometheus can be installed by downloading and extracting +the latest release for your system distribution from the [Prometheus download page](https://prometheus.io/download/). + +For example, on a DebianOS distribution you could run + +```bash +wget https://github.com/prometheus/prometheus/releases/download/v2.38.0/prometheus-2.38.0.linux-amd64.tar.gz +tar xvfz prometheus-2.38.0.linux-amd64.tar.gz +``` + +For more advanced installations, +Prometheus has a handy [Getting Started](https://prometheus.io/docs/prometheus/latest/getting_started/) page to guide you through the process. +There are also many third party guides on installing Prometheus for specific distributions, +such as [this old but still relevant one](https://www.digitalocean.com/community/tutorials/how-to-install-prometheus-on-ubuntu-16-04) from DigitalOcean. +We also suggest running Prometheus as a service, +as explained by [this guide](https://www.devopsschool.com/blog/how-to-run-prometheus-server-as-a-service/). +Bear in mind that we'll be creating our own `prometheus.yml` configuration file later on when you encounter this in any of the guides. + +### Installing Grafana + +Follow the [installation instructions](https://grafana.com/docs/grafana/latest/setup-grafana/installation/) appropriate to your distribution to install Grafana. +The stable version of the Grafana Enterprise Edition is the free, recommended edition to install. + +## Configure Prometheus + +1. Create a file called `prometheus.yml` with the following content: + +```yml +global: + scrape_interval: 15s + +scrape_configs: + - job_name: 'prometheus' + scrape_interval: 5s + static_configs: + - targets: ['localhost:9090'] + - job_name: 'nwaku' + scrape_interval: 1s + static_configs: + - targets: ['localhost:'] +``` + +Replace `` with the metrics HTTP server port of your running nwaku instance. +For default configurations metrics are reported on port `8008` of the `localhost`. +If you've used `--ports-shift`, or explicitly set the metrics port using `--metrics-server-port`, this port will be different from the default. +It's possible to extract the metrics server port from the startup logs of the nwaku node. +Look for a log with the format below and substitute `nwaku_port` with the value reported after `serverPort=`: + +``` +INF 2022-09-16 12:14:12.739+01:00 Metrics HTTP server started topics="wakunode.setup.metrics" tid=6243 file=wakunode2_setup_metrics.nim:29 serverIp=127.0.0.1 serverPort=8009 +``` + +2. Start Prometheus using the config file you created above: + +```bash +./path/to/prometheus --config.file=/path/to/prometheus.yml & +``` + +3. Verify that Prometheus is running correctly. + +Once Prometheus is running, it exposes by default a management console on port `9090`. +If you are running Prometheus locally, for example, +you can visit http://localhost:9090/ in a browser to view basic info about the running instance. +http://localhost:9090/targets shows the state of the different metrics server endpoints that we configured in `prometheus.yml`. +In our case we'd expect Prometheus to successfully scrape metrics off two endpoints, +the running nwaku instance and Prometheus itself. + +## Configure Grafana + +1. Start the Grafana server, if it's not running already after installation. + +```bash +sudo systemctl start grafana-server +``` + +2. Open Grafana in your browser. + +Grafana exposes its interface by default on port `3000`. +For example, if you are running Grafana locally, +you can find it by navigating to http://localhost:3000/. +If you are prompted for a username and password, +the default is `admin` in both cases. + +3. Set Prometheus as your data source. + +[These instructions](https://grafana.com/docs/grafana/latest/datasources/add-a-data-source/) describe how to add a new data source. +The default values for setting up a Prometheus data source should be sufficient. + +4. Create a new dashboard or import an existing one. + +You can now visualize metrics off your running nwaku instance by [creating a new dashboard and adding panels](https://grafana.com/docs/grafana/latest/dashboards/add-organize-panels/) for the metric(s) of your choice. +To get you started, +we have published a [basic monitoring dashboard for a single nwaku node](https://github.com/status-im/nwaku/blob/d4e899fba77389d20ca19c73a9443501039cdef2/metrics/waku-single-node-dashboard.json) +which you can [import to your Grafana instance](https://grafana.com/docs/grafana/latest/dashboards/manage-dashboards/#import-a-dashboard). + +5. Happy monitoring! + +Some of the most important metrics to keep an eye on include: +- `libp2p_peers` as an indication of how many peers your node is connected to, +- `waku_node_messages_total` to view the total amount of network traffic relayed by your node and +- `waku_node_errors` as a rough indication of basic operating errors logged by the node. + diff --git a/docs/operators/how-to/run-with-rln.md b/docs/operators/how-to/run-with-rln.md new file mode 100644 index 0000000..ef1a6c2 --- /dev/null +++ b/docs/operators/how-to/run-with-rln.md @@ -0,0 +1,89 @@ +# How to run spam prevention on your nwaku node (RLN) + +This guide explains how to run a nwaku node with RLN (Rate Limiting Nullifier) enabled. + +[RLN](https://rfc.vac.dev/spec/32/) is a protocol integrated into waku v2, +which prevents spam-based attacks on the network. + +For further background on the research for RLN tailored to waku, refer +to [this](https://rfc.vac.dev/spec/17/) RFC. + +Registering to the membership group has been left out for brevity. +If you would like to register to the membership group and send messages with RLN, +refer to the [on-chain chat2 tutorial](../../tutorial/onchain-rln-relay-chat2.md). + +This guide specifically allows a node to participate in RLN testnet 2. +You may alter the rln-specific arguments as required. + +## Prerequisites + +1. Follow the [droplet quickstart](../droplet-quickstart.md) or the [build guide](./build.md) till the `make` command for the wakunode2 binary. + +> Note: If you would like to run a nwaku node with RLN enabled within a docker container, skip ahead to step 2. + +## 1. Build wakunode2 + +Run - +```bash +make wakunode2 +``` + +## 2. Update the runtime arguments + +Follow [Step 10](../droplet-quickstart.md#10-run-nwaku) of the [droplet quickstart](../droplet-quickstart.md) guide, while replacing the run command with - + +```bash +export LINEA_SEPOLIA_HTTP_NODE_ADDRESS= +export RLN_RELAY_CONTRACT_ADDRESS="0xB9cd878C90E49F797B4431fBF4fb333108CB90e6" # Replace this with any compatible implementation +$WAKUNODE_DIR/wakunode2 \ +--store:true \ +--persist-messages \ +--dns-discovery \ +--dns-discovery-url:"$WAKU_FLEET" \ +--discv5-discovery:true \ +--rln-relay:true \ +--rln-relay-dynamic:true \ +--rln-relay-eth-contract-address:"$RLN_RELAY_CONTRACT_ADDRESS" \ +--rln-relay-eth-client-address:"$LINEA_SEPOLIA_HTTP_NODE_ADDRESS" +``` + +OR + +If you are running the nwaku node within docker, follow [Step 2](../docker-quickstart.md#step-2-run) while replacing the run command with - + +```bash +export WAKU_FLEET= +export LINEA_SEPOLIA_HTTP_NODE_ADDRESS= +export RLN_RELAY_CONTRACT_ADDRESS="0xB9cd878C90E49F797B4431fBF4fb333108CB90e6" # Replace this with any compatible implementation +docker run -i -t -p 60000:60000 -p 9000:9000/udp wakuorg/nwaku:v0.36.0 \ + --dns-discovery:true \ + --dns-discovery-url:"$WAKU_FLEET" \ + --discv5-discovery \ + --nat:extip:[yourpublicip] \ # or, if you are behind a nat: --nat=any + --rln-relay:true \ + --rln-relay-dynamic:true \ + --rln-relay-eth-contract-address:"$RLN_RELAY_CONTRACT_ADDRESS" \ + --rln-relay-eth-client-address:"$LINEA_SEPOLIA_HTTP_NODE_ADDRESS" +``` + +> Note: You can choose to keep connections to other nodes alive by adding the `--keep-alive` flag. + +Following is the list of additional fields that have been added to the +runtime arguments - + +1. `--rln-relay`: Allows waku-rln-relay to be mounted into the setup of the nwaku node +2. `--rln-relay-dynamic`: Enables waku-rln-relay to connect to an ethereum node to fetch the membership group +3. `--rln-relay-eth-contract-address`: The contract address of an RLN membership group +4. `--rln-relay-eth-client-address`: The HTTP url to a Linea Sepolia ethereum node + +You should now have nwaku running, with RLN enabled! + +To see metrics related to the functioning of RLN, refer to this [guide](./todo). +You can also refer to the periodic logging, for a few metrics like - + +- number of spam messages +- number of valid messages +- number of invalid messages + + +> Note: This guide will be updated in the future to include features like slashing. diff --git a/docs/operators/how-to/run.md b/docs/operators/how-to/run.md new file mode 100644 index 0000000..bc90394 --- /dev/null +++ b/docs/operators/how-to/run.md @@ -0,0 +1,196 @@ +# Running nwaku + +Nwaku binaries can be [built](./build.md) and run on Linux and macOS. +Windows support is experimental. + +```sh +# Run with default configuration +./build/wakunode2 + +# See available command line options +./build/wakunode2 --help +``` + +## Default configuration + +By default a nwaku node will: +- generate a new private key and libp2p identities after every restart. +See [this tutorial](./configure-key.md) if you want to generate and configure a persistent private key. +- listen for incoming libp2p connections on the default TCP port (`60000`) +- enable `relay` protocol +- subscribe to the default clusterId (0) and shard (0) +- enable `store` protocol, but only as a client. +This implies that the nwaku node will not persist any historical messages itself, +but can query `store` service peers who do so. +To configure `store` as a service node, +see [this tutorial](./configure-store.md). + +> **Note:** The `filter` and `lightpush` protocols are _not_ enabled by default. +Consult the [configuration guide](./configure.md) on how to configure your nwaku node to run these protocols. + +Some typical non-default configurations are explained below. +For more advanced configuration, see the [configuration guide](./configure.md). +Different ways to connect to other nodes are expanded upon in our [connection guide](./connect.md). + +## Finding your listening address(es) + +Find the log entry beginning with `Listening on`. +It should be printed at INFO level when you start your node +and contains a list of all publicly announced listening addresses for the nwaku node. + +For example + +``` +INF 2022-05-11 16:42:30.591+02:00 Listening on topics="wakunode" tid=6661 file=wakunode2.nim:941 full=[/ip4/0.0.0.0/tcp/60000/p2p/16Uiu2HAkzjwwgEAXfeGNMKFPSpc6vGBRqCdTLG5q3Gmk2v4pQw7H][/ip4/0.0.0.0/tcp/8000/ws/p2p/16Uiu2HAkzjwwgEAXfeGNMKFPSpc6vGBRqCdTLG5q3Gmk2v4pQw7H] +``` + +indicates that your node is listening on the TCP transport address + +``` +/ip4/0.0.0.0/tcp/60000/p2p/16Uiu2HAkzjwwgEAXfeGNMKFPSpc6vGBRqCdTLG5q3Gmk2v4pQw7H +``` + +and websocket address + +``` +/ip4/0.0.0.0/tcp/8000/ws/p2p/16Uiu2HAkzjwwgEAXfeGNMKFPSpc6vGBRqCdTLG5q3Gmk2v4pQw7H +``` + +You can also query a running node for its listening addresses +using the REST API. + +```bash +curl http://localhost:8645/debug/v1/info -s | jq +``` + +## Finding your discoverable ENR address(es) + +A nwaku node can encode its addressing information in an [Ethereum Node Record (ENR)](https://eips.ethereum.org/EIPS/eip-778) according to [`31/WAKU2-ENR`](https://rfc.vac.dev/spec/31/). +These ENR are most often used for discovery purposes. + +### ENR for DNS discovery + +Find the log entry beginning with `DNS: discoverable ENR`. +It should be printed at INFO level when you start your node with [DNS discovery enabled](./configure-dns-disc.md) +and contains an ENR that can be added to node lists discoverable via DNS. + +For example + +``` +INF 2022-05-20 11:52:48.772+02:00 DNS: discoverable ENR topics="wakunode" tid=5182 file=wakunode2.nim:941 enr=enr:-Iu4QBZs5huNuEAjI9WA0HOAjzpmp39vKJAtYRG3HXH86-i3HGcxMgupIkyDBmBq9qJ2wFfgMiW8AUzUxTFMAzfJM5MBgmlkgnY0gmlwhAAAAACJc2VjcDI1NmsxoQN0EcrUbHrL_O_kNXDlBvcO1I4yZUdNk7VZI5GsXaWgvYN0Y3CC6mCFd2FrdTID +``` + +indicates that your node addresses are encoded in the ENR + +``` +enr=enr:-Iu4QBZs5huNuEAjI9WA0HOAjzpmp39vKJAtYRG3HXH86-i3HGcxMgupIkyDBmBq9qJ2wFfgMiW8AUzUxTFMAzfJM5MBgmlkgnY0gmlwhAAAAACJc2VjcDI1NmsxoQN0EcrUbHrL_O_kNXDlBvcO1I4yZUdNk7VZI5GsXaWgvYN0Y3CC6mCFd2FrdTID +``` + +### ENR for Discovery v5 + +Find the log entry beginning with `Discv5: discoverable ENR`. +It should be printed at INFO level when you start your node with [Waku Discovery v5 enabled](https://rfc.vac.dev/spec/33/) +and contains the ENR that will be discoverable by other peers. + +For example + +``` +INF 2022-05-20 11:52:48.775+02:00 Discv5: discoverable ENR topics="wakunode" tid=5182 file=wakunode2.nim:905 enr=enr:-IO4QDxToTg86pPCK2KvMeVCXC2ADVZWrxXSvNZeaoa0JhShbM5qed69RQz1s1mWEEqJ3aoklo_7EU9iIBcPMVeKlCQBgmlkgnY0iXNlY3AyNTZrMaEDdBHK1Gx6y_zv5DVw5Qb3DtSOMmVHTZO1WSORrF2loL2DdWRwgiMohXdha3UyAw +``` + +indicates that your node addresses are encoded in the ENR + +``` +enr=enr:-IO4QDxToTg86pPCK2KvMeVCXC2ADVZWrxXSvNZeaoa0JhShbM5qed69RQz1s1mWEEqJ3aoklo_7EU9iIBcPMVeKlCQBgmlkgnY0iXNlY3AyNTZrMaEDdBHK1Gx6y_zv5DVw5Qb3DtSOMmVHTZO1WSORrF2loL2DdWRwgiMohXdha3UyAw +``` + +## Typical configuration (relay node) + +The typical configuration for a nwaku node is to run the `relay` protocol, +subscribed to the default pubsub topic `/waku/2/rs/0/0`, +and connecting to one or more existing peers. +We assume below that running nodes also participate in Discovery v5 +to continually discover and connect to random peers for a more robust mesh. + +### Connecting to known peer(s) + +A typical run configuration for a nwaku node is to connect to existing peers with known listening addresses using the `--staticnode` option. +The `--staticnode` option can be repeated for each peer you want to connect to on startup. +This is also useful if you want to run several nwaku instances locally +and therefore know the listening addresses of all peers. + +As an example, consider a nwaku node that connects to two known peers +on the same local host (with IP `0.0.0.0`) +with TCP ports `60002` and `60003`, +and peer IDs `16Uiu2HAkzjwwgEAXfeGNMKFPSpc6vGBRqCdTLG5q3Gmk2v4pQw7H` and `16Uiu2HAmFBA7LGtwY5WVVikdmXVo3cKLqkmvVtuDu63fe8safeQJ` respectively. +The Discovery v5 routing table can similarly be bootstrapped using a static ENR. +We include an example below. + +```sh +./build/wakunode2 \ + --ports-shift:1 \ + --staticnode:/ip4/0.0.0.0/tcp/60002/p2p/16Uiu2HAkzjwwgEAXfeGNMKFPSpc6vGBRqCdTLG5q3Gmk2v4pQw7H \ + --staticnode:/ip4/0.0.0.0/tcp/60003/p2p/16Uiu2HAmFBA7LGtwY5WVVikdmXVo3cKLqkmvVtuDu63fe8safeQJ \ + --discv5-discovery:true \ + --discv5-bootstrap-node:enr:-JK4QM2ylZVUhVPqXrqhWWi38V46bF2XZXPSHh_D7f2PmUHbIw-4DidCBnBnm-IbxtjXOFbdMMgpHUv4dYVH6TgnkucBgmlkgnY0gmowhCJ6_HaJc2VjcDI1NmsxoQM06FsT6EJ57mzR_wiLu2Bz1dER2nUFSCpaFzCccQtnhYN0Y3CCdl-DdWRwgiMohXdha3UyDw +``` + +> **Tip:** `--ports-shift` shifts all configured ports forward by the configured amount. +This is another useful option when running several nwaku instances on a single machine +and would like to avoid port clashes without manually configuring each port. + +### Connecting to the `waku.sandbox` network + +*See [this explainer](https://github.com/status-im/nwaku/blob/6ebe26ad0587d56a87a879d89b7328f67f048911/docs/contributors/waku-fleets.md) on the different networks and Waku v2 fleets.* + +You can use DNS discovery to bootstrap connection to the existing production network. +Discovery v5 will attempt to extract the ENRs of the discovered nodes as bootstrap entries to the routing table. + +```sh +./build/wakunode2 \ + --ports-shift:1 \ + --dns-discovery:true \ + --dns-discovery-url:enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im \ + --discv5-discovery:true +``` + +### Connecting to the `waku.test` network + +*See [this explainer](https://github.com/status-im/nwaku/blob/6ebe26ad0587d56a87a879d89b7328f67f048911/docs/contributors/waku-fleets.md) on the different networks and Waku v2 fleets.* + +You can use DNS discovery to bootstrap connection to the existing test network. +Discovery v5 will attempt to extract the ENRs of the discovered nodes as bootstrap entries to the routing table. + +```sh +./build/wakunode2 \ + --ports-shift:1 \ + --dns-discovery:true \ + --dns-discovery-url:enrtree://AOGYWMBYOUIMOENHXCHILPKY3ZRFEULMFI4DOM442QSZ73TT2A7VI@test.waku.nodes.status.im \ + --discv5-discovery:true +``` + +## Typical configuration (relay and store service node) + +Often nwaku nodes choose to also store historical messages +from where it can be queried by other peers who may have been temporarily offline. +For example, a typical configuration for such a store service node, +[connecting to the `waku.test`](#connecting-to-the-wakutest-network) fleet on startup, +appears below. + +```sh +./build/wakunode2 \ + --ports-shift:1 \ + --store:true \ + --persist-messages:true \ + --db-path:/mnt/nwaku/data/db1/ \ + --store-capacity:150000 \ + --dns-discovery:true \ + --dns-discovery-url:enrtree://AOGYWMBYOUIMOENHXCHILPKY3ZRFEULMFI4DOM442QSZ73TT2A7VI@test.waku.nodes.status.im \ + --discv5-discovery:true +``` + +See our [store configuration tutorial](./configure-store.md) for more. + +## Interact with a running nwaku node + +A running nwaku node can be interacted with using the [REST API](https://github.com/waku-org/nwaku/blob/master/docs/api/rest-api.md). diff --git a/docs/operators/overview.md b/docs/operators/overview.md new file mode 100644 index 0000000..f43652a --- /dev/null +++ b/docs/operators/overview.md @@ -0,0 +1,39 @@ +# Overview: running a nwaku node + +This guide provides on overview for newcomers +on how to build and run a nwaku node +for the most common use cases. +For a more advanced configuration see our [configuration guides](./how-to/configure.md) + +To set up a nwaku node on a DigitalOcean droplet, +refer to our [quickstart guide for droplets](./droplet-quickstart.md). +If you prefer running nwaku in Docker container, +see our [Docker guide](./docker-quickstart.md). + +## 1. Build + +[Build the nwaku node](./how-to/build.md) +or download a precompiled binary from our [releases page](https://github.com/waku-org/nwaku/releases). + +If you'd like to test latest changes without building the binaries yourself, you can refer to [nightly release](https://github.com/waku-org/nwaku/releases/tag/nightly). + +Docker images are published to [wakuorg/nwaku](https://hub.docker.com/r/wakuorg/nwaku/tags) on Docker Hub. +See our [Docker quickstart guide](./docker-quickstart.md) to run nwaku in a Docker container. + +## 2. Run + +[Run the nwaku node](./how-to/run.md) using a default or common configuration +or [configure](./how-to/configure.md) the node for more advanced use cases. + +[Connect](./how-to/connect.md) the nwaku node to other peers to start communicating. + +## 3. Interact + +A running nwaku node can be interacted with using the [REST API](../api/v2/rest-api.md). + +> **Note:** REST API functionality is in ALPHA and therefore it is disabled by default. To configure a nwaku node with this enabled, use the `--rest:true` CLI option. + + +```bash +curl http://localhost:8546/debug/v1/info -s | jq +``` diff --git a/docs/operators/quickstart.md b/docs/operators/quickstart.md new file mode 100644 index 0000000..47c6195 --- /dev/null +++ b/docs/operators/quickstart.md @@ -0,0 +1,61 @@ +# Quickstart: running a nwaku node + +This guide helps you run a nwaku node with typical configuration. +It connects your node to the `waku.sandbox` fleet for bootstrapping +and enables discovery v5 for continuous peer discovery. +Only [`relay`](https://rfc.vac.dev/spec/11/) protocol is enabled. +For a more comprehensive overview, +see our [step-by-step guide](./overview.md). + +## Option 1: run nwaku binary + +*Prerequisites are the usual developer tools, +such as a C compiler, Make, Bash and Git.* + +```bash +git clone --recurse-submodules https://github.com/waku-org/nwaku +cd nwaku +make wakunode2 +./build/wakunode2 \ + --dns-discovery:true \ + --dns-discovery-url:enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im \ + --discv5-discovery \ + --nat=extip:[yourpublicip] # or, if you are behind a nat: --nat=any +``` + +## Option 2: run nwaku in a Docker container + +*Prerequisite is a [Docker installation](./docker-quickstart.md#prerequisites).* + +```bash +docker run -i -t -p 60000:60000 -p 9000:9000/udp \ + wakuorg/nwaku:v0.20.0 \ # or, the image:tag of your choice + --dns-discovery:true \ + --dns-discovery-url:enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im \ + --discv5-discovery \ + --nat:extip:[yourpublicip] # or, if you are behind a nat: --nat=any +``` + +## Option 3: run nwaku with docker compose + +*Prerequisites: `docker` and `docker-compose`*. +Allows to run `nwaku` with `prometheus` and `grafana`, with an already provisioned dashboard, in a few simple steps. +See [nwaku-compose](https://github.com/waku-org/nwaku-compose). + +```bash +git clone https://github.com/waku-org/nwaku-compose +cd nwaku-compose +docker-compose up -d +``` + +Go to [http://localhost:3000/d/yns_4vFVk/nwaku-monitoring?orgId=1](http://localhost:3000/d/yns_4vFVk/nwaku-monitoring?orgId=1) and after some seconds, your node metrics will be live there. +As simple as that. + +## Tips and tricks + +To find the public IP of your host, +you can use + +```bash +dig TXT +short o-o.myaddr.l.google.com @ns1.google.com | awk -F'"' '{ print $2}' +``` diff --git a/docs/tutorial/chat2.md b/docs/tutorial/chat2.md new file mode 100644 index 0000000..f6489f9 --- /dev/null +++ b/docs/tutorial/chat2.md @@ -0,0 +1,212 @@ +# Using the `chat2` application + +## Background + +The `chat2` application is a basic command-line chat app using the [Waku v2 suite of protocols](https://rfc.vac.dev/). +It optionally connects to a [fleet of nodes](fleets.status.im) to provide end-to-end p2p chat capabilities. +Each fleet is a publicly accessible network of Waku v2 peers, providing a bootstrap connection point for new peers, historical message storage, etc. +The Waku team is currently using this application on the _sandbox_ fleet for internal testing. +For more information on the available fleets, see [`Connecting to a Waku v2 fleet`](#connecting-to-a-waku-v2-fleet). +If you want to try our protocols, or join the dogfooding fun, follow the instructions below. + +## Preparation + +Ensure you have cloned the `nim-waku` repository and installed all prerequisites as per [these instructions](https://github.com/status-im/nim-waku). + +Make the `chat2` target. + +``` +make chat2 +``` + +## Basic application usage + +To start the `chat2` application in its most basic form, run the following from the project directory + +``` +./build/chat2 +``` + +You should be prompted to provide a nickname for the chat session. + +``` +Choose a nickname >> +``` + +After entering a nickname, the app will randomly select and connect to a peer from the `sandbox` fleet. + +``` +No static peers configured. Choosing one at random from sandbox fleet... +``` + +It will then attempt to download historical messages from a random peer in the `sandbox` fleet. + +``` +Store enabled, but no store nodes configured. Choosing one at random from sandbox fleet... +``` + +Wait for the chat prompt (`>>`) and chat away! + +To gracefully exit the `chat2` application, use the `/exit` [in-chat option](#in-chat-options) + +``` +>> /exit +quitting... +``` + +## Retrieving historical messages + +The `chat2` application can retrieve historical chat messages from a node supporting and running the [Waku v2 store protocol](https://rfc.vac.dev/spec/13/), and will attempt to do so by default. +It's possible to query a *specific* store node by configuring its `multiaddr` as `storenode` when starting the app: + +``` +./build/chat2 --storenode:/dns4/node-01.do-ams3.waku.test.status.im/tcp/30303/p2p/16Uiu2HAkykgaECHswi3YKJ5dMLbq2kPVCo89fcyTd38UcQD6ej5W +``` + +Alternatively, the `chat2` application will select a random `storenode` for you from the configured fleet (`sandbox` by default) if `storenode` is left unspecified. + +``` +./build/chat2 +``` + +To disable historical message retrieval, use the `--store:false` option: + +``` +./build/chat2 --store:false +``` + +## Specifying a static peer + +In order to connect to a *specific* node as [`relay`](https://rfc.vac.dev/spec/11/) peer, define that node's `multiaddr` as a `staticnode` when starting the app: + +``` +./build/chat2 --staticnode:/dns4/node-01.do-ams3.waku.test.status.im/tcp/30303/p2p/16Uiu2HAkykgaECHswi3YKJ5dMLbq2kPVCo89fcyTd38UcQD6ej5W +``` + +This will bypass the random peer selection process and connect to the specified node. + +## Connecting to a Waku v2 fleet + +It is possible to specify a specific Waku v2 fleet to connect to when starting the app by using the `--fleet` option: + +``` +./build/chat2 --fleet:test +``` + +There are currently two fleets to select from, namely _sandbox_ (`waku.sandbox`) and _test_ (`waku.test`). +The `test` fleet is updated with each incremental change to the `nim-waku` codebase. +As a result it may have more advanced and experimental features, but will be less stable than `sandbox`. +The `sandbox` fleet is a deployed network of the latest released Waku v2 nodes. +If no `fleet` is specified, `chat2` will connect to the `sandbox` fleet by default. +To start `chat2` without connecting to a fleet, use the `--fleet:none` option _or_ [specify a static peer](#specifying-a-static-peer). + +## Specifying a content topic + +To publish chat messages on a specific [content topic](https://rfc.vac.dev/spec/14/#wakumessage), use the `--content-topic` option: + +``` +./build/chat2 --content-topic:/waku/2/my-content-topic/proto +``` + +> **NOTE:** Currently (2021/05/26) the content topic defaults to `/waku/2/huilong/proto` if left unspecified, where `huilong` is the name of our latest testnet. + +## In-chat options + +| Command | Effect | +| --- | --- | +| `/help` | displays available in-chat commands | +| `/connect` | interactively connect to a new peer | +| `/nick` | change nickname for current chat session | +| `/exit` | exits the current chat session | + +## `chat2` message protobuf format + +Each `chat2` message is encoded as follows + +```protobuf +message Chat2Message { + uint64 timestamp = 1; + string nick = 2; + bytes payload = 3; +} +``` + +where `timestamp` is the Unix timestamp of the message, `nick` is the relevant `chat2` user's selected nickname and `payload` is the actual chat message being sent. +The `payload` is the byte array representation of a UTF8 encoded string. + +# Bridge messages between `chat2` and matterbridge + +To facilitate `chat2` use in a variety of contexts, a `chat2bridge` can be deployed to bridge messages between `chat2` and any protocol supported by matterbridge. + +## Configure and run matterbridge + +1. Download and install [matterbridge](https://github.com/42wim/matterbridge) and configure an instance for the protocol(s) you want to bridge to. +Basic configuration instructions [here](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config) +2. Configure the matterbridge API. +This is used by the `chat2bridge` to relay `chat2` messages to and from matterbridge. +Configuration instructions for the matterbridge API can be found [here](https://github.com/42wim/matterbridge/wiki/Api). +The full matterbridge API specification can be found [here](https://app.swaggerhub.com/apis-docs/matterbridge/matterbridge-api/0.1.0-oas3). +The template below shows an example of a `matterbridge.toml` configuration file for bridging `chat2` to Discord. +Follow the matterbridge [Discord instructions](https://github.com/42wim/matterbridge/wiki/Section-Discord-%28basic%29) to configure your own `Token` and `Server`. +```toml +[discord.mydiscord] + +# You can get your token by following the instructions on +# https://github.com/42wim/matterbridge/wiki/Discord-bot-setup. +# If you want roles/groups mentions to be shown with names instead of ID, +# you'll need to give your bot the "Manage Roles" permission. +Token="MTk4NjIyNDgzNDcdOTI1MjQ4.Cl2FMZ.ZnCjm1XVW7vRze4b7Cq4se7kKWs-abD" + +Server="myserver" # picked from guilds the bot is connected to + +RemoteNickFormat="{NICK}@chat2: " + +[api.myapi] +BindAddress="127.0.0.1:4242" +Buffer=1000 +RemoteNickFormat="{NICK}@{PROTOCOL}" + +[[gateway]] +name="gateway1" +enable=true + +[[gateway.inout]] +account="discord.mydiscord" +channel="general" + +[[gateway.inout]] +account="api.myapi" +channel="api" +``` +3. Run matterbridge using the configuration file created in the previous step. +Note the API listening address and port in the matterbridge logs (configured as the `BindAddress` in the previous step). +``` +./matterbridge -conf matterbridge.toml +``` +``` +[0000] INFO api: Listening on 127.0.0.1:4242 +``` +## Configure and run `chat2bridge` +1. From the `nim-waku` project directory, make the `chat2bridge` target +``` +make chat2bridge +``` +2. Run `chat2bridge` with the following configuration options: +``` +--mb-host-address Listening address of the Matterbridge host +--mb-host-port Listening port of the Matterbridge host +--mb-gateway Matterbridge gateway +``` +``` +./build/chat2bridge --mb-host-address=127.0.0.1 --mb-host-port=4242 --mb-gateway="gateway1" +``` +Note that `chat2bridge` encompasses a full `wakunode2` which can be configured with the normal configuration parameters. +For a full list of configuration options, run `--help`. +``` +./build/chat2bridge --help +``` +## Connect `chat2bridge` to a `chat2` network +1. To bridge messages on an existing `chat2` network, connect to any relay peer(s) in that network from `chat2bridge`. +This can be done by either specifying the peer(s) as a `--staticnode` when starting the `chat2bridge` or calling the [`post_waku_v2_admin_v1_peers`](https://rfc.vac.dev/spec/16/#post_waku_v2_admin_v1_peers) method on the JSON-RPC API. +Note that the latter requires the `chat2bridge` to be run with `--rpc=true` and `--rpc-admin=true`. +1. To bridge from a new `chat2` instance, simply specify the `chat2bridge` listening address as a `chat2` [static peer](#Specifying-a-static-peer). diff --git a/docs/tutorial/db-migration.md b/docs/tutorial/db-migration.md new file mode 100644 index 0000000..905d5d1 --- /dev/null +++ b/docs/tutorial/db-migration.md @@ -0,0 +1,61 @@ +# Database Migration +This tutorial explains the database migration process in nim-waku. + +# Contributors Guide +## Database Migration Flow +Nim-waku utilizes the built-in `user_version` variable that Sqlite provides for tracking the database versions. +The [user_version](https://github.com/waku-org/nwaku/blob/master/waku/waku_archive/driver/sqlite_driver/migrations.nim) MUST be bumped up for every update on the database e.g, table schema/title change. +Each update should be accompanied by a migration script to move the content of the old version of the database to the new version. +The script MUST be added to the respective folder as explained in [Migration Folder Structure](#migration-folder-structure) with the proper naming as given in [ Migration Script Naming](#migration-file-naming). + +The migration is invoked whenever the database `user_version` is behind the target [user_version](https://github.com/waku-org/nwaku/blob/master/waku/waku_archive/driver/sqlite_driver/migrations.nim) indicated in the nim-waku application. +The respective migration scripts located in the [migrations folder](https://github.com/waku-org/nwaku/tree/master/migrations) will be executed to upgrade the database from its old version to the target version. + +## Migration Folder Structure +The [migrations folder](https://github.com/waku-org/nwaku/tree/master/migrations) is structured as below. + +``` +migrations/ +├── message_store +│   ├── 00001_addMessageTable.up.sql +│   ├── 00002_addSenderTimeStamp.up.sql +│   ├── ... +└── peer_store + └── 00001_addPeerTable.up.sql +``` + + + +The migration scripts are managed in two separate folders `message_store` and `peer_store`. +The `message_store` folder contains the migration scripts related to the message store tables. Similarly, the `peer_store` folder contains the scripts relevant to the peer store tables. + + +## Migration File Naming +The files in [migrations folder](https://github.com/waku-org/nwaku/tree/master/migrations) MUST follow the following naming style in order to be properly included in the migration process. +Files with invalid naming will be eliminated from the migration process. + +`_..sql` + +- `version number`: This number should match the target value of `user_version`. +- `migration script description`: A short description of what the migration script does. +- `up|down`: One of the keywords of `up` or `down` should be selected. + `up` stands for upgrade and `down` means downgrade. + +### Example +A migration file with the name `00002_addTableX.up.sql` should be interpreted as: +- `00002`: The targeted `user_version` number. +- `addTableX`: What the script does. +- `up`: This script `upgrade`s the database from `user_version = 00001` to the `user_version = 00002`. + +A downgrade migration file corresponding to the `00002_addTableX.up.sql` can be e.g., `00001_removeTableX.down.sql` and should be interpreted as: +- `00001`: The targeted `user_version` number. +- `removeTableX`: What the script does. +- `down`: This script `downgrade`s the database from `user_version = 00002` to the `user_version = 00001`. + +There can be more than one migration file for the same `user_version`. +The migration process will consider all such files while upgrading/downgrading the database. +Note that currently we **DO NOT** support **down migration**. + +# User Guide +Migrations work out of the box. +However, if you want to be extra sure, please take a backup of the SQLite database prior to upgrading your nim-waku version since we currently don't support downgrades of DB. diff --git a/docs/tutorial/dingpu.md b/docs/tutorial/dingpu.md new file mode 100644 index 0000000..0d21978 --- /dev/null +++ b/docs/tutorial/dingpu.md @@ -0,0 +1,44 @@ +# Dingpu testnet + +> TODO (2023-05-24): Deprecate or fix + +*NOTE: Some of these addresses might change. To get the latest, please see `curl -s https://fleets.status.im | jq '.fleets["waku.test"]'`* + +## Basic chat usage + +> If historical messaging is desired, the chat app requires that the remote peer specified in `storenode` option supports the WakuStore protocol. For the current cluster node deployed as part of Dingpu this is already the case. + +Start two chat apps: + +``` +./build/chat2 --ports-shift:0 --storenode:/ip4/178.128.141.171/tcp/60000/p2p/16Uiu2HAkykgaECHswi3YKJ5dMLbq2kPVCo89fcyTd38UcQD6ej5W --staticnode:/ip4/178.128.141.171/tcp/60000/p2p/16Uiu2HAkykgaECHswi3YKJ5dMLbq2kPVCo89fcyTd38UcQD6ej5W +./build/chat2 --ports-shift:1 --storenode:/ip4/178.128.141.171/tcp/60000/p2p/16Uiu2HAkykgaECHswi3YKJ5dMLbq2kPVCo89fcyTd38UcQD6ej5W --staticnode:/ip4/178.128.141.171/tcp/60000/p2p/16Uiu2HAkykgaECHswi3YKJ5dMLbq2kPVCo89fcyTd38UcQD6ej5W +``` + +By specifying `staticnode` it connects to that node subscribes to the `waku` topic. This ensures messages are relayed properly. + +Then type messages to publish. + +## Interactively add a node + +There is also an interactive mode. Type `/connect` then paste address of other node. However, this currently has some timing issues with mesh not being updated, so it is advised not to use this until this has been addressed. See https://github.com/waku-org/nwaku/issues/231 + +## Dingpu cluster node + +> TODO (2024-03-11): Fix node multiaddr + +## Run a node + +To just run a node and not interact on the chat it is enough to run `wakunode2`: +``` +./build/wakunode2 --staticnode: +``` + +You can also run the `wakubridge` process, which runs both a Waku v1 and Waku v2 +node. Currently, it has the same effect as running a `wakunode` and `wakunode2` +process separately, but bridging functionality will be added later to this +application. + +``` +./build/wakubridge --staticnodev2: --fleetv1:test +``` diff --git a/docs/tutorial/dns-disc.md b/docs/tutorial/dns-disc.md new file mode 100644 index 0000000..c9cc24e --- /dev/null +++ b/docs/tutorial/dns-disc.md @@ -0,0 +1,69 @@ +# Waku v2 DNS-based Discovery Basic Tutorial + +## Background + +Waku v2 DNS discovery is a method by which a node may find other peers by retrieving an encoded node list via DNS. +To achieve this, Waku v2 uses a Nim implementation of [EIP-1459](https://eips.ethereum.org/EIPS/eip-1459). +According to EIP-1459, the peer list is encoded as a [Merkle tree](https://www.wikiwand.com/en/Merkle_tree) of TXT records. +Connectivity information for each peer, including [wire address](https://docs.libp2p.io/concepts/addressing/) and [peer ID](https://docs.libp2p.io/concepts/peer-id/), are encapsulated in signed [Ethereum Node Records (ENR)](https://eips.ethereum.org/EIPS/eip-778). + +## Mapping ENR to `multiaddr` + +EIP-1459 DNS discovery is a scheme for retrieving an ENR list via DNS. +Waku v2 addressing is based on [libp2p addressing](https://docs.libp2p.io/concepts/addressing/), which uses a `multiaddr` scheme. + +The ENR is constructed according to [EIP-778](https://eips.ethereum.org/EIPS/eip-778). +It maps to the equivalent `libp2p` `multiaddr` for the Waku v2 node as follows: + +| ENR Key | ENR Value | +|-------------|------------------------------------------------------------------------| +| `id` | name of identity scheme. For Waku v2 generally `v4` | +| `secp256k1` | the compressed `secp256k1` public key belong to the libp2p peer ID as per [specification](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#keys). This is used to construct the `/p2p/` portion of the node's `multiaddr` | +| ip | IPv4 address. Corresponds to `/ip4/` portion of the node's `multiaddr` | +| tcp | TCP port. Corresponds to `/tcp/` portion of the node's `multiaddr` | + +The `nim-waku` implementation with integrated DNS discovery already takes care of the ENR to `multiaddr` conversion. + +## Usage + +Ensure you have built [`wakunode2`](https://github.com/status-im/nim-waku) or [`chat2`](./chat2.md) as per the linked instructions. + +The following command line options are available for both `wakunode2` or `chat2`. + +``` +--dns-discovery Enable DNS Discovery +--dns-discovery-url URL for DNS node list in format 'enrtree://@' +``` + +- `--dns-discovery` is used to enable DNS discovery on the node. Waku DNS discovery is disabled by default. +- `--dns-discovery-url` is mandatory if DNS discovery is enabled. It contains the URL for the node list. The URL must be in the format `enrtree://@` where `` is the fully qualified domain name and `` is the base32 encoding of the compressed 32-byte public key that signed the list at that location. See [EIP-1459](https://eips.ethereum.org/EIPS/eip-1459#specification) or the example below to illustrate. + +A node will attempt connection to all discovered nodes. + +## Example for `waku.test` fleet + +To illustrate the above and prove the concept, +a list of `waku.test` fleet nodes was encoded according to EIP-1459 and deployed to `test.waku.nodes.status.im`. +The list was signed by the public key `AOGYWMBYOUIMOENHXCHILPKY3ZRFEULMFI4DOM442QSZ73TT2A7VI`. +The complete URL for DNS discovery is therefore: `enrtree://AOGYWMBYOUIMOENHXCHILPKY3ZRFEULMFI4DOM442QSZ73TT2A7VI@test.waku.nodes.status.im`. + +To run a `wakunode2` with DNS-based discovery of `waku.test` nodes: + +``` +./build/wakunode2 --dns-discovery:true --dns-discovery-url:enrtree://AOGYWMBYOUIMOENHXCHILPKY3ZRFEULMFI4DOM442QSZ73TT2A7VI@test.waku.nodes.status.im +``` + +Similarly, for `chat2`: + +``` +./build/chat2 --dns-discovery:true --dns-discovery-url:enrtree://AOGYWMBYOUIMOENHXCHILPKY3ZRFEULMFI4DOM442QSZ73TT2A7VI@test.waku.nodes.status.im +``` + +The node will discover and attempt connection to all `waku.test` nodes during setup procedures. + +To use specific DNS name servers, one or more `--dns-addrs-name-server` arguments can be added: + +``` +./build/wakunode2 --dns-discovery:true --dns-discovery-url:enrtree://AOGYWMBYOUIMOENHXCHILPKY3ZRFEULMFI4DOM442QSZ73TT2A7VI@test.waku.nodes.status.im --dns-dis +covery-name-server:8.8.8.8 --dns-addrs-name-server:8.8.4.4 +``` diff --git a/docs/tutorial/filter.md b/docs/tutorial/filter.md new file mode 100644 index 0000000..2f1a423 --- /dev/null +++ b/docs/tutorial/filter.md @@ -0,0 +1,35 @@ +# Running Filter Protocol + +> TODO (2023-05-24): Deprecate or fix + +## How to + +Build: + +``` +# make wakunode2 is run as part of scripts2 target +make scripts2 +``` + +Run two nodes and connect them: + +``` +# Starts listening on 60000 with RPC server on 8545. +# Note the "listening on address" in logs. +./build/wakunode2 --ports-shift:0 + +# Run another node with staticnode argument +./build/wakunode2 --ports-shift:1 --staticnode:/ip4/0.0.0.0/tcp/60000/p2p/16Uiu2HAmF4tuht6fmna6uDqoSMgFqhUrdaVR6VQRyGr6sCpfS2jp --filternode:/ip4/0.0.0.0/tcp/60000/p2p/16Uiu2HAmF4tuht6fmna6uDqoSMgFqhUrdaVR6VQRyGr6sCpfS2jp +``` + +You should see your nodes connecting. + +Do basic RPC calls: + +``` +./build/rpc_subscribe 8545 +./build/rpc_subscribe_filter 8546 # enter your content topic; default is "1" +./build/rpc_publish 8545 # enter your message in STDIN +``` + +You should see other node receive something. diff --git a/docs/tutorial/heaptrack.md b/docs/tutorial/heaptrack.md new file mode 100644 index 0000000..d651489 --- /dev/null +++ b/docs/tutorial/heaptrack.md @@ -0,0 +1,114 @@ +# Heaptrack in Nim Waku + +## Background +Given that RAM is a limited resource, it is crucial to have a good insight on what is going on with the memory used by a particular process. + +## Heaptrack +Heaptrack is a tool that allows to generate memory usage reports. +It operates in two modes: +- preload: the tracking is made from the beginning. +- inject: the tracking starts at a certain time by attaching to a running process. + +### Building Heaptrack (tried on Ubuntu) +- `git clone git@github.com:KDE/heaptrack.git` +- `mkdir build; cd build` +- `cmake ..` + At this point, make sure the cmake doesn't complain about any missing dependency. + Among others, the most tricky deps are obtained by the next commands: + - `sudo apt install libkf5i18n-dev` + - `sudo apt install libkf5itemmodels-dev` + - `sudo apt install libkf5threadweaver-dev` + - `sudo apt install libkf5service-dev` + - `sudo apt install libkf5completion-dev` + - `sudo apt install libkf5itemviews-dev` + - `sudo apt install libkf5jobwidgets-dev` + - `sudo apt install libkf5solid-dev` + - `sudo apt install libkf5coreaddons-dev` + - `sudo apt install libkf5auth-dev` + - `sudo apt install libkf5codecs-dev` + - `sudo apt install libkf5configwidgets-dev` + - `sudo apt install libkf5xmlgui-dev` + - `sudo apt install libkf5widgetsaddons-dev` + - `sudo apt install libqt5gui5` + - `sudo apt install libkf5kio-dev` + - `sudo apt install libkf5iconthemes-dev` +- `make` +- On completion, the `bin/heaptrack_gui` and `bin/heaptrack` binaries will be generated. + - heaptrack: needed to generate the report. + - heaptrack_gui: needed to analyse the report. + +## Heaptrack & Nwaku +nwaku supports heaptrack, but it needs a special compilation setting. + +### Patch Nim compiler to register allocations on Heaptrack + +Currently, we rely on the official Nim repository. So we need to patch the Nim compiler to register allocations and deallocations on Heaptrack. +For Nim 2.2.4 version, we created a patch that can be applied as: +```bash +git apply --directory=vendor/nimbus-build-system/vendor/Nim docs/tutorial/nim.2.2.4_heaptracker_addon.patch +git add . +git commit -m "Add heaptrack support to Nim compiler - temporary patch" +``` + +> Until heaptrack support is not available in official Nim, so it is important to keep it in the `nimbus-build-system` repository. +> Commit ensures that `make update` will not override the patch unintentionally. + +> We are planning to make it available through an official PR for Nim. + +When the patch is applied, we can build wakunode2 with heaptrack support. + +### Build nwaku with heaptrack support + +`make -j HEAPTRACKER=1 wakunode2` + +### Create nwaku memory report with heaptrack + +nwaku only works correctly with heaptrack operating in 'preload' mode, i.e. the memory is tracked from the beginning. +To achieve this, the `heaptrack` binary should be prepended to the usual `wakunode`: + +e.g.: +`/build/bin/heaptrack /build/wakunode2 ...` + +While the above is running, a file with the next format is being populated with allocs/deallocs stats in the current folder: + + ``` + heaptrack...gz +e.g.: + heaptrack.wakunode2.23125.gz + ``` + +### Build a Docker image with Heaptrack + Nim Waku +Having Docker properly installed in your machine, do the next: + +- cd to the `nwaku` root folder. +- ```sudo make docker-image DOCKER_IMAGE_NAME=docker_repo:docker_tag HEAPTRACKER=1``` +- alternatively you can use the `docker-quick-image` target, this is faster but creates an ubuntu based image, so your local build environment must match. + +That will create a Docker image with both nwaku and heaptrack. The container's entry point is `ENTRYPOINT ["/heaptrack/build/bin/heaptrack", "/usr/bin/wakunode"]`, so the memory report starts being generated from the beginning. + +#### Notice for using heaptrack supporting image with `docker compose` + +Take care that wakunode2 should be started as +``` +exec /heaptrack/build/bin/heaptrack /usr/bin/wakunode\ +... all the arguments you want to pass to wakunode ... +``` + +### Extract report file from a running Docker container +Bear in mind that if you restart the container, the previous report will get lost. Therefore, before restarting, it is important to extract it from the container once you consider it has enough information. + +While the Docker container is running, run the next command: +``` +sudo docker cp 768e7de52d3c:/heaptrack.wakunode.1.gz . +``` +(replace the 768.. with your docker container id.). + +### Analyse a heaptrack report +``` +/bin/heaptrack_gui heaptrack.wakunode.1.gz +``` + +You should be able to see memory allocations. It is important +to see a legend like shown below: + +![Example of a good heaptrack report](imgs/good_heaptrack_report_example.png) diff --git a/docs/tutorial/imgs/good_heaptrack_report_example.png b/docs/tutorial/imgs/good_heaptrack_report_example.png new file mode 100644 index 0000000000000000000000000000000000000000..088ef5117db71b8cf924c43e2aa3809f49c61cc8 GIT binary patch literal 353365 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

UkCgKb3Y=>Ha5ZtmYZ8fJ@ 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�!=NLfEDwR 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�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⧀jnH!>YWIi+|Nt5+wv8I_Edk|V& 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