This commit is contained in:
Mark Sinclair
2025-10-10 15:13:47 +01:00
parent a50c9ac3fb
commit e18e64bf21
20 changed files with 364 additions and 1 deletions
@@ -0,0 +1,32 @@
{
"db_name": "SQLite",
"query": "\n SELECT epoch_id as \"epoch_id: u32\", serialised_key, serialization_revision as \"serialization_revision: u8\"\n FROM master_verification_key WHERE epoch_id = ?\n ",
"describe": {
"columns": [
{
"name": "epoch_id: u32",
"ordinal": 0,
"type_info": "Integer"
},
{
"name": "serialised_key",
"ordinal": 1,
"type_info": "Blob"
},
{
"name": "serialization_revision: u8",
"ordinal": 2,
"type_info": "Integer"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false
]
},
"hash": "0112296b190328a3856d1adf51aafa2525da6c0b871633aad80ad555db9cf47c"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO ecash_deposit_usage (deposit_id, ticketbooks_requested_on, client_pubkey, request_uuid)\n VALUES (?, ?, ?, ?)\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 4
},
"nullable": []
},
"hash": "1fc72f8ba24039548047e1766c9105614dea7fd301f0ec38bfe85bfe546dad40"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n DELETE FROM blinded_shares WHERE created < ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "28681fcd8e2d4326f628681b8f2a317aabce063a650be362d3a8ed83cc7c3549"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO global_expiration_date_signatures(expiration_date, epoch_id, serialised_signatures, serialization_revision)\n VALUES (?, ?, ?, ?)\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 4
},
"nullable": []
},
"hash": "2930ca6e3875c74acb7abb9ad889f166ad7f57681f76a1d0c7723d007c1f2c1e"
}
@@ -0,0 +1,20 @@
{
"db_name": "SQLite",
"query": "\n SELECT error_message\n FROM blinded_shares\n WHERE id = ?;\n ",
"describe": {
"columns": [
{
"name": "error_message",
"ordinal": 0,
"type_info": "Text"
}
],
"parameters": {
"Right": 1
},
"nullable": [
true
]
},
"hash": "396f40c33f0f62796eb7449d640bd97845350f4fb9f806c60b93c7cebd5e410d"
}
@@ -0,0 +1,26 @@
{
"db_name": "SQLite",
"query": "\n SELECT serialised_signatures, serialization_revision as \"serialization_revision: u8\"\n FROM global_expiration_date_signatures\n WHERE expiration_date = ? AND epoch_id = ?\n ",
"describe": {
"columns": [
{
"name": "serialised_signatures",
"ordinal": 0,
"type_info": "Blob"
},
{
"name": "serialization_revision: u8",
"ordinal": 1,
"type_info": "Integer"
}
],
"parameters": {
"Right": 2
},
"nullable": [
false,
false
]
},
"hash": "3cc446220668fb3e02f0578104291d2a2af57656b405212af414d765b2263347"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n DELETE FROM partial_blinded_wallet_failure WHERE created < ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "52b378e282d93db941eff53b5b311e5732ece0bf84ea98f2328b20add8f2b5ef"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "INSERT INTO master_verification_key(epoch_id, serialised_key, serialization_revision) VALUES (?, ?, ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
},
"hash": "70d8f240ad6edda6b8c7f2e800e7fca89d80869484f2f3c66cabb898f0298c62"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO partial_blinded_wallet_failure(corresponding_deposit, epoch_id, expiration_date, node_id, created, failure_message)\n VALUES (?, ?, ?, ?, ?, ?)\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 6
},
"nullable": []
},
"hash": "97d97ebb6bc8f4114fdea9ebc9f57f91a11f5057273cb70bd0e629712d17dd41"
}
@@ -0,0 +1,32 @@
{
"db_name": "SQLite",
"query": "\n SELECT epoch_id as \"epoch_id: u32\", serialised_signatures, serialization_revision as \"serialization_revision: u8\"\n FROM global_coin_index_signatures WHERE epoch_id = ?\n ",
"describe": {
"columns": [
{
"name": "epoch_id: u32",
"ordinal": 0,
"type_info": "Integer"
},
{
"name": "serialised_signatures",
"ordinal": 1,
"type_info": "Blob"
},
{
"name": "serialization_revision: u8",
"ordinal": 2,
"type_info": "Integer"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false
]
},
"hash": "a8b7ce0fe4755c28b96d1e503e313ab15fed747fb0cee1c9f949fb58461b3f79"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n DELETE FROM partial_blinded_wallet WHERE created < ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "b8257a0832d0124f0a8aaaf81dc6a811c593aea8febf1f891117e5e84213f147"
}
@@ -0,0 +1,38 @@
{
"db_name": "SQLite",
"query": "\n SELECT\n t1.node_id as \"node_id!\",\n t1.blinded_signature as \"blinded_signature!\",\n t1.epoch_id as \"epoch_id!\",\n t1.expiration_date as \"expiration_date!: Date\"\n FROM partial_blinded_wallet as t1\n JOIN ecash_deposit_usage as t2\n on t1.corresponding_deposit = t2.deposit_id\n JOIN blinded_shares as t3\n ON t2.request_uuid = t3.request_uuid\n WHERE t3.device_id = ? AND t3.credential_id = ?;\n ",
"describe": {
"columns": [
{
"name": "node_id!",
"ordinal": 0,
"type_info": "Integer"
},
{
"name": "blinded_signature!",
"ordinal": 1,
"type_info": "Blob"
},
{
"name": "epoch_id!",
"ordinal": 2,
"type_info": "Integer"
},
{
"name": "expiration_date!: Date",
"ordinal": 3,
"type_info": "Date"
}
],
"parameters": {
"Right": 2
},
"nullable": [
true,
true,
true,
true
]
},
"hash": "c2b841762bdb963fff337ef5c8ec9f560017b4da6b0303ea0397d9568229e167"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "INSERT INTO global_coin_index_signatures(epoch_id, serialised_signatures, serialization_revision) VALUES (?, ?, ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
},
"hash": "d3510846941fa2525926b9bfbcdabd806877ce914b514d4f7cd6be318c4debe6"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO partial_blinded_wallet(corresponding_deposit, epoch_id, expiration_date, node_id, created, blinded_signature)\n VALUES (?, ?, ?, ?, ?, ?)\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 6
},
"nullable": []
},
"hash": "db176e98198fe594d88eb860d918f633a94d18a19b7f0f96935a62560def7d0f"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n UPDATE ecash_deposit_usage\n SET ticketbook_request_error = ?\n WHERE deposit_id = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "e584253e3856355899537eb8fc152f2bfed2d918b894ec0f588e38dd5e8ad726"
}
@@ -0,0 +1,38 @@
{
"db_name": "SQLite",
"query": "\n SELECT t1.node_id, t1.blinded_signature, t1.epoch_id, t1.expiration_date as \"expiration_date!: Date\"\n FROM partial_blinded_wallet as t1\n JOIN ecash_deposit_usage as t2\n on t1.corresponding_deposit = t2.deposit_id\n JOIN blinded_shares as t3\n ON t2.request_uuid = t3.request_uuid\n WHERE t3.id = ?;\n ",
"describe": {
"columns": [
{
"name": "node_id",
"ordinal": 0,
"type_info": "Integer"
},
{
"name": "blinded_signature",
"ordinal": 1,
"type_info": "Blob"
},
{
"name": "epoch_id",
"ordinal": 2,
"type_info": "Integer"
},
{
"name": "expiration_date!: Date",
"ordinal": 3,
"type_info": "Date"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
false
]
},
"hash": "e77ffab19b099b84470fe5611716a2e314787586a46cffd074abb67f2f4d109e"
}
@@ -0,0 +1,20 @@
{
"db_name": "SQLite",
"query": "\n SELECT error_message\n FROM blinded_shares\n WHERE device_id = ? AND credential_id = ?;\n ",
"describe": {
"columns": [
{
"name": "error_message",
"ordinal": 0,
"type_info": "Text"
}
],
"parameters": {
"Right": 2
},
"nullable": [
true
]
},
"hash": "ef60c2683211cc4ec2d3e46392518a1f62fa67dfe8f130deb876ebee11bf1602"
}
@@ -1,5 +1,5 @@
use crate::ticketbook_manager::TicketbookManagerConfig;
use clap::Parser;
use clap::{Parser, Subcommand};
use nym_bin_common::bin_info;
use nym_credential_proxy_lib::shared_state::ecash_state::TicketType;
use reqwest::Url;
@@ -105,6 +105,19 @@ pub(crate) struct Cli {
#[clap(flatten)]
pub(crate) ticketbook: TicketbookArgs,
#[command(subcommand)]
pub(crate) command: Option<Commands>,
}
#[derive(Subcommand, Debug)]
pub(crate) enum Commands {
/// Scrape a single node and output detailed debug logs
ScrapeNode {
/// The id of the node to scrape
#[arg(long)]
node_id: i64,
},
}
#[derive(Debug, Parser)]
@@ -1,4 +1,6 @@
use crate::cli::Commands;
use crate::monitor::DelegationsCache;
use crate::node_scraper::helpers::scrape_and_store_description_by_node_id;
use crate::ticketbook_manager::TicketbookManager;
use crate::ticketbook_manager::state::TicketbookManagerState;
use clap::Parser;
@@ -45,6 +47,17 @@ async fn main() -> anyhow::Result<()> {
let storage = db::Storage::init(connection_url, args.sqlx_busy_timeout_s).await?;
let db_pool = storage.pool_owned();
match args.command {
Some(Commands::ScrapeNode { node_id }) => {
tracing::info!("Scraping node with id {node_id}...");
scrape_and_store_description_by_node_id(&db_pool, node_id).await?;
return Ok(());
}
None => {
// default behaviour
}
}
// Start the node scraper
let scraper = node_scraper::DescriptionScraper::new(storage.pool_owned());
shutdown_manager.spawn_with_shutdown(async move {
@@ -118,6 +118,17 @@ pub fn sanitize_description(
}
}
pub async fn scrape_and_store_description_by_node_id(pool: &DbPool, node_id: i64) -> Result<()> {
let nodes = crate::db::queries::get_nodes_for_scraping(pool).await?;
match nodes.iter().find(|n| *n.node_kind.node_id() == node_id) {
Some(node) => Ok(scrape_and_store_description(pool, node.clone()).await?),
None => {
error!("Could not find node with id {node_id}");
Err(anyhow!("Could not find node with id {node_id}"))
}
}
}
pub async fn scrape_and_store_description(pool: &DbPool, node: ScraperNodeInfo) -> Result<()> {
let client = build_client()?;
let urls = node.contact_addresses();