diff --git a/Cargo.lock b/Cargo.lock index 914a4dd1..94880644 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2733,6 +2733,7 @@ dependencies = [ "env_logger", "indexer_service_protocol", "indexer_service_rpc", + "itertools 0.14.0", "jsonrpsee", "leptos", "leptos_axum", diff --git a/artifacts/program_methods/amm.bin b/artifacts/program_methods/amm.bin index 45e28420..359d062a 100644 Binary files a/artifacts/program_methods/amm.bin and b/artifacts/program_methods/amm.bin differ diff --git a/explorer_service/Cargo.toml b/explorer_service/Cargo.toml index 219f2bc0..1dc989d0 100644 --- a/explorer_service/Cargo.toml +++ b/explorer_service/Cargo.toml @@ -50,6 +50,9 @@ clap = { workspace = true, features = ["derive"], optional = true } url = { workspace = true, optional = true } env_logger = { workspace = true, optional = true } +# Mandatory server side dependencies +itertools.workspace = true + [features] hydrate = ["leptos/hydrate"] ssr = [ diff --git a/explorer_service/src/api.rs b/explorer_service/src/api.rs index d0785949..4dfd75cd 100644 --- a/explorer_service/src/api.rs +++ b/explorer_service/src/api.rs @@ -83,6 +83,17 @@ pub async fn get_block_by_id(block_id: BlockId) -> Result .map_err(|e| ServerFnError::ServerError(format!("RPC error: {}", e))) } +/// Get latest block ID +#[server] +pub async fn get_latest_block_id() -> Result { + use indexer_service_rpc::RpcClient as _; + let client = expect_context::(); + client + .get_last_finalized_block_id() + .await + .map_err(|e| ServerFnError::ServerError(format!("RPC error: {}", e))) +} + /// Get block by hash #[server] pub async fn get_block_by_hash(block_hash: HashType) -> Result { diff --git a/explorer_service/src/lib.rs b/explorer_service/src/lib.rs index 489636fd..e2b2291e 100644 --- a/explorer_service/src/lib.rs +++ b/explorer_service/src/lib.rs @@ -28,7 +28,7 @@ pub fn App() -> impl IntoView { view! { - + <Title text="LEZ Block Explorer" /> <Meta name="description" content="Explore the blockchain - view blocks, transactions, and accounts" /> <Router> @@ -36,7 +36,7 @@ pub fn App() -> impl IntoView { <header class="app-header"> <nav class="app-nav"> <a href="/" class="nav-logo"> - "LEE Blockchain Explorer" + "LEZ Block Explorer" </a> </nav> </header> @@ -69,7 +69,7 @@ pub fn App() -> impl IntoView { </main> <footer class="app-footer"> - <p>"LEE Blockchain Explorer © 2026"</p> + <p>"LEZ Block Explorer © 2026"</p> </footer> </div> </Router> diff --git a/explorer_service/src/main.rs b/explorer_service/src/main.rs index 63d54d70..6cc4a9a4 100644 --- a/explorer_service/src/main.rs +++ b/explorer_service/src/main.rs @@ -10,7 +10,7 @@ async fn main() { env_logger::init(); - /// LEE Blockchain Explorer Server CLI arguments. + /// LEZ Block Explorer Server CLI arguments. #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct Args { diff --git a/explorer_service/src/pages/main_page.rs b/explorer_service/src/pages/main_page.rs index ffd625c8..3cfb832d 100644 --- a/explorer_service/src/pages/main_page.rs +++ b/explorer_service/src/pages/main_page.rs @@ -7,6 +7,8 @@ use crate::{ components::{AccountPreview, BlockPreview, TransactionPreview}, }; +const RECENT_BLOCKS_LIMIT: u64 = 10; + /// Main page component #[component] pub fn MainPage() -> impl IntoView { @@ -38,7 +40,21 @@ pub fn MainPage() -> impl IntoView { }); // Load recent blocks on mount - let recent_blocks_resource = Resource::new(|| (), |_| async { api::get_blocks(0, 10).await }); + let recent_blocks_resource = Resource::new( + || (), + |_| async { + match api::get_latest_block_id().await { + Ok(last_id) => { + api::get_blocks( + std::cmp::max(last_id.saturating_sub(RECENT_BLOCKS_LIMIT) as u32, 1), + (RECENT_BLOCKS_LIMIT + 1) as u32, + ) + .await + } + Err(err) => Err(err), + } + }, + ); // Handle search - update URL parameter let on_search = move |ev: SubmitEvent| { @@ -58,7 +74,7 @@ pub fn MainPage() -> impl IntoView { view! { <div class="main-page"> <div class="page-header"> - <h1>"LEE Blockchain Explorer"</h1> + <h1>"LEZ Block Explorer"</h1> </div> <div class="search-section"> diff --git a/explorer_service/src/pages/transaction_page.rs b/explorer_service/src/pages/transaction_page.rs index d0f1b4da..2859719f 100644 --- a/explorer_service/src/pages/transaction_page.rs +++ b/explorer_service/src/pages/transaction_page.rs @@ -4,6 +4,7 @@ use indexer_service_protocol::{ HashType, PrivacyPreservingMessage, PrivacyPreservingTransaction, ProgramDeploymentMessage, ProgramDeploymentTransaction, PublicMessage, PublicTransaction, Transaction, WitnessSet, }; +use itertools::{EitherOrBoth, Itertools}; use leptos::prelude::*; use leptos_router::{components::A, hooks::use_params_map}; @@ -65,7 +66,8 @@ pub fn TransactionPage() -> impl IntoView { </div> </div> - {match tx { + { + match tx { Transaction::Public(ptx) => { let PublicTransaction { hash: _, @@ -115,9 +117,11 @@ pub fn TransactionPage() -> impl IntoView { <div class="accounts-list"> {account_ids .into_iter() - .zip(nonces.into_iter()) - .map(|(account_id, nonce)| { - let account_id_str = account_id.to_string(); + .zip_longest(nonces.into_iter()) + .map(|maybe_pair| { + match maybe_pair { + EitherOrBoth::Both(account_id, nonce) => { + let account_id_str = account_id.to_string(); view! { <div class="account-item"> <A href=format!("/account/{}", account_id_str)> @@ -128,6 +132,33 @@ pub fn TransactionPage() -> impl IntoView { </span> </div> } + } + EitherOrBoth::Left(account_id) => { + let account_id_str = account_id.to_string(); + view! { + <div class="account-item"> + <A href=format!("/account/{}", account_id_str)> + <span class="hash">{account_id_str}</span> + </A> + <span class="nonce"> + " (nonce: "{"Not affected by this transaction".to_string()}" )" + </span> + </div> + } + } + EitherOrBoth::Right(_) => { + view! { + <div class="account-item"> + <A href=format!("/account/{}", "Account not found")> + <span class="hash">{"Account not found"}</span> + </A> + <span class="nonce"> + " (nonce: "{"Account not found".to_string()}" )" + </span> + </div> + } + } + } }) .collect::<Vec<_>>()} </div> @@ -189,9 +220,11 @@ pub fn TransactionPage() -> impl IntoView { <div class="accounts-list"> {public_account_ids .into_iter() - .zip(nonces.into_iter()) - .map(|(account_id, nonce)| { - let account_id_str = account_id.to_string(); + .zip_longest(nonces.into_iter()) + .map(|maybe_pair| { + match maybe_pair { + EitherOrBoth::Both(account_id, nonce) => { + let account_id_str = account_id.to_string(); view! { <div class="account-item"> <A href=format!("/account/{}", account_id_str)> @@ -202,6 +235,33 @@ pub fn TransactionPage() -> impl IntoView { </span> </div> } + } + EitherOrBoth::Left(account_id) => { + let account_id_str = account_id.to_string(); + view! { + <div class="account-item"> + <A href=format!("/account/{}", account_id_str)> + <span class="hash">{account_id_str}</span> + </A> + <span class="nonce"> + " (nonce: "{"Not affected by this transaction".to_string()}" )" + </span> + </div> + } + } + EitherOrBoth::Right(_) => { + view! { + <div class="account-item"> + <A href=format!("/account/{}", "Account not found")> + <span class="hash">{"Account not found"}</span> + </A> + <span class="nonce"> + " (nonce: "{"Account not found".to_string()}" )" + </span> + </div> + } + } + } }) .collect::<Vec<_>>()} </div> diff --git a/flake.lock b/flake.lock index a12fbc85..d0df80e3 100644 --- a/flake.lock +++ b/flake.lock @@ -15,7 +15,41 @@ "type": "github" } }, + "logos-blockchain-circuits": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1770979891, + "narHash": "sha256-cvkVnE7btuFLzv70ORAZve9K1Huiplq0iECgXSXb0ZY=", + "owner": "logos-blockchain", + "repo": "logos-blockchain-circuits", + "rev": "ec7d298e5a3a0507bb8570df86cdf78dc452d024", + "type": "github" + }, + "original": { + "owner": "logos-blockchain", + "repo": "logos-blockchain-circuits", + "type": "github" + } + }, "nixpkgs": { + "locked": { + "lastModified": 1769461804, + "narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { "locked": { "lastModified": 1770019141, "narHash": "sha256-VKS4ZLNx4PNrABoB0L8KUpc1fE7CLpQXQs985tGfaCU=", @@ -34,7 +68,8 @@ "root": { "inputs": { "crane": "crane", - "nixpkgs": "nixpkgs", + "logos-blockchain-circuits": "logos-blockchain-circuits", + "nixpkgs": "nixpkgs_2", "rust-overlay": "rust-overlay" } }, diff --git a/flake.nix b/flake.nix index a9751f5a..be20b56b 100644 --- a/flake.nix +++ b/flake.nix @@ -10,6 +10,10 @@ }; crane.url = "github:ipetkov/crane"; + + logos-blockchain-circuits = { + url = "github:logos-blockchain/logos-blockchain-circuits"; + }; }; outputs = @@ -18,6 +22,7 @@ nixpkgs, rust-overlay, crane, + logos-blockchain-circuits, ... }: let @@ -107,6 +112,7 @@ '' + pkgs.lib.optionalString pkgs.stdenv.isDarwin '' export PATH="$PATH:/usr/bin" ''; + LOGOS_BLOCKCHAIN_CIRCUITS = logos-blockchain-circuits.packages.${system}.default; }; walletFfiPackage = craneLib.buildPackage ( diff --git a/indexer/core/src/block_store.rs b/indexer/core/src/block_store.rs index fc7641a1..ce3881bd 100644 --- a/indexer/core/src/block_store.rs +++ b/indexer/core/src/block_store.rs @@ -2,7 +2,10 @@ use std::{path::Path, sync::Arc}; use anyhow::Result; use bedrock_client::HeaderId; -use common::{block::Block, transaction::NSSATransaction}; +use common::{ + block::{BedrockStatus, Block}, + transaction::NSSATransaction, +}; use nssa::{Account, AccountId, V02State}; use storage::indexer::RocksDBIO; @@ -100,7 +103,7 @@ impl IndexerStore { Ok(self.final_state()?.get_account_by_id(*account_id)) } - pub fn put_block(&self, block: Block, l1_header: HeaderId) -> Result<()> { + pub fn put_block(&self, mut block: Block, l1_header: HeaderId) -> Result<()> { let mut final_state = self.dbio.final_state()?; for transaction in &block.body.transactions { @@ -110,6 +113,11 @@ impl IndexerStore { .execute_check_on_state(&mut final_state)?; } + // ToDo: Currently we are fetching only finalized blocks + // if it changes, the following lines need to be updated + // to represent correct block finality + block.bedrock_status = BedrockStatus::Finalized; + Ok(self.dbio.put_block(block, l1_header.into())?) } } diff --git a/indexer/core/src/lib.rs b/indexer/core/src/lib.rs index b24cb1bd..6d56eb18 100644 --- a/indexer/core/src/lib.rs +++ b/indexer/core/src/lib.rs @@ -15,7 +15,6 @@ use crate::{block_store::IndexerStore, config::IndexerConfig}; pub mod block_store; pub mod config; -pub mod state; #[derive(Clone)] pub struct IndexerCore { @@ -123,6 +122,10 @@ impl IndexerCore { l2_blocks: l2_block_vec, l1_header, } in start_buff { + let mut l2_blocks_parsed_ids: Vec<_> = l2_block_vec.iter().map(|block| block.header.block_id).collect(); + l2_blocks_parsed_ids.sort(); + info!("Parsed {} L2 blocks with ids {:?}", l2_block_vec.len(), l2_blocks_parsed_ids); + for l2_block in l2_block_vec { self.store.put_block(l2_block.clone(), l1_header)?; @@ -153,6 +156,10 @@ impl IndexerCore { l2_blocks: l2_block_vec, l1_header: header, } in buff { + let mut l2_blocks_parsed_ids: Vec<_> = l2_block_vec.iter().map(|block| block.header.block_id).collect(); + l2_blocks_parsed_ids.sort(); + info!("Parsed {} L2 blocks with ids {:?}", l2_block_vec.len(), l2_blocks_parsed_ids); + for l2_block in l2_block_vec { self.store.put_block(l2_block.clone(), header)?; @@ -260,7 +267,7 @@ impl IndexerCore { Ok(BackfillData { block_data: block_buffer, - curr_fin_l1_lib_header: backfill_limit, + curr_fin_l1_lib_header: curr_last_l1_lib_header, }) } diff --git a/indexer/core/src/state.rs b/indexer/core/src/state.rs deleted file mode 100644 index bd05971f..00000000 --- a/indexer/core/src/state.rs +++ /dev/null @@ -1,9 +0,0 @@ -use std::sync::Arc; - -use tokio::sync::RwLock; - -#[derive(Debug, Clone)] -pub struct IndexerState { - // Only one field for now, for testing. - pub latest_seen_block: Arc<RwLock<u64>>, -} diff --git a/indexer/service/Dockerfile b/indexer/service/Dockerfile index 081e8b06..bf77ffd2 100644 --- a/indexer/service/Dockerfile +++ b/indexer/service/Dockerfile @@ -3,13 +3,43 @@ FROM lukemathwalker/cargo-chef:latest-rust-1.91.1-slim-trixie AS chef # Install build dependencies RUN apt-get update && apt-get install -y \ + build-essential \ pkg-config \ libssl-dev \ libclang-dev \ clang \ + cmake \ + ninja-build \ curl \ + git \ && rm -rf /var/lib/apt/lists/* +# Install r0vm +# Use quick install for x86-64 (risczero provides binaries only for this linux platform) +# Manual build for other platforms (including arm64 Linux) +RUN ARCH=$(uname -m); \ + if [ "$ARCH" = "x86_64" ]; then \ + echo "Using quick install for $ARCH"; \ + curl -L https://risczero.com/install | bash; \ + export PATH="/root/.cargo/bin:/root/.risc0/bin:${PATH}"; \ + rzup install; \ + else \ + echo "Using manual build for $ARCH"; \ + git clone --depth 1 --branch release-3.0 https://github.com/risc0/risc0.git; \ + git clone --depth 1 --branch r0.1.91.1 https://github.com/risc0/rust.git; \ + cd /risc0; \ + cargo install --path rzup; \ + rzup build --path /rust rust --verbose; \ + cargo install --path risc0/cargo-risczero; \ + fi +ENV PATH="/root/.cargo/bin:/root/.risc0/bin:${PATH}" +RUN cp "$(which r0vm)" /usr/local/bin/r0vm +RUN test -x /usr/local/bin/r0vm +RUN r0vm --version + +# Install logos blockchain circuits +RUN curl -sSL https://raw.githubusercontent.com/logos-blockchain/logos-blockchain/main/scripts/setup-logos-blockchain-circuits.sh | bash + WORKDIR /indexer_service # Planner stage - generates dependency recipe @@ -48,6 +78,12 @@ RUN useradd -m -u 1000 -s /bin/bash indexer_service_user && \ # Copy binary from builder COPY --from=builder --chown=indexer_service_user:indexer_service_user /indexer_service/target/release/indexer_service /usr/local/bin/indexer_service +# Copy r0vm binary from builder +COPY --from=builder --chown=indexer_service_user:indexer_service_user /usr/local/bin/r0vm /usr/local/bin/r0vm + +# Copy logos blockchain circuits from builder +COPY --from=builder --chown=indexer_service_user:indexer_service_user /root/.logos-blockchain-circuits /home/indexer_service_user/.logos-blockchain-circuits + # Copy entrypoint script COPY indexer/service/docker-entrypoint.sh /docker-entrypoint.sh RUN chmod +x /docker-entrypoint.sh diff --git a/indexer/service/configs/indexer_config.json b/indexer/service/configs/indexer_config.json index 7d7a317c..247caa8e 100644 --- a/indexer/service/configs/indexer_config.json +++ b/indexer/service/configs/indexer_config.json @@ -1,6 +1,6 @@ { "home": "./indexer/service", - "consensus_info_polling_interval": "1s", + "consensus_info_polling_interval": "60s", "bedrock_client_config": { "addr": "http://localhost:8080", "backoff": { diff --git a/indexer/service/rpc/Cargo.toml b/indexer/service/rpc/Cargo.toml index 2bed63ae..b2194882 100644 --- a/indexer/service/rpc/Cargo.toml +++ b/indexer/service/rpc/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" license = { workspace = true } [dependencies] -indexer_service_protocol = { workspace = true } +indexer_service_protocol = { workspace = true, features = ["convert"] } jsonrpsee = { workspace = true, features = ["macros"] } serde_json.workspace = true diff --git a/nssa/src/state.rs b/nssa/src/state.rs index 1e347552..4c9a79b8 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -2504,6 +2504,12 @@ pub mod tests { fn user_token_b_holding_new_definition() -> u128 { 7_500 } + + fn lp_supply_init() -> u128 { + // isqrt(vault_a_balance_init * vault_b_balance_init) = isqrt(5_000 * 2_500) = 3535 + (BalanceForTests::vault_a_balance_init() * BalanceForTests::vault_b_balance_init()) + .isqrt() + } } struct IdForTests; @@ -3098,7 +3104,7 @@ pub mod tests { balance: 0u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForTests::token_lp_definition_id(), - balance: BalanceForTests::user_token_a_holding_new_definition(), + balance: BalanceForTests::lp_supply_init(), }), nonce: 0, } @@ -3110,7 +3116,7 @@ pub mod tests { balance: 0u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("LP Token"), - total_supply: BalanceForTests::vault_a_balance_init(), + total_supply: BalanceForTests::lp_supply_init(), metadata_id: None, }), nonce: 0, @@ -3127,7 +3133,7 @@ pub mod tests { vault_a_id: IdForTests::vault_a_id(), vault_b_id: IdForTests::vault_b_id(), liquidity_pool_id: IdForTests::token_lp_definition_id(), - liquidity_pool_supply: BalanceForTests::user_token_a_holding_new_definition(), + liquidity_pool_supply: BalanceForTests::lp_supply_init(), reserve_a: BalanceForTests::vault_a_balance_init(), reserve_b: BalanceForTests::vault_b_balance_init(), fees: 0u128, @@ -3417,7 +3423,7 @@ pub mod tests { let user_token_b_post = state.get_account_by_id(IdForTests::user_token_b_id()); let user_token_lp_post = state.get_account_by_id(IdForTests::user_token_lp_id()); - let expected_pool = AccountForTests::pool_definition_init(); + let expected_pool = AccountForTests::pool_definition_new_init(); let expected_vault_a = AccountForTests::vault_a_init(); let expected_vault_b = AccountForTests::vault_b_init(); let expected_token_lp = AccountForTests::token_lp_definition_new_init(); diff --git a/programs/amm/src/new_definition.rs b/programs/amm/src/new_definition.rs index ab0b241a..af54adce 100644 --- a/programs/amm/src/new_definition.rs +++ b/programs/amm/src/new_definition.rs @@ -77,7 +77,7 @@ pub fn new_definition( ); // LP Token minting calculation - // We assume LP is based on the initial deposit amount for Token_A. + let initial_lp = (token_a_amount.get() * token_b_amount.get()).isqrt(); // Update pool account let mut pool_post = pool.account.clone(); @@ -87,7 +87,7 @@ pub fn new_definition( vault_a_id: vault_a.account_id, vault_b_id: vault_b.account_id, liquidity_pool_id: pool_definition_lp.account_id, - liquidity_pool_supply: token_a_amount.into(), + liquidity_pool_supply: initial_lp, reserve_a: token_a_amount.into(), reserve_b: token_b_amount.into(), fees: 0u128, // TODO: we assume all fees are 0 for now. @@ -124,11 +124,11 @@ pub fn new_definition( let instruction = if pool.account == Account::default() { token_core::Instruction::NewFungibleDefinition { name: String::from("LP Token"), - total_supply: token_a_amount.into(), + total_supply: initial_lp, } } else { token_core::Instruction::Mint { - amount_to_mint: token_a_amount.into(), + amount_to_mint: initial_lp, } }; diff --git a/programs/amm/src/tests.rs b/programs/amm/src/tests.rs index 021e32b2..203e3284 100644 --- a/programs/amm/src/tests.rs +++ b/programs/amm/src/tests.rs @@ -70,7 +70,7 @@ impl BalanceForTests { } fn remove_actual_a_successful() -> u128 { - 100 + 141 } fn remove_min_amount_b_low() -> u128 { @@ -105,6 +105,11 @@ impl BalanceForTests { 20 } + fn lp_supply_init() -> u128 { + // sqrt(vault_a_reserve_init * vault_b_reserve_init) = sqrt(1000 * 500) = 707 + (BalanceForTests::vault_a_reserve_init() * BalanceForTests::vault_b_reserve_init()).isqrt() + } + fn vault_a_swap_test_1() -> u128 { 1_500 } @@ -142,11 +147,11 @@ impl BalanceForTests { } fn vault_a_remove_successful() -> u128 { - 900 + 859 } fn vault_b_remove_successful() -> u128 { - 450 + 430 } } @@ -249,7 +254,7 @@ impl ChainedCallForTests { TOKEN_PROGRAM_ID, vec![pool_lp_auth, AccountForTests::user_holding_lp_init()], &token_core::Instruction::Mint { - amount_to_mint: BalanceForTests::add_successful_amount_a(), + amount_to_mint: 282, }, ) .with_pda_seeds(vec![compute_liquidity_token_pda_seed( @@ -282,7 +287,7 @@ impl ChainedCallForTests { TOKEN_PROGRAM_ID, vec![vault_b_auth, AccountForTests::user_holding_b()], &token_core::Instruction::Transfer { - amount_to_transfer: BalanceForTests::remove_min_amount_b_low(), + amount_to_transfer: 70, }, ) .with_pda_seeds(vec![compute_vault_pda_seed( @@ -341,7 +346,7 @@ impl ChainedCallForTests { AccountForTests::user_holding_lp_uninit(), ], &token_core::Instruction::Mint { - amount_to_mint: BalanceForTests::add_successful_amount_a(), + amount_to_mint: BalanceForTests::lp_supply_init(), }, ) .with_pda_seeds(vec![compute_liquidity_token_pda_seed( @@ -568,7 +573,7 @@ impl AccountForTests { balance: 0u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("test"), - total_supply: BalanceForTests::vault_a_reserve_init(), + total_supply: BalanceForTests::lp_supply_init(), metadata_id: None, }), nonce: 0, @@ -585,7 +590,7 @@ impl AccountForTests { balance: 0u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("test"), - total_supply: BalanceForTests::vault_a_reserve_init(), + total_supply: BalanceForTests::lp_supply_init(), metadata_id: None, }), nonce: 0, @@ -638,7 +643,7 @@ impl AccountForTests { vault_a_id: IdForTests::vault_a_id(), vault_b_id: IdForTests::vault_b_id(), liquidity_pool_id: IdForTests::token_lp_definition_id(), - liquidity_pool_supply: BalanceForTests::vault_a_reserve_init(), + liquidity_pool_supply: BalanceForTests::lp_supply_init(), reserve_a: BalanceForTests::vault_a_reserve_init(), reserve_b: BalanceForTests::vault_b_reserve_init(), fees: 0u128, @@ -662,7 +667,7 @@ impl AccountForTests { vault_a_id: IdForTests::vault_a_id(), vault_b_id: IdForTests::vault_b_id(), liquidity_pool_id: IdForTests::token_lp_definition_id(), - liquidity_pool_supply: BalanceForTests::vault_a_reserve_init(), + liquidity_pool_supply: BalanceForTests::lp_supply_init(), reserve_a: 0, reserve_b: BalanceForTests::vault_b_reserve_init(), fees: 0u128, @@ -686,7 +691,7 @@ impl AccountForTests { vault_a_id: IdForTests::vault_a_id(), vault_b_id: IdForTests::vault_b_id(), liquidity_pool_id: IdForTests::token_lp_definition_id(), - liquidity_pool_supply: BalanceForTests::vault_a_reserve_init(), + liquidity_pool_supply: BalanceForTests::lp_supply_init(), reserve_a: BalanceForTests::vault_a_reserve_init(), reserve_b: 0, fees: 0u128, @@ -758,7 +763,7 @@ impl AccountForTests { vault_a_id: IdForTests::vault_a_id(), vault_b_id: IdForTests::vault_b_id(), liquidity_pool_id: IdForTests::token_lp_definition_id(), - liquidity_pool_supply: BalanceForTests::vault_a_reserve_init(), + liquidity_pool_supply: BalanceForTests::lp_supply_init(), reserve_a: BalanceForTests::vault_a_swap_test_1(), reserve_b: BalanceForTests::vault_b_swap_test_1(), fees: 0u128, @@ -782,7 +787,7 @@ impl AccountForTests { vault_a_id: IdForTests::vault_a_id(), vault_b_id: IdForTests::vault_b_id(), liquidity_pool_id: IdForTests::token_lp_definition_id(), - liquidity_pool_supply: BalanceForTests::vault_a_reserve_init(), + liquidity_pool_supply: BalanceForTests::lp_supply_init(), reserve_a: BalanceForTests::vault_a_swap_test_2(), reserve_b: BalanceForTests::vault_b_swap_test_2(), fees: 0u128, @@ -830,7 +835,7 @@ impl AccountForTests { vault_a_id: IdForTests::vault_a_id(), vault_b_id: IdForTests::vault_b_id(), liquidity_pool_id: IdForTests::token_lp_definition_id(), - liquidity_pool_supply: BalanceForTests::vault_a_add_successful(), + liquidity_pool_supply: 989, reserve_a: BalanceForTests::vault_a_add_successful(), reserve_b: BalanceForTests::vault_b_add_successful(), fees: 0u128, @@ -854,7 +859,7 @@ impl AccountForTests { vault_a_id: IdForTests::vault_a_id(), vault_b_id: IdForTests::vault_b_id(), liquidity_pool_id: IdForTests::token_lp_definition_id(), - liquidity_pool_supply: BalanceForTests::vault_a_remove_successful(), + liquidity_pool_supply: 607, reserve_a: BalanceForTests::vault_a_remove_successful(), reserve_b: BalanceForTests::vault_b_remove_successful(), fees: 0u128, @@ -878,7 +883,7 @@ impl AccountForTests { vault_a_id: IdForTests::vault_a_id(), vault_b_id: IdForTests::vault_b_id(), liquidity_pool_id: IdForTests::token_lp_definition_id(), - liquidity_pool_supply: BalanceForTests::vault_a_reserve_init(), + liquidity_pool_supply: BalanceForTests::lp_supply_init(), reserve_a: BalanceForTests::vault_a_reserve_init(), reserve_b: BalanceForTests::vault_b_reserve_init(), fees: 0u128, @@ -902,7 +907,7 @@ impl AccountForTests { vault_a_id: IdForTests::vault_a_id(), vault_b_id: IdForTests::vault_b_id(), liquidity_pool_id: IdForTests::token_lp_definition_id(), - liquidity_pool_supply: BalanceForTests::vault_a_reserve_init(), + liquidity_pool_supply: BalanceForTests::lp_supply_init(), reserve_a: BalanceForTests::vault_a_reserve_init(), reserve_b: BalanceForTests::vault_b_reserve_init(), fees: 0u128, @@ -958,7 +963,7 @@ impl AccountForTests { vault_a_id: IdForTests::vault_a_id(), vault_b_id: IdForTests::vault_b_id(), liquidity_pool_id: IdForTests::token_lp_definition_id(), - liquidity_pool_supply: BalanceForTests::vault_a_reserve_init(), + liquidity_pool_supply: BalanceForTests::lp_supply_init(), reserve_a: BalanceForTests::vault_a_reserve_init(), reserve_b: BalanceForTests::vault_b_reserve_init(), fees: 0u128, @@ -1717,3 +1722,73 @@ fn test_call_swap_chained_call_successful_2() { ChainedCallForTests::cc_swap_token_b_test_2() ); } + +#[test] +fn test_new_definition_lp_asymmetric_amounts() { + let (post_states, chained_calls) = new_definition( + AccountForTests::pool_definition_inactive(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_uninit(), + NonZero::new(BalanceForTests::vault_a_reserve_init()).unwrap(), + NonZero::new(BalanceForTests::vault_b_reserve_init()).unwrap(), + AMM_PROGRAM_ID, + ); + + // check the minted LP amount + let pool_post = post_states[0].clone(); + let pool_def = PoolDefinition::try_from(&pool_post.account().data).unwrap(); + assert_eq!( + pool_def.liquidity_pool_supply, + BalanceForTests::lp_supply_init() + ); + + let chained_call_lp = chained_calls[0].clone(); + assert!(chained_call_lp == ChainedCallForTests::cc_new_definition_token_lp()); +} + +#[test] +fn test_new_definition_lp_symmetric_amounts() { + // token_a=100, token_b=100 → LP=sqrt(10_000)=100 + let token_a_amount = 100u128; + let token_b_amount = 100u128; + let expected_lp = (token_a_amount * token_b_amount).isqrt(); + assert_eq!(expected_lp, 100); + + let (post_states, chained_calls) = new_definition( + AccountForTests::pool_definition_inactive(), + AccountForTests::vault_a_init(), + AccountForTests::vault_b_init(), + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_a(), + AccountForTests::user_holding_b(), + AccountForTests::user_holding_lp_uninit(), + NonZero::new(token_a_amount).unwrap(), + NonZero::new(token_b_amount).unwrap(), + AMM_PROGRAM_ID, + ); + + let pool_post = post_states[0].clone(); + let pool_def = PoolDefinition::try_from(&pool_post.account().data).unwrap(); + assert_eq!(pool_def.liquidity_pool_supply, expected_lp); + + let chained_call_lp = chained_calls[0].clone(); + let expected_lp_call = ChainedCall::new( + TOKEN_PROGRAM_ID, + vec![ + AccountForTests::pool_lp_init(), + AccountForTests::user_holding_lp_uninit(), + ], + &token_core::Instruction::Mint { + amount_to_mint: expected_lp, + }, + ) + .with_pda_seeds(vec![compute_liquidity_token_pda_seed( + IdForTests::pool_definition_id(), + )]); + + assert_eq!(chained_call_lp, expected_lp_call); +} diff --git a/sequencer_core/src/block_settlement_client.rs b/sequencer_core/src/block_settlement_client.rs index 075ebd11..15612835 100644 --- a/sequencer_core/src/block_settlement_client.rs +++ b/sequencer_core/src/block_settlement_client.rs @@ -28,7 +28,7 @@ pub trait BlockSettlementClientTrait: Clone { /// Create and sign a transaction for inscribing data. fn create_inscribe_tx(&self, block: &Block) -> Result<(SignedMantleTx, MsgId)> { let inscription_data = borsh::to_vec(block)?; - log::info!( + log::debug!( "The size of the block {} is {} bytes", block.header.block_id, inscription_data.len() @@ -104,7 +104,7 @@ impl BlockSettlementClientTrait for BlockSettlementClient { .await .context("Failed to post transaction to Bedrock")?; - log::info!("Posted block to Bedrock with parent id {parent_id:?} and msg id: {msg_id:?}"); + log::debug!("Posted block to Bedrock with parent id {parent_id:?} and msg id: {msg_id:?}"); Ok(()) } diff --git a/sequencer_runner/configs/debug/sequencer_config.json b/sequencer_runner/configs/debug/sequencer_config.json index 002228f4..b53124c2 100644 --- a/sequencer_runner/configs/debug/sequencer_config.json +++ b/sequencer_runner/configs/debug/sequencer_config.json @@ -20,50 +20,50 @@ "indexer_rpc_url": "ws://localhost:8779", "initial_accounts": [ { - "account_id": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", + "account_id": "6iArKUXxhUJqS7kCaPNhwMWt3ro71PDyBj7jwAyE2VQV", "balance": 10000 }, { - "account_id": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", + "account_id": "7wHg9sbJwc6h3NP1S9bekfAzB8CHifEcxKswCKUt3YQo", "balance": 20000 } ], "initial_commitments": [ { - "npk": [ - 63, - 202, - 178, - 231, - 183, - 82, - 237, - 212, - 216, - 221, - 215, - 255, - 153, - 101, + "npk":[ 177, - 161, - 254, - 210, - 128, - 122, - 54, - 190, - 230, - 151, - 183, 64, - 225, - 229, - 113, 1, - 228, - 97 - ], + 11, + 87, + 38, + 254, + 159, + 231, + 165, + 1, + 94, + 64, + 137, + 243, + 76, + 249, + 101, + 251, + 129, + 33, + 101, + 189, + 30, + 42, + 11, + 191, + 34, + 103, + 186, + 227, + 230 + ] , "account": { "program_owner": [ 0, @@ -82,38 +82,38 @@ }, { "npk": [ - 192, - 251, - 166, - 243, - 167, - 236, - 84, - 249, - 35, + 32, + 67, + 72, + 164, + 106, + 53, + 66, + 239, + 141, + 15, + 52, + 230, 136, - 130, - 172, - 219, - 225, - 161, - 139, - 229, - 89, + 177, + 2, + 236, + 207, 243, - 125, + 134, + 135, + 210, + 143, + 87, + 232, + 215, + 128, 194, - 213, - 209, - 30, - 23, - 174, - 100, - 244, - 124, - 74, - 140, - 47 + 120, + 113, + 224, + 4, + 165 ], "account": { "program_owner": [ diff --git a/sequencer_runner/src/lib.rs b/sequencer_runner/src/lib.rs index 7a02bfc3..d74792c8 100644 --- a/sequencer_runner/src/lib.rs +++ b/sequencer_runner/src/lib.rs @@ -182,8 +182,16 @@ async fn retry_pending_blocks(seq_core: &Arc<Mutex<SequencerCore>>) -> Result<() (pending_blocks, client) }; - for block in pending_blocks.iter() { + if !pending_blocks.is_empty() { info!( + "Resubmitting blocks from {} to {}", + pending_blocks.first().unwrap().header.block_id, + pending_blocks.last().unwrap().header.block_id + ); + } + + for block in pending_blocks.iter() { + debug!( "Resubmitting pending block with id {}", block.header.block_id );