diff --git a/.gitattributes b/.gitattributes index 24e0b39b6a..43c43ce94a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ nym-validator-rewarder/.sqlx/** diff=nodiff +nym-node-status-api/nym-node-status-api/.sqlx/** diff=nodiff diff --git a/.github/workflows/ci-check-ns-api-version.yml b/.github/workflows/ci-check-ns-api-version.yml index 2298e1fab7..7ea704d703 100644 --- a/.github/workflows/ci-check-ns-api-version.yml +++ b/.github/workflows/ci-check-ns-api-version.yml @@ -22,17 +22,16 @@ jobs: cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml - name: Check if git tag exists - uses: actions/checkout@v4 - - run: | + run: | TAG=${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} if [[ -z "$TAG" ]]; then echo "Tag is empty" exit 1 fi - if git ls-remote --tags origin | grep -q "refs/tags/$TAG$" ; then + git ls-remote --tags origin | awk '{print $2}' + if git ls-remote --tags origin | awk '{print $2}' | grep -q "refs/tags/$TAG$" ; then echo "Tag '$TAG' ALREADY EXISTS on the remote" - # TODO uncomment after bumping NS API version - # exit 1 + exit 1 else echo "Tag '$TAG' does not exist on the remote" fi @@ -45,13 +44,14 @@ jobs: echo "Tag is empty" exit 1 fi - curl -su "${{ secrets.HARBOR_ROBOT_USERNAME }}":"${{ secrets.HARBOR_ROBOT_SECRET }}" "$registry/v2/$repo_name/tags/list" | jq - curl -su ${{ secrets.HARBOR_ROBOT_USERNAME }}:${{ secrets.HARBOR_ROBOT_SECRET }} "$registry/v2/$repo_name/tags/list" | jq -e --arg search $TAG '.tags | index($search)' > /dev/null - result=$? - if [ "${result}" -eq 0 ]; then - echo "Version '$TAG' defined in Cargo.toml already exists as tag in harbor repo" - # TODO uncomment after bumping NS API version - # exit 1 + curl -su ${{ secrets.HARBOR_ROBOT_USERNAME }}:${{ secrets.HARBOR_ROBOT_SECRET }} "$registry/v2/$repo_name/tags/list" | jq + exists=$(curl -su ${{ secrets.HARBOR_ROBOT_USERNAME }}:${{ secrets.HARBOR_ROBOT_SECRET }} "$registry/v2/$repo_name/tags/list" | jq --arg tag $TAG '.tags | contains([$tag])' ) + if [[ $exists = "true" ]]; then + echo "Version '$TAG' defined in Cargo.toml ALREADY EXISTS as tag in harbor repo" + exit 1 + elif [[ $exists = "false" ]]; then + echo "Version '$TAG' doesn't exist on the remote" else - echo "Version '$TAG' doesn't exist on the remote" + echo "Unknown output '$exists'" + exit 1 fi diff --git a/Cargo.lock b/Cargo.lock index 00e49d7ca8..e55e95af49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6339,7 +6339,7 @@ dependencies = [ [[package]] name = "nym-node-status-api" -version = "1.0.2" +version = "1.0.3" dependencies = [ "ammonia", "anyhow", diff --git a/nym-node-status-api/nym-node-status-agent/run.sh b/nym-node-status-api/nym-node-status-agent/run.sh index a01e513a1c..544c6ca731 100755 --- a/nym-node-status-api/nym-node-status-agent/run.sh +++ b/nym-node-status-api/nym-node-status-agent/run.sh @@ -3,7 +3,7 @@ set -eu export ENVIRONMENT=${ENVIRONMENT:-"mainnet"} -probe_git_ref="nym-vpn-core-v1.3.2" +probe_git_ref="nym-vpn-core-v1.4.0" crate_root=$(dirname $(realpath "$0")) monorepo_root=$(realpath "${crate_root}/../..") diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-01ee4a30bc3104712e5bc371a45d614a89d88adf02358800433e06100c13c548.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-01ee4a30bc3104712e5bc371a45d614a89d88adf02358800433e06100c13c548.json new file mode 100644 index 0000000000..d59ea9da1a --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-01ee4a30bc3104712e5bc371a45d614a89d88adf02358800433e06100c13c548.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "\n INSERT INTO mixnode_daily_stats (\n mix_id, date_utc,\n total_stake, packets_received,\n packets_sent, packets_dropped\n ) VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT(mix_id, date_utc) DO UPDATE SET\n total_stake = excluded.total_stake,\n packets_received = mixnode_daily_stats.packets_received + excluded.packets_received,\n packets_sent = mixnode_daily_stats.packets_sent + excluded.packets_sent,\n packets_dropped = mixnode_daily_stats.packets_dropped + excluded.packets_dropped\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 6 + }, + "nullable": [] + }, + "hash": "01ee4a30bc3104712e5bc371a45d614a89d88adf02358800433e06100c13c548" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-8c6c1c67df2d06da74825872f448d30505801b56506668499f9da718f1d6b8f8.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-021c6c65d1ed806d8430bef7883906b42a7e4b280c8efb32db15d7c6a51d7a27.json similarity index 76% rename from nym-node-status-api/nym-node-status-api/.sqlx/query-8c6c1c67df2d06da74825872f448d30505801b56506668499f9da718f1d6b8f8.json rename to nym-node-status-api/nym-node-status-api/.sqlx/query-021c6c65d1ed806d8430bef7883906b42a7e4b280c8efb32db15d7c6a51d7a27.json index 8ce60c2b8c..2ca61a8300 100644 --- a/nym-node-status-api/nym-node-status-api/.sqlx/query-8c6c1c67df2d06da74825872f448d30505801b56506668499f9da718f1d6b8f8.json +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-021c6c65d1ed806d8430bef7883906b42a7e4b280c8efb32db15d7c6a51d7a27.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "\n SELECT mix_id as node_id, host, http_api_port \n FROM mixnodes \n WHERE bonded = true\n ", + "query": "\n SELECT mix_id as node_id, host, http_api_port\n FROM mixnodes\n WHERE bonded = true\n ", "describe": { "columns": [ { @@ -28,5 +28,5 @@ false ] }, - "hash": "8c6c1c67df2d06da74825872f448d30505801b56506668499f9da718f1d6b8f8" + "hash": "021c6c65d1ed806d8430bef7883906b42a7e4b280c8efb32db15d7c6a51d7a27" } diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-06065394c157927e4002ddd5c7c1af626ae15728d615f539470cd7c189312385.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-06065394c157927e4002ddd5c7c1af626ae15728d615f539470cd7c189312385.json deleted file mode 100644 index 205bfdc79b..0000000000 --- a/nym-node-status-api/nym-node-status-api/.sqlx/query-06065394c157927e4002ddd5c7c1af626ae15728d615f539470cd7c189312385.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "\n INSERT INTO mixnode_description (\n mix_id, moniker, website, security_contact, details, last_updated_utc\n ) VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT (mix_id) DO UPDATE SET\n moniker = excluded.moniker,\n website = excluded.website,\n security_contact = excluded.security_contact,\n details = excluded.details,\n last_updated_utc = excluded.last_updated_utc\n ", - "describe": { - "columns": [], - "parameters": { - "Right": 6 - }, - "nullable": [] - }, - "hash": "06065394c157927e4002ddd5c7c1af626ae15728d615f539470cd7c189312385" -} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-124d45b9604439584650f401607c46bdbd162c7c689f74fe9ddfdfd48f5ddc07.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-124d45b9604439584650f401607c46bdbd162c7c689f74fe9ddfdfd48f5ddc07.json new file mode 100644 index 0000000000..62823cff34 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-124d45b9604439584650f401607c46bdbd162c7c689f74fe9ddfdfd48f5ddc07.json @@ -0,0 +1,44 @@ +{ + "db_name": "SQLite", + "query": "\n SELECT\n date_utc as \"date_utc!\",\n SUM(total_stake) as \"total_stake!: i64\",\n SUM(packets_received) as \"total_packets_received!: i64\",\n SUM(packets_sent) as \"total_packets_sent!: i64\",\n SUM(packets_dropped) as \"total_packets_dropped!: i64\"\n FROM (\n SELECT\n date_utc,\n n.total_stake,\n n.packets_received,\n n.packets_sent,\n n.packets_dropped\n FROM nym_node_daily_mixing_stats n\n UNION ALL\n SELECT\n m.date_utc,\n m.total_stake,\n m.packets_received,\n m.packets_sent,\n m.packets_dropped\n FROM mixnode_daily_stats m\n LEFT JOIN nym_node_daily_mixing_stats ON m.mix_id = nym_node_daily_mixing_stats.node_id\n WHERE nym_node_daily_mixing_stats.node_id IS NULL\n )\n GROUP BY date_utc\n ORDER BY date_utc ASC\n ", + "describe": { + "columns": [ + { + "name": "date_utc!", + "ordinal": 0, + "type_info": "Text" + }, + { + "name": "total_stake!: i64", + "ordinal": 1, + "type_info": "Int" + }, + { + "name": "total_packets_received!: i64", + "ordinal": 2, + "type_info": "Int" + }, + { + "name": "total_packets_sent!: i64", + "ordinal": 3, + "type_info": "Int" + }, + { + "name": "total_packets_dropped!: i64", + "ordinal": 4, + "type_info": "Int" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false, + false, + true, + true, + true + ] + }, + "hash": "124d45b9604439584650f401607c46bdbd162c7c689f74fe9ddfdfd48f5ddc07" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-18abc8fde56cf86baed7b4afa38f2c63cdf90f2f3b6d81afb9000bb0968dcaea.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-18abc8fde56cf86baed7b4afa38f2c63cdf90f2f3b6d81afb9000bb0968dcaea.json deleted file mode 100644 index 9bc2966149..0000000000 --- a/nym-node-status-api/nym-node-status-api/.sqlx/query-18abc8fde56cf86baed7b4afa38f2c63cdf90f2f3b6d81afb9000bb0968dcaea.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "UPDATE mixnodes\n SET bonded = ?, last_updated_utc = ?\n WHERE id = ?;", - "describe": { - "columns": [], - "parameters": { - "Right": 3 - }, - "nullable": [] - }, - "hash": "18abc8fde56cf86baed7b4afa38f2c63cdf90f2f3b6d81afb9000bb0968dcaea" -} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-21e44766729777756f6eb04bf3b81df3e591008a1e3fd664ed83ca86ac51bd8c.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-21e44766729777756f6eb04bf3b81df3e591008a1e3fd664ed83ca86ac51bd8c.json new file mode 100644 index 0000000000..52929bc782 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-21e44766729777756f6eb04bf3b81df3e591008a1e3fd664ed83ca86ac51bd8c.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "\n INSERT INTO mixnode_packet_stats_raw (\n mix_id, timestamp_utc, packets_received, packets_sent, packets_dropped\n ) VALUES (?, ?, ?, ?, ?)\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 5 + }, + "nullable": [] + }, + "hash": "21e44766729777756f6eb04bf3b81df3e591008a1e3fd664ed83ca86ac51bd8c" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-227539374e7473f6f9642289c5b5d1bcd636315ab23537cb5f6d2f82a2bcb7bf.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-227539374e7473f6f9642289c5b5d1bcd636315ab23537cb5f6d2f82a2bcb7bf.json new file mode 100644 index 0000000000..5a10f1d2c2 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-227539374e7473f6f9642289c5b5d1bcd636315ab23537cb5f6d2f82a2bcb7bf.json @@ -0,0 +1,26 @@ +{ + "db_name": "SQLite", + "query": "SELECT\n node_id,\n bond_info as \"bond_info: serde_json::Value\"\n FROM\n nym_nodes\n WHERE\n bond_info IS NOT NULL\n AND\n self_described IS NOT NULL\n ", + "describe": { + "columns": [ + { + "name": "node_id", + "ordinal": 0, + "type_info": "Int64" + }, + { + "name": "bond_info: serde_json::Value", + "ordinal": 1, + "type_info": "Text" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false, + true + ] + }, + "hash": "227539374e7473f6f9642289c5b5d1bcd636315ab23537cb5f6d2f82a2bcb7bf" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-25300e435780101fa207c8e26ef2f49ba5db84d63e89440bb494e8327fe73686.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-25300e435780101fa207c8e26ef2f49ba5db84d63e89440bb494e8327fe73686.json new file mode 100644 index 0000000000..fa5ef3a17f --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-25300e435780101fa207c8e26ef2f49ba5db84d63e89440bb494e8327fe73686.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "\n SELECT gateway_identity_key\n FROM gateways\n WHERE bonded = true\n ", + "describe": { + "columns": [ + { + "name": "gateway_identity_key", + "ordinal": 0, + "type_info": "Text" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false + ] + }, + "hash": "25300e435780101fa207c8e26ef2f49ba5db84d63e89440bb494e8327fe73686" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-283f49a65c7d70bf271702ff6a5c7ad6e68c81932d295ff18ed198c54706a57c.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-283f49a65c7d70bf271702ff6a5c7ad6e68c81932d295ff18ed198c54706a57c.json new file mode 100644 index 0000000000..a20a89ee84 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-283f49a65c7d70bf271702ff6a5c7ad6e68c81932d295ff18ed198c54706a57c.json @@ -0,0 +1,86 @@ +{ + "db_name": "SQLite", + "query": "SELECT\n node_id,\n ed25519_identity_pubkey,\n total_stake,\n ip_addresses as \"ip_addresses!: serde_json::Value\",\n mix_port,\n x25519_sphinx_pubkey,\n node_role as \"node_role: serde_json::Value\",\n supported_roles as \"supported_roles: serde_json::Value\",\n entry as \"entry: serde_json::Value\",\n performance,\n self_described as \"self_described: serde_json::Value\",\n bond_info as \"bond_info: serde_json::Value\"\n FROM\n nym_nodes\n WHERE\n self_described IS NOT NULL\n AND\n bond_info IS NOT NULL\n ", + "describe": { + "columns": [ + { + "name": "node_id", + "ordinal": 0, + "type_info": "Int64" + }, + { + "name": "ed25519_identity_pubkey", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "total_stake", + "ordinal": 2, + "type_info": "Int64" + }, + { + "name": "ip_addresses!: serde_json::Value", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "mix_port", + "ordinal": 4, + "type_info": "Int64" + }, + { + "name": "x25519_sphinx_pubkey", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "node_role: serde_json::Value", + "ordinal": 6, + "type_info": "Text" + }, + { + "name": "supported_roles: serde_json::Value", + "ordinal": 7, + "type_info": "Text" + }, + { + "name": "entry: serde_json::Value", + "ordinal": 8, + "type_info": "Text" + }, + { + "name": "performance", + "ordinal": 9, + "type_info": "Text" + }, + { + "name": "self_described: serde_json::Value", + "ordinal": 10, + "type_info": "Text" + }, + { + "name": "bond_info: serde_json::Value", + "ordinal": 11, + "type_info": "Text" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + false, + true, + true + ] + }, + "hash": "283f49a65c7d70bf271702ff6a5c7ad6e68c81932d295ff18ed198c54706a57c" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-3825020ab0ecbffe83270c57ec74fb7987a6807d3381a6068c79b127a668b190.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-3825020ab0ecbffe83270c57ec74fb7987a6807d3381a6068c79b127a668b190.json new file mode 100644 index 0000000000..3f34dd62c6 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-3825020ab0ecbffe83270c57ec74fb7987a6807d3381a6068c79b127a668b190.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "\n INSERT INTO mixnode_description (\n mix_id, moniker, website, security_contact, details, last_updated_utc\n ) VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT (mix_id) DO UPDATE SET\n moniker = excluded.moniker,\n website = excluded.website,\n security_contact = excluded.security_contact,\n details = excluded.details,\n last_updated_utc = excluded.last_updated_utc\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 6 + }, + "nullable": [] + }, + "hash": "3825020ab0ecbffe83270c57ec74fb7987a6807d3381a6068c79b127a668b190" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-3cd5cb4bfca4243925da4ddbccd811e842090e98982e1032670df77961870b32.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-3cd5cb4bfca4243925da4ddbccd811e842090e98982e1032670df77961870b32.json new file mode 100644 index 0000000000..60ecc30618 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-3cd5cb4bfca4243925da4ddbccd811e842090e98982e1032670df77961870b32.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO mixnodes\n (mix_id, identity_key, bonded, total_stake,\n host, http_api_port, full_details,\n self_described, last_updated_utc, is_dp_delegatee)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(mix_id) DO UPDATE SET\n bonded=excluded.bonded,\n total_stake=excluded.total_stake, host=excluded.host,\n http_api_port=excluded.http_api_port,\n full_details=excluded.full_details,self_described=excluded.self_described,\n last_updated_utc=excluded.last_updated_utc,\n is_dp_delegatee = excluded.is_dp_delegatee;", + "describe": { + "columns": [], + "parameters": { + "Right": 10 + }, + "nullable": [] + }, + "hash": "3cd5cb4bfca4243925da4ddbccd811e842090e98982e1032670df77961870b32" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-3d3a1fa429e3090741c6b6a8e82e692afc04b51e8782bcbf59f1eb4116112536.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-3d3a1fa429e3090741c6b6a8e82e692afc04b51e8782bcbf59f1eb4116112536.json deleted file mode 100644 index 10158436b6..0000000000 --- a/nym-node-status-api/nym-node-status-api/.sqlx/query-3d3a1fa429e3090741c6b6a8e82e692afc04b51e8782bcbf59f1eb4116112536.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "UPDATE gateways\n SET bonded = ?, last_updated_utc = ?\n WHERE id = ?;", - "describe": { - "columns": [], - "parameters": { - "Right": 3 - }, - "nullable": [] - }, - "hash": "3d3a1fa429e3090741c6b6a8e82e692afc04b51e8782bcbf59f1eb4116112536" -} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-3d5fc502f976f5081f01352856b8632c29c81bfafb043bb8744129cf9e0266ad.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-3e7e987780937873cdb393b157d7708c9f01047b0689eb0d4f7a973b328c609d.json similarity index 81% rename from nym-node-status-api/nym-node-status-api/.sqlx/query-3d5fc502f976f5081f01352856b8632c29c81bfafb043bb8744129cf9e0266ad.json rename to nym-node-status-api/nym-node-status-api/.sqlx/query-3e7e987780937873cdb393b157d7708c9f01047b0689eb0d4f7a973b328c609d.json index e8725a21d1..380af2fd77 100644 --- a/nym-node-status-api/nym-node-status-api/.sqlx/query-3d5fc502f976f5081f01352856b8632c29c81bfafb043bb8744129cf9e0266ad.json +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-3e7e987780937873cdb393b157d7708c9f01047b0689eb0d4f7a973b328c609d.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT\n id as \"id!\",\n gateway_identity_key as \"gateway_identity_key!\",\n self_described as \"self_described?\",\n explorer_pretty_bond as \"explorer_pretty_bond?\"\n FROM gateways\n WHERE gateway_identity_key = ?\n ORDER BY gateway_identity_key\n LIMIT 1", + "query": "SELECT\n id as \"id!\",\n gateway_identity_key as \"gateway_identity_key!\",\n self_described as \"self_described?\",\n explorer_pretty_bond as \"explorer_pretty_bond?\"\n FROM gateways\n WHERE gateway_identity_key = ?\n AND bonded = true\n ORDER BY gateway_identity_key\n LIMIT 1", "describe": { "columns": [ { @@ -34,5 +34,5 @@ true ] }, - "hash": "3d5fc502f976f5081f01352856b8632c29c81bfafb043bb8744129cf9e0266ad" + "hash": "3e7e987780937873cdb393b157d7708c9f01047b0689eb0d4f7a973b328c609d" } diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-71a455c705f9c25d3843ff2fb8629d1320a5eb10797cdb5a435455d22c6aeac1.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-3eb1d8491bda3c1d6e071b6eb364b9a979f4bdb11ea81b2d0f022555bab51ecb.json similarity index 61% rename from nym-node-status-api/nym-node-status-api/.sqlx/query-71a455c705f9c25d3843ff2fb8629d1320a5eb10797cdb5a435455d22c6aeac1.json rename to nym-node-status-api/nym-node-status-api/.sqlx/query-3eb1d8491bda3c1d6e071b6eb364b9a979f4bdb11ea81b2d0f022555bab51ecb.json index 983f04a451..1560c0d4e8 100644 --- a/nym-node-status-api/nym-node-status-api/.sqlx/query-71a455c705f9c25d3843ff2fb8629d1320a5eb10797cdb5a435455d22c6aeac1.json +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-3eb1d8491bda3c1d6e071b6eb364b9a979f4bdb11ea81b2d0f022555bab51ecb.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT\n gw.gateway_identity_key as \"gateway_identity_key!\",\n gw.bonded as \"bonded: bool\",\n gw.blacklisted as \"blacklisted: bool\",\n gw.performance as \"performance!\",\n gw.self_described as \"self_described?\",\n gw.explorer_pretty_bond as \"explorer_pretty_bond?\",\n gw.last_probe_result as \"last_probe_result?\",\n gw.last_probe_log as \"last_probe_log?\",\n gw.last_testrun_utc as \"last_testrun_utc?\",\n gw.last_updated_utc as \"last_updated_utc!\",\n COALESCE(gd.moniker, \"NA\") as \"moniker!\",\n COALESCE(gd.website, \"NA\") as \"website!\",\n COALESCE(gd.security_contact, \"NA\") as \"security_contact!\",\n COALESCE(gd.details, \"NA\") as \"details!\"\n FROM gateways gw\n LEFT JOIN gateway_description gd\n ON gw.gateway_identity_key = gd.gateway_identity_key\n ORDER BY gw.gateway_identity_key", + "query": "SELECT\n gw.gateway_identity_key as \"gateway_identity_key!\",\n gw.bonded as \"bonded: bool\",\n gw.performance as \"performance!\",\n gw.self_described as \"self_described?\",\n gw.explorer_pretty_bond as \"explorer_pretty_bond?\",\n gw.last_probe_result as \"last_probe_result?\",\n gw.last_probe_log as \"last_probe_log?\",\n gw.last_testrun_utc as \"last_testrun_utc?\",\n gw.last_updated_utc as \"last_updated_utc!\",\n COALESCE(gd.moniker, \"NA\") as \"moniker!\",\n COALESCE(gd.website, \"NA\") as \"website!\",\n COALESCE(gd.security_contact, \"NA\") as \"security_contact!\",\n COALESCE(gd.details, \"NA\") as \"details!\"\n FROM gateways gw\n LEFT JOIN gateway_description gd\n ON gw.gateway_identity_key = gd.gateway_identity_key\n ORDER BY gw.gateway_identity_key", "describe": { "columns": [ { @@ -14,63 +14,58 @@ "type_info": "Int64" }, { - "name": "blacklisted: bool", + "name": "performance!", "ordinal": 2, "type_info": "Int64" }, - { - "name": "performance!", - "ordinal": 3, - "type_info": "Int64" - }, { "name": "self_described?", - "ordinal": 4, + "ordinal": 3, "type_info": "Text" }, { "name": "explorer_pretty_bond?", - "ordinal": 5, + "ordinal": 4, "type_info": "Text" }, { "name": "last_probe_result?", - "ordinal": 6, + "ordinal": 5, "type_info": "Text" }, { "name": "last_probe_log?", - "ordinal": 7, + "ordinal": 6, "type_info": "Text" }, { "name": "last_testrun_utc?", - "ordinal": 8, + "ordinal": 7, "type_info": "Int64" }, { "name": "last_updated_utc!", - "ordinal": 9, + "ordinal": 8, "type_info": "Int64" }, { "name": "moniker!", - "ordinal": 10, + "ordinal": 9, "type_info": "Text" }, { "name": "website!", - "ordinal": 11, + "ordinal": 10, "type_info": "Text" }, { "name": "security_contact!", - "ordinal": 12, + "ordinal": 11, "type_info": "Text" }, { "name": "details!", - "ordinal": 13, + "ordinal": 12, "type_info": "Text" } ], @@ -82,7 +77,6 @@ false, false, false, - false, true, true, true, @@ -94,5 +88,5 @@ false ] }, - "hash": "71a455c705f9c25d3843ff2fb8629d1320a5eb10797cdb5a435455d22c6aeac1" + "hash": "3eb1d8491bda3c1d6e071b6eb364b9a979f4bdb11ea81b2d0f022555bab51ecb" } diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-3fc2baabf194b147b20be2a49401cc0c100a1d7a7c347393adde2410fa6f4dfe.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-3fc2baabf194b147b20be2a49401cc0c100a1d7a7c347393adde2410fa6f4dfe.json new file mode 100644 index 0000000000..b99c055794 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-3fc2baabf194b147b20be2a49401cc0c100a1d7a7c347393adde2410fa6f4dfe.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "\n SELECT\n total_stake\n FROM mixnodes\n WHERE mix_id = ?\n ", + "describe": { + "columns": [ + { + "name": "total_stake", + "ordinal": 0, + "type_info": "Int64" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false + ] + }, + "hash": "3fc2baabf194b147b20be2a49401cc0c100a1d7a7c347393adde2410fa6f4dfe" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-4b61a4bc32333c92a8f5ad4ad0017b40dc01845f554b5479f37855d89b309e6f.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-4b61a4bc32333c92a8f5ad4ad0017b40dc01845f554b5479f37855d89b309e6f.json deleted file mode 100644 index 8b9c9699f8..0000000000 --- a/nym-node-status-api/nym-node-status-api/.sqlx/query-4b61a4bc32333c92a8f5ad4ad0017b40dc01845f554b5479f37855d89b309e6f.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT\n id as \"id!\",\n gateway_identity_key as \"identity_key!\",\n bonded as \"bonded: bool\"\n FROM gateways\n WHERE bonded = ?", - "describe": { - "columns": [ - { - "name": "id!", - "ordinal": 0, - "type_info": "Int64" - }, - { - "name": "identity_key!", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "bonded: bool", - "ordinal": 2, - "type_info": "Int64" - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [ - false, - false, - false - ] - }, - "hash": "4b61a4bc32333c92a8f5ad4ad0017b40dc01845f554b5479f37855d89b309e6f" -} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-5912ea335a957d217f5e2b3a63a25b31715c2098310fe7a9db688bc2fd36aad4.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-5912ea335a957d217f5e2b3a63a25b31715c2098310fe7a9db688bc2fd36aad4.json new file mode 100644 index 0000000000..08bc84273c --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-5912ea335a957d217f5e2b3a63a25b31715c2098310fe7a9db688bc2fd36aad4.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "\n INSERT INTO nym_node_daily_mixing_stats (\n node_id, date_utc,\n total_stake, packets_received,\n packets_sent, packets_dropped\n ) VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT(node_id, date_utc) DO UPDATE SET\n total_stake = excluded.total_stake,\n packets_received = nym_node_daily_mixing_stats.packets_received + excluded.packets_received,\n packets_sent = nym_node_daily_mixing_stats.packets_sent + excluded.packets_sent,\n packets_dropped = nym_node_daily_mixing_stats.packets_dropped + excluded.packets_dropped\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 6 + }, + "nullable": [] + }, + "hash": "5912ea335a957d217f5e2b3a63a25b31715c2098310fe7a9db688bc2fd36aad4" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-664e059ac2c58e1115fe214376a6b326b31c93298f20019772cce2e277a194f8.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-664e059ac2c58e1115fe214376a6b326b31c93298f20019772cce2e277a194f8.json new file mode 100644 index 0000000000..2ba3ec13fa --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-664e059ac2c58e1115fe214376a6b326b31c93298f20019772cce2e277a194f8.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO nym_nodes\n (node_id, ed25519_identity_pubkey,\n total_stake,\n ip_addresses, mix_port,\n x25519_sphinx_pubkey, node_role,\n supported_roles, entry,\n self_described,\n bond_info,\n performance, last_updated_utc\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(node_id) DO UPDATE SET\n ed25519_identity_pubkey=excluded.ed25519_identity_pubkey,\n ip_addresses=excluded.ip_addresses,\n mix_port=excluded.mix_port,\n x25519_sphinx_pubkey=excluded.x25519_sphinx_pubkey,\n node_role=excluded.node_role,\n supported_roles=excluded.supported_roles,\n entry=excluded.entry,\n self_described=excluded.self_described,\n bond_info=excluded.bond_info,\n performance=excluded.performance,\n last_updated_utc=excluded.last_updated_utc\n ;", + "describe": { + "columns": [], + "parameters": { + "Right": 13 + }, + "nullable": [] + }, + "hash": "664e059ac2c58e1115fe214376a6b326b31c93298f20019772cce2e277a194f8" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-6eb1a682cf13205cf701590021cdf795147ac3724e89df5b2f24f7215d87dce1.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-6eb1a682cf13205cf701590021cdf795147ac3724e89df5b2f24f7215d87dce1.json deleted file mode 100644 index 86b61631a6..0000000000 --- a/nym-node-status-api/nym-node-status-api/.sqlx/query-6eb1a682cf13205cf701590021cdf795147ac3724e89df5b2f24f7215d87dce1.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT INTO mixnodes\n (mix_id, identity_key, bonded, total_stake,\n host, http_api_port, blacklisted, full_details,\n self_described, last_updated_utc, is_dp_delegatee)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(mix_id) DO UPDATE SET\n bonded=excluded.bonded,\n total_stake=excluded.total_stake, host=excluded.host,\n http_api_port=excluded.http_api_port,blacklisted=excluded.blacklisted,\n full_details=excluded.full_details,self_described=excluded.self_described,\n last_updated_utc=excluded.last_updated_utc,\n is_dp_delegatee = excluded.is_dp_delegatee;", - "describe": { - "columns": [], - "parameters": { - "Right": 11 - }, - "nullable": [] - }, - "hash": "6eb1a682cf13205cf701590021cdf795147ac3724e89df5b2f24f7215d87dce1" -} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-7526390c3d17622564067f153867295a279179315650f6fb363d5f3177bf70e3.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-7526390c3d17622564067f153867295a279179315650f6fb363d5f3177bf70e3.json new file mode 100644 index 0000000000..c339cc96bd --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-7526390c3d17622564067f153867295a279179315650f6fb363d5f3177bf70e3.json @@ -0,0 +1,26 @@ +{ + "db_name": "SQLite", + "query": "SELECT\n node_id,\n self_described as \"self_described: serde_json::Value\"\n FROM\n nym_nodes\n WHERE\n self_described IS NOT NULL\n ", + "describe": { + "columns": [ + { + "name": "node_id", + "ordinal": 0, + "type_info": "Int64" + }, + { + "name": "self_described: serde_json::Value", + "ordinal": 1, + "type_info": "Text" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false, + true + ] + }, + "hash": "7526390c3d17622564067f153867295a279179315650f6fb363d5f3177bf70e3" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-7b3e44e1dea0568d331017216e5375684086bbeb80f3b251adc761bae0dafe92.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-7b3e44e1dea0568d331017216e5375684086bbeb80f3b251adc761bae0dafe92.json deleted file mode 100644 index 61863d2d8a..0000000000 --- a/nym-node-status-api/nym-node-status-api/.sqlx/query-7b3e44e1dea0568d331017216e5375684086bbeb80f3b251adc761bae0dafe92.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "db_name": "SQLite", - "query": "\n SELECT packets_received, packets_sent, packets_dropped\n FROM mixnode_packet_stats_raw\n WHERE mix_id = ?\n ORDER BY timestamp_utc DESC\n LIMIT 1 OFFSET 1\n ", - "describe": { - "columns": [ - { - "name": "packets_received", - "ordinal": 0, - "type_info": "Int64" - }, - { - "name": "packets_sent", - "ordinal": 1, - "type_info": "Int64" - }, - { - "name": "packets_dropped", - "ordinal": 2, - "type_info": "Int64" - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [ - true, - true, - true - ] - }, - "hash": "7b3e44e1dea0568d331017216e5375684086bbeb80f3b251adc761bae0dafe92" -} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-84e784b7ceb479f37fa312dd9a8bb0b3debc04cd251cdfaa438bce7aca7c5992.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-84e784b7ceb479f37fa312dd9a8bb0b3debc04cd251cdfaa438bce7aca7c5992.json deleted file mode 100644 index 34f356d1b6..0000000000 --- a/nym-node-status-api/nym-node-status-api/.sqlx/query-84e784b7ceb479f37fa312dd9a8bb0b3debc04cd251cdfaa438bce7aca7c5992.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "\n INSERT INTO mixnode_packet_stats_raw (\n mix_id, timestamp_utc, packets_received, packets_sent, packets_dropped\n ) VALUES (?, ?, ?, ?, ?)\n ", - "describe": { - "columns": [], - "parameters": { - "Right": 5 - }, - "nullable": [] - }, - "hash": "84e784b7ceb479f37fa312dd9a8bb0b3debc04cd251cdfaa438bce7aca7c5992" -} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-8571faad2f66e08f24acfbfe036d17ca6eb090df7f6d52ef89c5d51564f8b45c.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-8571faad2f66e08f24acfbfe036d17ca6eb090df7f6d52ef89c5d51564f8b45c.json deleted file mode 100644 index 3f171170db..0000000000 --- a/nym-node-status-api/nym-node-status-api/.sqlx/query-8571faad2f66e08f24acfbfe036d17ca6eb090df7f6d52ef89c5d51564f8b45c.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "UPDATE gateways\n SET blacklisted = true\n WHERE gateway_identity_key = ?;", - "describe": { - "columns": [], - "parameters": { - "Right": 1 - }, - "nullable": [] - }, - "hash": "8571faad2f66e08f24acfbfe036d17ca6eb090df7f6d52ef89c5d51564f8b45c" -} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-9104e50524ad5a103bd199a0531d73b74876e9aecda2117227e2e180258d91a1.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-9104e50524ad5a103bd199a0531d73b74876e9aecda2117227e2e180258d91a1.json new file mode 100644 index 0000000000..e3e26ae088 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-9104e50524ad5a103bd199a0531d73b74876e9aecda2117227e2e180258d91a1.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "\n INSERT INTO nym_node_descriptions (\n node_id, moniker, website, security_contact, details, last_updated_utc\n ) VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT (node_id) DO UPDATE SET\n moniker = excluded.moniker,\n website = excluded.website,\n security_contact = excluded.security_contact,\n details = excluded.details,\n last_updated_utc = excluded.last_updated_utc\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 6 + }, + "nullable": [] + }, + "hash": "9104e50524ad5a103bd199a0531d73b74876e9aecda2117227e2e180258d91a1" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-9334f0c91252fcd7ec72558a271222615bb282e5334665700709ae475a5daea2.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-9334f0c91252fcd7ec72558a271222615bb282e5334665700709ae475a5daea2.json new file mode 100644 index 0000000000..5f5dcdcf44 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-9334f0c91252fcd7ec72558a271222615bb282e5334665700709ae475a5daea2.json @@ -0,0 +1,86 @@ +{ + "db_name": "SQLite", + "query": "SELECT\n node_id,\n ed25519_identity_pubkey,\n total_stake,\n ip_addresses as \"ip_addresses!: serde_json::Value\",\n mix_port,\n x25519_sphinx_pubkey,\n node_role as \"node_role: serde_json::Value\",\n supported_roles as \"supported_roles: serde_json::Value\",\n entry as \"entry: serde_json::Value\",\n performance,\n self_described as \"self_described: serde_json::Value\",\n bond_info as \"bond_info: serde_json::Value\"\n FROM\n nym_nodes\n ", + "describe": { + "columns": [ + { + "name": "node_id", + "ordinal": 0, + "type_info": "Int64" + }, + { + "name": "ed25519_identity_pubkey", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "total_stake", + "ordinal": 2, + "type_info": "Int64" + }, + { + "name": "ip_addresses!: serde_json::Value", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "mix_port", + "ordinal": 4, + "type_info": "Int64" + }, + { + "name": "x25519_sphinx_pubkey", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "node_role: serde_json::Value", + "ordinal": 6, + "type_info": "Text" + }, + { + "name": "supported_roles: serde_json::Value", + "ordinal": 7, + "type_info": "Text" + }, + { + "name": "entry: serde_json::Value", + "ordinal": 8, + "type_info": "Text" + }, + { + "name": "performance", + "ordinal": 9, + "type_info": "Text" + }, + { + "name": "self_described: serde_json::Value", + "ordinal": 10, + "type_info": "Text" + }, + { + "name": "bond_info: serde_json::Value", + "ordinal": 11, + "type_info": "Text" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + false, + true, + true + ] + }, + "hash": "9334f0c91252fcd7ec72558a271222615bb282e5334665700709ae475a5daea2" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-9796d354ae075eab4cbd3438839c39da94025494395ec7b093aefef696f2d0c5.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-9796d354ae075eab4cbd3438839c39da94025494395ec7b093aefef696f2d0c5.json new file mode 100644 index 0000000000..967a2c648c --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-9796d354ae075eab4cbd3438839c39da94025494395ec7b093aefef696f2d0c5.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO gateways\n (gateway_identity_key, bonded,\n self_described, explorer_pretty_bond,\n last_updated_utc, performance)\n VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT(gateway_identity_key) DO UPDATE SET\n bonded=excluded.bonded,\n self_described=excluded.self_described,\n explorer_pretty_bond=excluded.explorer_pretty_bond,\n last_updated_utc=excluded.last_updated_utc,\n performance = excluded.performance;", + "describe": { + "columns": [], + "parameters": { + "Right": 6 + }, + "nullable": [] + }, + "hash": "9796d354ae075eab4cbd3438839c39da94025494395ec7b093aefef696f2d0c5" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-97f4b340bb0f6c9c78d77b24d4f9d3d13ab61cbaac6f8c3cfc06c95e0f13252f.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-97f4b340bb0f6c9c78d77b24d4f9d3d13ab61cbaac6f8c3cfc06c95e0f13252f.json new file mode 100644 index 0000000000..53ad65993f --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-97f4b340bb0f6c9c78d77b24d4f9d3d13ab61cbaac6f8c3cfc06c95e0f13252f.json @@ -0,0 +1,32 @@ +{ + "db_name": "SQLite", + "query": "\n SELECT\n COALESCE(packets_received, 0) as packets_received,\n COALESCE(packets_sent, 0) as packets_sent,\n COALESCE(packets_dropped, 0) as packets_dropped\n FROM nym_nodes_packet_stats_raw\n WHERE node_id = ?\n ORDER BY timestamp_utc DESC\n LIMIT 1 OFFSET 1\n ", + "describe": { + "columns": [ + { + "name": "packets_received", + "ordinal": 0, + "type_info": "Int64" + }, + { + "name": "packets_sent", + "ordinal": 1, + "type_info": "Int64" + }, + { + "name": "packets_dropped", + "ordinal": 2, + "type_info": "Int64" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "97f4b340bb0f6c9c78d77b24d4f9d3d13ab61cbaac6f8c3cfc06c95e0f13252f" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-a14d5767512bc88ac47b667c47a773b548ccb20bc539839766080d8455439339.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-a14d5767512bc88ac47b667c47a773b548ccb20bc539839766080d8455439339.json deleted file mode 100644 index d729065fcb..0000000000 --- a/nym-node-status-api/nym-node-status-api/.sqlx/query-a14d5767512bc88ac47b667c47a773b548ccb20bc539839766080d8455439339.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "\n INSERT INTO mixnode_daily_stats (\n mix_id, date_utc, total_stake, packets_received, packets_sent, packets_dropped\n ) VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT(mix_id, date_utc) DO UPDATE SET\n total_stake = excluded.total_stake,\n packets_received = mixnode_daily_stats.packets_received + excluded.packets_received,\n packets_sent = mixnode_daily_stats.packets_sent + excluded.packets_sent,\n packets_dropped = mixnode_daily_stats.packets_dropped + excluded.packets_dropped\n ", - "describe": { - "columns": [], - "parameters": { - "Right": 6 - }, - "nullable": [] - }, - "hash": "a14d5767512bc88ac47b667c47a773b548ccb20bc539839766080d8455439339" -} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-b41fc93f5dc7a397e8898776bf1335d9c26fe1447309f46623bcfee4537991b1.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-b41fc93f5dc7a397e8898776bf1335d9c26fe1447309f46623bcfee4537991b1.json new file mode 100644 index 0000000000..cf560141fd --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-b41fc93f5dc7a397e8898776bf1335d9c26fe1447309f46623bcfee4537991b1.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "DELETE FROM nym_nodes\n WHERE node_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "b41fc93f5dc7a397e8898776bf1335d9c26fe1447309f46623bcfee4537991b1" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-c42917c9542c1d720d92035863064741aefc9f7a7d1630f6b863ebd8174b6684.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-c42917c9542c1d720d92035863064741aefc9f7a7d1630f6b863ebd8174b6684.json new file mode 100644 index 0000000000..86b8a642bd --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-c42917c9542c1d720d92035863064741aefc9f7a7d1630f6b863ebd8174b6684.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "UPDATE\n mixnodes\n SET\n bonded = false\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 0 + }, + "nullable": [] + }, + "hash": "c42917c9542c1d720d92035863064741aefc9f7a7d1630f6b863ebd8174b6684" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-c5e3cd7284b334df5aa979b1627ea1f6dc2aed00cedde25f2be3567e47064351.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-c5e3cd7284b334df5aa979b1627ea1f6dc2aed00cedde25f2be3567e47064351.json deleted file mode 100644 index 2e4f34fd85..0000000000 --- a/nym-node-status-api/nym-node-status-api/.sqlx/query-c5e3cd7284b334df5aa979b1627ea1f6dc2aed00cedde25f2be3567e47064351.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "db_name": "SQLite", - "query": "\n SELECT\n date_utc as \"date_utc!\",\n packets_received as \"total_packets_received!: i64\",\n packets_sent as \"total_packets_sent!: i64\",\n packets_dropped as \"total_packets_dropped!: i64\",\n total_stake as \"total_stake!: i64\"\n FROM (\n SELECT\n date_utc,\n SUM(packets_received) as packets_received,\n SUM(packets_sent) as packets_sent,\n SUM(packets_dropped) as packets_dropped,\n SUM(total_stake) as total_stake\n FROM mixnode_daily_stats\n GROUP BY date_utc\n ORDER BY date_utc DESC\n LIMIT 30\n )\n GROUP BY date_utc\n ORDER BY date_utc\n ", - "describe": { - "columns": [ - { - "name": "date_utc!", - "ordinal": 0, - "type_info": "Text" - }, - { - "name": "total_packets_received!: i64", - "ordinal": 1, - "type_info": "Int64" - }, - { - "name": "total_packets_sent!: i64", - "ordinal": 2, - "type_info": "Int64" - }, - { - "name": "total_packets_dropped!: i64", - "ordinal": 3, - "type_info": "Int64" - }, - { - "name": "total_stake!: i64", - "ordinal": 4, - "type_info": "Int64" - } - ], - "parameters": { - "Right": 0 - }, - "nullable": [ - false, - true, - true, - true, - false - ] - }, - "hash": "c5e3cd7284b334df5aa979b1627ea1f6dc2aed00cedde25f2be3567e47064351" -} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-c7ba2621becb9ac4b5dee0ce303dadfcf19095935867a51cbd5b8362d1505fcc.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-c7ba2621becb9ac4b5dee0ce303dadfcf19095935867a51cbd5b8362d1505fcc.json deleted file mode 100644 index 4d0edd1e88..0000000000 --- a/nym-node-status-api/nym-node-status-api/.sqlx/query-c7ba2621becb9ac4b5dee0ce303dadfcf19095935867a51cbd5b8362d1505fcc.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT\n id as \"id!\",\n identity_key as \"identity_key!\",\n bonded as \"bonded: bool\"\n FROM mixnodes\n WHERE bonded = ?", - "describe": { - "columns": [ - { - "name": "id!", - "ordinal": 0, - "type_info": "Int64" - }, - { - "name": "identity_key!", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "bonded: bool", - "ordinal": 2, - "type_info": "Int64" - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [ - false, - false, - false - ] - }, - "hash": "c7ba2621becb9ac4b5dee0ce303dadfcf19095935867a51cbd5b8362d1505fcc" -} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-c910788edefe64bbb34379702bcbde9ec6159c9fa03b13652e1f620dcd92125e.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-c910788edefe64bbb34379702bcbde9ec6159c9fa03b13652e1f620dcd92125e.json new file mode 100644 index 0000000000..5c06c0e053 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-c910788edefe64bbb34379702bcbde9ec6159c9fa03b13652e1f620dcd92125e.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "\n SELECT mix_id\n FROM mixnodes\n WHERE bonded = true\n ", + "describe": { + "columns": [ + { + "name": "mix_id", + "ordinal": 0, + "type_info": "Int64" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false + ] + }, + "hash": "c910788edefe64bbb34379702bcbde9ec6159c9fa03b13652e1f620dcd92125e" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-969acbff4b128d3a3dc998bb5db1a4c8b4c106767e0276435dc23fcfd6acfe4f.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-d2e07d44594ca5b44a6100482ff432c39d761f2a0ac1d6515cf73416f2eb6c61.json similarity index 51% rename from nym-node-status-api/nym-node-status-api/.sqlx/query-969acbff4b128d3a3dc998bb5db1a4c8b4c106767e0276435dc23fcfd6acfe4f.json rename to nym-node-status-api/nym-node-status-api/.sqlx/query-d2e07d44594ca5b44a6100482ff432c39d761f2a0ac1d6515cf73416f2eb6c61.json index 007f4ecb4f..abcb28773f 100644 --- a/nym-node-status-api/nym-node-status-api/.sqlx/query-969acbff4b128d3a3dc998bb5db1a4c8b4c106767e0276435dc23fcfd6acfe4f.json +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-d2e07d44594ca5b44a6100482ff432c39d761f2a0ac1d6515cf73416f2eb6c61.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "\n SELECT\n total_stake\n FROM mixnodes\n WHERE mix_id = ?\n ", + "query": "\n SELECT\n total_stake\n FROM nym_nodes\n WHERE node_id = ?\n ", "describe": { "columns": [ { @@ -16,5 +16,5 @@ false ] }, - "hash": "969acbff4b128d3a3dc998bb5db1a4c8b4c106767e0276435dc23fcfd6acfe4f" + "hash": "d2e07d44594ca5b44a6100482ff432c39d761f2a0ac1d6515cf73416f2eb6c61" } diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-d8ea93e781666e6267902170709ee2aa37f6163525bbdce1a4cebef4a285f8d9.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-d8ea93e781666e6267902170709ee2aa37f6163525bbdce1a4cebef4a285f8d9.json deleted file mode 100644 index 94e5513279..0000000000 --- a/nym-node-status-api/nym-node-status-api/.sqlx/query-d8ea93e781666e6267902170709ee2aa37f6163525bbdce1a4cebef4a285f8d9.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT INTO gateways\n (gateway_identity_key, bonded, blacklisted,\n self_described, explorer_pretty_bond,\n last_updated_utc, performance)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(gateway_identity_key) DO UPDATE SET\n bonded=excluded.bonded,\n blacklisted=excluded.blacklisted,\n self_described=excluded.self_described,\n explorer_pretty_bond=excluded.explorer_pretty_bond,\n last_updated_utc=excluded.last_updated_utc,\n performance = excluded.performance;", - "describe": { - "columns": [], - "parameters": { - "Right": 7 - }, - "nullable": [] - }, - "hash": "d8ea93e781666e6267902170709ee2aa37f6163525bbdce1a4cebef4a285f8d9" -} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-f1f47a4490c3e1330885ef3cf3cda054f2cf760520a46a94db22a02a9cb53dba.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-f1f47a4490c3e1330885ef3cf3cda054f2cf760520a46a94db22a02a9cb53dba.json new file mode 100644 index 0000000000..3f55754cc9 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-f1f47a4490c3e1330885ef3cf3cda054f2cf760520a46a94db22a02a9cb53dba.json @@ -0,0 +1,32 @@ +{ + "db_name": "SQLite", + "query": "\n SELECT\n COALESCE(packets_received, 0) as packets_received,\n COALESCE(packets_sent, 0) as packets_sent,\n COALESCE(packets_dropped, 0) as packets_dropped\n FROM mixnode_packet_stats_raw\n WHERE mix_id = ?\n ORDER BY timestamp_utc DESC\n LIMIT 1 OFFSET 1\n ", + "describe": { + "columns": [ + { + "name": "packets_received", + "ordinal": 0, + "type_info": "Int64" + }, + { + "name": "packets_sent", + "ordinal": 1, + "type_info": "Int64" + }, + { + "name": "packets_dropped", + "ordinal": 2, + "type_info": "Int64" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "f1f47a4490c3e1330885ef3cf3cda054f2cf760520a46a94db22a02a9cb53dba" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-f2a7e7229b414a6283685558d1d0731d21b1a92eb39481cf342b87c3b5b0f759.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-f2a7e7229b414a6283685558d1d0731d21b1a92eb39481cf342b87c3b5b0f759.json new file mode 100644 index 0000000000..dd5529e9e7 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-f2a7e7229b414a6283685558d1d0731d21b1a92eb39481cf342b87c3b5b0f759.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "\n INSERT INTO gateway_description (\n gateway_identity_key,\n moniker,\n website,\n security_contact,\n details,\n last_updated_utc\n ) VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT (gateway_identity_key) DO UPDATE SET\n moniker = excluded.moniker,\n website = excluded.website,\n security_contact = excluded.security_contact,\n details = excluded.details,\n last_updated_utc = excluded.last_updated_utc\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 6 + }, + "nullable": [] + }, + "hash": "f2a7e7229b414a6283685558d1d0731d21b1a92eb39481cf342b87c3b5b0f759" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-f0a4316081d1be9444a87b95d933d31cb4bcc4071d31d8d2f7755e2d2c2e3e35.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-f75af377da33db1455c6e0f612e0fa9583888f343b8b59faf37fc6799b244379.json similarity index 60% rename from nym-node-status-api/nym-node-status-api/.sqlx/query-f0a4316081d1be9444a87b95d933d31cb4bcc4071d31d8d2f7755e2d2c2e3e35.json rename to nym-node-status-api/nym-node-status-api/.sqlx/query-f75af377da33db1455c6e0f612e0fa9583888f343b8b59faf37fc6799b244379.json index d3f7611ba2..484facb672 100644 --- a/nym-node-status-api/nym-node-status-api/.sqlx/query-f0a4316081d1be9444a87b95d933d31cb4bcc4071d31d8d2f7755e2d2c2e3e35.json +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-f75af377da33db1455c6e0f612e0fa9583888f343b8b59faf37fc6799b244379.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT\n mn.mix_id as \"mix_id!\",\n mn.bonded as \"bonded: bool\",\n mn.blacklisted as \"blacklisted: bool\",\n mn.is_dp_delegatee as \"is_dp_delegatee: bool\",\n mn.total_stake as \"total_stake!\",\n mn.full_details as \"full_details!\",\n mn.self_described as \"self_described\",\n mn.last_updated_utc as \"last_updated_utc!\",\n COALESCE(md.moniker, \"NA\") as \"moniker!\",\n COALESCE(md.website, \"NA\") as \"website!\",\n COALESCE(md.security_contact, \"NA\") as \"security_contact!\",\n COALESCE(md.details, \"NA\") as \"details!\"\n FROM mixnodes mn\n LEFT JOIN mixnode_description md ON mn.mix_id = md.mix_id\n ORDER BY mn.mix_id", + "query": "SELECT\n mn.mix_id as \"mix_id!\",\n mn.bonded as \"bonded: bool\",\n mn.is_dp_delegatee as \"is_dp_delegatee: bool\",\n mn.total_stake as \"total_stake!\",\n mn.full_details as \"full_details!\",\n mn.self_described as \"self_described\",\n mn.last_updated_utc as \"last_updated_utc!\",\n COALESCE(md.moniker, \"NA\") as \"moniker!\",\n COALESCE(md.website, \"NA\") as \"website!\",\n COALESCE(md.security_contact, \"NA\") as \"security_contact!\",\n COALESCE(md.details, \"NA\") as \"details!\"\n FROM mixnodes mn\n LEFT JOIN mixnode_description md ON mn.mix_id = md.mix_id\n ORDER BY mn.mix_id", "describe": { "columns": [ { @@ -14,53 +14,48 @@ "type_info": "Int64" }, { - "name": "blacklisted: bool", + "name": "is_dp_delegatee: bool", "ordinal": 2, "type_info": "Int64" }, { - "name": "is_dp_delegatee: bool", + "name": "total_stake!", "ordinal": 3, "type_info": "Int64" }, - { - "name": "total_stake!", - "ordinal": 4, - "type_info": "Int64" - }, { "name": "full_details!", - "ordinal": 5, + "ordinal": 4, "type_info": "Text" }, { "name": "self_described", - "ordinal": 6, + "ordinal": 5, "type_info": "Text" }, { "name": "last_updated_utc!", - "ordinal": 7, + "ordinal": 6, "type_info": "Int64" }, { "name": "moniker!", - "ordinal": 8, + "ordinal": 7, "type_info": "Text" }, { "name": "website!", - "ordinal": 9, + "ordinal": 8, "type_info": "Text" }, { "name": "security_contact!", - "ordinal": 10, + "ordinal": 9, "type_info": "Text" }, { "name": "details!", - "ordinal": 11, + "ordinal": 10, "type_info": "Text" } ], @@ -72,7 +67,6 @@ false, false, false, - false, true, true, false, @@ -82,5 +76,5 @@ false ] }, - "hash": "f0a4316081d1be9444a87b95d933d31cb4bcc4071d31d8d2f7755e2d2c2e3e35" + "hash": "f75af377da33db1455c6e0f612e0fa9583888f343b8b59faf37fc6799b244379" } diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-f7e3fa31d68c028bf39cc95389f29f8758ec922dd2e7ea064a1e537e580c9ee5.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-f7e3fa31d68c028bf39cc95389f29f8758ec922dd2e7ea064a1e537e580c9ee5.json new file mode 100644 index 0000000000..da95053996 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-f7e3fa31d68c028bf39cc95389f29f8758ec922dd2e7ea064a1e537e580c9ee5.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "UPDATE\n gateways\n SET\n bonded = false\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 0 + }, + "nullable": [] + }, + "hash": "f7e3fa31d68c028bf39cc95389f29f8758ec922dd2e7ea064a1e537e580c9ee5" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-fb2fcd26974ce4c3f5055fa2ca8c266223814c19ab2a5763a0575274d684d02e.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-fb2fcd26974ce4c3f5055fa2ca8c266223814c19ab2a5763a0575274d684d02e.json new file mode 100644 index 0000000000..50a09435c0 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-fb2fcd26974ce4c3f5055fa2ca8c266223814c19ab2a5763a0575274d684d02e.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "SELECT\n node_id as \"node_id!: i64\"\n FROM\n nym_nodes\n ", + "describe": { + "columns": [ + { + "name": "node_id!: i64", + "ordinal": 0, + "type_info": "Int64" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + true + ] + }, + "hash": "fb2fcd26974ce4c3f5055fa2ca8c266223814c19ab2a5763a0575274d684d02e" +} diff --git a/nym-node-status-api/nym-node-status-api/.sqlx/query-fcb1698d9e0e3a14524c92e7c99a811588c2bbc50d4975487a0464321a1b18c9.json b/nym-node-status-api/nym-node-status-api/.sqlx/query-fcb1698d9e0e3a14524c92e7c99a811588c2bbc50d4975487a0464321a1b18c9.json new file mode 100644 index 0000000000..296c6389d2 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/.sqlx/query-fcb1698d9e0e3a14524c92e7c99a811588c2bbc50d4975487a0464321a1b18c9.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "\n INSERT INTO nym_nodes_packet_stats_raw (\n node_id, timestamp_utc, packets_received, packets_sent, packets_dropped\n ) VALUES (?, ?, ?, ?, ?)\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 5 + }, + "nullable": [] + }, + "hash": "fcb1698d9e0e3a14524c92e7c99a811588c2bbc50d4975487a0464321a1b18c9" +} diff --git a/nym-node-status-api/nym-node-status-api/Cargo.toml b/nym-node-status-api/nym-node-status-api/Cargo.toml index d3e70db0c6..2cd1ed4d72 100644 --- a/nym-node-status-api/nym-node-status-api/Cargo.toml +++ b/nym-node-status-api/nym-node-status-api/Cargo.toml @@ -3,9 +3,7 @@ [package] name = "nym-node-status-api" - - -version = "1.0.2" +version = "1.0.3" authors.workspace = true repository.workspace = true homepage.workspace = true diff --git a/nym-node-status-api/nym-node-status-api/launch_node_status_api.sh b/nym-node-status-api/nym-node-status-api/launch_node_status_api.sh index b8a16eb3ce..bd21bee53d 100755 --- a/nym-node-status-api/nym-node-status-api/launch_node_status_api.sh +++ b/nym-node-status-api/nym-node-status-api/launch_node_status_api.sh @@ -5,13 +5,8 @@ set -e user_rust_log_preference=$RUST_LOG export ENVIRONMENT=${ENVIRONMENT:-"mainnet"} export NYM_API_CLIENT_TIMEOUT=60 -export EXPLORER_CLIENT_TIMEOUT=60 export NODE_STATUS_API_TESTRUN_REFRESH_INTERVAL=120 -if [ "$ENVIRONMENT" = "mainnet" ]; then - export NYM_NODE_STATUS_API_HM_URL="https://harbourmaster.nymtech.net" -fi - # public counterpart of the agent's private key. # For TESTING only. NOT used in any other environment export NODE_STATUS_API_AGENT_KEY_LIST="H4z8kx5Kkf5JMQHhxaW1MwYndjKCDHC7HsVhHTFfBZ4J" diff --git a/nym-node-status-api/nym-node-status-api/migrations/005_node_self_described.sql b/nym-node-status-api/nym-node-status-api/migrations/005_node_self_described.sql new file mode 100644 index 0000000000..8ba7102df1 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/migrations/005_node_self_described.sql @@ -0,0 +1,61 @@ +ALTER TABLE nym_nodes ADD COLUMN self_described TEXT; +ALTER TABLE nym_nodes ADD COLUMN bond_info TEXT; + +-- # Why recreate tables? +-- I need DELETE with CASCADE functionality, but ALTER TABLE doesn't support +-- adding constraints (which CASCADE is). So I recreate tables with proper +-- constraints and fill them with existing data. + +-- To avoid invalidating existing FK references, temporarily disable FK enforcement. +PRAGMA foreign_keys=off; + +DROP INDEX IF EXISTS idx_nym_nodes_packet_stats_raw_node_id_timestamp_utc; + +ALTER TABLE nym_node_descriptions RENAME TO _nym_node_descriptions_old; +ALTER TABLE nym_nodes_packet_stats_raw RENAME TO _nym_nodes_packet_stats_raw_old; +ALTER TABLE nym_node_daily_mixing_stats RENAME TO _nym_node_daily_mixing_stats_old; + +CREATE TABLE nym_node_descriptions ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + node_id INTEGER UNIQUE NOT NULL, + moniker VARCHAR, + website VARCHAR, + security_contact VARCHAR, + details VARCHAR, + last_updated_utc INTEGER NOT NULL, + FOREIGN KEY (node_id) REFERENCES nym_nodes (node_id) ON DELETE CASCADE +); + +CREATE TABLE nym_nodes_packet_stats_raw ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + node_id INTEGER NOT NULL, + timestamp_utc INTEGER NOT NULL, + packets_received INTEGER, + packets_sent INTEGER, + packets_dropped INTEGER, + FOREIGN KEY (node_id) REFERENCES nym_nodes (node_id) ON DELETE CASCADE +); + +CREATE INDEX idx_nym_nodes_packet_stats_raw_node_id_timestamp_utc ON nym_nodes_packet_stats_raw (node_id, timestamp_utc); + +CREATE TABLE nym_node_daily_mixing_stats ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + node_id INTEGER NOT NULL, + total_stake BIGINT NOT NULL, + date_utc VARCHAR NOT NULL, + packets_received INTEGER DEFAULT 0, + packets_sent INTEGER DEFAULT 0, + packets_dropped INTEGER DEFAULT 0, + FOREIGN KEY (node_id) REFERENCES nym_nodes (node_id) ON DELETE CASCADE, + UNIQUE (node_id, date_utc) -- This constraint automatically creates an index +); + +INSERT INTO nym_node_descriptions SELECT * FROM _nym_node_descriptions_old; +INSERT INTO nym_nodes_packet_stats_raw SELECT * FROM _nym_nodes_packet_stats_raw_old; +INSERT INTO nym_node_daily_mixing_stats SELECT * FROM _nym_node_daily_mixing_stats_old; + +DROP TABLE _nym_node_descriptions_old; +DROP TABLE _nym_nodes_packet_stats_raw_old; +DROP TABLE _nym_node_daily_mixing_stats_old; + +PRAGMA foreign_keys=on; diff --git a/nym-node-status-api/nym-node-status-api/src/db/mod.rs b/nym-node-status-api/nym-node-status-api/src/db/mod.rs index 86e25e9227..cc3398964c 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/mod.rs @@ -1,5 +1,9 @@ use anyhow::{anyhow, Result}; -use sqlx::{migrate::Migrator, sqlite::SqliteConnectOptions, ConnectOptions, SqlitePool}; +use sqlx::{ + migrate::Migrator, + sqlite::{SqliteAutoVacuum, SqliteConnectOptions, SqliteSynchronous}, + ConnectOptions, SqlitePool, +}; use std::str::FromStr; pub(crate) mod models; @@ -16,6 +20,10 @@ pub(crate) struct Storage { impl Storage { pub async fn init(connection_url: String) -> Result { let connect_options = SqliteConnectOptions::from_str(&connection_url)? + .journal_mode(sqlx::sqlite::SqliteJournalMode::Wal) + .synchronous(SqliteSynchronous::Normal) + .auto_vacuum(SqliteAutoVacuum::Incremental) + .foreign_keys(true) .create_if_missing(true) .disable_statement_logging(); diff --git a/nym-node-status-api/nym-node-status-api/src/db/models.rs b/nym-node-status-api/nym-node-status-api/src/db/models.rs index 2bd0931ffa..062399bca5 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/models.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/models.rs @@ -2,20 +2,33 @@ use std::str::FromStr; use crate::{ http::{self, models::SummaryHistory}, - utils::NumericalCheckedCast, + utils::{decimal_to_i64, NumericalCheckedCast}, }; use anyhow::Context; use nym_contracts_common::Percent; use nym_crypto::asymmetric::{ed25519, x25519}; use nym_network_defaults::DEFAULT_NYM_NODE_HTTP_PORT; use nym_node_requests::api::v1::node::models::NodeDescription; -use nym_validator_client::nym_api::SkimmedNode; +use nym_validator_client::{ + client::NymNodeDetails, models::NymNodeDescription, nym_api::SkimmedNode, +}; use serde::{Deserialize, Serialize}; use sqlx::FromRow; use strum_macros::{EnumString, FromRepr}; use time::{Date, OffsetDateTime}; use utoipa::ToSchema; +macro_rules! serialize_opt_to_value { + ($var:expr) => {{ + match $var { + None => Ok(None), + Some(ref value) => serde_json::to_value(value).map(Some).map_err(|err| { + anyhow::anyhow!("Failed to serialize {}: {:?}", stringify!($var), err) + }), + } + }}; +} + pub(crate) struct GatewayInsertRecord { pub(crate) identity_key: String, pub(crate) bonded: bool, @@ -360,6 +373,7 @@ impl TryFrom for http::models::SessionStats { } } +#[derive(strum_macros::Display)] pub(crate) enum ScrapeNodeKind { LegacyMixnode { mix_id: i64 }, MixingNymNode { node_id: i64 }, @@ -406,11 +420,11 @@ impl ScraperNodeInfo { } } +#[allow(dead_code)] // it's not dead code but clippy doesn't detect usage in sqlx macros #[derive(sqlx::Decode, Debug)] pub(crate) struct NymNodeDto { pub node_id: i64, pub ed25519_identity_pubkey: String, - #[allow(dead_code)] // it's not dead code but clippy doesn't detect usage in sqlx macros pub total_stake: i64, pub ip_addresses: serde_json::Value, pub mix_port: i64, @@ -419,8 +433,11 @@ pub(crate) struct NymNodeDto { pub supported_roles: serde_json::Value, pub entry: Option, pub performance: String, + pub self_described: Option, + pub bond_info: Option, } +#[allow(dead_code)] // it's not dead code but clippy doesn't detect usage in sqlx macros #[derive(Debug)] pub(crate) struct NymNodeInsertRecord { pub node_id: i64, @@ -433,13 +450,27 @@ pub(crate) struct NymNodeInsertRecord { pub supported_roles: serde_json::Value, pub performance: String, pub entry: Option, + pub self_described: Option, + pub bond_info: Option, pub last_updated_utc: String, } impl NymNodeInsertRecord { - pub fn new(skimmed_node: SkimmedNode, total_stake: i64) -> anyhow::Result { + pub fn new( + skimmed_node: SkimmedNode, + bond_info: Option<&NymNodeDetails>, + self_described: Option<&NymNodeDescription>, + ) -> anyhow::Result { let now = OffsetDateTime::now_utc().to_string(); + // if bond info is missing, set stake to 0 + let total_stake = bond_info + .map(|info| decimal_to_i64(info.total_stake())) + .unwrap_or(0); + let entry = serialize_opt_to_value!(skimmed_node.entry)?; + let bond_info = serialize_opt_to_value!(bond_info)?; + let self_described = serialize_opt_to_value!(self_described)?; + let record = Self { node_id: skimmed_node.node_id.into(), ed25519_identity_pubkey: skimmed_node.ed25519_identity_pubkey.to_base58_string(), @@ -450,10 +481,9 @@ impl NymNodeInsertRecord { node_role: serde_json::to_value(&skimmed_node.role)?, supported_roles: serde_json::to_value(skimmed_node.supported_roles)?, performance: skimmed_node.performance.value().to_string(), - entry: match skimmed_node.entry { - Some(entry) => Some(serde_json::to_value(entry)?), - None => None, - }, + entry, + self_described, + bond_info, last_updated_utc: now, }; diff --git a/nym-node-status-api/nym-node-status-api/src/db/queries/gateways.rs b/nym-node-status-api/nym-node-status-api/src/db/queries/gateways.rs index cf23115ea1..92e9d7d849 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/queries/gateways.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/queries/gateways.rs @@ -30,11 +30,22 @@ pub(crate) async fn select_gateway_identity( Ok(record.gateway_identity_key) } -pub(crate) async fn insert_gateways( +pub(crate) async fn update_bonded_gateways( pool: &DbPool, gateways: Vec, ) -> anyhow::Result<()> { - let mut db = pool.acquire().await?; + let mut tx = pool.begin().await?; + + sqlx::query!( + r#"UPDATE + gateways + SET + bonded = false + "#, + ) + .execute(&mut *tx) + .await?; + for record in gateways { sqlx::query!( "INSERT INTO gateways @@ -55,10 +66,12 @@ pub(crate) async fn insert_gateways( record.last_updated_utc, record.performance ) - .execute(&mut *db) + .execute(&mut *tx) .await?; } + tx.commit().await?; + Ok(()) } @@ -101,7 +114,7 @@ pub(crate) async fn get_all_gateways(pool: &DbPool) -> anyhow::Result anyhow::Result> { +pub(crate) async fn get_bonded_gateway_id_keys(pool: &DbPool) -> anyhow::Result> { let mut conn = pool.acquire().await?; let items = sqlx::query!( r#" diff --git a/nym-node-status-api/nym-node-status-api/src/db/queries/mixnodes.rs b/nym-node-status-api/nym-node-status-api/src/db/queries/mixnodes.rs index 67cb3d554f..0b5f6e8abd 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/queries/mixnodes.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/queries/mixnodes.rs @@ -11,12 +11,24 @@ use crate::{ http::models::{DailyStats, Mixnode}, }; -pub(crate) async fn insert_mixnodes( +pub(crate) async fn update_mixnodes( pool: &DbPool, mixnodes: Vec, ) -> anyhow::Result<()> { - let mut conn = pool.acquire().await?; + let mut tx = pool.begin().await?; + // mark all as unbonded + sqlx::query!( + r#"UPDATE + mixnodes + SET + bonded = false + "#, + ) + .execute(&mut *tx) + .await?; + + // existing nodes get updated on insert for record in mixnodes.iter() { // https://www.sqlite.org/lang_upsert.html sqlx::query!( @@ -43,10 +55,12 @@ pub(crate) async fn insert_mixnodes( record.last_updated_utc, record.is_dp_delegatee ) - .execute(&mut *conn) + .execute(&mut *tx) .await?; } + tx.commit().await?; + Ok(()) } @@ -126,7 +140,7 @@ pub(crate) async fn get_daily_stats(pool: &DbPool) -> anyhow::Result anyhow::Result> { +pub(crate) async fn get_bonded_mix_ids(pool: &DbPool) -> anyhow::Result> { let mut conn = pool.acquire().await?; let items = sqlx::query!( r#" diff --git a/nym-node-status-api/nym-node-status-api/src/db/queries/mod.rs b/nym-node-status-api/nym-node-status-api/src/db/queries/mod.rs index 4103df77b4..2e5a864ba6 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/queries/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/queries/mod.rs @@ -9,12 +9,15 @@ mod summary; pub(crate) mod testruns; pub(crate) use gateways::{ - get_all_gateway_id_keys, get_all_gateways, insert_gateways, select_gateway_identity, + get_all_gateways, get_bonded_gateway_id_keys, select_gateway_identity, update_bonded_gateways, }; pub(crate) use gateways_stats::{delete_old_records, get_sessions_stats, insert_session_records}; pub(crate) use misc::insert_summaries; -pub(crate) use mixnodes::{get_all_mix_ids, get_all_mixnodes, get_daily_stats, insert_mixnodes}; -pub(crate) use nym_nodes::{get_nym_nodes, insert_nym_nodes}; +pub(crate) use mixnodes::{get_all_mixnodes, get_bonded_mix_ids, get_daily_stats, update_mixnodes}; +pub(crate) use nym_nodes::{ + get_active_nym_nodes, get_all_nym_nodes, get_described_node_bond_info, get_node_descriptions, + update_nym_nodes, +}; pub(crate) use packet_stats::{ get_raw_node_stats, insert_daily_node_stats, insert_node_packet_stats, }; diff --git a/nym-node-status-api/nym-node-status-api/src/db/queries/nym_nodes.rs b/nym-node-status-api/nym-node-status-api/src/db/queries/nym_nodes.rs index fcfbe8d8e3..6280af8148 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/queries/nym_nodes.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/queries/nym_nodes.rs @@ -1,22 +1,21 @@ -use std::collections::HashMap; - use anyhow::Context; use futures_util::TryStreamExt; -use nym_validator_client::{client::NymNodeDetails, nym_api::SkimmedNode}; +use nym_validator_client::{ + client::{NodeId, NymNodeDetails}, + models::NymNodeDescription, +}; +use std::collections::{HashMap, HashSet}; use tracing::instrument; -use crate::{ - db::{ - models::{NymNodeDto, NymNodeInsertRecord}, - DbPool, - }, - utils::decimal_to_i64, +use crate::db::{ + models::{NymNodeDto, NymNodeInsertRecord}, + DbPool, }; -pub(crate) async fn get_nym_nodes(pool: &DbPool) -> anyhow::Result> { +pub(crate) async fn get_all_nym_nodes(pool: &DbPool) -> anyhow::Result> { let mut conn = pool.acquire().await?; - let items = sqlx::query_as!( + sqlx::query_as!( NymNodeDto, r#"SELECT node_id, @@ -28,44 +27,77 @@ pub(crate) async fn get_nym_nodes(pool: &DbPool) -> anyhow::Result>() - .await?; - - let mut skimmed_nodes = Vec::new(); - for item in items { - let node_id = item.node_id; - match SkimmedNode::try_from(item) { - Ok(node) => skimmed_nodes.push(node), - Err(e) => { - tracing::warn!("Failed to decode node_id={}: {}", node_id, e); - } - } - } - - Ok(skimmed_nodes) + .await + .map_err(From::from) } -#[instrument(level = "debug", skip_all)] -pub(crate) async fn insert_nym_nodes( - pool: &DbPool, - nym_nodes: Vec, - bonded_node_info: &HashMap, -) -> anyhow::Result<()> { +/// if a node doesn't expose its self-described endpoint, it can't route traffic +/// - https://nym.com/docs/operators/nodes/nym-node/bonding +/// +/// same if it's not bonded in the mixnet smart contract +/// - https://nym.com/docs/operators/tokenomics/mixnet-rewards#rewarded-set-selection +pub(crate) async fn get_active_nym_nodes(pool: &DbPool) -> anyhow::Result> { let mut conn = pool.acquire().await?; - for nym_node in nym_nodes.into_iter() { - let total_stake = bonded_node_info - .get(&nym_node.node_id) - .map(|details| decimal_to_i64(details.total_stake())) - .unwrap_or(0); + sqlx::query_as!( + NymNodeDto, + r#"SELECT + node_id, + ed25519_identity_pubkey, + total_stake, + ip_addresses as "ip_addresses!: serde_json::Value", + mix_port, + x25519_sphinx_pubkey, + node_role as "node_role: serde_json::Value", + supported_roles as "supported_roles: serde_json::Value", + entry as "entry: serde_json::Value", + performance, + self_described as "self_described: serde_json::Value", + bond_info as "bond_info: serde_json::Value" + FROM + nym_nodes + WHERE + self_described IS NOT NULL + AND + bond_info IS NOT NULL + "#, + ) + .fetch(&mut *conn) + .try_collect::>() + .await + .map_err(From::from) +} - let record = NymNodeInsertRecord::new(nym_node, total_stake)?; +#[instrument(level = "debug", skip_all, fields(node_records=node_records.len()))] +pub(crate) async fn update_nym_nodes( + pool: &DbPool, + node_records: Vec, +) -> anyhow::Result { + let mut tx = pool.begin().await?; + + let mut nodes_to_delete = sqlx::query!( + r#"SELECT + node_id as "node_id!: i64" + FROM + nym_nodes + "#, + ) + .fetch_all(&mut *tx) + .await + .map(|records| records.into_iter().map(|record| record.node_id as NodeId))? + .collect::>(); + + let inserted = node_records.len(); + for record in node_records { // https://www.sqlite.org/lang_upsert.html sqlx::query!( "INSERT INTO nym_nodes @@ -74,9 +106,11 @@ pub(crate) async fn insert_nym_nodes( ip_addresses, mix_port, x25519_sphinx_pubkey, node_role, supported_roles, entry, + self_described, + bond_info, performance, last_updated_utc ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(node_id) DO UPDATE SET ed25519_identity_pubkey=excluded.ed25519_identity_pubkey, ip_addresses=excluded.ip_addresses, @@ -85,6 +119,8 @@ pub(crate) async fn insert_nym_nodes( node_role=excluded.node_role, supported_roles=excluded.supported_roles, entry=excluded.entry, + self_described=excluded.self_described, + bond_info=excluded.bond_info, performance=excluded.performance, last_updated_utc=excluded.last_updated_utc ;", @@ -97,13 +133,104 @@ pub(crate) async fn insert_nym_nodes( record.node_role, record.supported_roles, record.entry, + record.self_described, + record.bond_info, record.performance, record.last_updated_utc, ) - .execute(&mut *conn) + .execute(&mut *tx) .await - .with_context(|| format!("node_id={}", record.node_id))?; + .with_context(|| format!("Failed to INSERT node_id={}", record.node_id))?; + + // if node was updated, remove it from the list + nodes_to_delete.remove(&(record.node_id as NodeId)); } - Ok(()) + if !nodes_to_delete.is_empty() { + tracing::debug!("DELETING {} obsolete nodes", nodes_to_delete.len()); + } + + // clean up leftover nodes, which weren't inserted/updated + for node_id in nodes_to_delete { + sqlx::query!( + "DELETE FROM nym_nodes + WHERE node_id = ?", + node_id, + ) + .execute(&mut *tx) + .await + .map_err(|e| anyhow::anyhow!("Failed to DELETE node_id={}: {}", node_id, e))?; + } + + tx.commit().await?; + + Ok(inserted) +} + +pub(crate) async fn get_described_node_bond_info( + pool: &DbPool, +) -> anyhow::Result> { + let mut conn = pool.acquire().await?; + + sqlx::query!( + r#"SELECT + node_id, + bond_info as "bond_info: serde_json::Value" + FROM + nym_nodes + WHERE + bond_info IS NOT NULL + AND + self_described IS NOT NULL + "#, + ) + .fetch_all(&mut *conn) + .await + .map(|records| { + records + .into_iter() + .filter_map(|record| { + record + .bond_info + // only return details for nodes which have details stored + .and_then(|bond_info| serde_json::from_value::(bond_info).ok()) + .map(|res| (record.node_id as NodeId, res)) + }) + .collect::>() + }) + .map_err(From::from) +} + +pub(crate) async fn get_node_descriptions( + pool: &DbPool, +) -> anyhow::Result> { + let mut conn = pool.acquire().await?; + + sqlx::query!( + r#"SELECT + node_id, + self_described as "self_described: serde_json::Value" + FROM + nym_nodes + WHERE + self_described IS NOT NULL + "#, + ) + .fetch_all(&mut *conn) + .await + .map(|records| { + records + .into_iter() + .filter_map(|record| { + record + .self_described + // only return details for nodes which have details stored + .and_then(|description| { + serde_json::from_value::(description).ok() + }) + .map(|res| (record.node_id as NodeId, res)) + }) + .collect::>() + }) + .map_err(From::from) } diff --git a/nym-node-status-api/nym-node-status-api/src/db/queries/scraper.rs b/nym-node-status-api/nym-node-status-api/src/db/queries/scraper.rs index 52cff30a01..87d9fea229 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/queries/scraper.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/queries/scraper.rs @@ -7,45 +7,56 @@ use crate::{ }; use anyhow::Result; use chrono::Utc; +use nym_validator_client::nym_api::SkimmedNode; pub(crate) async fn get_nodes_for_scraping(pool: &DbPool) -> Result> { let mut nodes_to_scrape = Vec::new(); - let mixnode_ids = queries::get_all_mix_ids(pool).await?; - let gateway_keys = queries::get_all_gateway_id_keys(pool).await?; + let mixnode_ids = queries::get_bonded_mix_ids(pool).await?; + let gateway_keys = queries::get_bonded_gateway_id_keys(pool).await?; let mut entry_exit_nodes = 0; - queries::get_nym_nodes(pool) - .await? - .into_iter() - .for_each(|node| { - // due to polyfilling, Nym nodes table might contain legacy mixnodes - // as well. Mark them as such here. - let node_kind = if mixnode_ids.contains(&node.node_id.into()) { - ScrapeNodeKind::LegacyMixnode { - mix_id: node.node_id.into(), + let skimmed_nodes = queries::get_active_nym_nodes(pool).await.map(|nodes_dto| { + nodes_dto.into_iter().filter_map(|node| { + let node_id = node.node_id; + match SkimmedNode::try_from(node) { + Ok(node) => Some(node), + Err(e) => { + tracing::error!("Failed to decode node_id={}: {}", node_id, e); + None } - } else if gateway_keys.contains(&node.ed25519_identity_pubkey.to_base58_string()) { - entry_exit_nodes += 1; - ScrapeNodeKind::EntryExitNymNode { - node_id: node.node_id.into(), - identity_key: node.ed25519_identity_pubkey.to_base58_string(), - } - } else { - ScrapeNodeKind::MixingNymNode { - node_id: node.node_id.into(), - } - }; - nodes_to_scrape.push(ScraperNodeInfo { - node_kind, - hosts: node - .ip_addresses - .into_iter() - .map(|ip| ip.to_string()) - .collect::>(), - http_api_port: node.mix_port.into(), - }) - }); + } + }) + })?; + + skimmed_nodes.for_each(|node| { + // TODO: relies on polyfilling: Nym nodes table might contain legacy mixnodes + // as well. Categorize them here. + let node_kind = if mixnode_ids.contains(&node.node_id.into()) { + ScrapeNodeKind::LegacyMixnode { + mix_id: node.node_id.into(), + } + } else if gateway_keys.contains(&node.ed25519_identity_pubkey.to_base58_string()) { + entry_exit_nodes += 1; + ScrapeNodeKind::EntryExitNymNode { + node_id: node.node_id.into(), + identity_key: node.ed25519_identity_pubkey.to_base58_string(), + } + } else { + ScrapeNodeKind::MixingNymNode { + node_id: node.node_id.into(), + } + }; + nodes_to_scrape.push(ScraperNodeInfo { + node_kind, + hosts: node + .ip_addresses + .into_iter() + .map(|ip| ip.to_string()) + .collect::>(), + http_api_port: node.mix_port.into(), + }) + }); tracing::debug!("Fetched {} 🌟 total nym nodes", nodes_to_scrape.len()); tracing::debug!("Fetched {} 🚪 entry/exit nodes", entry_exit_nodes); diff --git a/nym-node-status-api/nym-node-status-api/src/http/api/mod.rs b/nym-node-status-api/nym-node-status-api/src/http/api/mod.rs index 6483a44519..1ba2711ec3 100644 --- a/nym-node-status-api/nym-node-status-api/src/http/api/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/http/api/mod.rs @@ -10,6 +10,7 @@ use crate::http::{server::HttpServer, state::AppState}; pub(crate) mod gateways; pub(crate) mod metrics; pub(crate) mod mixnodes; +pub(crate) mod nym_nodes; pub(crate) mod services; pub(crate) mod summary; pub(crate) mod testruns; @@ -38,6 +39,7 @@ impl RouterBuilder { .nest("/summary", summary::routes()) .nest("/metrics", metrics::routes()), ) + .nest("/v3", Router::new().nest("/nym-nodes", nym_nodes::routes())) .nest( "/internal", Router::new().nest("/testruns", testruns::routes()), diff --git a/nym-node-status-api/nym-node-status-api/src/http/api/nym_nodes.rs b/nym-node-status-api/nym-node-status-api/src/http/api/nym_nodes.rs new file mode 100644 index 0000000000..0bcb3ceadc --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/src/http/api/nym_nodes.rs @@ -0,0 +1,42 @@ +use axum::{ + extract::{Query, State}, + Json, Router, +}; +use tracing::instrument; + +use crate::http::{ + error::{HttpError, HttpResult}, + models::ExtendedNymNode, + state::AppState, + PagedResult, Pagination, +}; + +pub(crate) fn routes() -> Router { + Router::new().route("/", axum::routing::get(nym_nodes)) +} + +#[utoipa::path( + tag = "Nym Nodes", + get, + params( + Pagination + ), + path = "/v3/nym-nodes", + responses( + (status = 200, body = PagedResult) + ) +)] +#[instrument(level = tracing::Level::DEBUG, skip_all, fields(page=pagination.page, size=pagination.size))] +async fn nym_nodes( + Query(pagination): Query, + State(state): State, +) -> HttpResult>> { + let db = state.db_pool(); + + let nodes = state.cache().get_nym_nodes_list(db).await.map_err(|e| { + tracing::error!("{e}"); + HttpError::internal() + })?; + + Ok(Json(PagedResult::paginate(pagination, nodes))) +} diff --git a/nym-node-status-api/nym-node-status-api/src/http/models.rs b/nym-node-status-api/nym-node-status-api/src/http/models.rs index a3975b3a02..3ff313e450 100644 --- a/nym-node-status-api/nym-node-status-api/src/http/models.rs +++ b/nym-node-status-api/nym-node-status-api/src/http/models.rs @@ -1,4 +1,6 @@ +use cosmwasm_std::Decimal; use nym_node_requests::api::v1::node::models::NodeDescription; +use nym_validator_client::client::NodeId; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; @@ -45,6 +47,23 @@ pub struct Mixnode { pub last_updated_utc: String, } +#[derive(Clone, Debug, utoipa::ToSchema, Deserialize, Serialize)] +pub(crate) struct ExtendedNymNode { + pub(crate) node_id: NodeId, + pub(crate) identity_key: String, + pub(crate) uptime: f64, + #[schema(value_type = String)] + pub(crate) total_stake: Decimal, + pub(crate) original_pledge: u128, + pub(crate) bonding_address: String, + pub(crate) bonded: bool, + pub(crate) node_type: String, + pub(crate) ip_address: String, + pub(crate) accepted_tnc: bool, + pub(crate) description: serde_json::Value, + pub(crate) rewarding_details: serde_json::Value, +} + #[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] pub struct DailyStats { pub date_utc: String, diff --git a/nym-node-status-api/nym-node-status-api/src/http/state.rs b/nym-node-status-api/nym-node-status-api/src/http/state.rs index f1aea18cb8..8073a3afd4 100644 --- a/nym-node-status-api/nym-node-status-api/src/http/state.rs +++ b/nym-node-status-api/nym-node-status-api/src/http/state.rs @@ -1,12 +1,16 @@ -use std::{sync::Arc, time::Duration}; +use std::{collections::HashMap, sync::Arc, time::Duration}; +use cosmwasm_std::Decimal; use moka::{future::Cache, Entry}; +use nym_contracts_common::NaiveFloat; use nym_crypto::asymmetric::ed25519::PublicKey; +use nym_validator_client::{models::DescribedNodeType, nym_api::SkimmedNode}; use tokio::sync::RwLock; +use tracing::instrument; use crate::{ - db::DbPool, - http::models::{DailyStats, Gateway, Mixnode, SummaryHistory}, + db::{queries, DbPool}, + http::models::{DailyStats, ExtendedNymNode, Gateway, Mixnode, SummaryHistory}, }; use super::models::SessionStats; @@ -53,6 +57,7 @@ impl AppState { static GATEWAYS_LIST_KEY: &str = "gateways"; static MIXNODES_LIST_KEY: &str = "mixnodes"; +static NYM_NODES_LIST_KEY: &str = "nym_nodes"; static MIXSTATS_LIST_KEY: &str = "mixstats"; static SUMMARY_HISTORY_LIST_KEY: &str = "summary-history"; static SESSION_STATS_LIST_KEY: &str = "session-stats"; @@ -63,6 +68,7 @@ const MIXNODE_STATS_HISTORY_DAYS: usize = 30; pub(crate) struct HttpCache { gateways: Cache>>>, mixnodes: Cache>>>, + nym_nodes: Cache>>>, mixstats: Cache>>>, history: Cache>>>, session_stats: Cache>>>, @@ -79,6 +85,10 @@ impl HttpCache { .max_capacity(2) .time_to_live(Duration::from_secs(ttl_seconds)) .build(), + nym_nodes: Cache::builder() + .max_capacity(2) + .time_to_live(Duration::from_secs(ttl_seconds)) + .build(), mixstats: Cache::builder() .max_capacity(2) .time_to_live(Duration::from_secs(ttl_seconds)) @@ -181,6 +191,47 @@ impl HttpCache { } } + pub async fn upsert_nym_node_list( + &self, + nym_node_list: Vec, + ) -> Entry>>> { + self.nym_nodes + .entry_by_ref(NYM_NODES_LIST_KEY) + .and_upsert_with(|maybe_entry| async { + if let Some(entry) = maybe_entry { + let v = entry.into_value(); + let mut guard = v.write().await; + *guard = nym_node_list; + v.clone() + } else { + Arc::new(RwLock::new(nym_node_list)) + } + }) + .await + } + + pub async fn get_nym_nodes_list(&self, db: &DbPool) -> anyhow::Result> { + match self.nym_nodes.get(NYM_NODES_LIST_KEY).await { + Some(guard) => { + tracing::trace!("Fetching from cache..."); + let read_lock = guard.read().await; + Ok(read_lock.clone()) + } + None => { + tracing::trace!("No nym nodes in cache, refreshing cache from DB..."); + + let nym_nodes = aggregate_node_info_from_db(db).await.inspect(|nym_nodes| { + if nym_nodes.is_empty() { + tracing::warn!("Database contains 0 nym nodes"); + } + })?; + self.upsert_nym_node_list(nym_nodes.clone()).await; + + Ok(nym_nodes) + } + } + } + pub async fn upsert_mixnode_stats( &self, mixnode_stats: Vec, @@ -293,3 +344,81 @@ impl HttpCache { .await } } + +#[instrument(level = "info", skip_all)] +async fn aggregate_node_info_from_db(pool: &DbPool) -> anyhow::Result> { + let node_bond_info = queries::get_described_node_bond_info(pool).await?; + tracing::debug!("Described nodes with bond info: {}", node_bond_info.len()); + + let skimmed_nodes = queries::get_all_nym_nodes(pool).await.map(|records| { + records + .into_iter() + .filter_map(|dto| SkimmedNode::try_from(dto).ok()) + .map(|skimmed_node| (skimmed_node.node_id, skimmed_node)) + .collect::>() + })?; + tracing::debug!("Skimmed nodes: {}", skimmed_nodes.len()); + + let described_nodes = queries::get_node_descriptions(pool).await?; + tracing::debug!("Described nodes: {}", described_nodes.len()); + + let mut parsed_nym_nodes = Vec::new(); + for (node_id, described_node) in described_nodes { + let bond_details = node_bond_info.get(&node_id); + let bonded = bond_details.is_some(); + let total_stake = bond_details + .map(|details| details.total_stake()) + .unwrap_or(Decimal::zero()); + let identity_key = described_node.ed25519_identity_key().to_string(); + + let original_pledge = bond_details + .map(|details| details.original_pledge().amount.u128()) + .unwrap_or(0u128); + let rewarding_details = &node_bond_info + .get(&node_id) + .map(|details| details.rewarding_details.clone()); + + let uptime = skimmed_nodes + .get(&node_id) + .map(|node| node.performance.naive_to_f64()) + .unwrap_or(0.0); + let node_type = match described_node.contract_node_type { + DescribedNodeType::NymNode => "nym_node".to_string(), + DescribedNodeType::LegacyMixnode => "legacy_mixnode".to_string(), + DescribedNodeType::LegacyGateway => "legacy_gateway".to_string(), + }; + let ip_address = described_node + .description + .host_information + .ip_address + .first() + .map(ToString::to_string) + .unwrap_or_default(); + let accepted_tnc = described_node + .description + .auxiliary_details + .accepted_operator_terms_and_conditions; + let description = described_node.description; + + let bonding_address = bond_details + .map(|details| details.bond_information.owner.to_string()) + .unwrap_or_default(); + + parsed_nym_nodes.push(ExtendedNymNode { + node_id, + identity_key, + total_stake, + uptime, + ip_address, + original_pledge, + bonding_address, + bonded, + node_type, + accepted_tnc, + description: serde_json::to_value(description).unwrap_or_default(), + rewarding_details: serde_json::to_value(rewarding_details).unwrap_or_default(), + }); + } + + Ok(parsed_nym_nodes) +} diff --git a/nym-node-status-api/nym-node-status-api/src/mixnet_scraper/mod.rs b/nym-node-status-api/nym-node-status-api/src/mixnet_scraper/mod.rs index 983775eec9..686d043987 100644 --- a/nym-node-status-api/nym-node-status-api/src/mixnet_scraper/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/mixnet_scraper/mod.rs @@ -134,8 +134,9 @@ impl Scraper { node.node_id() ), Err(e) => debug!( - "📝 ❌ Description task #{} for node {} failed: {}", + "📝 ❌ Description task #{} for {} {} failed: {}", task_id, + node.node_kind, node.node_id(), e ), @@ -178,8 +179,9 @@ impl Scraper { node.node_id() ), Err(e) => debug!( - "📊 ❌ Packet stats task #{} for node {} failed: {}", + "📊 ❌ Packet stats task #{} for {} {} failed: {}", task_id, + node.node_kind, node.node_id(), e ), diff --git a/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs b/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs index 81711d7640..d3e9398b5c 100644 --- a/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs @@ -1,9 +1,10 @@ #![allow(deprecated)] use crate::db::models::{ - gateway, mixnode, GatewayInsertRecord, MixnodeRecord, NetworkSummary, ASSIGNED_ENTRY_COUNT, - ASSIGNED_EXIT_COUNT, ASSIGNED_MIXING_COUNT, GATEWAYS_BONDED_COUNT, GATEWAYS_HISTORICAL_COUNT, - MIXNODES_HISTORICAL_COUNT, MIXNODES_LEGACY_COUNT, NYMNODES_DESCRIBED_COUNT, NYMNODE_COUNT, + gateway, mixnode, GatewayInsertRecord, MixnodeRecord, NetworkSummary, NymNodeInsertRecord, + ASSIGNED_ENTRY_COUNT, ASSIGNED_EXIT_COUNT, ASSIGNED_MIXING_COUNT, GATEWAYS_BONDED_COUNT, + GATEWAYS_HISTORICAL_COUNT, MIXNODES_HISTORICAL_COUNT, MIXNODES_LEGACY_COUNT, + NYMNODES_DESCRIBED_COUNT, NYMNODE_COUNT, }; use crate::db::{queries, DbPool}; use crate::monitor::geodata::{Location, NodeGeoData}; @@ -11,7 +12,7 @@ use crate::utils::{decimal_to_i64, LogError, NumericalCheckedCast}; use anyhow::anyhow; use moka::future::Cache; use nym_network_defaults::NymNetworkDetails; -use nym_validator_client::client::{NodeId, NymApiClientExt}; +use nym_validator_client::client::{NodeId, NymApiClientExt, NymNodeDetails}; use nym_validator_client::models::{ LegacyDescribedMixNode, MixNodeBondAnnotated, NymNodeDescription, }; @@ -107,19 +108,24 @@ impl Monitor { let described_nodes = api_client .get_all_described_nodes() .await - .log_error("get_all_described_nodes")?; + .log_error("get_all_described_nodes")? + .into_iter() + .map(|elem| (elem.node_id, elem)) + .collect::>(); tracing::info!("🟣 described nodes: {}", described_nodes.len()); let gateways = described_nodes .iter() - .filter(|node| { - node.description.declared_role.entry - || node.description.declared_role.exit_ipr - || node.description.declared_role.exit_nr + .filter_map(|(_, node)| { + if node.description.declared_role.entry || node.description.declared_role.exit_ipr { + Some(node) + } else { + None + } }) .collect::>(); - let bonded_node_info = api_client + let bonded_nym_nodes = api_client .get_all_bonded_nym_nodes() .await? .into_iter() @@ -127,22 +133,27 @@ impl Monitor { // for faster reads .collect::>(); - tracing::info!("🟣 bonded_nodes: {}", bonded_node_info.len()); + tracing::info!("🟣 bonded_nodes: {}", bonded_nym_nodes.len()); + // returns only bonded nodes let nym_nodes = api_client .get_all_basic_nodes() .await .log_error("get_all_basic_nodes")?; - queries::insert_nym_nodes(&self.db_pool, nym_nodes.clone(), &bonded_node_info) + tracing::info!("🟣 get_all_basic_nodes: {}", nym_nodes.len()); + + let nym_node_records = + self.prepare_nym_node_data(nym_nodes.clone(), &bonded_nym_nodes, &described_nodes); + queries::update_nym_nodes(&self.db_pool, nym_node_records) .await - .map(|_| { - tracing::debug!("{} nym nodes written to DB!", nym_nodes.len()); + .map(|inserted| { + tracing::debug!("{} nym nodes written to DB!", inserted); })?; let mut gateway_geodata = Vec::new(); for gateway in gateways.iter() { - if let Some(node_details) = bonded_node_info.get(&gateway.node_id) { + if let Some(node_details) = bonded_nym_nodes.get(&gateway.node_id) { let bond_info = &node_details.bond_information; let gw_geodata = NodeGeoData { identity_key: bond_info.node.identity_key.to_owned(), @@ -170,6 +181,7 @@ impl Monitor { .map(|elem| elem.identity_key().to_owned()) .collect::>(); + // TODO this assumes polyfilling of legacy mixnodes on Nym API let mixnodes_legacy = nym_nodes .iter() .filter(|node| { @@ -208,11 +220,12 @@ impl Monitor { let assigned_mixing_count = mixing_assigned_nodes.len(); let count_legacy_mixnodes = mixnodes_legacy.len(); - let gateway_records = self.prepare_gateway_data(&gateways, gateway_geodata, &nym_nodes)?; + let gateway_records = + self.prepare_gateway_data(&gateways, gateway_geodata, &nym_nodes, &bonded_nym_nodes)?; let pool = self.db_pool.clone(); let gateways_count = gateway_records.len(); - queries::insert_gateways(&pool, gateway_records) + queries::update_bonded_gateways(&pool, gateway_records) .await .map(|_| { tracing::debug!("{} gateway records written to DB!", gateways_count); @@ -224,7 +237,7 @@ impl Monitor { delegation_program_members, )?; let mixnodes_count = mixnode_records.len(); - queries::insert_mixnodes(&pool, mixnode_records) + queries::update_mixnodes(&pool, mixnode_records) .await .map(|_| { tracing::debug!("{} mixnode info written to DB!", mixnodes_count); @@ -317,17 +330,45 @@ impl Monitor { } } + fn prepare_nym_node_data( + &self, + skimmed_nodes: Vec, + bonded_node_info: &HashMap, + described_nodes: &HashMap, + ) -> Vec { + skimmed_nodes + .into_iter() + .filter_map(|skimmed_node| { + let node_id = skimmed_node.node_id; + let bond_info = bonded_node_info.get(&skimmed_node.node_id); + let self_described = described_nodes.get(&skimmed_node.node_id); + match NymNodeInsertRecord::new(skimmed_node, bond_info, self_described) { + Ok(record) => Some(record), + Err(err) => { + tracing::error!( + "Failed to create insert record for node {}: {}", + node_id, + err + ); + None + } + } + }) + .collect::>() + } + fn prepare_gateway_data( &self, described_gateways: &[&NymNodeDescription], gateway_geodata: Vec, skimmed_gateways: &[SkimmedNode], + bonded_nodes: &HashMap, ) -> anyhow::Result> { let mut gateway_records = Vec::new(); for gateway in described_gateways { let identity_key = gateway.ed25519_identity_key().to_base58_string(); - let bonded = true; + let bonded = bonded_nodes.contains_key(&gateway.node_id); let last_updated_utc = chrono::offset::Utc::now().timestamp(); let self_described = serde_json::to_string(&gateway.description)?; @@ -373,6 +414,7 @@ impl Monitor { for mixnode in mixnodes { let mix_id = mixnode.mix_id(); let identity_key = mixnode.identity_key(); + // only bonded nodes are given to this function let bonded = true; let total_stake = decimal_to_i64(mixnode.mixnode_details.total_stake()); let node_info = mixnode.mix_node(); diff --git a/nym-node-status-api/nym-node-status-api/src/testruns/queue.rs b/nym-node-status-api/nym-node-status-api/src/testruns/queue.rs index db1f72e3a7..6de0579741 100644 --- a/nym-node-status-api/nym-node-status-api/src/testruns/queue.rs +++ b/nym-node-status-api/nym-node-status-api/src/testruns/queue.rs @@ -24,6 +24,7 @@ pub(crate) async fn try_queue_testrun( explorer_pretty_bond as "explorer_pretty_bond?" FROM gateways WHERE gateway_identity_key = ? + AND bonded = true ORDER BY gateway_identity_key LIMIT 1"#, identity_key,