diff --git a/monero-rpc-pool/.sqlx/query-03e5b2bccf8bffb962a56443448311800bb832efe37fe6c52181bd7bf631740c.json b/monero-rpc-pool/.sqlx/query-03e5b2bccf8bffb962a56443448311800bb832efe37fe6c52181bd7bf631740c.json new file mode 100644 index 00000000..39b40ef9 --- /dev/null +++ b/monero-rpc-pool/.sqlx/query-03e5b2bccf8bffb962a56443448311800bb832efe37fe6c52181bd7bf631740c.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "SELECT id FROM monero_nodes WHERE scheme = ? AND host = ? AND port = ?", + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 3 + }, + "nullable": [ + true + ] + }, + "hash": "03e5b2bccf8bffb962a56443448311800bb832efe37fe6c52181bd7bf631740c" +} diff --git a/monero-rpc-pool/.sqlx/query-08d143b977a7fa23b289c22dee3cab4d64debeea9932c58047cc6244d136f80d.json b/monero-rpc-pool/.sqlx/query-08d143b977a7fa23b289c22dee3cab4d64debeea9932c58047cc6244d136f80d.json new file mode 100644 index 00000000..fe50e71a --- /dev/null +++ b/monero-rpc-pool/.sqlx/query-08d143b977a7fa23b289c22dee3cab4d64debeea9932c58047cc6244d136f80d.json @@ -0,0 +1,110 @@ +{ + "db_name": "SQLite", + "query": "\n SELECT \n n.id as \"id!: i64\",\n n.scheme,\n n.host,\n n.port,\n n.network,\n n.first_seen_at,\n CAST(COALESCE(stats.success_count, 0) AS INTEGER) as \"success_count!: i64\",\n CAST(COALESCE(stats.failure_count, 0) AS INTEGER) as \"failure_count!: i64\",\n stats.last_success as \"last_success?: String\",\n stats.last_failure as \"last_failure?: String\",\n stats.last_checked as \"last_checked?: String\",\n CAST(CASE WHEN reliable_nodes.node_id IS NOT NULL THEN 1 ELSE 0 END AS INTEGER) as \"is_reliable!: i64\",\n stats.avg_latency_ms as \"avg_latency_ms?: f64\",\n stats.min_latency_ms as \"min_latency_ms?: f64\",\n stats.max_latency_ms as \"max_latency_ms?: f64\",\n stats.last_latency_ms as \"last_latency_ms?: f64\"\n FROM monero_nodes n\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n MAX(CASE WHEN was_successful THEN timestamp END) as last_success,\n MAX(CASE WHEN NOT was_successful THEN timestamp END) as last_failure,\n MAX(timestamp) as last_checked,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms,\n MIN(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as min_latency_ms,\n MAX(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as max_latency_ms,\n (SELECT latency_ms FROM health_checks hc2 WHERE hc2.node_id = health_checks.node_id ORDER BY timestamp DESC LIMIT 1) as last_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) stats ON n.id = stats.node_id\n LEFT JOIN (\n SELECT DISTINCT node_id FROM (\n SELECT \n n2.id as node_id,\n COALESCE(s2.success_count, 0) as success_count,\n COALESCE(s2.failure_count, 0) as failure_count,\n s2.avg_latency_ms,\n (CAST(COALESCE(s2.success_count, 0) AS REAL) / CAST(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0) AS REAL)) * \n (MIN(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0), 200) / 200.0) * 0.8 +\n CASE \n WHEN s2.avg_latency_ms IS NOT NULL THEN (1.0 - (MIN(s2.avg_latency_ms, 2000) / 2000.0)) * 0.2\n ELSE 0.0 \n END as reliability_score\n FROM monero_nodes n2\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) s2 ON n2.id = s2.node_id\n WHERE n2.network = ? AND (COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0)) > 0\n ORDER BY reliability_score DESC\n LIMIT 4\n )\n ) reliable_nodes ON n.id = reliable_nodes.node_id\n WHERE n.network = ? AND (COALESCE(stats.success_count, 0) + COALESCE(stats.failure_count, 0)) > 0\n ORDER BY \n (CAST(COALESCE(stats.success_count, 0) AS REAL) / CAST(COALESCE(stats.success_count, 0) + COALESCE(stats.failure_count, 0) AS REAL)) DESC,\n stats.avg_latency_ms ASC\n LIMIT ?\n ", + "describe": { + "columns": [ + { + "name": "id!: i64", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "scheme", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "host", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "port", + "ordinal": 3, + "type_info": "Integer" + }, + { + "name": "network", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "first_seen_at", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "success_count!: i64", + "ordinal": 6, + "type_info": "Null" + }, + { + "name": "failure_count!: i64", + "ordinal": 7, + "type_info": "Null" + }, + { + "name": "last_success?: String", + "ordinal": 8, + "type_info": "Null" + }, + { + "name": "last_failure?: String", + "ordinal": 9, + "type_info": "Null" + }, + { + "name": "last_checked?: String", + "ordinal": 10, + "type_info": "Null" + }, + { + "name": "is_reliable!: i64", + "ordinal": 11, + "type_info": "Null" + }, + { + "name": "avg_latency_ms?: f64", + "ordinal": 12, + "type_info": "Null" + }, + { + "name": "min_latency_ms?: f64", + "ordinal": 13, + "type_info": "Null" + }, + { + "name": "max_latency_ms?: f64", + "ordinal": 14, + "type_info": "Null" + }, + { + "name": "last_latency_ms?: f64", + "ordinal": 15, + "type_info": "Float" + } + ], + "parameters": { + "Right": 3 + }, + "nullable": [ + true, + false, + false, + false, + false, + false, + null, + null, + null, + null, + null, + null, + null, + null, + null, + true + ] + }, + "hash": "08d143b977a7fa23b289c22dee3cab4d64debeea9932c58047cc6244d136f80d" +} diff --git a/monero-rpc-pool/.sqlx/query-0aa34e769813a40e0518f5311ff95685fd5278103d13f56795ff5a51b0ef8036.json b/monero-rpc-pool/.sqlx/query-0aa34e769813a40e0518f5311ff95685fd5278103d13f56795ff5a51b0ef8036.json new file mode 100644 index 00000000..26659748 --- /dev/null +++ b/monero-rpc-pool/.sqlx/query-0aa34e769813a40e0518f5311ff95685fd5278103d13f56795ff5a51b0ef8036.json @@ -0,0 +1,110 @@ +{ + "db_name": "SQLite", + "query": "\n SELECT \n n.id as \"id!: i64\",\n n.scheme,\n n.host,\n n.port,\n n.network,\n n.first_seen_at,\n CAST(COALESCE(stats.success_count, 0) AS INTEGER) as \"success_count!: i64\",\n CAST(COALESCE(stats.failure_count, 0) AS INTEGER) as \"failure_count!: i64\",\n stats.last_success as \"last_success?: String\",\n stats.last_failure as \"last_failure?: String\",\n stats.last_checked as \"last_checked?: String\",\n CAST(CASE WHEN reliable_nodes.node_id IS NOT NULL THEN 1 ELSE 0 END AS INTEGER) as \"is_reliable!: i64\",\n stats.avg_latency_ms as \"avg_latency_ms?: f64\",\n stats.min_latency_ms as \"min_latency_ms?: f64\",\n stats.max_latency_ms as \"max_latency_ms?: f64\",\n stats.last_latency_ms as \"last_latency_ms?: f64\"\n FROM monero_nodes n\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n MAX(CASE WHEN was_successful THEN timestamp END) as last_success,\n MAX(CASE WHEN NOT was_successful THEN timestamp END) as last_failure,\n MAX(timestamp) as last_checked,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms,\n MIN(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as min_latency_ms,\n MAX(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as max_latency_ms,\n (SELECT latency_ms FROM health_checks hc2 WHERE hc2.node_id = health_checks.node_id ORDER BY timestamp DESC LIMIT 1) as last_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) stats ON n.id = stats.node_id\n LEFT JOIN (\n SELECT DISTINCT node_id FROM (\n SELECT \n n2.id as node_id,\n COALESCE(s2.success_count, 0) as success_count,\n COALESCE(s2.failure_count, 0) as failure_count,\n s2.avg_latency_ms,\n (CAST(COALESCE(s2.success_count, 0) AS REAL) / CAST(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0) AS REAL)) * \n (MIN(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0), 200) / 200.0) * 0.8 +\n CASE \n WHEN s2.avg_latency_ms IS NOT NULL THEN (1.0 - (MIN(s2.avg_latency_ms, 2000) / 2000.0)) * 0.2\n ELSE 0.0 \n END as reliability_score\n FROM monero_nodes n2\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) s2 ON n2.id = s2.node_id\n WHERE n2.network = ? AND (COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0)) > 0\n ORDER BY reliability_score DESC\n LIMIT 4\n )\n ) reliable_nodes ON n.id = reliable_nodes.node_id\n WHERE n.network = ?\n ORDER BY stats.avg_latency_ms ASC, stats.success_count DESC\n ", + "describe": { + "columns": [ + { + "name": "id!: i64", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "scheme", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "host", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "port", + "ordinal": 3, + "type_info": "Integer" + }, + { + "name": "network", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "first_seen_at", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "success_count!: i64", + "ordinal": 6, + "type_info": "Null" + }, + { + "name": "failure_count!: i64", + "ordinal": 7, + "type_info": "Null" + }, + { + "name": "last_success?: String", + "ordinal": 8, + "type_info": "Null" + }, + { + "name": "last_failure?: String", + "ordinal": 9, + "type_info": "Null" + }, + { + "name": "last_checked?: String", + "ordinal": 10, + "type_info": "Null" + }, + { + "name": "is_reliable!: i64", + "ordinal": 11, + "type_info": "Null" + }, + { + "name": "avg_latency_ms?: f64", + "ordinal": 12, + "type_info": "Null" + }, + { + "name": "min_latency_ms?: f64", + "ordinal": 13, + "type_info": "Null" + }, + { + "name": "max_latency_ms?: f64", + "ordinal": 14, + "type_info": "Null" + }, + { + "name": "last_latency_ms?: f64", + "ordinal": 15, + "type_info": "Float" + } + ], + "parameters": { + "Right": 2 + }, + "nullable": [ + true, + false, + false, + false, + false, + false, + null, + null, + null, + null, + null, + null, + null, + null, + null, + true + ] + }, + "hash": "0aa34e769813a40e0518f5311ff95685fd5278103d13f56795ff5a51b0ef8036" +} diff --git a/monero-rpc-pool/.sqlx/query-2a378cb109fe284ba3a939aed1bcb50dc694c89ef1eb08bf3d62e7d9e0902a4e.json b/monero-rpc-pool/.sqlx/query-2a378cb109fe284ba3a939aed1bcb50dc694c89ef1eb08bf3d62e7d9e0902a4e.json new file mode 100644 index 00000000..80c4546b --- /dev/null +++ b/monero-rpc-pool/.sqlx/query-2a378cb109fe284ba3a939aed1bcb50dc694c89ef1eb08bf3d62e7d9e0902a4e.json @@ -0,0 +1,110 @@ +{ + "db_name": "SQLite", + "query": "\n SELECT \n n.id as \"id!: i64\",\n n.scheme,\n n.host,\n n.port,\n n.network,\n n.first_seen_at,\n CAST(COALESCE(stats.success_count, 0) AS INTEGER) as \"success_count!: i64\",\n CAST(COALESCE(stats.failure_count, 0) AS INTEGER) as \"failure_count!: i64\",\n stats.last_success as \"last_success?: String\",\n stats.last_failure as \"last_failure?: String\",\n stats.last_checked as \"last_checked?: String\",\n CAST(CASE WHEN reliable_nodes.node_id IS NOT NULL THEN 1 ELSE 0 END AS INTEGER) as \"is_reliable!: i64\",\n stats.avg_latency_ms as \"avg_latency_ms?: f64\",\n stats.min_latency_ms as \"min_latency_ms?: f64\",\n stats.max_latency_ms as \"max_latency_ms?: f64\",\n stats.last_latency_ms as \"last_latency_ms?: f64\"\n FROM monero_nodes n\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n MAX(CASE WHEN was_successful THEN timestamp END) as last_success,\n MAX(CASE WHEN NOT was_successful THEN timestamp END) as last_failure,\n MAX(timestamp) as last_checked,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms,\n MIN(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as min_latency_ms,\n MAX(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as max_latency_ms,\n (SELECT latency_ms FROM health_checks hc2 WHERE hc2.node_id = health_checks.node_id ORDER BY timestamp DESC LIMIT 1) as last_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) stats ON n.id = stats.node_id\n LEFT JOIN (\n SELECT DISTINCT node_id FROM (\n SELECT \n n2.id as node_id,\n COALESCE(s2.success_count, 0) as success_count,\n COALESCE(s2.failure_count, 0) as failure_count,\n s2.avg_latency_ms,\n (CAST(COALESCE(s2.success_count, 0) AS REAL) / CAST(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0) AS REAL)) * \n (MIN(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0), 200) / 200.0) * 0.8 +\n CASE \n WHEN s2.avg_latency_ms IS NOT NULL THEN (1.0 - (MIN(s2.avg_latency_ms, 2000) / 2000.0)) * 0.2\n ELSE 0.0 \n END as reliability_score\n FROM monero_nodes n2\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) s2 ON n2.id = s2.node_id\n WHERE n2.network = ? AND (COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0)) > 0\n ORDER BY reliability_score DESC\n LIMIT 4\n )\n ) reliable_nodes ON n.id = reliable_nodes.node_id\n WHERE n.network = ?\n ORDER BY RANDOM()\n LIMIT ?\n ", + "describe": { + "columns": [ + { + "name": "id!: i64", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "scheme", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "host", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "port", + "ordinal": 3, + "type_info": "Integer" + }, + { + "name": "network", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "first_seen_at", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "success_count!: i64", + "ordinal": 6, + "type_info": "Null" + }, + { + "name": "failure_count!: i64", + "ordinal": 7, + "type_info": "Null" + }, + { + "name": "last_success?: String", + "ordinal": 8, + "type_info": "Null" + }, + { + "name": "last_failure?: String", + "ordinal": 9, + "type_info": "Null" + }, + { + "name": "last_checked?: String", + "ordinal": 10, + "type_info": "Null" + }, + { + "name": "is_reliable!: i64", + "ordinal": 11, + "type_info": "Null" + }, + { + "name": "avg_latency_ms?: f64", + "ordinal": 12, + "type_info": "Null" + }, + { + "name": "min_latency_ms?: f64", + "ordinal": 13, + "type_info": "Null" + }, + { + "name": "max_latency_ms?: f64", + "ordinal": 14, + "type_info": "Null" + }, + { + "name": "last_latency_ms?: f64", + "ordinal": 15, + "type_info": "Float" + } + ], + "parameters": { + "Right": 3 + }, + "nullable": [ + true, + false, + false, + false, + false, + false, + null, + null, + null, + null, + null, + null, + null, + null, + null, + true + ] + }, + "hash": "2a378cb109fe284ba3a939aed1bcb50dc694c89ef1eb08bf3d62e7d9e0902a4e" +} diff --git a/monero-rpc-pool/.sqlx/query-3e8f39a6ec4443cec6497672891d12bbf7c1d0aca061827740af88ced863ae23.json b/monero-rpc-pool/.sqlx/query-37157927724c8bc647bf4f76f5698631cbd40637778dfa83e8f644ae6a7cf75b.json similarity index 65% rename from monero-rpc-pool/.sqlx/query-3e8f39a6ec4443cec6497672891d12bbf7c1d0aca061827740af88ced863ae23.json rename to monero-rpc-pool/.sqlx/query-37157927724c8bc647bf4f76f5698631cbd40637778dfa83e8f644ae6a7cf75b.json index d208a702..04e09ff7 100644 --- a/monero-rpc-pool/.sqlx/query-3e8f39a6ec4443cec6497672891d12bbf7c1d0aca061827740af88ced863ae23.json +++ b/monero-rpc-pool/.sqlx/query-37157927724c8bc647bf4f76f5698631cbd40637778dfa83e8f644ae6a7cf75b.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "\n SELECT \n id as \"id!: i64\",\n scheme,\n host,\n port,\n full_url,\n network as \"network!: String\",\n first_seen_at\n FROM monero_nodes \n ORDER BY id\n ", + "query": "\n SELECT \n id as \"id!: i64\",\n scheme,\n host,\n port,\n network as \"network!: String\",\n first_seen_at\n FROM monero_nodes \n ORDER BY id\n ", "describe": { "columns": [ { @@ -24,25 +24,27 @@ "type_info": "Integer" }, { - "name": "full_url", + "name": "network!: String", "ordinal": 4, "type_info": "Text" }, - { - "name": "network!: String", - "ordinal": 5, - "type_info": "Text" - }, { "name": "first_seen_at", - "ordinal": 6, + "ordinal": 5, "type_info": "Text" } ], "parameters": { "Right": 0 }, - "nullable": [false, false, false, false, false, false, false] + "nullable": [ + false, + false, + false, + false, + false, + false + ] }, - "hash": "3e8f39a6ec4443cec6497672891d12bbf7c1d0aca061827740af88ced863ae23" + "hash": "37157927724c8bc647bf4f76f5698631cbd40637778dfa83e8f644ae6a7cf75b" } diff --git a/monero-rpc-pool/.sqlx/query-3870c77c7c5fbb9bdd57c365765178a08de20e442a07f3e734e61c410e4f338e.json b/monero-rpc-pool/.sqlx/query-3870c77c7c5fbb9bdd57c365765178a08de20e442a07f3e734e61c410e4f338e.json new file mode 100644 index 00000000..45b2b60e --- /dev/null +++ b/monero-rpc-pool/.sqlx/query-3870c77c7c5fbb9bdd57c365765178a08de20e442a07f3e734e61c410e4f338e.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "\n INSERT INTO monero_nodes (scheme, host, port, network, first_seen_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT(scheme, host, port) DO UPDATE SET\n network = excluded.network,\n updated_at = excluded.updated_at\n RETURNING id\n ", + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 6 + }, + "nullable": [ + false + ] + }, + "hash": "3870c77c7c5fbb9bdd57c365765178a08de20e442a07f3e734e61c410e4f338e" +} diff --git a/monero-rpc-pool/.sqlx/query-549f5ef13ec7bf5d987dcb893753a9c903edcafa3a66bd82965b40a9e7f238b6.json b/monero-rpc-pool/.sqlx/query-549f5ef13ec7bf5d987dcb893753a9c903edcafa3a66bd82965b40a9e7f238b6.json deleted file mode 100644 index 7381e04d..00000000 --- a/monero-rpc-pool/.sqlx/query-549f5ef13ec7bf5d987dcb893753a9c903edcafa3a66bd82965b40a9e7f238b6.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "db_name": "SQLite", - "query": "\n SELECT \n n.id as \"id!: i64\",\n n.scheme,\n n.host,\n n.port,\n n.full_url,\n n.network,\n n.first_seen_at,\n CAST(COALESCE(stats.success_count, 0) AS INTEGER) as \"success_count!: i64\",\n CAST(COALESCE(stats.failure_count, 0) AS INTEGER) as \"failure_count!: i64\",\n stats.last_success as \"last_success?: String\",\n stats.last_failure as \"last_failure?: String\",\n stats.last_checked as \"last_checked?: String\",\n CAST(CASE WHEN reliable_nodes.node_id IS NOT NULL THEN 1 ELSE 0 END AS INTEGER) as \"is_reliable!: i64\",\n stats.avg_latency_ms as \"avg_latency_ms?: f64\",\n stats.min_latency_ms as \"min_latency_ms?: f64\",\n stats.max_latency_ms as \"max_latency_ms?: f64\",\n stats.last_latency_ms as \"last_latency_ms?: f64\"\n FROM monero_nodes n\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n MAX(CASE WHEN was_successful THEN timestamp END) as last_success,\n MAX(CASE WHEN NOT was_successful THEN timestamp END) as last_failure,\n MAX(timestamp) as last_checked,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms,\n MIN(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as min_latency_ms,\n MAX(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as max_latency_ms,\n (SELECT latency_ms FROM health_checks hc2 WHERE hc2.node_id = health_checks.node_id ORDER BY timestamp DESC LIMIT 1) as last_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) stats ON n.id = stats.node_id\n LEFT JOIN (\n SELECT DISTINCT node_id FROM (\n SELECT \n n2.id as node_id,\n COALESCE(s2.success_count, 0) as success_count,\n COALESCE(s2.failure_count, 0) as failure_count,\n s2.avg_latency_ms,\n (CAST(COALESCE(s2.success_count, 0) AS REAL) / CAST(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0) AS REAL)) * \n (MIN(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0), 200) / 200.0) * 0.8 +\n CASE \n WHEN s2.avg_latency_ms IS NOT NULL THEN (1.0 - (MIN(s2.avg_latency_ms, 2000) / 2000.0)) * 0.2\n ELSE 0.0 \n END as reliability_score\n FROM monero_nodes n2\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) s2 ON n2.id = s2.node_id\n WHERE n2.network = ? AND (COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0)) > 0\n ORDER BY reliability_score DESC\n LIMIT 4\n )\n ) reliable_nodes ON n.id = reliable_nodes.node_id\n WHERE n.network = ? AND (COALESCE(stats.success_count, 0) + COALESCE(stats.failure_count, 0)) > 0\n ORDER BY \n (CAST(COALESCE(stats.success_count, 0) AS REAL) / CAST(COALESCE(stats.success_count, 0) + COALESCE(stats.failure_count, 0) AS REAL)) DESC,\n stats.avg_latency_ms ASC\n LIMIT ?\n ", - "describe": { - "columns": [ - { - "name": "id!: i64", - "ordinal": 0, - "type_info": "Integer" - }, - { - "name": "scheme", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "host", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "port", - "ordinal": 3, - "type_info": "Integer" - }, - { - "name": "full_url", - "ordinal": 4, - "type_info": "Text" - }, - { - "name": "network", - "ordinal": 5, - "type_info": "Text" - }, - { - "name": "first_seen_at", - "ordinal": 6, - "type_info": "Text" - }, - { - "name": "success_count!: i64", - "ordinal": 7, - "type_info": "Null" - }, - { - "name": "failure_count!: i64", - "ordinal": 8, - "type_info": "Null" - }, - { - "name": "last_success?: String", - "ordinal": 9, - "type_info": "Null" - }, - { - "name": "last_failure?: String", - "ordinal": 10, - "type_info": "Null" - }, - { - "name": "last_checked?: String", - "ordinal": 11, - "type_info": "Null" - }, - { - "name": "is_reliable!: i64", - "ordinal": 12, - "type_info": "Null" - }, - { - "name": "avg_latency_ms?: f64", - "ordinal": 13, - "type_info": "Null" - }, - { - "name": "min_latency_ms?: f64", - "ordinal": 14, - "type_info": "Null" - }, - { - "name": "max_latency_ms?: f64", - "ordinal": 15, - "type_info": "Null" - }, - { - "name": "last_latency_ms?: f64", - "ordinal": 16, - "type_info": "Float" - } - ], - "parameters": { - "Right": 3 - }, - "nullable": [ - true, - false, - false, - false, - false, - false, - false, - null, - null, - null, - null, - null, - null, - null, - null, - null, - true - ] - }, - "hash": "549f5ef13ec7bf5d987dcb893753a9c903edcafa3a66bd82965b40a9e7f238b6" -} diff --git a/monero-rpc-pool/.sqlx/query-5736de2aac47eb69d7f6835d266aa28732b02a5e8e055ffaebcb452ed1b5044c.json b/monero-rpc-pool/.sqlx/query-5736de2aac47eb69d7f6835d266aa28732b02a5e8e055ffaebcb452ed1b5044c.json deleted file mode 100644 index d7a0eb31..00000000 --- a/monero-rpc-pool/.sqlx/query-5736de2aac47eb69d7f6835d266aa28732b02a5e8e055ffaebcb452ed1b5044c.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "\n UPDATE monero_nodes \n SET network = ?, updated_at = ?\n WHERE full_url = ?\n ", - "describe": { - "columns": [], - "parameters": { - "Right": 3 - }, - "nullable": [] - }, - "hash": "5736de2aac47eb69d7f6835d266aa28732b02a5e8e055ffaebcb452ed1b5044c" -} diff --git a/monero-rpc-pool/.sqlx/query-5798d9589772742f074e0ecc2551a40d943bfb7ed2e295f09f12d77cb65ce821.json b/monero-rpc-pool/.sqlx/query-5798d9589772742f074e0ecc2551a40d943bfb7ed2e295f09f12d77cb65ce821.json deleted file mode 100644 index 3e52d837..00000000 --- a/monero-rpc-pool/.sqlx/query-5798d9589772742f074e0ecc2551a40d943bfb7ed2e295f09f12d77cb65ce821.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "db_name": "SQLite", - "query": "\n INSERT INTO monero_nodes (scheme, host, port, full_url, network, first_seen_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(full_url) DO UPDATE SET\n network = excluded.network,\n updated_at = excluded.updated_at\n RETURNING id\n ", - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Integer" - } - ], - "parameters": { - "Right": 7 - }, - "nullable": [false] - }, - "hash": "5798d9589772742f074e0ecc2551a40d943bfb7ed2e295f09f12d77cb65ce821" -} diff --git a/monero-rpc-pool/.sqlx/query-5a25c95c04b11a60a04ad97b5fb684e9a0cc2eb5daf64f33e924f0c38a2edfec.json b/monero-rpc-pool/.sqlx/query-5a25c95c04b11a60a04ad97b5fb684e9a0cc2eb5daf64f33e924f0c38a2edfec.json deleted file mode 100644 index 1d10eb38..00000000 --- a/monero-rpc-pool/.sqlx/query-5a25c95c04b11a60a04ad97b5fb684e9a0cc2eb5daf64f33e924f0c38a2edfec.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "db_name": "SQLite", - "query": "\n SELECT \n n.id as \"id!: i64\",\n n.scheme,\n n.host,\n n.port,\n n.full_url,\n n.network,\n n.first_seen_at,\n CAST(COALESCE(stats.success_count, 0) AS INTEGER) as \"success_count!: i64\",\n CAST(COALESCE(stats.failure_count, 0) AS INTEGER) as \"failure_count!: i64\",\n stats.last_success as \"last_success?: String\",\n stats.last_failure as \"last_failure?: String\",\n stats.last_checked as \"last_checked?: String\",\n CAST(CASE WHEN reliable_nodes.node_id IS NOT NULL THEN 1 ELSE 0 END AS INTEGER) as \"is_reliable!: i64\",\n stats.avg_latency_ms as \"avg_latency_ms?: f64\",\n stats.min_latency_ms as \"min_latency_ms?: f64\",\n stats.max_latency_ms as \"max_latency_ms?: f64\",\n stats.last_latency_ms as \"last_latency_ms?: f64\"\n FROM monero_nodes n\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n MAX(CASE WHEN was_successful THEN timestamp END) as last_success,\n MAX(CASE WHEN NOT was_successful THEN timestamp END) as last_failure,\n MAX(timestamp) as last_checked,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms,\n MIN(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as min_latency_ms,\n MAX(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as max_latency_ms,\n (SELECT latency_ms FROM health_checks hc2 WHERE hc2.node_id = health_checks.node_id ORDER BY timestamp DESC LIMIT 1) as last_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) stats ON n.id = stats.node_id\n LEFT JOIN (\n SELECT DISTINCT node_id FROM (\n SELECT \n n2.id as node_id,\n COALESCE(s2.success_count, 0) as success_count,\n COALESCE(s2.failure_count, 0) as failure_count,\n s2.avg_latency_ms,\n (CAST(COALESCE(s2.success_count, 0) AS REAL) / CAST(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0) AS REAL)) * \n (MIN(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0), 200) / 200.0) * 0.8 +\n CASE \n WHEN s2.avg_latency_ms IS NOT NULL THEN (1.0 - (MIN(s2.avg_latency_ms, 2000) / 2000.0)) * 0.2\n ELSE 0.0 \n END as reliability_score\n FROM monero_nodes n2\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) s2 ON n2.id = s2.node_id\n WHERE n2.network = ? AND (COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0)) > 0\n ORDER BY reliability_score DESC\n LIMIT 4\n )\n ) reliable_nodes ON n.id = reliable_nodes.node_id\n WHERE n.network = ?\n ORDER BY RANDOM()\n LIMIT ?\n ", - "describe": { - "columns": [ - { - "name": "id!: i64", - "ordinal": 0, - "type_info": "Integer" - }, - { - "name": "scheme", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "host", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "port", - "ordinal": 3, - "type_info": "Integer" - }, - { - "name": "full_url", - "ordinal": 4, - "type_info": "Text" - }, - { - "name": "network", - "ordinal": 5, - "type_info": "Text" - }, - { - "name": "first_seen_at", - "ordinal": 6, - "type_info": "Text" - }, - { - "name": "success_count!: i64", - "ordinal": 7, - "type_info": "Null" - }, - { - "name": "failure_count!: i64", - "ordinal": 8, - "type_info": "Null" - }, - { - "name": "last_success?: String", - "ordinal": 9, - "type_info": "Null" - }, - { - "name": "last_failure?: String", - "ordinal": 10, - "type_info": "Null" - }, - { - "name": "last_checked?: String", - "ordinal": 11, - "type_info": "Null" - }, - { - "name": "is_reliable!: i64", - "ordinal": 12, - "type_info": "Null" - }, - { - "name": "avg_latency_ms?: f64", - "ordinal": 13, - "type_info": "Null" - }, - { - "name": "min_latency_ms?: f64", - "ordinal": 14, - "type_info": "Null" - }, - { - "name": "max_latency_ms?: f64", - "ordinal": 15, - "type_info": "Null" - }, - { - "name": "last_latency_ms?: f64", - "ordinal": 16, - "type_info": "Float" - } - ], - "parameters": { - "Right": 3 - }, - "nullable": [ - true, - false, - false, - false, - false, - false, - false, - null, - null, - null, - null, - null, - null, - null, - null, - null, - true - ] - }, - "hash": "5a25c95c04b11a60a04ad97b5fb684e9a0cc2eb5daf64f33e924f0c38a2edfec" -} diff --git a/monero-rpc-pool/.sqlx/query-5ff27bdd9b6e7aadc8dd4936e0ee7e6a611aaef28697a0e9535dfb30d1c4861d.json b/monero-rpc-pool/.sqlx/query-5ff27bdd9b6e7aadc8dd4936e0ee7e6a611aaef28697a0e9535dfb30d1c4861d.json deleted file mode 100644 index 825adc0c..00000000 --- a/monero-rpc-pool/.sqlx/query-5ff27bdd9b6e7aadc8dd4936e0ee7e6a611aaef28697a0e9535dfb30d1c4861d.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "db_name": "SQLite", - "query": "\n SELECT \n n.id as \"id!: i64\",\n n.scheme,\n n.host,\n n.port,\n n.full_url,\n n.network,\n n.first_seen_at,\n CAST(COALESCE(stats.success_count, 0) AS INTEGER) as \"success_count!: i64\",\n CAST(COALESCE(stats.failure_count, 0) AS INTEGER) as \"failure_count!: i64\",\n stats.last_success as \"last_success?: String\",\n stats.last_failure as \"last_failure?: String\",\n stats.last_checked as \"last_checked?: String\",\n CAST(CASE WHEN reliable_nodes.node_id IS NOT NULL THEN 1 ELSE 0 END AS INTEGER) as \"is_reliable!: i64\",\n stats.avg_latency_ms as \"avg_latency_ms?: f64\",\n stats.min_latency_ms as \"min_latency_ms?: f64\",\n stats.max_latency_ms as \"max_latency_ms?: f64\",\n stats.last_latency_ms as \"last_latency_ms?: f64\"\n FROM monero_nodes n\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n MAX(CASE WHEN was_successful THEN timestamp END) as last_success,\n MAX(CASE WHEN NOT was_successful THEN timestamp END) as last_failure,\n MAX(timestamp) as last_checked,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms,\n MIN(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as min_latency_ms,\n MAX(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as max_latency_ms,\n (SELECT latency_ms FROM health_checks hc2 WHERE hc2.node_id = health_checks.node_id ORDER BY timestamp DESC LIMIT 1) as last_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) stats ON n.id = stats.node_id\n LEFT JOIN (\n SELECT DISTINCT node_id FROM (\n SELECT \n n2.id as node_id,\n COALESCE(s2.success_count, 0) as success_count,\n COALESCE(s2.failure_count, 0) as failure_count,\n s2.avg_latency_ms,\n (CAST(COALESCE(s2.success_count, 0) AS REAL) / CAST(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0) AS REAL)) * \n (MIN(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0), 200) / 200.0) * 0.8 +\n CASE \n WHEN s2.avg_latency_ms IS NOT NULL THEN (1.0 - (MIN(s2.avg_latency_ms, 2000) / 2000.0)) * 0.2\n ELSE 0.0 \n END as reliability_score\n FROM monero_nodes n2\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) s2 ON n2.id = s2.node_id\n WHERE n2.network = ? AND (COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0)) > 0\n ORDER BY reliability_score DESC\n LIMIT 4\n )\n ) reliable_nodes ON n.id = reliable_nodes.node_id\n WHERE n.network = ?\n ORDER BY stats.avg_latency_ms ASC, stats.success_count DESC\n ", - "describe": { - "columns": [ - { - "name": "id!: i64", - "ordinal": 0, - "type_info": "Integer" - }, - { - "name": "scheme", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "host", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "port", - "ordinal": 3, - "type_info": "Integer" - }, - { - "name": "full_url", - "ordinal": 4, - "type_info": "Text" - }, - { - "name": "network", - "ordinal": 5, - "type_info": "Text" - }, - { - "name": "first_seen_at", - "ordinal": 6, - "type_info": "Text" - }, - { - "name": "success_count!: i64", - "ordinal": 7, - "type_info": "Null" - }, - { - "name": "failure_count!: i64", - "ordinal": 8, - "type_info": "Null" - }, - { - "name": "last_success?: String", - "ordinal": 9, - "type_info": "Null" - }, - { - "name": "last_failure?: String", - "ordinal": 10, - "type_info": "Null" - }, - { - "name": "last_checked?: String", - "ordinal": 11, - "type_info": "Null" - }, - { - "name": "is_reliable!: i64", - "ordinal": 12, - "type_info": "Null" - }, - { - "name": "avg_latency_ms?: f64", - "ordinal": 13, - "type_info": "Null" - }, - { - "name": "min_latency_ms?: f64", - "ordinal": 14, - "type_info": "Null" - }, - { - "name": "max_latency_ms?: f64", - "ordinal": 15, - "type_info": "Null" - }, - { - "name": "last_latency_ms?: f64", - "ordinal": 16, - "type_info": "Float" - } - ], - "parameters": { - "Right": 2 - }, - "nullable": [ - true, - false, - false, - false, - false, - false, - false, - null, - null, - null, - null, - null, - null, - null, - null, - null, - true - ] - }, - "hash": "5ff27bdd9b6e7aadc8dd4936e0ee7e6a611aaef28697a0e9535dfb30d1c4861d" -} diff --git a/monero-rpc-pool/.sqlx/query-75ad770e6f70443871f919c26c189aaefc306e2a72b456fc2d03d4aa870e150b.json b/monero-rpc-pool/.sqlx/query-75ad770e6f70443871f919c26c189aaefc306e2a72b456fc2d03d4aa870e150b.json new file mode 100644 index 00000000..b6e4a1e2 --- /dev/null +++ b/monero-rpc-pool/.sqlx/query-75ad770e6f70443871f919c26c189aaefc306e2a72b456fc2d03d4aa870e150b.json @@ -0,0 +1,110 @@ +{ + "db_name": "SQLite", + "query": "\n SELECT \n n.id as \"id!: i64\",\n n.scheme,\n n.host,\n n.port,\n n.network,\n n.first_seen_at,\n CAST(COALESCE(stats.success_count, 0) AS INTEGER) as \"success_count!: i64\",\n CAST(COALESCE(stats.failure_count, 0) AS INTEGER) as \"failure_count!: i64\",\n stats.last_success as \"last_success?: String\",\n stats.last_failure as \"last_failure?: String\",\n stats.last_checked as \"last_checked?: String\",\n CAST(CASE WHEN reliable_nodes.node_id IS NOT NULL THEN 1 ELSE 0 END AS INTEGER) as \"is_reliable!: i64\",\n stats.avg_latency_ms as \"avg_latency_ms?: f64\",\n stats.min_latency_ms as \"min_latency_ms?: f64\",\n stats.max_latency_ms as \"max_latency_ms?: f64\",\n stats.last_latency_ms as \"last_latency_ms?: f64\"\n FROM monero_nodes n\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n MAX(CASE WHEN was_successful THEN timestamp END) as last_success,\n MAX(CASE WHEN NOT was_successful THEN timestamp END) as last_failure,\n MAX(timestamp) as last_checked,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms,\n MIN(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as min_latency_ms,\n MAX(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as max_latency_ms,\n (SELECT latency_ms FROM health_checks hc2 WHERE hc2.node_id = health_checks.node_id ORDER BY timestamp DESC LIMIT 1) as last_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) stats ON n.id = stats.node_id\n LEFT JOIN (\n SELECT DISTINCT node_id FROM (\n SELECT \n n2.id as node_id,\n COALESCE(s2.success_count, 0) as success_count,\n COALESCE(s2.failure_count, 0) as failure_count,\n s2.avg_latency_ms,\n (CAST(COALESCE(s2.success_count, 0) AS REAL) / CAST(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0) AS REAL)) * \n (MIN(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0), 200) / 200.0) * 0.8 +\n CASE \n WHEN s2.avg_latency_ms IS NOT NULL THEN (1.0 - (MIN(s2.avg_latency_ms, 2000) / 2000.0)) * 0.2\n ELSE 0.0 \n END as reliability_score\n FROM monero_nodes n2\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) s2 ON n2.id = s2.node_id\n WHERE n2.network = ? AND (COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0)) > 0\n ORDER BY reliability_score DESC\n LIMIT 4\n )\n ) reliable_nodes ON n.id = reliable_nodes.node_id\n WHERE n.network = ? AND stats.success_count > 0\n ORDER BY stats.avg_latency_ms ASC, stats.success_count DESC\n ", + "describe": { + "columns": [ + { + "name": "id!: i64", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "scheme", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "host", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "port", + "ordinal": 3, + "type_info": "Integer" + }, + { + "name": "network", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "first_seen_at", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "success_count!: i64", + "ordinal": 6, + "type_info": "Null" + }, + { + "name": "failure_count!: i64", + "ordinal": 7, + "type_info": "Null" + }, + { + "name": "last_success?: String", + "ordinal": 8, + "type_info": "Null" + }, + { + "name": "last_failure?: String", + "ordinal": 9, + "type_info": "Null" + }, + { + "name": "last_checked?: String", + "ordinal": 10, + "type_info": "Null" + }, + { + "name": "is_reliable!: i64", + "ordinal": 11, + "type_info": "Null" + }, + { + "name": "avg_latency_ms?: f64", + "ordinal": 12, + "type_info": "Null" + }, + { + "name": "min_latency_ms?: f64", + "ordinal": 13, + "type_info": "Null" + }, + { + "name": "max_latency_ms?: f64", + "ordinal": 14, + "type_info": "Null" + }, + { + "name": "last_latency_ms?: f64", + "ordinal": 15, + "type_info": "Float" + } + ], + "parameters": { + "Right": 2 + }, + "nullable": [ + true, + false, + false, + false, + false, + false, + null, + null, + null, + null, + null, + null, + null, + null, + null, + true + ] + }, + "hash": "75ad770e6f70443871f919c26c189aaefc306e2a72b456fc2d03d4aa870e150b" +} diff --git a/monero-rpc-pool/.sqlx/query-9f6d042ab61e1d3d652d85c7d77d86a847c4a25d4ee0eab57380d10b94d2686d.json b/monero-rpc-pool/.sqlx/query-9f6d042ab61e1d3d652d85c7d77d86a847c4a25d4ee0eab57380d10b94d2686d.json new file mode 100644 index 00000000..bd967a26 --- /dev/null +++ b/monero-rpc-pool/.sqlx/query-9f6d042ab61e1d3d652d85c7d77d86a847c4a25d4ee0eab57380d10b94d2686d.json @@ -0,0 +1,110 @@ +{ + "db_name": "SQLite", + "query": "\n SELECT \n n.id as \"id!: i64\",\n n.scheme,\n n.host,\n n.port,\n n.network,\n n.first_seen_at,\n CAST(COALESCE(stats.success_count, 0) AS INTEGER) as \"success_count!: i64\",\n CAST(COALESCE(stats.failure_count, 0) AS INTEGER) as \"failure_count!: i64\",\n stats.last_success as \"last_success?: String\",\n stats.last_failure as \"last_failure?: String\",\n stats.last_checked as \"last_checked?: String\",\n CAST(CASE WHEN reliable_nodes.node_id IS NOT NULL THEN 1 ELSE 0 END AS INTEGER) as \"is_reliable!: i64\",\n stats.avg_latency_ms as \"avg_latency_ms?: f64\",\n stats.min_latency_ms as \"min_latency_ms?: f64\",\n stats.max_latency_ms as \"max_latency_ms?: f64\",\n stats.last_latency_ms as \"last_latency_ms?: f64\"\n FROM monero_nodes n\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n MAX(CASE WHEN was_successful THEN timestamp END) as last_success,\n MAX(CASE WHEN NOT was_successful THEN timestamp END) as last_failure,\n MAX(timestamp) as last_checked,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms,\n MIN(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as min_latency_ms,\n MAX(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as max_latency_ms,\n (SELECT latency_ms FROM health_checks hc2 WHERE hc2.node_id = health_checks.node_id ORDER BY timestamp DESC LIMIT 1) as last_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) stats ON n.id = stats.node_id\n LEFT JOIN (\n SELECT DISTINCT node_id FROM (\n SELECT \n n2.id as node_id,\n COALESCE(s2.success_count, 0) as success_count,\n COALESCE(s2.failure_count, 0) as failure_count,\n s2.avg_latency_ms,\n (CAST(COALESCE(s2.success_count, 0) AS REAL) / CAST(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0) AS REAL)) * \n (MIN(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0), 200) / 200.0) * 0.8 +\n CASE \n WHEN s2.avg_latency_ms IS NOT NULL THEN (1.0 - (MIN(s2.avg_latency_ms, 2000) / 2000.0)) * 0.2\n ELSE 0.0 \n END as reliability_score\n FROM monero_nodes n2\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) s2 ON n2.id = s2.node_id\n WHERE n2.network = ? AND (COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0)) > 0\n ORDER BY reliability_score DESC\n LIMIT 4\n )\n ) reliable_nodes ON n.id = reliable_nodes.node_id\n WHERE n.network = ?\n ORDER BY RANDOM()\n LIMIT ?\n ", + "describe": { + "columns": [ + { + "name": "id!: i64", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "scheme", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "host", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "port", + "ordinal": 3, + "type_info": "Integer" + }, + { + "name": "network", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "first_seen_at", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "success_count!: i64", + "ordinal": 6, + "type_info": "Null" + }, + { + "name": "failure_count!: i64", + "ordinal": 7, + "type_info": "Null" + }, + { + "name": "last_success?: String", + "ordinal": 8, + "type_info": "Null" + }, + { + "name": "last_failure?: String", + "ordinal": 9, + "type_info": "Null" + }, + { + "name": "last_checked?: String", + "ordinal": 10, + "type_info": "Null" + }, + { + "name": "is_reliable!: i64", + "ordinal": 11, + "type_info": "Null" + }, + { + "name": "avg_latency_ms?: f64", + "ordinal": 12, + "type_info": "Null" + }, + { + "name": "min_latency_ms?: f64", + "ordinal": 13, + "type_info": "Null" + }, + { + "name": "max_latency_ms?: f64", + "ordinal": 14, + "type_info": "Null" + }, + { + "name": "last_latency_ms?: f64", + "ordinal": 15, + "type_info": "Float" + } + ], + "parameters": { + "Right": 3 + }, + "nullable": [ + true, + false, + false, + false, + false, + false, + null, + null, + null, + null, + null, + null, + null, + null, + null, + true + ] + }, + "hash": "9f6d042ab61e1d3d652d85c7d77d86a847c4a25d4ee0eab57380d10b94d2686d" +} diff --git a/monero-rpc-pool/.sqlx/query-a032eb9773d4553aeaff4fb15ed99dbaef7d16d48750ee7bd4ab83233a9a732b.json b/monero-rpc-pool/.sqlx/query-a032eb9773d4553aeaff4fb15ed99dbaef7d16d48750ee7bd4ab83233a9a732b.json deleted file mode 100644 index be9ea1c3..00000000 --- a/monero-rpc-pool/.sqlx/query-a032eb9773d4553aeaff4fb15ed99dbaef7d16d48750ee7bd4ab83233a9a732b.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "db_name": "SQLite", - "query": "\n SELECT \n n.id as \"id!: i64\",\n n.scheme,\n n.host,\n n.port,\n n.full_url,\n n.network,\n n.first_seen_at,\n CAST(COALESCE(stats.success_count, 0) AS INTEGER) as \"success_count!: i64\",\n CAST(COALESCE(stats.failure_count, 0) AS INTEGER) as \"failure_count!: i64\",\n stats.last_success as \"last_success?: String\",\n stats.last_failure as \"last_failure?: String\",\n stats.last_checked as \"last_checked?: String\",\n CAST(1 AS INTEGER) as \"is_reliable!: i64\",\n stats.avg_latency_ms as \"avg_latency_ms?: f64\",\n stats.min_latency_ms as \"min_latency_ms?: f64\",\n stats.max_latency_ms as \"max_latency_ms?: f64\",\n stats.last_latency_ms as \"last_latency_ms?: f64\"\n FROM monero_nodes n\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n MAX(CASE WHEN was_successful THEN timestamp END) as last_success,\n MAX(CASE WHEN NOT was_successful THEN timestamp END) as last_failure,\n MAX(timestamp) as last_checked,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms,\n MIN(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as min_latency_ms,\n MAX(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as max_latency_ms,\n (SELECT latency_ms FROM health_checks hc2 WHERE hc2.node_id = health_checks.node_id ORDER BY timestamp DESC LIMIT 1) as last_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) stats ON n.id = stats.node_id\n WHERE n.network = ? AND (COALESCE(stats.success_count, 0) + COALESCE(stats.failure_count, 0)) > 0\n ORDER BY \n (CAST(COALESCE(stats.success_count, 0) AS REAL) / CAST(COALESCE(stats.success_count, 0) + COALESCE(stats.failure_count, 0) AS REAL)) * \n (MIN(COALESCE(stats.success_count, 0) + COALESCE(stats.failure_count, 0), 200) / 200.0) * 0.8 +\n CASE \n WHEN stats.avg_latency_ms IS NOT NULL THEN (1.0 - (MIN(stats.avg_latency_ms, 2000) / 2000.0)) * 0.2\n ELSE 0.0 \n END DESC\n LIMIT 4\n ", - "describe": { - "columns": [ - { - "name": "id!: i64", - "ordinal": 0, - "type_info": "Integer" - }, - { - "name": "scheme", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "host", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "port", - "ordinal": 3, - "type_info": "Integer" - }, - { - "name": "full_url", - "ordinal": 4, - "type_info": "Text" - }, - { - "name": "network", - "ordinal": 5, - "type_info": "Text" - }, - { - "name": "first_seen_at", - "ordinal": 6, - "type_info": "Text" - }, - { - "name": "success_count!: i64", - "ordinal": 7, - "type_info": "Null" - }, - { - "name": "failure_count!: i64", - "ordinal": 8, - "type_info": "Null" - }, - { - "name": "last_success?: String", - "ordinal": 9, - "type_info": "Null" - }, - { - "name": "last_failure?: String", - "ordinal": 10, - "type_info": "Null" - }, - { - "name": "last_checked?: String", - "ordinal": 11, - "type_info": "Null" - }, - { - "name": "is_reliable!: i64", - "ordinal": 12, - "type_info": "Null" - }, - { - "name": "avg_latency_ms?: f64", - "ordinal": 13, - "type_info": "Null" - }, - { - "name": "min_latency_ms?: f64", - "ordinal": 14, - "type_info": "Null" - }, - { - "name": "max_latency_ms?: f64", - "ordinal": 15, - "type_info": "Null" - }, - { - "name": "last_latency_ms?: f64", - "ordinal": 16, - "type_info": "Float" - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [ - true, - false, - false, - false, - false, - false, - false, - null, - null, - null, - null, - null, - null, - null, - null, - null, - true - ] - }, - "hash": "a032eb9773d4553aeaff4fb15ed99dbaef7d16d48750ee7bd4ab83233a9a732b" -} diff --git a/monero-rpc-pool/.sqlx/query-b6d85d42bf72888afa22e27710e8cfe3885ed226ae6ae02d6585c1f2f4140d68.json b/monero-rpc-pool/.sqlx/query-b6d85d42bf72888afa22e27710e8cfe3885ed226ae6ae02d6585c1f2f4140d68.json new file mode 100644 index 00000000..50ed040f --- /dev/null +++ b/monero-rpc-pool/.sqlx/query-b6d85d42bf72888afa22e27710e8cfe3885ed226ae6ae02d6585c1f2f4140d68.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "\n UPDATE monero_nodes \n SET network = ?, updated_at = ?\n WHERE scheme = ? AND host = ? AND port = ?\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 5 + }, + "nullable": [] + }, + "hash": "b6d85d42bf72888afa22e27710e8cfe3885ed226ae6ae02d6585c1f2f4140d68" +} diff --git a/monero-rpc-pool/.sqlx/query-b96b866cfc801e275e39e788993d26f6dba1a17a0dee265333c4ae5817ff1e55.json b/monero-rpc-pool/.sqlx/query-b96b866cfc801e275e39e788993d26f6dba1a17a0dee265333c4ae5817ff1e55.json new file mode 100644 index 00000000..489f7e61 --- /dev/null +++ b/monero-rpc-pool/.sqlx/query-b96b866cfc801e275e39e788993d26f6dba1a17a0dee265333c4ae5817ff1e55.json @@ -0,0 +1,110 @@ +{ + "db_name": "SQLite", + "query": "\n SELECT \n n.id as \"id!: i64\",\n n.scheme,\n n.host,\n n.port,\n n.network,\n n.first_seen_at,\n CAST(COALESCE(stats.success_count, 0) AS INTEGER) as \"success_count!: i64\",\n CAST(COALESCE(stats.failure_count, 0) AS INTEGER) as \"failure_count!: i64\",\n stats.last_success as \"last_success?: String\",\n stats.last_failure as \"last_failure?: String\",\n stats.last_checked as \"last_checked?: String\",\n CAST(1 AS INTEGER) as \"is_reliable!: i64\",\n stats.avg_latency_ms as \"avg_latency_ms?: f64\",\n stats.min_latency_ms as \"min_latency_ms?: f64\",\n stats.max_latency_ms as \"max_latency_ms?: f64\",\n stats.last_latency_ms as \"last_latency_ms?: f64\"\n FROM monero_nodes n\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n MAX(CASE WHEN was_successful THEN timestamp END) as last_success,\n MAX(CASE WHEN NOT was_successful THEN timestamp END) as last_failure,\n MAX(timestamp) as last_checked,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms,\n MIN(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as min_latency_ms,\n MAX(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as max_latency_ms,\n (SELECT latency_ms FROM health_checks hc2 WHERE hc2.node_id = health_checks.node_id ORDER BY timestamp DESC LIMIT 1) as last_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) stats ON n.id = stats.node_id\n WHERE n.network = ? AND (COALESCE(stats.success_count, 0) + COALESCE(stats.failure_count, 0)) > 0\n ORDER BY \n (CAST(COALESCE(stats.success_count, 0) AS REAL) / CAST(COALESCE(stats.success_count, 0) + COALESCE(stats.failure_count, 0) AS REAL)) * \n (MIN(COALESCE(stats.success_count, 0) + COALESCE(stats.failure_count, 0), 200) / 200.0) * 0.8 +\n CASE \n WHEN stats.avg_latency_ms IS NOT NULL THEN (1.0 - (MIN(stats.avg_latency_ms, 2000) / 2000.0)) * 0.2\n ELSE 0.0 \n END DESC\n LIMIT 4\n ", + "describe": { + "columns": [ + { + "name": "id!: i64", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "scheme", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "host", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "port", + "ordinal": 3, + "type_info": "Integer" + }, + { + "name": "network", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "first_seen_at", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "success_count!: i64", + "ordinal": 6, + "type_info": "Null" + }, + { + "name": "failure_count!: i64", + "ordinal": 7, + "type_info": "Null" + }, + { + "name": "last_success?: String", + "ordinal": 8, + "type_info": "Null" + }, + { + "name": "last_failure?: String", + "ordinal": 9, + "type_info": "Null" + }, + { + "name": "last_checked?: String", + "ordinal": 10, + "type_info": "Null" + }, + { + "name": "is_reliable!: i64", + "ordinal": 11, + "type_info": "Null" + }, + { + "name": "avg_latency_ms?: f64", + "ordinal": 12, + "type_info": "Null" + }, + { + "name": "min_latency_ms?: f64", + "ordinal": 13, + "type_info": "Null" + }, + { + "name": "max_latency_ms?: f64", + "ordinal": 14, + "type_info": "Null" + }, + { + "name": "last_latency_ms?: f64", + "ordinal": 15, + "type_info": "Float" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + true, + false, + false, + false, + false, + false, + null, + null, + null, + null, + null, + null, + null, + null, + null, + true + ] + }, + "hash": "b96b866cfc801e275e39e788993d26f6dba1a17a0dee265333c4ae5817ff1e55" +} diff --git a/monero-rpc-pool/.sqlx/query-ba231efaf208a42fa857f716ef296b428c937f2eb7c8ce9c631f7f721e914c14.json b/monero-rpc-pool/.sqlx/query-ba231efaf208a42fa857f716ef296b428c937f2eb7c8ce9c631f7f721e914c14.json deleted file mode 100644 index 9f0cd24a..00000000 --- a/monero-rpc-pool/.sqlx/query-ba231efaf208a42fa857f716ef296b428c937f2eb7c8ce9c631f7f721e914c14.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "db_name": "SQLite", - "query": "\n SELECT \n n.id as \"id!: i64\",\n n.scheme,\n n.host,\n n.port,\n n.full_url,\n n.network,\n n.first_seen_at,\n CAST(COALESCE(stats.success_count, 0) AS INTEGER) as \"success_count!: i64\",\n CAST(COALESCE(stats.failure_count, 0) AS INTEGER) as \"failure_count!: i64\",\n stats.last_success as \"last_success?: String\",\n stats.last_failure as \"last_failure?: String\",\n stats.last_checked as \"last_checked?: String\",\n CAST(CASE WHEN reliable_nodes.node_id IS NOT NULL THEN 1 ELSE 0 END AS INTEGER) as \"is_reliable!: i64\",\n stats.avg_latency_ms as \"avg_latency_ms?: f64\",\n stats.min_latency_ms as \"min_latency_ms?: f64\",\n stats.max_latency_ms as \"max_latency_ms?: f64\",\n stats.last_latency_ms as \"last_latency_ms?: f64\"\n FROM monero_nodes n\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n MAX(CASE WHEN was_successful THEN timestamp END) as last_success,\n MAX(CASE WHEN NOT was_successful THEN timestamp END) as last_failure,\n MAX(timestamp) as last_checked,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms,\n MIN(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as min_latency_ms,\n MAX(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as max_latency_ms,\n (SELECT latency_ms FROM health_checks hc2 WHERE hc2.node_id = health_checks.node_id ORDER BY timestamp DESC LIMIT 1) as last_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) stats ON n.id = stats.node_id\n LEFT JOIN (\n SELECT DISTINCT node_id FROM (\n SELECT \n n2.id as node_id,\n COALESCE(s2.success_count, 0) as success_count,\n COALESCE(s2.failure_count, 0) as failure_count,\n s2.avg_latency_ms,\n (CAST(COALESCE(s2.success_count, 0) AS REAL) / CAST(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0) AS REAL)) * \n (MIN(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0), 200) / 200.0) * 0.8 +\n CASE \n WHEN s2.avg_latency_ms IS NOT NULL THEN (1.0 - (MIN(s2.avg_latency_ms, 2000) / 2000.0)) * 0.2\n ELSE 0.0 \n END as reliability_score\n FROM monero_nodes n2\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) s2 ON n2.id = s2.node_id\n WHERE n2.network = ? AND (COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0)) > 0\n ORDER BY reliability_score DESC\n LIMIT 4\n )\n ) reliable_nodes ON n.id = reliable_nodes.node_id\n WHERE n.network = ?\n ORDER BY RANDOM()\n LIMIT ?\n ", - "describe": { - "columns": [ - { - "name": "id!: i64", - "ordinal": 0, - "type_info": "Integer" - }, - { - "name": "scheme", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "host", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "port", - "ordinal": 3, - "type_info": "Integer" - }, - { - "name": "full_url", - "ordinal": 4, - "type_info": "Text" - }, - { - "name": "network", - "ordinal": 5, - "type_info": "Text" - }, - { - "name": "first_seen_at", - "ordinal": 6, - "type_info": "Text" - }, - { - "name": "success_count!: i64", - "ordinal": 7, - "type_info": "Null" - }, - { - "name": "failure_count!: i64", - "ordinal": 8, - "type_info": "Null" - }, - { - "name": "last_success?: String", - "ordinal": 9, - "type_info": "Null" - }, - { - "name": "last_failure?: String", - "ordinal": 10, - "type_info": "Null" - }, - { - "name": "last_checked?: String", - "ordinal": 11, - "type_info": "Null" - }, - { - "name": "is_reliable!: i64", - "ordinal": 12, - "type_info": "Null" - }, - { - "name": "avg_latency_ms?: f64", - "ordinal": 13, - "type_info": "Null" - }, - { - "name": "min_latency_ms?: f64", - "ordinal": 14, - "type_info": "Null" - }, - { - "name": "max_latency_ms?: f64", - "ordinal": 15, - "type_info": "Null" - }, - { - "name": "last_latency_ms?: f64", - "ordinal": 16, - "type_info": "Float" - } - ], - "parameters": { - "Right": 3 - }, - "nullable": [ - true, - false, - false, - false, - false, - false, - false, - null, - null, - null, - null, - null, - null, - null, - null, - null, - true - ] - }, - "hash": "ba231efaf208a42fa857f716ef296b428c937f2eb7c8ce9c631f7f721e914c14" -} diff --git a/monero-rpc-pool/.sqlx/query-d32d91ca2debc4212841282533482b2ff081234c7f9f848a7223ae04234995d9.json b/monero-rpc-pool/.sqlx/query-d32d91ca2debc4212841282533482b2ff081234c7f9f848a7223ae04234995d9.json index b7cd990e..f1dcd349 100644 --- a/monero-rpc-pool/.sqlx/query-d32d91ca2debc4212841282533482b2ff081234c7f9f848a7223ae04234995d9.json +++ b/monero-rpc-pool/.sqlx/query-d32d91ca2debc4212841282533482b2ff081234c7f9f848a7223ae04234995d9.json @@ -17,7 +17,10 @@ "parameters": { "Right": 1 }, - "nullable": [true, true] + "nullable": [ + true, + true + ] }, "hash": "d32d91ca2debc4212841282533482b2ff081234c7f9f848a7223ae04234995d9" } diff --git a/monero-rpc-pool/.sqlx/query-e0865335c2dcb040a34e3f1305fe1a823d6fcde4a061def602cba30971817781.json b/monero-rpc-pool/.sqlx/query-e0865335c2dcb040a34e3f1305fe1a823d6fcde4a061def602cba30971817781.json deleted file mode 100644 index af454eda..00000000 --- a/monero-rpc-pool/.sqlx/query-e0865335c2dcb040a34e3f1305fe1a823d6fcde4a061def602cba30971817781.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT id FROM monero_nodes WHERE full_url = ?", - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Integer" - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [true] - }, - "hash": "e0865335c2dcb040a34e3f1305fe1a823d6fcde4a061def602cba30971817781" -} diff --git a/monero-rpc-pool/.sqlx/query-fac12e3ca6ac1db1a4812a5390a333ec95a2e5e2cd554c169ceecc61b7ff2864.json b/monero-rpc-pool/.sqlx/query-fac12e3ca6ac1db1a4812a5390a333ec95a2e5e2cd554c169ceecc61b7ff2864.json deleted file mode 100644 index 199c59c9..00000000 --- a/monero-rpc-pool/.sqlx/query-fac12e3ca6ac1db1a4812a5390a333ec95a2e5e2cd554c169ceecc61b7ff2864.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "db_name": "SQLite", - "query": "\n SELECT \n n.id as \"id!: i64\",\n n.scheme,\n n.host,\n n.port,\n n.full_url,\n n.network,\n n.first_seen_at,\n CAST(COALESCE(stats.success_count, 0) AS INTEGER) as \"success_count!: i64\",\n CAST(COALESCE(stats.failure_count, 0) AS INTEGER) as \"failure_count!: i64\",\n stats.last_success as \"last_success?: String\",\n stats.last_failure as \"last_failure?: String\",\n stats.last_checked as \"last_checked?: String\",\n CAST(CASE WHEN reliable_nodes.node_id IS NOT NULL THEN 1 ELSE 0 END AS INTEGER) as \"is_reliable!: i64\",\n stats.avg_latency_ms as \"avg_latency_ms?: f64\",\n stats.min_latency_ms as \"min_latency_ms?: f64\",\n stats.max_latency_ms as \"max_latency_ms?: f64\",\n stats.last_latency_ms as \"last_latency_ms?: f64\"\n FROM monero_nodes n\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n MAX(CASE WHEN was_successful THEN timestamp END) as last_success,\n MAX(CASE WHEN NOT was_successful THEN timestamp END) as last_failure,\n MAX(timestamp) as last_checked,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms,\n MIN(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as min_latency_ms,\n MAX(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as max_latency_ms,\n (SELECT latency_ms FROM health_checks hc2 WHERE hc2.node_id = health_checks.node_id ORDER BY timestamp DESC LIMIT 1) as last_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) stats ON n.id = stats.node_id\n LEFT JOIN (\n SELECT DISTINCT node_id FROM (\n SELECT \n n2.id as node_id,\n COALESCE(s2.success_count, 0) as success_count,\n COALESCE(s2.failure_count, 0) as failure_count,\n s2.avg_latency_ms,\n (CAST(COALESCE(s2.success_count, 0) AS REAL) / CAST(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0) AS REAL)) * \n (MIN(COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0), 200) / 200.0) * 0.8 +\n CASE \n WHEN s2.avg_latency_ms IS NOT NULL THEN (1.0 - (MIN(s2.avg_latency_ms, 2000) / 2000.0)) * 0.2\n ELSE 0.0 \n END as reliability_score\n FROM monero_nodes n2\n LEFT JOIN (\n SELECT \n node_id,\n SUM(CASE WHEN was_successful THEN 1 ELSE 0 END) as success_count,\n SUM(CASE WHEN NOT was_successful THEN 1 ELSE 0 END) as failure_count,\n AVG(CASE WHEN was_successful AND latency_ms IS NOT NULL THEN latency_ms END) as avg_latency_ms\n FROM health_checks \n GROUP BY node_id\n ) s2 ON n2.id = s2.node_id\n WHERE n2.network = ? AND (COALESCE(s2.success_count, 0) + COALESCE(s2.failure_count, 0)) > 0\n ORDER BY reliability_score DESC\n LIMIT 4\n )\n ) reliable_nodes ON n.id = reliable_nodes.node_id\n WHERE n.network = ? AND stats.success_count > 0\n ORDER BY stats.avg_latency_ms ASC, stats.success_count DESC\n ", - "describe": { - "columns": [ - { - "name": "id!: i64", - "ordinal": 0, - "type_info": "Integer" - }, - { - "name": "scheme", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "host", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "port", - "ordinal": 3, - "type_info": "Integer" - }, - { - "name": "full_url", - "ordinal": 4, - "type_info": "Text" - }, - { - "name": "network", - "ordinal": 5, - "type_info": "Text" - }, - { - "name": "first_seen_at", - "ordinal": 6, - "type_info": "Text" - }, - { - "name": "success_count!: i64", - "ordinal": 7, - "type_info": "Null" - }, - { - "name": "failure_count!: i64", - "ordinal": 8, - "type_info": "Null" - }, - { - "name": "last_success?: String", - "ordinal": 9, - "type_info": "Null" - }, - { - "name": "last_failure?: String", - "ordinal": 10, - "type_info": "Null" - }, - { - "name": "last_checked?: String", - "ordinal": 11, - "type_info": "Null" - }, - { - "name": "is_reliable!: i64", - "ordinal": 12, - "type_info": "Null" - }, - { - "name": "avg_latency_ms?: f64", - "ordinal": 13, - "type_info": "Null" - }, - { - "name": "min_latency_ms?: f64", - "ordinal": 14, - "type_info": "Null" - }, - { - "name": "max_latency_ms?: f64", - "ordinal": 15, - "type_info": "Null" - }, - { - "name": "last_latency_ms?: f64", - "ordinal": 16, - "type_info": "Float" - } - ], - "parameters": { - "Right": 2 - }, - "nullable": [ - true, - false, - false, - false, - false, - false, - false, - null, - null, - null, - null, - null, - null, - null, - null, - null, - true - ] - }, - "hash": "fac12e3ca6ac1db1a4812a5390a333ec95a2e5e2cd554c169ceecc61b7ff2864" -} diff --git a/monero-rpc-pool/.sqlx/query-ffa1b76d20c86d6bea02bd03e5e7de159adbb7c7c0ef585ce4df9ec648bea7f8.json b/monero-rpc-pool/.sqlx/query-ffa1b76d20c86d6bea02bd03e5e7de159adbb7c7c0ef585ce4df9ec648bea7f8.json index 0ab81591..fb2e5879 100644 --- a/monero-rpc-pool/.sqlx/query-ffa1b76d20c86d6bea02bd03e5e7de159adbb7c7c0ef585ce4df9ec648bea7f8.json +++ b/monero-rpc-pool/.sqlx/query-ffa1b76d20c86d6bea02bd03e5e7de159adbb7c7c0ef585ce4df9ec648bea7f8.json @@ -22,7 +22,11 @@ "parameters": { "Right": 2 }, - "nullable": [false, true, false] + "nullable": [ + false, + true, + false + ] }, "hash": "ffa1b76d20c86d6bea02bd03e5e7de159adbb7c7c0ef585ce4df9ec648bea7f8" } diff --git a/monero-rpc-pool/src/database.rs b/monero-rpc-pool/src/database.rs index c5440275..bb3bb445 100644 --- a/monero-rpc-pool/src/database.rs +++ b/monero-rpc-pool/src/database.rs @@ -149,14 +149,13 @@ impl Database { port: i64, network: &str, ) -> Result { - let full_url = format!("{}://{}:{}", scheme, host, port); let now = chrono::Utc::now().to_rfc3339(); let result = sqlx::query!( r#" - INSERT INTO monero_nodes (scheme, host, port, full_url, network, first_seen_at, updated_at) - VALUES (?, ?, ?, ?, ?, ?, ?) - ON CONFLICT(full_url) DO UPDATE SET + INSERT INTO monero_nodes (scheme, host, port, network, first_seen_at, updated_at) + VALUES (?, ?, ?, ?, ?, ?) + ON CONFLICT(scheme, host, port) DO UPDATE SET network = excluded.network, updated_at = excluded.updated_at RETURNING id @@ -164,7 +163,6 @@ impl Database { scheme, host, port, - full_url, network, now, now @@ -176,26 +174,28 @@ impl Database { } /// Update a node's network after it has been identified - pub async fn update_node_network(&self, url: &str, network: &str) -> Result<()> { + pub async fn update_node_network(&self, scheme: &str, host: &str, port: i64, network: &str) -> Result<()> { let now = chrono::Utc::now().to_rfc3339(); let result = sqlx::query!( r#" UPDATE monero_nodes SET network = ?, updated_at = ? - WHERE full_url = ? + WHERE scheme = ? AND host = ? AND port = ? "#, network, now, - url + scheme, + host, + port ) .execute(&self.pool) .await?; if result.rows_affected() > 0 { - debug!("Updated network for node {} to {}", url, network); + debug!("Updated network for node {}://{}:{} to {}", scheme, host, port, network); } else { - warn!("Failed to update network for node {}: not found", url); + warn!("Failed to update network for node {}://{}:{}: not found", scheme, host, port); } Ok(()) @@ -204,21 +204,23 @@ impl Database { /// Record a health check event pub async fn record_health_check( &self, - url: &str, + scheme: &str, + host: &str, + port: i64, was_successful: bool, latency_ms: Option, ) -> Result<()> { let now = chrono::Utc::now().to_rfc3339(); // First get the node_id - let node_row = sqlx::query!("SELECT id FROM monero_nodes WHERE full_url = ?", url) + let node_row = sqlx::query!("SELECT id FROM monero_nodes WHERE scheme = ? AND host = ? AND port = ?", scheme, host, port) .fetch_optional(&self.pool) .await?; let node_id = match node_row { Some(row) => row.id, None => { - warn!("Cannot record health check for unknown node: {}", url); + warn!("Cannot record health check for unknown node: {}://{}:{}", scheme, host, port); return Ok(()); } }; @@ -248,7 +250,6 @@ impl Database { n.scheme, n.host, n.port, - n.full_url, n.network, n.first_seen_at, CAST(COALESCE(stats.success_count, 0) AS INTEGER) as "success_count!: i64", @@ -353,7 +354,6 @@ impl Database { n.scheme, n.host, n.port, - n.full_url, n.network, n.first_seen_at, CAST(COALESCE(stats.success_count, 0) AS INTEGER) as "success_count!: i64", @@ -516,7 +516,6 @@ impl Database { n.scheme, n.host, n.port, - n.full_url, n.network, n.first_seen_at, CAST(COALESCE(stats.success_count, 0) AS INTEGER) as "success_count!: i64", @@ -623,7 +622,6 @@ impl Database { n.scheme, n.host, n.port, - n.full_url, n.network, n.first_seen_at, CAST(COALESCE(stats.success_count, 0) AS INTEGER) as "success_count!: i64", @@ -734,7 +732,6 @@ impl Database { n.scheme, n.host, n.port, - n.full_url, n.network, n.first_seen_at, CAST(COALESCE(stats.success_count, 0) AS INTEGER) as "success_count!: i64", @@ -835,7 +832,6 @@ impl Database { n.scheme, n.host, n.port, - n.full_url, n.network, n.first_seen_at, CAST(COALESCE(stats.success_count, 0) AS INTEGER) as "success_count!: i64", diff --git a/monero-rpc-pool/src/discovery.rs b/monero-rpc-pool/src/discovery.rs index 4222070c..be347f7a 100644 --- a/monero-rpc-pool/src/discovery.rs +++ b/monero-rpc-pool/src/discovery.rs @@ -116,7 +116,7 @@ impl NodeDiscovery { } /// Enhanced health check that detects network and validates node identity - pub async fn check_node_health(&self, url: &str) -> Result { + pub async fn check_node_health(&self, scheme: &str, host: &str, port: i64) -> Result { let start_time = Instant::now(); let rpc_request = serde_json::json!({ @@ -125,8 +125,8 @@ impl NodeDiscovery { "method": "get_info" }); - let full_url = format!("{}/json_rpc", url); - let response = self.client.post(&full_url).json(&rpc_request).send().await; + let node_url = format!("{}://{}:{}/json_rpc", scheme, host, port); + let response = self.client.post(&node_url).json(&rpc_request).send().await; let latency = start_time.elapsed(); @@ -214,7 +214,6 @@ impl NodeDiscovery { scheme, host, port, - full_url, network as "network!: String", first_seen_at FROM monero_nodes @@ -229,12 +228,14 @@ impl NodeDiscovery { let mut corrected_count = 0; for node in all_nodes { - match self.check_node_health(&node.full_url).await { + match self.check_node_health(&node.scheme, &node.host, node.port).await { Ok(outcome) => { // Always record the health check self.db .record_health_check( - &node.full_url, + &node.scheme, + &node.host, + node.port, outcome.was_successful, if outcome.was_successful { Some(outcome.latency.as_millis() as f64) @@ -251,10 +252,11 @@ impl NodeDiscovery { if let Some(discovered_network) = outcome.discovered_network { let discovered_network_str = network_to_string(&discovered_network); if node.network != discovered_network_str { + let node_url = format!("{}://{}:{}", node.scheme, node.host, node.port); warn!("Network mismatch detected for node {}: stored={}, discovered={}. Correcting...", - node.full_url, node.network, discovered_network_str); + node_url, node.network, discovered_network_str); self.db - .update_node_network(&node.full_url, &discovered_network_str) + .update_node_network(&node.scheme, &node.host, node.port, &discovered_network_str) .await?; corrected_count += 1; } @@ -264,7 +266,7 @@ impl NodeDiscovery { } Err(_e) => { self.db - .record_health_check(&node.full_url, false, None) + .record_health_check(&node.scheme, &node.host, node.port, false, None) .await?; } } diff --git a/monero-rpc-pool/src/pool.rs b/monero-rpc-pool/src/pool.rs index 9f9cb740..7d5a281b 100644 --- a/monero-rpc-pool/src/pool.rs +++ b/monero-rpc-pool/src/pool.rs @@ -100,15 +100,15 @@ impl NodePool { score } - pub async fn record_success(&self, url: &str, latency_ms: f64) -> Result<()> { + pub async fn record_success(&self, scheme: &str, host: &str, port: i64, latency_ms: f64) -> Result<()> { self.db - .record_health_check(url, true, Some(latency_ms)) + .record_health_check(scheme, host, port, true, Some(latency_ms)) .await?; Ok(()) } - pub async fn record_failure(&self, url: &str) -> Result<()> { - self.db.record_health_check(url, false, None).await?; + pub async fn record_failure(&self, scheme: &str, host: &str, port: i64) -> Result<()> { + self.db.record_health_check(scheme, host, port, false, None).await?; Ok(()) } diff --git a/monero-rpc-pool/src/simple_handlers.rs b/monero-rpc-pool/src/simple_handlers.rs index f718225a..68ac930a 100644 --- a/monero-rpc-pool/src/simple_handlers.rs +++ b/monero-rpc-pool/src/simple_handlers.rs @@ -60,7 +60,7 @@ fn extract_jsonrpc_method(body: &[u8]) -> Option { } async fn raw_http_request( - node_url: &str, + node_url: (String, String, i64), path: &str, method: &str, headers: &HeaderMap, @@ -71,7 +71,8 @@ async fn raw_http_request( .build() .map_err(|e| HandlerError::RequestError(format!("{:#?}", e)))?; - let url = format!("{}{}", node_url, path); + let (scheme, host, port) = &node_url; + let url = format!("{}://{}:{}{}", scheme, host, port, path); // Use generic request method to support any HTTP verb let http_method = method @@ -148,31 +149,33 @@ async fn raw_http_request( Ok(axum_response) } -async fn record_success(state: &AppState, node_url: &str, latency_ms: f64) { +async fn record_success(state: &AppState, scheme: &str, host: &str, port: i64, latency_ms: f64) { let node_pool_guard = state.node_pool.read().await; - if let Err(e) = node_pool_guard.record_success(node_url, latency_ms).await { - error!("Failed to record success for {}: {}", node_url, e); + if let Err(e) = node_pool_guard.record_success(scheme, host, port, latency_ms).await { + error!("Failed to record success for {}://{}:{}: {}", scheme, host, port, e); } } -async fn record_failure(state: &AppState, node_url: &str) { +async fn record_failure(state: &AppState, scheme: &str, host: &str, port: i64) { let node_pool_guard = state.node_pool.read().await; - if let Err(e) = node_pool_guard.record_failure(node_url).await { - error!("Failed to record failure for {}: {}", node_url, e); + if let Err(e) = node_pool_guard.record_failure(scheme, host, port).await { + error!("Failed to record failure for {}://{}:{}: {}", scheme, host, port, e); } } async fn single_raw_request( state: &AppState, - node_url: String, + node_url: (String, String, i64), path: &str, method: &str, headers: &HeaderMap, body: Option<&[u8]>, -) -> Result<(Response, String, f64), HandlerError> { +) -> Result<(Response, (String, String, i64), f64), HandlerError> { + let (scheme, host, port) = &node_url; + let start_time = Instant::now(); - match raw_http_request(&node_url, path, method, headers, body).await { + match raw_http_request(node_url.clone(), path, method, headers, body).await { Ok(response) => { let elapsed = start_time.elapsed(); let latency_ms = elapsed.as_millis() as f64; @@ -187,22 +190,22 @@ async fn single_raw_request( .map_err(|e| HandlerError::RequestError(format!("{:#?}", e)))?; if is_jsonrpc_error(&body_bytes) { - record_failure(state, &node_url).await; + record_failure(state, scheme, host, *port).await; return Err(HandlerError::RequestError("JSON-RPC error".to_string())); } // Reconstruct response with the body we consumed let response = Response::from_parts(parts, Body::from(body_bytes)); - record_success(state, &node_url, latency_ms).await; + record_success(state, scheme, host, *port, latency_ms).await; Ok((response, node_url, latency_ms)) } else { // For non-JSON-RPC endpoints, HTTP success is enough - record_success(state, &node_url, latency_ms).await; + record_success(state, scheme, host, *port, latency_ms).await; Ok((response, node_url, latency_ms)) } } else { // Non-200 status codes are failures - record_failure(state, &node_url).await; + record_failure(state, scheme, host, *port).await; Err(HandlerError::RequestError(format!( "HTTP {}", response.status() @@ -210,7 +213,7 @@ async fn single_raw_request( } } Err(e) => { - record_failure(state, &node_url).await; + record_failure(state, scheme, host, *port).await; Err(e) } } @@ -246,9 +249,9 @@ async fn race_requests( .await .map_err(|e| HandlerError::PoolError(e.to_string()))?; - let pool: Vec = reliable_nodes + let pool: Vec<(String, String, i64)> = reliable_nodes .into_iter() - .map(|node| node.full_url()) + .map(|node| (node.scheme, node.host, node.port)) .collect(); pool @@ -286,7 +289,7 @@ async fn race_requests( } // Store node URLs for error tracking before consuming them - let current_nodes: Vec = [&node1_option, &node2_option] + let current_nodes: Vec<(String, String, i64)> = [&node1_option, &node2_option] .iter() .filter_map(|opt| opt.as_ref()) .cloned() @@ -362,6 +365,9 @@ async fn race_requests( match result { Ok((response, winning_node, latency_ms)) => { + let (scheme, host, port) = &winning_node; + let winning_node = format!("{}://{}:{}", scheme, host, port); + match &jsonrpc_method { Some(rpc_method) => { debug!( @@ -377,14 +383,15 @@ async fn race_requests( tried_nodes.len() ), } - record_success(state, &winning_node, latency_ms).await; + record_success(state, scheme, host, *port, latency_ms).await; return Ok(response); } Err(e) => { // Since we don't know which specific node failed in the race, // record the error for all nodes in this batch - for node_url in ¤t_nodes { - collected_errors.push((node_url.clone(), e.to_string())); + for (scheme, host, port) in ¤t_nodes { + let node_display = format!("{}://{}:{}", scheme, host, port); + collected_errors.push((node_display, e.to_string())); } debug!( "Request failed: {} - retrying with different nodes from pool...",