From 45c6e6febba5e3e41bcd2eb4c789e04d5dbccd91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marijan=20Petri=C4=8Devi=C4=87?= Date: Mon, 15 Jul 2024 13:53:40 +0200 Subject: [PATCH 1/9] cctl: configure verbosity depending on tracing log level --- kairos-test-utils/src/cctl.rs | 76 +++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/kairos-test-utils/src/cctl.rs b/kairos-test-utils/src/cctl.rs index 00c1dbc3..d05bc209 100644 --- a/kairos-test-utils/src/cctl.rs +++ b/kairos-test-utils/src/cctl.rs @@ -51,6 +51,16 @@ pub struct DeployableContract { pub path: PathBuf, } +pub fn casper_client_verbosity() -> Verbosity { + if tracing::enabled!(tracing::Level::TRACE) { + Verbosity::High + } else if tracing::enabled!(tracing::Level::DEBUG) { + Verbosity::Medium + } else { + Verbosity::Low + } +} + // max amount allowed to be used on gas fees pub const MAX_GAS_FEE_PAYMENT_AMOUNT: u64 = 10_000_000_000_000; @@ -139,32 +149,34 @@ impl CCTLNetwork { // This prevents retrying forever even after ctrl-c let timed_out = start_time.elapsed().as_secs() > 60; - get_node_status(JsonRpcId::Number(1), &casper_node_rpc_url, Verbosity::Low) - .await - .map_err(|err| { - let elapsed = start_time.elapsed().as_secs(); - tracing::info!("Running for {elapsed}s, Error: {err:?}"); - err - }) - .map_err(|err| match &err { - err if timed_out => { - backoff::Error::permanent(anyhow!("Timeout on error: {err:?}")) - } - Error::ResponseIsHttpError { .. } | Error::FailedToGetResponse { .. } => { - backoff::Error::transient(anyhow!(err)) - } - _ => backoff::Error::permanent(anyhow!(err)), - }) - .map(|success| match success.result.reactor_state { - ReactorState::Validate => Ok(()), - // _ if timed_out => Ok(()), - rs if timed_out => Err(backoff::Error::permanent(anyhow!( - "Node didn't reach the VALIDATE state before timeout: {rs:?}" - ))), - _ => Err(backoff::Error::transient(anyhow!( - "Node didn't reach the VALIDATE state yet" - ))), - })? + get_node_status( + JsonRpcId::Number(1), + &casper_node_rpc_url, + casper_client_verbosity(), + ) + .await + .map_err(|err| { + let elapsed = start_time.elapsed().as_secs(); + tracing::info!("Running for {elapsed}s, Error: {err:?}"); + err + }) + .map_err(|err| match &err { + err if timed_out => backoff::Error::permanent(anyhow!("Timeout on error: {err:?}")), + Error::ResponseIsHttpError { .. } | Error::FailedToGetResponse { .. } => { + backoff::Error::transient(anyhow!(err)) + } + _ => backoff::Error::permanent(anyhow!(err)), + }) + .map(|success| match success.result.reactor_state { + ReactorState::Validate => Ok(()), + // _ if timed_out => Ok(()), + rs if timed_out => Err(backoff::Error::permanent(anyhow!( + "Node didn't reach the VALIDATE state before timeout: {rs:?}" + ))), + _ => Err(backoff::Error::transient(anyhow!( + "Node didn't reach the VALIDATE state yet" + ))), + })? }) .await .expect("Waiting for network to pass genesis failed"); @@ -243,6 +255,8 @@ async fn deploy_contract( path.to_str().unwrap() ); + let casper_client_verbosity = casper_client_verbosity(); + let contract_bytes = fs::read(path)?; let contract = ExecutableDeployItem::new_module_bytes(contract_bytes.into(), runtime_args.clone()); @@ -262,7 +276,7 @@ async fn deploy_contract( let deploy_hash = put_deploy( expected_rpc_id.clone(), casper_node_rpc_url, - Verbosity::High, + casper_client_verbosity, deploy, ) .await @@ -284,7 +298,7 @@ async fn deploy_contract( let response = get_deploy( expected_rpc_id.clone(), casper_node_rpc_url, - Verbosity::High, + casper_client_verbosity, deploy_hash, false, ) @@ -330,7 +344,7 @@ async fn deploy_contract( let state_root_hash = get_state_root_hash( expected_rpc_id.clone(), casper_node_rpc_url, - Verbosity::High, + casper_client_verbosity, Option::None, ) .await @@ -350,7 +364,7 @@ async fn deploy_contract( let account = get_account( expected_rpc_id.clone(), casper_node_rpc_url, - Verbosity::High, + casper_client_verbosity, Option::None, contract_deployer_pkey.clone(), ) @@ -369,7 +383,7 @@ async fn deploy_contract( let contract_hash: casper_client_types::ContractHash = query_global_state( expected_rpc_id.clone(), casper_node_rpc_url, - Verbosity::High, + casper_client_verbosity, casper_client::rpcs::GlobalStateIdentifier::StateRootHash(state_root_hash), // fetches recent blocks state root hash account_key, vec![hash_name.clone()], From 567b7204224d6693a3e872b58bfd7a9e34e48dc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marijan=20Petri=C4=8Devi=C4=87?= Date: Mon, 15 Jul 2024 13:54:01 +0200 Subject: [PATCH 2/9] cctl: increase timeout value --- kairos-test-utils/src/cctl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kairos-test-utils/src/cctl.rs b/kairos-test-utils/src/cctl.rs index d05bc209..a8514591 100644 --- a/kairos-test-utils/src/cctl.rs +++ b/kairos-test-utils/src/cctl.rs @@ -147,7 +147,7 @@ impl CCTLNetwork { tracing::info!("Waiting for network to pass genesis"); retry(ExponentialBackoff::default(), || async { // This prevents retrying forever even after ctrl-c - let timed_out = start_time.elapsed().as_secs() > 60; + let timed_out = start_time.elapsed().as_secs() > 90; get_node_status( JsonRpcId::Number(1), From 640b8077999d280c5a41914e8bcce64b55303523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marijan=20Petri=C4=8Devi=C4=87?= Date: Mon, 15 Jul 2024 13:54:29 +0200 Subject: [PATCH 3/9] cctl: don't use rng since we are testing --- Cargo.lock | 1 - kairos-test-utils/Cargo.toml | 1 - kairos-test-utils/src/cctl.rs | 100 ++++++++++++---------------------- 3 files changed, 34 insertions(+), 68 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 90acdd7b..830cc01f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2564,7 +2564,6 @@ dependencies = [ "hex", "kairos-server", "nom", - "rand 0.8.5", "reqwest 0.12.4", "sd-notify", "tempfile", diff --git a/kairos-test-utils/Cargo.toml b/kairos-test-utils/Cargo.toml index 664d72bd..4800300f 100644 --- a/kairos-test-utils/Cargo.toml +++ b/kairos-test-utils/Cargo.toml @@ -29,7 +29,6 @@ casper-types.workspace = true casper-client-types.workspace = true nom = "7" hex = "0.4" -rand = "0.8" sd-notify = "0.4" tokio = { version = "1", features = [ "full", "tracing", "macros" ] } tempfile = "3" diff --git a/kairos-test-utils/src/cctl.rs b/kairos-test-utils/src/cctl.rs index a8514591..86d08fb2 100644 --- a/kairos-test-utils/src/cctl.rs +++ b/kairos-test-utils/src/cctl.rs @@ -9,7 +9,6 @@ use casper_client::{ }; use casper_client_types::{ContractHash, ExecutionResult, Key, PublicKey, RuntimeArgs, SecretKey}; use hex::FromHex; -use rand::Rng; use std::io::{self, Write}; use std::path::Path; use std::path::PathBuf; @@ -272,31 +271,23 @@ async fn deploy_contract( .build()?; tracing::info!("Submitting contract deploy"); - let expected_rpc_id = JsonRpcId::Number(rand::thread_rng().gen::()); let deploy_hash = put_deploy( - expected_rpc_id.clone(), + JsonRpcId::Number(1), casper_node_rpc_url, casper_client_verbosity, deploy, ) .await .map_err(Into::::into) - .and_then(|response| { - if response.id == expected_rpc_id { - Ok(response.result.deploy_hash) - } else { - Err(anyhow!("JSON RPC Id missmatch")) - } - })?; + .map(|response| response.result.deploy_hash)?; tracing::info!("Waiting for successful contract initialization"); let start = Instant::now(); retry(ExponentialBackoff::default(), || async { let timed_out = start.elapsed().as_secs() > 60; - let expected_rpc_id = JsonRpcId::Number(rand::thread_rng().gen::()); let response = get_deploy( - expected_rpc_id.clone(), + JsonRpcId::Number(1), casper_node_rpc_url, casper_client_verbosity, deploy_hash, @@ -316,23 +307,19 @@ async fn deploy_contract( _ => backoff::Error::permanent(anyhow!(err)), })?; - if response.id == expected_rpc_id { - match response.result.execution_results.first() { - Some(result) => match &result.result { - ExecutionResult::Failure { error_message, .. } => { - Err(backoff::Error::permanent(anyhow!(error_message.clone()))) - } - ExecutionResult::Success { .. } => Ok(()), - }, - None if timed_out => Err(backoff::Error::permanent(anyhow!( - "Timeout on error: No execution results" - ))), - None => Err(backoff::Error::transient(anyhow!( - "No execution results there yet" - ))), - } - } else { - Err(backoff::Error::permanent(anyhow!("JSON RPC Id missmatch"))) + match response.result.execution_results.first() { + Some(result) => match &result.result { + ExecutionResult::Failure { error_message, .. } => { + Err(backoff::Error::permanent(anyhow!(error_message.clone()))) + } + ExecutionResult::Success { .. } => Ok(()), + }, + None if timed_out => Err(backoff::Error::permanent(anyhow!( + "Timeout on error: No execution results" + ))), + None => Err(backoff::Error::transient(anyhow!( + "No execution results there yet" + ))), } }) .await?; @@ -340,9 +327,8 @@ async fn deploy_contract( tracing::info!("Fetching deployed contract hash"); // Query global state - let expected_rpc_id = JsonRpcId::Number(rand::thread_rng().gen::()); let state_root_hash = get_state_root_hash( - expected_rpc_id.clone(), + JsonRpcId::Number(1), casper_node_rpc_url, casper_client_verbosity, Option::None, @@ -350,19 +336,14 @@ async fn deploy_contract( .await .map_err(Into::::into) .and_then(|response| { - if response.id == expected_rpc_id { - response - .result - .state_root_hash - .ok_or(anyhow!("No state root hash present in response")) - } else { - Err(anyhow!("JSON RPC Id missmatch")) - } + response + .result + .state_root_hash + .ok_or(anyhow!("No state root hash present in response")) })?; - let expected_rpc_id = JsonRpcId::Number(rand::thread_rng().gen::()); let account = get_account( - expected_rpc_id.clone(), + JsonRpcId::Number(1), casper_node_rpc_url, casper_client_verbosity, Option::None, @@ -370,18 +351,11 @@ async fn deploy_contract( ) .await .map_err(Into::::into) - .and_then(|response| { - if response.id == expected_rpc_id { - Ok(response.result.account) - } else { - Err(anyhow!("JSON RPC Id missmatch")) - } - })?; + .map(|response| response.result.account)?; - let expected_rpc_id = JsonRpcId::Number(rand::thread_rng().gen::()); let account_key = Key::Account(*account.account_hash()); let contract_hash: casper_client_types::ContractHash = query_global_state( - expected_rpc_id.clone(), + JsonRpcId::Number(1), casper_node_rpc_url, casper_client_verbosity, casper_client::rpcs::GlobalStateIdentifier::StateRootHash(state_root_hash), // fetches recent blocks state root hash @@ -390,22 +364,16 @@ async fn deploy_contract( ) .await .map_err(Into::::into) - .and_then(|response| { - if response.id == expected_rpc_id { - match response.result.stored_value { - StoredValue::ContractPackage(contract_package) => Ok(*contract_package - .versions() - .next() - .expect("Expected at least one contract version") - .contract_hash()), - other => Err(anyhow!( - "Unexpected result type, type is not a CLValue: {:?}", - other - )), - } - } else { - Err(anyhow!("JSON RPC Id missmatch")) - } + .and_then(|response| match response.result.stored_value { + StoredValue::ContractPackage(contract_package) => Ok(*contract_package + .versions() + .next() + .expect("Expected at least one contract version") + .contract_hash()), + other => Err(anyhow!( + "Unexpected result type, type is not a CLValue: {:?}", + other + )), })?; tracing::info!( "Successfully fetched the contract hash for {}: {}", From 11211ad745248864f7b437093e2165fb900de9ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marijan=20Petri=C4=8Devi=C4=87?= Date: Mon, 22 Jul 2024 15:47:49 +0200 Subject: [PATCH 4/9] kairos-server: add query_transaction_handler --- kairos-server/src/lib.rs | 25 +++---- kairos-server/src/routes/mod.rs | 2 + nixos/modules/kairos.nix | 115 +++++++++++++++++++++++--------- 3 files changed, 96 insertions(+), 46 deletions(-) diff --git a/kairos-server/src/lib.rs b/kairos-server/src/lib.rs index 773669d4..a441bf51 100644 --- a/kairos-server/src/lib.rs +++ b/kairos-server/src/lib.rs @@ -26,25 +26,22 @@ use kairos_data::new as new_pool; pub type PublicKey = Vec; type Signature = Vec; -#[cfg(not(feature = "deposit-mock"))] pub fn app_router(state: ServerState) -> Router { - Router::new() + let mut router = Router::new() .typed_post(routes::deposit_handler) .typed_post(routes::withdraw_handler) .typed_post(routes::transfer_handler) - .with_state(state) -} - -#[cfg(feature = "deposit-mock")] -pub fn app_router(state: ServerState) -> Router { - Router::new() - .typed_post(routes::deposit_handler) - .typed_post(routes::withdraw_handler) - .typed_post(routes::transfer_handler) - .typed_post(routes::deposit_mock_handler) .typed_post(routes::get_nonce_handler) - .typed_get(routes::contract_hash_handler) - .with_state(state) + .typed_get(routes::contract_hash_handler); + #[cfg(feature = "deposit-mock")] + { + router = router.typed_post(routes::deposit_mock_handler) + } + #[cfg(feature = "database")] + { + router = router.typed_post(routes::query_transactions_handler); + } + router.with_state(state) } pub async fn run_l1_sync(server_state: Arc) { diff --git a/kairos-server/src/routes/mod.rs b/kairos-server/src/routes/mod.rs index 7da4b4dd..c26becf6 100644 --- a/kairos-server/src/routes/mod.rs +++ b/kairos-server/src/routes/mod.rs @@ -12,6 +12,8 @@ pub use contract_hash::contract_hash_handler; pub use deposit::deposit_handler; #[cfg(feature = "deposit-mock")] pub use deposit_mock::deposit_mock_handler; +#[cfg(feature = "database")] +pub use fetch::query_transactions_handler; pub use get_nonce::get_nonce_handler; pub use transfer::transfer_handler; pub use withdraw::withdraw_handler; diff --git a/nixos/modules/kairos.nix b/nixos/modules/kairos.nix index 81a9e093..9a34a83f 100644 --- a/nixos/modules/kairos.nix +++ b/nixos/modules/kairos.nix @@ -1,4 +1,4 @@ -{ lib, pkgs, config, ... }: +{ lib, config, ... }: let inherit (lib) types @@ -121,7 +121,6 @@ in }; }; - logLevel = mkOption { type = types.enum [ "error" @@ -135,42 +134,94 @@ in The log-level that should be used. ''; }; - }; - config = mkIf cfg.enable { - - systemd.services.kairos = - { - description = "kairos"; - documentation = [ "" ]; - wantedBy = [ "multi-user.target" ]; - after = [ "network-online.target" "kairos-prover.service" ]; - requires = [ "network-online.target" "kairos-prover.service" ]; - environment = { - RUST_LOG = cfg.logLevel; - KAIROS_SERVER_SOCKET_ADDR = "${cfg.bindAddress}:${builtins.toString cfg.port}"; - KAIROS_SERVER_CASPER_RPC = cfg.casperRpcUrl; - KAIROS_SERVER_CASPER_SSE = cfg.casperSseUrl; - KAIROS_SERVER_CASPER_SYNC_INTERVAL = builtins.toString cfg.casperSyncInterval; - KAIROS_SERVER_DEMO_CONTRACT_HASH = cfg.demoContractHash; - KAIROS_PROVER_SERVER_URL = "${cfg.prover.protocol}://${cfg.prover.bindAddress}:${builtins.toString cfg.prover.port}"; - } // optionalAttrs (!builtins.isNull cfg.prover.maxBatchSize) { - KAIROS_SERVER_MAX_BATCH_SIZE = cfg.maxBatchSize; - } // optionalAttrs (!builtins.isNull cfg.prover.maxBatchDuration) { - KAIROS_SERVER_MAX_BATCH_SECONDS = cfg.prover.maxBatchDuration; + database = mkOption { + description = "The database connection"; + type = types.submodule { + host = mkOption { + type = types.str; + default = "/run/postgresql"; + example = "/run/postgresql"; + description = '' + Host of the PostgreSQL server + ''; + }; + + port = mkOption { + type = types.port; + default = config.services.postgresql.port; + description = '' + Port of the PostgreSQL server + ''; + }; + + databaseName = mkOption { + type = types.str; + default = "kairos"; + example = "kairos"; + description = '' + Name of the PostgreSQL database + ''; + }; + + userName = mkOption { + type = types.str; + default = "kairos"; + example = "kairos"; + description = '' + Username for the PostgreSQL connection + ''; + }; + }; + }; + + config = mkIf cfg.enable { + + systemd.services.kairos = + { + description = "kairos"; + documentation = [ "" ]; + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" "kairos-prover.service" "postgresql.service" ]; + requires = [ "network-online.target" "kairos-prover.service" "postgresql.service" ]; + environment = { + RUST_LOG = cfg.logLevel; + KAIROS_SERVER_SOCKET_ADDR = "${cfg.bindAddress}:${builtins.toString cfg.port}"; + KAIROS_SERVER_CASPER_RPC = cfg.casperRpcUrl; + KAIROS_SERVER_CASPER_SSE = cfg.casperSseUrl; + KAIROS_SERVER_CASPER_SYNC_INTERVAL = builtins.toString cfg.casperSyncInterval; + KAIROS_SERVER_DEMO_CONTRACT_HASH = cfg.demoContractHash; + KAIROS_PROVER_SERVER_URL = "${cfg.prover.protocol}://${cfg.prover.bindAddress}:${builtins.toString cfg.prover.port}"; + KAIROS_SERVER_DB_ADDR = "postgresql://${cfg.database.userName}@localhost:${cfg.database.port}/${cfg.database.databaseName}?host=${cfg.database.host}"; + } // optionalAttrs (!builtins.isNull cfg.prover.maxBatchSize) { + KAIROS_SERVER_MAX_BATCH_SIZE = cfg.maxBatchSize; + } // optionalAttrs (!builtins.isNull cfg.prover.maxBatchDuration) { + KAIROS_SERVER_MAX_BATCH_SECONDS = cfg.prover.maxBatchDuration; + }; + serviceConfig = mkMerge [ + { + ExecStart = ''${lib.getExe cfg.package}''; + Restart = "always"; + DynamicUser = true; + } + ]; }; - serviceConfig = mkMerge [ + + services.kairos-prover = { + enable = true; + inherit (cfg.prover) bindAddress port; + }; + + services.postgresql = { + enable = true; + ensureDatabases = [ cfg.database.databaseName ]; + ensureUsers = [ { - ExecStart = ''${lib.getExe cfg.package}''; - Restart = "always"; - DynamicUser = true; + name = cfg.database.user; + ensureDBOwnership = true; } ]; }; - - services.kairos-prover = { - enable = true; - inherit (cfg.prover) bindAddress port; }; }; } From b3126aedff9fe43cd8937fdd9d75a4801c56040e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marijan=20Petri=C4=8Devi=C4=87?= Date: Mon, 22 Jul 2024 15:48:10 +0200 Subject: [PATCH 5/9] kairos-server/l1-sync: insert deposit into database --- kairos-server/src/l1_sync/event_manager.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/kairos-server/src/l1_sync/event_manager.rs b/kairos-server/src/l1_sync/event_manager.rs index d19290ef..82ead090 100644 --- a/kairos-server/src/l1_sync/event_manager.rs +++ b/kairos-server/src/l1_sync/event_manager.rs @@ -7,6 +7,8 @@ use casper_event_toolkit::rpc::client::CasperClient; use crate::state::ServerStateInner; use kairos_circuit_logic::transactions::{KairosTransaction, L1Deposit}; +#[cfg(feature = "database")] +use kairos_data::transaction as db; use super::error::L1SyncError; @@ -69,6 +71,16 @@ impl EventManager { let recipient: Vec = deposit.recipient; let txn = KairosTransaction::Deposit(L1Deposit { amount, recipient }); + #[cfg(feature = "database")] + db::insert(&self.server_state.pool, txn.clone()) + .await + .map_err(|e| { + L1SyncError::UnexpectedError(format!( + "Failed to add to database: {}", + e + )) + })?; + // Push deposit to trie. self.server_state .batch_state_manager From acde8dc78ccea6e3e2419701ec7c3ba0f927c3ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marijan=20Petri=C4=8Devi=C4=87?= Date: Mon, 22 Jul 2024 15:48:41 +0200 Subject: [PATCH 6/9] kairos: add database to default features --- kairos-cli/Cargo.toml | 2 +- kairos-server/Cargo.toml | 2 +- kairos-test-utils/Cargo.toml | 1 + kairos-test-utils/src/kairos.rs | 6 ++++-- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/kairos-cli/Cargo.toml b/kairos-cli/Cargo.toml index fb320d51..6c2021b8 100644 --- a/kairos-cli/Cargo.toml +++ b/kairos-cli/Cargo.toml @@ -14,7 +14,7 @@ license.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["demo"] +default = ["demo", "database"] all-tests = ["cctl-tests", "database"] cctl-tests = [] demo = ["dep:kairos-test-utils", "dep:tokio", "dep:dotenvy"] diff --git a/kairos-server/Cargo.toml b/kairos-server/Cargo.toml index efc97248..895adb8b 100644 --- a/kairos-server/Cargo.toml +++ b/kairos-server/Cargo.toml @@ -12,7 +12,7 @@ name = "kairos-server" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["cctl-tests", "deposit-mock"] +default = ["cctl-tests", "deposit-mock", "database"] all-tests = ["cctl-tests", "deposit-mock", "database"] cctl-tests = [] deposit-mock = [] diff --git a/kairos-test-utils/Cargo.toml b/kairos-test-utils/Cargo.toml index fd1ead89..4df8218e 100644 --- a/kairos-test-utils/Cargo.toml +++ b/kairos-test-utils/Cargo.toml @@ -14,6 +14,7 @@ bench = false [features] # FIXME enable cctl-tests once this crate is factored out in a separate repository #all-tests = ["cctl-tests"] +default = ["database"] all-tests = ["database"] cctl-tests = [] database = ["kairos-server/database"] diff --git a/kairos-test-utils/src/kairos.rs b/kairos-test-utils/src/kairos.rs index 9e5944b5..ab57fb0e 100644 --- a/kairos-test-utils/src/kairos.rs +++ b/kairos-test-utils/src/kairos.rs @@ -122,12 +122,14 @@ impl Drop for Kairos { #[cfg(test)] mod tests { use super::*; + #[cfg(feature = "database")] + use crate::postgres::PostgresDB; #[tokio::test] async fn test_kairos_starts_and_terminates() { let dummy_rpc = Url::parse("http://127.0.0.1:11101/rpc").unwrap(); let dummy_sse = Url::parse("http://127.0.0.1:18101/events/main").unwrap(); #[cfg(feature = "database")] - let dummy_postgres = Url::parse("postgres://kairos:kairos@localhost/kairos").unwrap(); + let postgres = PostgresDB::run(None).unwrap(); let _kairos = Kairos::run( &dummy_rpc, @@ -135,7 +137,7 @@ mod tests { None, None, #[cfg(feature = "database")] - &dummy_postgres, + &postgres.connection.clone().into(), ) .await .unwrap(); From 4d9a4731047682c398cc85e85f5df7e2b48e9b5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marijan=20Petri=C4=8Devi=C4=87?= Date: Mon, 22 Jul 2024 15:49:05 +0200 Subject: [PATCH 7/9] nixos/kairos: add database connection configuration and enable postgres --- nixos/modules/kairos.nix | 92 ++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 47 deletions(-) diff --git a/nixos/modules/kairos.nix b/nixos/modules/kairos.nix index 9a34a83f..41249ebb 100644 --- a/nixos/modules/kairos.nix +++ b/nixos/modules/kairos.nix @@ -135,9 +135,8 @@ in ''; }; - database = mkOption { - description = "The database connection"; - type = types.submodule { + database = + { host = mkOption { type = types.str; default = "/run/postgresql"; @@ -149,7 +148,7 @@ in port = mkOption { type = types.port; - default = config.services.postgresql.port; + default = config.services.postgresql.settings.port; description = '' Port of the PostgreSQL server ''; @@ -173,55 +172,54 @@ in ''; }; }; - }; - - config = mkIf cfg.enable { + }; - systemd.services.kairos = - { - description = "kairos"; - documentation = [ "" ]; - wantedBy = [ "multi-user.target" ]; - after = [ "network-online.target" "kairos-prover.service" "postgresql.service" ]; - requires = [ "network-online.target" "kairos-prover.service" "postgresql.service" ]; - environment = { - RUST_LOG = cfg.logLevel; - KAIROS_SERVER_SOCKET_ADDR = "${cfg.bindAddress}:${builtins.toString cfg.port}"; - KAIROS_SERVER_CASPER_RPC = cfg.casperRpcUrl; - KAIROS_SERVER_CASPER_SSE = cfg.casperSseUrl; - KAIROS_SERVER_CASPER_SYNC_INTERVAL = builtins.toString cfg.casperSyncInterval; - KAIROS_SERVER_DEMO_CONTRACT_HASH = cfg.demoContractHash; - KAIROS_PROVER_SERVER_URL = "${cfg.prover.protocol}://${cfg.prover.bindAddress}:${builtins.toString cfg.prover.port}"; - KAIROS_SERVER_DB_ADDR = "postgresql://${cfg.database.userName}@localhost:${cfg.database.port}/${cfg.database.databaseName}?host=${cfg.database.host}"; - } // optionalAttrs (!builtins.isNull cfg.prover.maxBatchSize) { - KAIROS_SERVER_MAX_BATCH_SIZE = cfg.maxBatchSize; - } // optionalAttrs (!builtins.isNull cfg.prover.maxBatchDuration) { - KAIROS_SERVER_MAX_BATCH_SECONDS = cfg.prover.maxBatchDuration; - }; - serviceConfig = mkMerge [ - { - ExecStart = ''${lib.getExe cfg.package}''; - Restart = "always"; - DynamicUser = true; - } - ]; + config = mkIf cfg.enable { + + systemd.services.kairos = + { + description = "kairos"; + documentation = [ "" ]; + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" "kairos-prover.service" "postgresql.service" ]; + requires = [ "network-online.target" "kairos-prover.service" "postgresql.service" ]; + environment = { + RUST_LOG = cfg.logLevel; + KAIROS_SERVER_SOCKET_ADDR = "${cfg.bindAddress}:${builtins.toString cfg.port}"; + KAIROS_SERVER_CASPER_RPC = cfg.casperRpcUrl; + KAIROS_SERVER_CASPER_SSE = cfg.casperSseUrl; + KAIROS_SERVER_CASPER_SYNC_INTERVAL = builtins.toString cfg.casperSyncInterval; + KAIROS_SERVER_DEMO_CONTRACT_HASH = cfg.demoContractHash; + KAIROS_PROVER_SERVER_URL = "${cfg.prover.protocol}://${cfg.prover.bindAddress}:${builtins.toString cfg.prover.port}"; + KAIROS_SERVER_DB_ADDR = "postgresql://${cfg.database.userName}@localhost:${builtins.toString cfg.database.port}/${cfg.database.databaseName}?host=${cfg.database.host}"; + } // optionalAttrs (!builtins.isNull cfg.prover.maxBatchSize) { + KAIROS_SERVER_MAX_BATCH_SIZE = cfg.maxBatchSize; + } // optionalAttrs (!builtins.isNull cfg.prover.maxBatchDuration) { + KAIROS_SERVER_MAX_BATCH_SECONDS = cfg.prover.maxBatchDuration; }; - - services.kairos-prover = { - enable = true; - inherit (cfg.prover) bindAddress port; - }; - - services.postgresql = { - enable = true; - ensureDatabases = [ cfg.database.databaseName ]; - ensureUsers = [ + serviceConfig = mkMerge [ { - name = cfg.database.user; - ensureDBOwnership = true; + ExecStart = ''${lib.getExe cfg.package}''; + Restart = "always"; + DynamicUser = true; } ]; }; + + services.kairos-prover = { + enable = true; + inherit (cfg.prover) bindAddress port; + }; + + services.postgresql = { + enable = true; + ensureDatabases = [ cfg.database.databaseName ]; + ensureUsers = [ + { + name = cfg.database.userName; + ensureDBOwnership = true; + } + ]; }; }; } From 819e75794cedd39046fa5af0e259291f0c5d392f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marijan=20Petri=C4=8Devi=C4=87?= Date: Mon, 22 Jul 2024 15:49:44 +0200 Subject: [PATCH 8/9] tests/e2e: test DA --- nixos/tests/end-to-end.nix | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/nixos/tests/end-to-end.nix b/nixos/tests/end-to-end.nix index edaa8443..d506cc0f 100644 --- a/nixos/tests/end-to-end.nix +++ b/nixos/tests/end-to-end.nix @@ -83,7 +83,6 @@ nixosTest { testScript = '' import json import backoff - import time # Utils def verify_deploy_success(json_data): @@ -104,6 +103,14 @@ nixosTest { if not verify_deploy_success(get_deploy_result): raise Exception("Success key not found in JSON") + @backoff.on_exception(backoff.expo, Exception, max_tries=5, jitter=backoff.full_jitter) + def wait_for_deposit(depositor, amount): + transactions_query = { "sender": depositor } + transactions_result = client.succeed("curl --fail-with-body -X POST http://kairos/api/v1/transactions -H 'Content-Type: application/json' -d '{}'".format(json.dumps(transactions_query))) + transactions = json.loads(transactions_result) + if not any(transaction.get("public_key") == depositor and transaction.get("amount") == str(amount) for transaction in transactions): + raise Exception("Couldn't find deposit for depositor {} with amount {} in transactions\n:{}".format(depositor, amount, transactions)) + # Test start_all() @@ -132,14 +139,19 @@ nixosTest { wait_for_successful_deploy(deposit_deploy_hash) - # wait for l2 to sync with l1 every 5 seconds - time.sleep(${builtins.toString (casperSyncInterval * 2)}) + wait_for_deposit(depositor, 3000000000) # transfer beneficiary = client.succeed("cat ${clientUsersDirectory}/user-3/public_key_hex") transfer_output = client.succeed("kairos-cli --kairos-server-address http://kairos transfer --amount 1000 --recipient {} --private-key {}".format(beneficiary, depositor_private_key)) assert "Transfer successfully sent to L2\n" in transfer_output, "The transfer command was not successful: {}".format(transfer_output) + # data availability + transactions_query = { "recipient": beneficiary } + transactions_result = client.succeed("curl --fail-with-body -X POST http://kairos/api/v1/transactions -H 'Content-Type: application/json' -d '{}'".format(json.dumps(transactions_query))) + transactions = json.loads(transactions_result) + assert any(transaction.get("recipient") == beneficiary and transaction.get("amount") == str(1000) for transaction in transactions), "Couldn't find the transfer in the L2's DA: {}".format(transactions) + # TODO test withdraw # TODO cctl does not provide any secp256k1 keys From 8e2c03147a221714cb25576ea4e35fb2a896c33f Mon Sep 17 00:00:00 2001 From: koxu1996 Date: Tue, 23 Jul 2024 08:32:40 +0200 Subject: [PATCH 9/9] Fix warning about missing private key consequences. --- kairos-server/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kairos-server/src/config.rs b/kairos-server/src/config.rs index a62f7509..983e17d2 100644 --- a/kairos-server/src/config.rs +++ b/kairos-server/src/config.rs @@ -46,7 +46,7 @@ impl ServerConfig { } } None => { - tracing::warn!("No secret key file provided. This server will not be able to sign or send depolys."); + tracing::warn!("No secret key file provided. This server will not be able to sign batch deploys."); } } let kairos_demo_contract_hash = parse_env_as::("KAIROS_SERVER_DEMO_CONTRACT_HASH")