From 324eec24dfb307908ce68d3bd145a85b0aa0e126 Mon Sep 17 00:00:00 2001 From: Pravdyvy Date: Fri, 9 Jan 2026 15:10:38 +0200 Subject: [PATCH 01/18] fix: indexer crate --- Cargo.lock | 31 +++++++++++++++++++++++++++++++ Cargo.toml | 5 ++++- indexer/Cargo.toml | 32 ++++++++++++++++++++++++++++++++ indexer/src/lib.rs | 14 ++++++++++++++ 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 indexer/Cargo.toml create mode 100644 indexer/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index df1c9ca6..ce029fb0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2864,6 +2864,37 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee796ad498c8d9a1d68e477df8f754ed784ef875de1414ebdaf169f70a6a784" +[[package]] +name = "indexer" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-stream", + "base58", + "base64", + "bedrock_client", + "borsh", + "bytemuck", + "clap", + "common", + "env_logger", + "futures", + "hex", + "indicatif", + "itertools 0.14.0", + "key_protocol", + "log", + "nssa", + "nssa_core", + "rand 0.8.5", + "risc0-zkvm", + "serde", + "serde_json", + "sha2", + "tokio", + "url", +] + [[package]] name = "indexmap" version = "1.9.3" diff --git a/Cargo.toml b/Cargo.toml index 35d0a408..83fdb493 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,8 @@ members = [ "examples/program_deployment", "examples/program_deployment/methods", "examples/program_deployment/methods/guest", - "bedrock_client", + "bedrock_client", + "indexer", ] [workspace.dependencies] @@ -35,6 +36,8 @@ sequencer_rpc = { path = "sequencer_rpc" } sequencer_runner = { path = "sequencer_runner" } wallet = { path = "wallet" } test_program_methods = { path = "test_program_methods" } +bedrock_client = { path = "bedrock_client" } +indexer = { path = "indexer" } tokio = { version = "1.28.2", features = [ "net", diff --git a/indexer/Cargo.toml b/indexer/Cargo.toml new file mode 100644 index 00000000..7984c944 --- /dev/null +++ b/indexer/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "indexer" +version = "0.1.0" +edition = "2024" + +[dependencies] +nssa_core.workspace = true +nssa.workspace = true +common.workspace = true +bedrock_client.workspace = true +key_protocol.workspace = true + +anyhow.workspace = true +serde_json.workspace = true +env_logger.workspace = true +log.workspace = true +serde.workspace = true +tokio.workspace = true +clap.workspace = true +base64.workspace = true +bytemuck.workspace = true +borsh.workspace = true +base58.workspace = true +hex.workspace = true +rand.workspace = true +itertools.workspace = true +sha2.workspace = true +futures.workspace = true +async-stream = "0.3.6" +indicatif = { version = "0.18.3", features = ["improved_unicode"] } +risc0-zkvm.workspace = true +url.workspace = true \ No newline at end of file diff --git a/indexer/src/lib.rs b/indexer/src/lib.rs new file mode 100644 index 00000000..904ab816 --- /dev/null +++ b/indexer/src/lib.rs @@ -0,0 +1,14 @@ +use bedrock_client::BedrockClient; +use futures::Stream; +use url::Url; + +pub struct IndexerCore { + pub bedrock_client: BedrockClient, + pub bedrock_url: Url, +} + +impl IndexerCore { + pub async fn subscribe_block_stream(&self) -> Result, bedrock_client::Error> { + self.bedrock_client.0.get_lib_stream(self.bedrock_url).await + } +} \ No newline at end of file From aa6da018ebfe86c120ee3058a91d362c863dc8ae Mon Sep 17 00:00:00 2001 From: Pravdyvy Date: Mon, 12 Jan 2026 15:51:24 +0200 Subject: [PATCH 02/18] feat: indexer crate reding and parsing --- Cargo.lock | 1 + Cargo.toml | 1 + indexer/Cargo.toml | 3 +- indexer/src/config.rs | 7 ++++ indexer/src/lib.rs | 91 ++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 indexer/src/config.rs diff --git a/Cargo.lock b/Cargo.lock index ce029fb0..326cc356 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2884,6 +2884,7 @@ dependencies = [ "itertools 0.14.0", "key_protocol", "log", + "nomos-core", "nssa", "nssa_core", "rand 0.8.5", diff --git a/Cargo.toml b/Cargo.toml index 83fdb493..35727ff5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,6 +83,7 @@ itertools = "0.14.0" url = "2.5.4" common-http-client = { git = "https://github.com/logos-blockchain/logos-blockchain.git", branch = "marbella-offsite-2025-12" } +nomos-core = { git = "https://github.com/logos-blockchain/logos-blockchain.git", branch = "marbella-offsite-2025-12" } rocksdb = { version = "0.24.0", default-features = false, features = [ "snappy", diff --git a/indexer/Cargo.toml b/indexer/Cargo.toml index 7984c944..2025a3b1 100644 --- a/indexer/Cargo.toml +++ b/indexer/Cargo.toml @@ -29,4 +29,5 @@ futures.workspace = true async-stream = "0.3.6" indicatif = { version = "0.18.3", features = ["improved_unicode"] } risc0-zkvm.workspace = true -url.workspace = true \ No newline at end of file +url.workspace = true +nomos-core.workspace = true \ No newline at end of file diff --git a/indexer/src/config.rs b/indexer/src/config.rs new file mode 100644 index 00000000..8818d15e --- /dev/null +++ b/indexer/src/config.rs @@ -0,0 +1,7 @@ +use nomos_core::mantle::ops::channel::ChannelId; + +#[derive(Debug)] +pub struct IndexerConfig { + pub resubscribe_interval: u64, + pub channel_id: ChannelId, +} diff --git a/indexer/src/lib.rs b/indexer/src/lib.rs index 904ab816..1474f85c 100644 --- a/indexer/src/lib.rs +++ b/indexer/src/lib.rs @@ -1,14 +1,93 @@ -use bedrock_client::BedrockClient; -use futures::Stream; +use anyhow::Result; +use bedrock_client::{BasicAuthCredentials, BedrockClient}; +use common::block::HashableBlockData; +use futures::StreamExt; +use nomos_core::mantle::{ + Op, SignedMantleTx, + ops::channel::{ChannelId, inscribe::InscriptionOp}, +}; +use tokio::sync::mpsc::Sender; use url::Url; +use crate::config::IndexerConfig; + +pub mod config; + pub struct IndexerCore { - pub bedrock_client: BedrockClient, + pub bedrock_client: BedrockClient, pub bedrock_url: Url, + pub channel_sender: Sender, + pub config: IndexerConfig, } impl IndexerCore { - pub async fn subscribe_block_stream(&self) -> Result, bedrock_client::Error> { - self.bedrock_client.0.get_lib_stream(self.bedrock_url).await + pub fn new( + addr: &str, + auth: Option, + sender: Sender, + config: IndexerConfig, + ) -> Result { + Ok(Self { + bedrock_client: BedrockClient::new(auth)?, + bedrock_url: Url::parse(addr)?, + channel_sender: sender, + config, + }) } -} \ No newline at end of file + + pub async fn subscribe_parse_block_stream(&self) -> Result<()> { + let mut stream_pinned = Box::pin( + self.bedrock_client + .0 + .get_lib_stream(self.bedrock_url.clone()) + .await?, + ); + + while let Some(block_info) = stream_pinned.next().await { + let header_id = block_info.header_id; + + if let Some(l1_block) = self + .bedrock_client + .0 + .get_block_by_id(self.bedrock_url.clone(), header_id) + .await? + { + let l2_blocks_parsed = parse_blocks( + l1_block.into_transactions().into_iter(), + &self.config.channel_id, + ); + + for l2_block in l2_blocks_parsed { + self.channel_sender.send(l2_block).await?; + } + } + } + + Ok(()) + } +} + +pub fn parse_blocks( + block_txs: impl Iterator, + decoded_channel_id: &ChannelId, +) -> Vec { + block_txs + .flat_map(|tx| { + tx.mantle_tx + .ops + .iter() + .filter_map(|op| match op { + Op::ChannelInscribe(InscriptionOp { + channel_id, + inscription, + .. + }) if channel_id == decoded_channel_id => { + // Assuming, that it is how block will be inscribed on l1 + borsh::from_slice::(inscription).ok() + } + _ => None, + }) + .collect::>() + }) + .collect() +} From 1fd6651121343be16288de03d725aab96b02cca6 Mon Sep 17 00:00:00 2001 From: Pravdyvy Date: Tue, 13 Jan 2026 11:20:44 +0200 Subject: [PATCH 03/18] fix: lock update --- Cargo.lock | 299 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 278 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0fe97b7b..199461bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -367,6 +367,15 @@ version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +[[package]] +name = "archery" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e0a5f99dfebb87bb342d0f53bb92c81842e100bbb915223e38349580e5441d" +dependencies = [ + "triomphe", +] + [[package]] name = "ark-bls12-381" version = "0.4.0" @@ -1098,7 +1107,7 @@ dependencies = [ [[package]] name = "broadcast-service" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "async-trait", "derivative", @@ -1267,6 +1276,35 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "chain-service" +version = "0.1.0" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" +dependencies = [ + "async-trait", + "broadcast-service", + "bytes", + "cryptarchia-engine", + "cryptarchia-sync", + "futures", + "groth16", + "nomos-core", + "nomos-ledger", + "nomos-network", + "nomos-storage", + "nomos-utils", + "num-bigint", + "overwatch", + "serde", + "serde_with", + "services-utils", + "strum", + "thiserror 1.0.69", + "tokio", + "tracing", + "tracing-futures", +] + [[package]] name = "chrono" version = "0.4.42" @@ -1294,7 +1332,7 @@ dependencies = [ [[package]] name = "circuits-prover" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "circuits-utils", "tempfile", @@ -1303,7 +1341,7 @@ dependencies = [ [[package]] name = "circuits-utils" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "dirs", ] @@ -1395,9 +1433,10 @@ dependencies = [ [[package]] name = "common-http-client" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "broadcast-service", + "chain-service", "futures", "nomos-core", "nomos-da-messages", @@ -1452,6 +1491,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "convert_case" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "convert_case" version = "0.10.0" @@ -1530,7 +1578,7 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "cryptarchia-engine" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "cfg_eval", "nomos-utils", @@ -1541,6 +1589,23 @@ dependencies = [ "tracing", ] +[[package]] +name = "cryptarchia-sync" +version = "0.1.0" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" +dependencies = [ + "bytes", + "cryptarchia-engine", + "futures", + "nomos-core", + "rand 0.8.5", + "serde", + "serde_with", + "thiserror 1.0.69", + "tokio", + "tracing", +] + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -2344,7 +2409,7 @@ dependencies = [ [[package]] name = "groth16" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "ark-bn254 0.4.0", "ark-ec 0.4.2", @@ -3047,7 +3112,7 @@ dependencies = [ [[package]] name = "key-management-system-keys" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "async-trait", "bytes", @@ -3072,7 +3137,7 @@ dependencies = [ [[package]] name = "key-management-system-macros" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "proc-macro2", "quote", @@ -3103,7 +3168,7 @@ dependencies = [ [[package]] name = "kzgrs" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "ark-bls12-381", "ark-ec 0.4.2", @@ -3122,7 +3187,7 @@ dependencies = [ [[package]] name = "kzgrs-backend" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "ark-ff 0.4.2", "ark-poly 0.4.2", @@ -3204,6 +3269,7 @@ dependencies = [ "bs58", "hkdf", "multihash", + "serde", "sha2", "thiserror 2.0.17", "tracing", @@ -3406,6 +3472,18 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "mmr" +version = "0.1.0" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" +dependencies = [ + "ark-ff 0.4.2", + "groth16", + "poseidon2", + "rpds", + "serde", +] + [[package]] name = "multiaddr" version = "0.18.2" @@ -3515,7 +3593,7 @@ dependencies = [ [[package]] name = "nomos-blend-crypto" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "blake2", "groth16", @@ -3530,10 +3608,32 @@ dependencies = [ "zeroize", ] +[[package]] +name = "nomos-blend-message" +version = "0.1.0" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" +dependencies = [ + "blake2", + "derivative", + "groth16", + "itertools 0.14.0", + "key-management-system-keys", + "nomos-blend-crypto", + "nomos-blend-proofs", + "nomos-core", + "nomos-utils", + "serde", + "serde-big-array", + "serde_with", + "thiserror 1.0.69", + "tracing", + "zeroize", +] + [[package]] name = "nomos-blend-proofs" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "ed25519-dalek", "generic-array 1.3.5", @@ -3548,7 +3648,7 @@ dependencies = [ [[package]] name = "nomos-core" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "ark-ff 0.4.2", "async-trait", @@ -3578,7 +3678,7 @@ dependencies = [ [[package]] name = "nomos-da-messages" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "blake2", "futures", @@ -3591,7 +3691,7 @@ dependencies = [ [[package]] name = "nomos-http-api-common" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "axum", "governor", @@ -3603,10 +3703,68 @@ dependencies = [ "tower_governor", ] +[[package]] +name = "nomos-ledger" +version = "0.1.0" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" +dependencies = [ + "cryptarchia-engine", + "groth16", + "key-management-system-keys", + "mmr", + "nomos-blend-crypto", + "nomos-blend-message", + "nomos-blend-proofs", + "nomos-core", + "nomos-utils", + "num-bigint", + "rand 0.8.5", + "rpds", + "serde", + "thiserror 1.0.69", + "tracing", + "utxotree", +] + +[[package]] +name = "nomos-network" +version = "0.1.0" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" +dependencies = [ + "async-trait", + "cryptarchia-sync", + "futures", + "nomos-core", + "overwatch", + "serde", + "tokio", + "tokio-stream", + "tracing", +] + +[[package]] +name = "nomos-storage" +version = "0.1.0" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" +dependencies = [ + "async-trait", + "bytes", + "cryptarchia-engine", + "futures", + "libp2p-identity", + "multiaddr", + "nomos-core", + "overwatch", + "serde", + "thiserror 1.0.69", + "tokio", + "tracing", +] + [[package]] name = "nomos-utils" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "async-trait", "blake2", @@ -3858,6 +4016,7 @@ source = "git+https://github.com/logos-co/Overwatch?rev=f5a9902#f5a99022f389d65a dependencies = [ "async-trait", "futures", + "overwatch-derive", "thiserror 2.0.17", "tokio", "tokio-stream", @@ -3865,6 +4024,18 @@ dependencies = [ "tracing", ] +[[package]] +name = "overwatch-derive" +version = "0.1.0" +source = "git+https://github.com/logos-co/Overwatch?rev=f5a9902#f5a99022f389d65adbd55e51f1e3f9eead62432a" +dependencies = [ + "convert_case 0.8.0", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "parking_lot" version = "0.12.5" @@ -3971,7 +4142,7 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "pol" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "circuits-prover", "circuits-utils", @@ -3999,7 +4170,7 @@ dependencies = [ [[package]] name = "poq" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "circuits-prover", "circuits-utils", @@ -4021,7 +4192,7 @@ checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "poseidon2" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "ark-bn254 0.4.0", "ark-ff 0.4.2", @@ -4074,6 +4245,28 @@ dependencies = [ "toml_edit 0.23.10+spec-1.0.0", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "proc-macro2" version = "1.0.103" @@ -4692,6 +4885,16 @@ dependencies = [ "librocksdb-sys", ] +[[package]] +name = "rpds" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e75f485e819d4d3015e6c0d55d02a4fd3db47c1993d9e603e0361fba2bffb34" +dependencies = [ + "archery", + "serde", +] + [[package]] name = "rrs-lib" version = "0.1.0" @@ -5034,6 +5237,15 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + [[package]] name = "serde_core" version = "1.0.228" @@ -5140,6 +5352,21 @@ dependencies = [ "serde", ] +[[package]] +name = "services-utils" +version = "0.1.0" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" +dependencies = [ + "async-trait", + "futures", + "log", + "overwatch", + "serde", + "serde_json", + "thiserror 1.0.69", + "tracing", +] + [[package]] name = "sha1" version = "0.10.6" @@ -5783,6 +6010,16 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + [[package]] name = "tracing-subscriber" version = "0.2.25" @@ -5792,6 +6029,12 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "triomphe" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39" + [[package]] name = "try-lock" version = "0.2.5" @@ -5895,6 +6138,20 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "utxotree" +version = "0.1.0" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" +dependencies = [ + "ark-ff 0.4.2", + "groth16", + "num-bigint", + "poseidon2", + "rpds", + "serde", + "thiserror 1.0.69", +] + [[package]] name = "valuable" version = "0.1.1" @@ -6342,7 +6599,7 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "witness-generator" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "circuits-utils", "tempfile", @@ -6497,7 +6754,7 @@ dependencies = [ [[package]] name = "zksign" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=feat-skip-zk-build#fde542bb8398189fe5e9bad688a527618261f63d" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?branch=marbella-offsite-2025-12#b47525f893353b0441a34a62b87c85ad27fb8519" dependencies = [ "circuits-prover", "circuits-utils", From bbbb1c1a23e9eaad2431e8dc4cbb06099ddb5d96 Mon Sep 17 00:00:00 2001 From: Pravdyvy Date: Tue, 13 Jan 2026 15:11:51 +0200 Subject: [PATCH 04/18] fix: indexer core added to all objects --- Cargo.lock | 6 ++++++ Cargo.toml | 2 +- common/src/block.rs | 4 ++++ indexer/Cargo.toml | 2 +- indexer/src/config.rs | 3 ++- indexer/src/lib.rs | 17 ++++++++++----- indexer/src/state.rs | 5 +++++ integration_tests/Cargo.toml | 1 + integration_tests/tests/tps.rs | 7 ++++++ sequencer_core/Cargo.toml | 3 ++- sequencer_core/src/config.rs | 7 ++++++ sequencer_core/src/lib.rs | 39 ++++++++++++++++++++++++++++------ sequencer_rpc/Cargo.toml | 2 ++ sequencer_rpc/src/lib.rs | 4 ++++ sequencer_rpc/src/net_utils.rs | 3 +++ sequencer_rpc/src/process.rs | 24 ++++++++++++++++++++- sequencer_runner/Cargo.toml | 2 ++ sequencer_runner/src/lib.rs | 21 +++++++++++++++++- 18 files changed, 134 insertions(+), 18 deletions(-) create mode 100644 indexer/src/state.rs diff --git a/Cargo.lock b/Cargo.lock index 199461bb..dee037a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2954,6 +2954,7 @@ dependencies = [ "env_logger", "futures", "hex", + "indexer", "key_protocol", "log", "nssa", @@ -5176,6 +5177,7 @@ dependencies = [ "chrono", "common", "futures", + "indexer", "log", "mempool", "nssa", @@ -5196,10 +5198,12 @@ dependencies = [ "anyhow", "base58", "base64", + "bedrock_client", "borsh", "common", "futures", "hex", + "indexer", "itertools 0.14.0", "log", "mempool", @@ -5218,9 +5222,11 @@ dependencies = [ "actix", "actix-web", "anyhow", + "bedrock_client", "clap", "common", "env_logger", + "indexer", "log", "sequencer_core", "sequencer_rpc", diff --git a/Cargo.toml b/Cargo.toml index 843e4f64..b010b08f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ members = [ "examples/program_deployment", "examples/program_deployment/methods", "examples/program_deployment/methods/guest", - "bedrock_client", + "bedrock_client", "indexer", ] diff --git a/common/src/block.rs b/common/src/block.rs index baba1e42..346c2126 100644 --- a/common/src/block.rs +++ b/common/src/block.rs @@ -69,6 +69,10 @@ impl HashableBlockData { }, } } + + pub fn block_hash(&self) -> BlockHash { + OwnHasher::hash(&borsh::to_vec(&self).unwrap()) + } } impl From for HashableBlockData { diff --git a/indexer/Cargo.toml b/indexer/Cargo.toml index 2025a3b1..6d05bed5 100644 --- a/indexer/Cargo.toml +++ b/indexer/Cargo.toml @@ -30,4 +30,4 @@ async-stream = "0.3.6" indicatif = { version = "0.18.3", features = ["improved_unicode"] } risc0-zkvm.workspace = true url.workspace = true -nomos-core.workspace = true \ No newline at end of file +nomos-core.workspace = true diff --git a/indexer/src/config.rs b/indexer/src/config.rs index 8818d15e..3c7a75fc 100644 --- a/indexer/src/config.rs +++ b/indexer/src/config.rs @@ -1,6 +1,7 @@ use nomos_core::mantle::ops::channel::ChannelId; +use serde::{Deserialize, Serialize}; -#[derive(Debug)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct IndexerConfig { pub resubscribe_interval: u64, pub channel_id: ChannelId, diff --git a/indexer/src/lib.rs b/indexer/src/lib.rs index 1474f85c..93c5094b 100644 --- a/indexer/src/lib.rs +++ b/indexer/src/lib.rs @@ -1,6 +1,6 @@ use anyhow::Result; use bedrock_client::{BasicAuthCredentials, BedrockClient}; -use common::block::HashableBlockData; +use common::block::{BlockHash, HashableBlockData}; use futures::StreamExt; use nomos_core::mantle::{ Op, SignedMantleTx, @@ -9,22 +9,24 @@ use nomos_core::mantle::{ use tokio::sync::mpsc::Sender; use url::Url; -use crate::config::IndexerConfig; +use crate::{config::IndexerConfig, state::IndexerState}; pub mod config; +pub mod state; pub struct IndexerCore { pub bedrock_client: BedrockClient, pub bedrock_url: Url, - pub channel_sender: Sender, + pub channel_sender: Sender, pub config: IndexerConfig, + pub state: IndexerState, } impl IndexerCore { pub fn new( addr: &str, auth: Option, - sender: Sender, + sender: Sender, config: IndexerConfig, ) -> Result { Ok(Self { @@ -32,6 +34,10 @@ impl IndexerCore { bedrock_url: Url::parse(addr)?, channel_sender: sender, config, + // No state setup for now, future task. + state: IndexerState { + latest_seen_block: 0, + }, }) } @@ -58,7 +64,8 @@ impl IndexerCore { ); for l2_block in l2_blocks_parsed { - self.channel_sender.send(l2_block).await?; + // Sending data into sequencer, may need to be expanded. + self.channel_sender.send(l2_block.block_hash()).await?; } } } diff --git a/indexer/src/state.rs b/indexer/src/state.rs new file mode 100644 index 00000000..74301688 --- /dev/null +++ b/indexer/src/state.rs @@ -0,0 +1,5 @@ +#[derive(Debug)] +pub struct IndexerState { + // Only one field for now, for testing. + pub latest_seen_block: u64, +} diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index b888c177..be29063c 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -11,6 +11,7 @@ sequencer_runner.workspace = true wallet.workspace = true common.workspace = true key_protocol.workspace = true +indexer.workspace = true anyhow.workspace = true env_logger.workspace = true diff --git a/integration_tests/tests/tps.rs b/integration_tests/tests/tps.rs index b62a3ce7..6c2de6d9 100644 --- a/integration_tests/tests/tps.rs +++ b/integration_tests/tests/tps.rs @@ -1,6 +1,7 @@ use std::time::{Duration, Instant}; use anyhow::Result; +use indexer::config::IndexerConfig; use integration_tests::TestContext; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use log::info; @@ -185,6 +186,12 @@ impl TpsTestManager { initial_accounts: initial_public_accounts, initial_commitments: vec![initial_commitment], signing_key: [37; 32], + bedrock_addr: "0.0.0.0".to_string(), + bedrock_auth: ("".to_string(), "".to_string()), + indexer_config: IndexerConfig { + resubscribe_interval: 100, + channel_id: [42; 32].into(), + }, } } } diff --git a/sequencer_core/Cargo.toml b/sequencer_core/Cargo.toml index a844c524..71fe0e16 100644 --- a/sequencer_core/Cargo.toml +++ b/sequencer_core/Cargo.toml @@ -9,6 +9,7 @@ nssa_core.workspace = true common.workspace = true storage.workspace = true mempool.workspace = true +indexer.workspace = true base58.workspace = true anyhow.workspace = true @@ -17,11 +18,11 @@ serde_json.workspace = true tempfile.workspace = true chrono.workspace = true log.workspace = true +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } [features] default = [] testnet = [] [dev-dependencies] -tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } futures.workspace = true diff --git a/sequencer_core/src/config.rs b/sequencer_core/src/config.rs index 4ef08803..785c5328 100644 --- a/sequencer_core/src/config.rs +++ b/sequencer_core/src/config.rs @@ -5,6 +5,7 @@ use std::{ }; use anyhow::Result; +use indexer::config::IndexerConfig; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, Clone)] @@ -47,6 +48,12 @@ pub struct SequencerConfig { pub initial_commitments: Vec, /// Sequencer own signing key pub signing_key: [u8; 32], + /// Bedrock addr + pub bedrock_addr: String, + /// Bedrock auth + pub bedrock_auth: (String, String), + /// Indexer config + pub indexer_config: IndexerConfig, } impl SequencerConfig { diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 8e193ff6..2c57a765 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -5,13 +5,14 @@ use anyhow::Result; use common::PINATA_BASE58; use common::{ HashType, - block::HashableBlockData, + block::{BlockHash, HashableBlockData}, transaction::{EncodedTransaction, NSSATransaction}, }; use config::SequencerConfig; use log::warn; use mempool::{MemPool, MemPoolHandle}; use serde::{Deserialize, Serialize}; +use tokio::sync::mpsc::Receiver; use crate::block_store::SequencerBlockStore; @@ -24,6 +25,9 @@ pub struct SequencerCore { mempool: MemPool, sequencer_config: SequencerConfig, chain_height: u64, + // No logic here for now + #[allow(unused)] + receiver: Receiver, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] @@ -42,7 +46,10 @@ impl std::error::Error for TransactionMalformationError {} impl SequencerCore { /// Start Sequencer from configuration and construct transaction sender - pub fn start_from_config(config: SequencerConfig) -> (Self, MemPoolHandle) { + pub fn start_from_config( + config: SequencerConfig, + receiver: Receiver, + ) -> (Self, MemPoolHandle) { let hashable_data = HashableBlockData { block_id: config.genesis_id, transactions: vec![], @@ -93,6 +100,7 @@ impl SequencerCore { mempool, chain_height: config.genesis_id, sequencer_config: config, + receiver, }; this.sync_state_with_stored_blocks(); @@ -248,6 +256,7 @@ mod tests { use base58::{FromBase58, ToBase58}; use common::test_utils::sequencer_sign_key_for_testing; + use indexer::config::IndexerConfig; use nssa::PrivateKey; use super::*; @@ -277,6 +286,12 @@ mod tests { initial_accounts, initial_commitments: vec![], signing_key: *sequencer_sign_key_for_testing().value(), + bedrock_addr: "0.0.0.0".to_string(), + bedrock_auth: ("".to_string(), "".to_string()), + indexer_config: IndexerConfig { + resubscribe_interval: 100, + channel_id: [42; 32].into(), + }, } } @@ -322,7 +337,9 @@ mod tests { async fn common_setup_with_config( config: SequencerConfig, ) -> (SequencerCore, MemPoolHandle) { - let (mut sequencer, mempool_handle) = SequencerCore::start_from_config(config); + let (_, receiver) = tokio::sync::mpsc::channel(100); + + let (mut sequencer, mempool_handle) = SequencerCore::start_from_config(config, receiver); let tx = common::test_utils::produce_dummy_empty_transaction(); mempool_handle.push(tx).await.unwrap(); @@ -337,7 +354,9 @@ mod tests { #[test] fn test_start_from_config() { let config = setup_sequencer_config(); - let (sequencer, _mempool_handle) = SequencerCore::start_from_config(config.clone()); + let (_, receiver) = tokio::sync::mpsc::channel(100); + let (sequencer, _mempool_handle) = + SequencerCore::start_from_config(config.clone(), receiver); assert_eq!(sequencer.chain_height, config.genesis_id); assert_eq!(sequencer.sequencer_config.max_num_tx_in_block, 10); @@ -396,7 +415,9 @@ mod tests { let initial_accounts = vec![initial_acc1, initial_acc2]; let config = setup_sequencer_config_variable_initial_accounts(initial_accounts); - let (sequencer, _mempool_handle) = SequencerCore::start_from_config(config.clone()); + let (_, receiver) = tokio::sync::mpsc::channel(100); + let (sequencer, _mempool_handle) = + SequencerCore::start_from_config(config.clone(), receiver); let acc1_account_id = config.initial_accounts[0] .account_id @@ -729,7 +750,9 @@ mod tests { // from `acc_1` to `acc_2`. The block created with that transaction will be kept stored in // the temporary directory for the block storage of this test. { - let (mut sequencer, mempool_handle) = SequencerCore::start_from_config(config.clone()); + let (_, receiver) = tokio::sync::mpsc::channel(100); + let (mut sequencer, mempool_handle) = + SequencerCore::start_from_config(config.clone(), receiver); let signing_key = PrivateKey::try_new([1; 32]).unwrap(); let tx = common::test_utils::create_transaction_native_token_transfer( @@ -753,7 +776,9 @@ mod tests { // Instantiating a new sequencer from the same config. This should load the existing block // with the above transaction and update the state to reflect that. - let (sequencer, _mempool_handle) = SequencerCore::start_from_config(config.clone()); + let (_, receiver) = tokio::sync::mpsc::channel(100); + let (sequencer, _mempool_handle) = + SequencerCore::start_from_config(config.clone(), receiver); let balance_acc_1 = sequencer.state.get_account_by_id(&acc1_account_id).balance; let balance_acc_2 = sequencer.state.get_account_by_id(&acc2_account_id).balance; diff --git a/sequencer_rpc/Cargo.toml b/sequencer_rpc/Cargo.toml index 2abd5400..cf95b009 100644 --- a/sequencer_rpc/Cargo.toml +++ b/sequencer_rpc/Cargo.toml @@ -8,6 +8,8 @@ nssa.workspace = true common.workspace = true mempool.workspace = true sequencer_core.workspace = true +indexer.workspace = true +bedrock_client.workspace = true anyhow.workspace = true serde_json.workspace = true diff --git a/sequencer_rpc/src/lib.rs b/sequencer_rpc/src/lib.rs index 89b3e8cd..d41dbbd3 100644 --- a/sequencer_rpc/src/lib.rs +++ b/sequencer_rpc/src/lib.rs @@ -8,6 +8,7 @@ use common::{ rpc_primitives::errors::{RpcError, RpcErrorKind}, transaction::EncodedTransaction, }; +use indexer::IndexerCore; use mempool::MemPoolHandle; pub use net_utils::*; use sequencer_core::SequencerCore; @@ -20,6 +21,9 @@ use self::types::err_rpc::RpcErr; // ToDo: Add necessary fields pub struct JsonHandler { sequencer_state: Arc>, + // No functionality for now. + #[allow(unused)] + indexer_state: Arc>, mempool_handle: MemPoolHandle, } diff --git a/sequencer_rpc/src/net_utils.rs b/sequencer_rpc/src/net_utils.rs index 8b9b7e64..dc1f287b 100644 --- a/sequencer_rpc/src/net_utils.rs +++ b/sequencer_rpc/src/net_utils.rs @@ -7,6 +7,7 @@ use common::{ transaction::EncodedTransaction, }; use futures::{Future, FutureExt}; +use indexer::IndexerCore; use log::info; use mempool::MemPoolHandle; use sequencer_core::SequencerCore; @@ -46,6 +47,7 @@ pub fn new_http_server( config: RpcConfig, seuquencer_core: Arc>, mempool_handle: MemPoolHandle, + indexer_core: Arc>, ) -> io::Result<(actix_web::dev::Server, SocketAddr)> { let RpcConfig { addr, @@ -55,6 +57,7 @@ pub fn new_http_server( info!(target:NETWORK, "Starting HTTP server at {addr}"); let handler = web::Data::new(JsonHandler { sequencer_state: seuquencer_core.clone(), + indexer_state: indexer_core.clone(), mempool_handle, }); diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index 387abf28..097fb47b 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -340,7 +340,9 @@ mod tests { use base58::ToBase58; use base64::{Engine, engine::general_purpose}; + use bedrock_client::BasicAuthCredentials; use common::{test_utils::sequencer_sign_key_for_testing, transaction::EncodedTransaction}; + use indexer::{IndexerCore, config::IndexerConfig}; use sequencer_core::{ SequencerCore, config::{AccountInitialData, SequencerConfig}, @@ -388,12 +390,30 @@ mod tests { initial_accounts, initial_commitments: vec![], signing_key: *sequencer_sign_key_for_testing().value(), + bedrock_addr: "0.0.0.0".to_string(), + bedrock_auth: ("".to_string(), "".to_string()), + indexer_config: IndexerConfig { + resubscribe_interval: 100, + channel_id: [42; 32].into(), + }, } } async fn components_for_tests() -> (JsonHandler, Vec, EncodedTransaction) { let config = sequencer_config_for_tests(); - let (mut sequencer_core, mempool_handle) = SequencerCore::start_from_config(config); + let (sender, receiver) = tokio::sync::mpsc::channel(100); + let indexer_core = IndexerCore::new( + &config.bedrock_addr, + Some(BasicAuthCredentials::new( + config.bedrock_auth.0.clone(), + Some(config.bedrock_auth.1.clone()), + )), + sender, + config.indexer_config.clone(), + ) + .unwrap(); + let (mut sequencer_core, mempool_handle) = + SequencerCore::start_from_config(config, receiver); let initial_accounts = sequencer_core.sequencer_config().initial_accounts.clone(); let signing_key = nssa::PrivateKey::try_new([1; 32]).unwrap(); @@ -419,10 +439,12 @@ mod tests { .unwrap(); let sequencer_core = Arc::new(Mutex::new(sequencer_core)); + let indexer_core = Arc::new(Mutex::new(indexer_core)); ( JsonHandler { sequencer_state: sequencer_core, + indexer_state: indexer_core, mempool_handle, }, initial_accounts, diff --git a/sequencer_runner/Cargo.toml b/sequencer_runner/Cargo.toml index 55f56dec..d98ecf66 100644 --- a/sequencer_runner/Cargo.toml +++ b/sequencer_runner/Cargo.toml @@ -7,6 +7,8 @@ edition = "2024" common.workspace = true sequencer_core = { workspace = true, features = ["testnet"] } sequencer_rpc.workspace = true +indexer.workspace = true +bedrock_client.workspace = true clap = { workspace = true, features = ["derive", "env"] } anyhow.workspace = true diff --git a/sequencer_runner/src/lib.rs b/sequencer_runner/src/lib.rs index 5c1ab920..c1863a17 100644 --- a/sequencer_runner/src/lib.rs +++ b/sequencer_runner/src/lib.rs @@ -2,8 +2,10 @@ use std::{net::SocketAddr, path::PathBuf, sync::Arc}; use actix_web::dev::ServerHandle; use anyhow::Result; +use bedrock_client::BasicAuthCredentials; use clap::Parser; use common::rpc_primitives::RpcConfig; +use indexer::IndexerCore; use log::info; use sequencer_core::{SequencerCore, config::SequencerConfig}; use sequencer_rpc::new_http_server; @@ -24,16 +26,33 @@ pub async fn startup_sequencer( let block_timeout = app_config.block_create_timeout_millis; let port = app_config.port; - let (sequencer_core, mempool_handle) = SequencerCore::start_from_config(app_config); + // ToDo: Maybe make buffer size configurable. + let (sender, receiver) = tokio::sync::mpsc::channel(100); + + let indexer_core = IndexerCore::new( + &app_config.bedrock_addr, + Some(BasicAuthCredentials::new( + app_config.bedrock_auth.0.clone(), + Some(app_config.bedrock_auth.1.clone()), + )), + sender, + app_config.indexer_config.clone(), + )?; + + info!("Indexer core set up"); + + let (sequencer_core, mempool_handle) = SequencerCore::start_from_config(app_config, receiver); info!("Sequencer core set up"); + let indexer_core_wrapped = Arc::new(Mutex::new(indexer_core)); let seq_core_wrapped = Arc::new(Mutex::new(sequencer_core)); let (http_server, addr) = new_http_server( RpcConfig::with_port(port), Arc::clone(&seq_core_wrapped), mempool_handle, + Arc::clone(&indexer_core_wrapped), )?; info!("HTTP server started"); let http_server_handle = http_server.handle(); From de5201e2123326e84d3359b433e024114a0ba4d8 Mon Sep 17 00:00:00 2001 From: Pravdyvy Date: Wed, 14 Jan 2026 16:16:45 +0200 Subject: [PATCH 05/18] feat: ci test 1 --- .github/workflows/ci.yml | 29 ++++++++++++++++++- indexer/src/lib.rs | 7 +++++ .../configs/sequencer/sequencer_config.json | 11 ++++++- integration_tests/src/lib.rs | 11 +++++-- integration_tests/tests/indexer.rs | 22 ++++++++++++++ sequencer_rpc/src/process.rs | 2 +- sequencer_runner/src/lib.rs | 18 ++++++++++-- 7 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 integration_tests/tests/indexer.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38161a0f..800b0422 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -105,7 +105,7 @@ jobs: env: RISC0_DEV_MODE: "1" RUST_LOG: "info" - run: cargo nextest run --no-fail-fast -- --skip tps_test + run: cargo nextest run --no-fail-fast -- --skip tps_test --skip indexer_run_local_node valid-proof-test: runs-on: ubuntu-latest @@ -127,6 +127,33 @@ jobs: RUST_LOG: "info" run: cargo test -p integration_tests -- --exact private::private_transfer_to_owned_account + indexer-test: + runs-on: ubuntu-latest + timeout-minutes: 60 + steps: + - uses: actions/checkout@v5 + with: + ref: ${{ github.head_ref }} + + - uses: ./.github/actions/install-system-deps + + - uses: ./.github/actions/install-risc0 + + - name: Install active toolchain + run: rustup install + + - name: Test indexer run + env: + RUST_LOG: "info" + run: | + git clone https://github.com/logos-blockchain/logos-blockchain.git + cd logos-blockchain + chmod 777 ./scripts/setup-nomos-circuits.sh && ./scripts/setup-nomos-circuits.sh + cargo build --all-features --all-targets + CONSENSUS_SLOT_TIME=5 POL_PROOF_DEV_MODE=true target/debug/nomos-node nodes/nomos-node/config-one-node.yaml --dev-mode-reset-chain-clock > /dev/null 2>&1 + cd .. + cargo test -p integration_tests -- --exact indexer_run_local_node + artifacts: runs-on: ubuntu-latest timeout-minutes: 60 diff --git a/indexer/src/lib.rs b/indexer/src/lib.rs index 93c5094b..f797ce1b 100644 --- a/indexer/src/lib.rs +++ b/indexer/src/lib.rs @@ -2,6 +2,7 @@ use anyhow::Result; use bedrock_client::{BasicAuthCredentials, BedrockClient}; use common::block::{BlockHash, HashableBlockData}; use futures::StreamExt; +use log::info; use nomos_core::mantle::{ Op, SignedMantleTx, ops::channel::{ChannelId, inscribe::InscriptionOp}, @@ -49,15 +50,21 @@ impl IndexerCore { .await?, ); + info!("Block stream joined"); + while let Some(block_info) = stream_pinned.next().await { let header_id = block_info.header_id; + info!("Observed L1 block at height {}", block_info.height); + if let Some(l1_block) = self .bedrock_client .0 .get_block_by_id(self.bedrock_url.clone(), header_id) .await? { + info!("Extracted L1 block at height {} with data {l1_block:#?}", block_info.height); + let l2_blocks_parsed = parse_blocks( l1_block.into_transactions().into_iter(), &self.config.channel_id, diff --git a/integration_tests/configs/sequencer/sequencer_config.json b/integration_tests/configs/sequencer/sequencer_config.json index 1548bb5b..dd6ce12d 100644 --- a/integration_tests/configs/sequencer/sequencer_config.json +++ b/integration_tests/configs/sequencer/sequencer_config.json @@ -154,5 +154,14 @@ 37, 37, 37 - ] + ], + "bedrock_addr": "http://127.0.0.1:8080", + "bedrock_auth": [ + "user", + "password" + ], + "indexer_config": { + "resubscribe_interval": 1000, + "channel_id": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" + } } \ No newline at end of file diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index 12d718ec..3602e9eb 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -38,6 +38,7 @@ static LOGGER: LazyLock<()> = LazyLock::new(env_logger::init); pub struct TestContext { sequencer_server_handle: ServerHandle, sequencer_loop_handle: JoinHandle>, + indexer_loop_handle: JoinHandle>, sequencer_client: SequencerClient, wallet: WalletCore, _temp_sequencer_dir: TempDir, @@ -68,7 +69,7 @@ impl TestContext { debug!("Test context setup"); - let (sequencer_server_handle, sequencer_addr, sequencer_loop_handle, temp_sequencer_dir) = + let (sequencer_server_handle, sequencer_addr, sequencer_loop_handle, temp_sequencer_dir, indexer_loop_handle) = Self::setup_sequencer(sequencer_config) .await .context("Failed to setup sequencer")?; @@ -92,6 +93,7 @@ impl TestContext { Ok(Self { sequencer_server_handle, sequencer_loop_handle, + indexer_loop_handle, sequencer_client, wallet, _temp_sequencer_dir: temp_sequencer_dir, @@ -101,7 +103,7 @@ impl TestContext { async fn setup_sequencer( mut config: SequencerConfig, - ) -> Result<(ServerHandle, SocketAddr, JoinHandle>, TempDir)> { + ) -> Result<(ServerHandle, SocketAddr, JoinHandle>, TempDir, JoinHandle>)> { let temp_sequencer_dir = tempfile::tempdir().context("Failed to create temp dir for sequencer home")?; @@ -113,7 +115,7 @@ impl TestContext { // Setting port to 0 lets the OS choose a free port for us config.port = 0; - let (sequencer_server_handle, sequencer_addr, sequencer_loop_handle) = + let (sequencer_server_handle, sequencer_addr, sequencer_loop_handle, indexer_loop_handle) = sequencer_runner::startup_sequencer(config).await?; Ok(( @@ -121,6 +123,7 @@ impl TestContext { sequencer_addr, sequencer_loop_handle, temp_sequencer_dir, + indexer_loop_handle )) } @@ -180,6 +183,7 @@ impl Drop for TestContext { let Self { sequencer_server_handle, sequencer_loop_handle, + indexer_loop_handle, sequencer_client: _, wallet: _, _temp_sequencer_dir, @@ -187,6 +191,7 @@ impl Drop for TestContext { } = self; sequencer_loop_handle.abort(); + indexer_loop_handle.abort(); // Can't wait here as Drop can't be async, but anyway stop signal should be sent sequencer_server_handle.stop(true).now_or_never(); diff --git a/integration_tests/tests/indexer.rs b/integration_tests/tests/indexer.rs new file mode 100644 index 00000000..b30499d5 --- /dev/null +++ b/integration_tests/tests/indexer.rs @@ -0,0 +1,22 @@ +use anyhow::Result; +use integration_tests::TestContext; +use log::info; +use tokio::test; + +#[test] +async fn indexer_run_local_node() -> Result<()> { + println!("Waiting 20 seconds for L1 node to start producing"); + tokio::time::sleep(std::time::Duration::from_secs(20)).await; + + let ctx = TestContext::new().await?; + + info!("Let's observe behaviour"); + + tokio::time::sleep(std::time::Duration::from_secs(30)).await; + + let gen_id = ctx.sequencer_client().get_genesis_id().await.unwrap(); + + info!("btw, gen id is {gen_id:?}"); + + Ok(()) +} \ No newline at end of file diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index 097fb47b..51fba4c0 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -390,7 +390,7 @@ mod tests { initial_accounts, initial_commitments: vec![], signing_key: *sequencer_sign_key_for_testing().value(), - bedrock_addr: "0.0.0.0".to_string(), + bedrock_addr: "http://127.0.0.1:8080".to_string(), bedrock_auth: ("".to_string(), "".to_string()), indexer_config: IndexerConfig { resubscribe_interval: 100, diff --git a/sequencer_runner/src/lib.rs b/sequencer_runner/src/lib.rs index c1863a17..35a60e4d 100644 --- a/sequencer_runner/src/lib.rs +++ b/sequencer_runner/src/lib.rs @@ -22,7 +22,7 @@ struct Args { pub async fn startup_sequencer( app_config: SequencerConfig, -) -> Result<(ServerHandle, SocketAddr, JoinHandle>)> { +) -> Result<(ServerHandle, SocketAddr, JoinHandle>, JoinHandle>)> { let block_timeout = app_config.block_create_timeout_millis; let port = app_config.port; @@ -78,7 +78,18 @@ pub async fn startup_sequencer( } }); - Ok((http_server_handle, addr, main_loop_handle)) + let indexer_loop_handle = tokio::spawn(async move { + { + let indexer_guard = indexer_core_wrapped.lock().await; + let res = indexer_guard.subscribe_parse_block_stream().await; + + info!("Indexer loop res is {res:#?}"); + } + + Ok(()) + }); + + Ok((http_server_handle, addr, main_loop_handle, indexer_loop_handle)) } pub async fn main_runner() -> Result<()> { @@ -98,9 +109,10 @@ pub async fn main_runner() -> Result<()> { } // ToDo: Add restart on failures - let (_, _, main_loop_handle) = startup_sequencer(app_config).await?; + let (_, _, main_loop_handle, indexer_loop_handle) = startup_sequencer(app_config).await?; main_loop_handle.await??; + indexer_loop_handle.await??; Ok(()) } From c2e09031e18583efad32dd8f9ba99b4f32b1ee27 Mon Sep 17 00:00:00 2001 From: Pravdyvy Date: Thu, 15 Jan 2026 15:44:48 +0200 Subject: [PATCH 06/18] fix: integration updates --- Cargo.lock | 489 +++++++++--------- indexer/src/config.rs | 2 - indexer/src/lib.rs | 46 +- indexer/src/message.rs | 7 + indexer/src/state.rs | 6 +- .../sequencer_config.json | 16 +- .../sequencer/detached/sequencer_config.json | 158 ++++++ integration_tests/src/lib.rs | 49 +- integration_tests/tests/indexer.rs | 8 +- integration_tests/tests/tps.rs | 7 - sequencer_core/src/config.rs | 15 +- sequencer_core/src/lib.rs | 33 +- sequencer_rpc/src/lib.rs | 2 +- sequencer_rpc/src/net_utils.rs | 2 +- sequencer_rpc/src/process.rs | 32 +- sequencer_runner/src/lib.rs | 70 ++- 16 files changed, 587 insertions(+), 355 deletions(-) create mode 100644 indexer/src/message.rs rename integration_tests/configs/sequencer/{ => bedrock_local_attached}/sequencer_config.json (93%) create mode 100644 integration_tests/configs/sequencer/detached/sequencer_config.json diff --git a/Cargo.lock b/Cargo.lock index d16d9793..8646b5d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -73,7 +73,7 @@ dependencies = [ "bitflags 2.10.0", "bytes", "bytestring", - "derive_more 2.1.0", + "derive_more 2.1.1", "encoding_rs", "foldhash", "futures-core", @@ -102,7 +102,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -215,7 +215,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -226,7 +226,7 @@ checksum = "b6ac1e58cded18cb28ddc17143c4dea5345b3ad575e14f32f66e4054a56eb271" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -270,7 +270,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "once_cell", "version_check", ] @@ -459,7 +459,7 @@ checksum = "e7e89fe77d1f0f4fe5b96dfc940923d88d17b6a773808124f21e764dfb063c6a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -557,7 +557,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -583,7 +583,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -746,7 +746,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -830,7 +830,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -841,7 +841,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -884,7 +884,7 @@ dependencies = [ "serde_urlencoded", "sync_wrapper", "tokio", - "tower 0.5.2", + "tower 0.5.3", "tower-layer", "tower-service", "tracing", @@ -947,9 +947,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.1" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bedrock_client" @@ -984,7 +984,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1101,13 +1101,13 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "broadcast-service" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "async-trait", "derivative", @@ -1152,7 +1152,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1223,9 +1223,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.49" +version = "1.2.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" +checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3" dependencies = [ "find-msvc-tools", "jobserver", @@ -1262,7 +1262,7 @@ checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1279,7 +1279,7 @@ dependencies = [ [[package]] name = "chain-service" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "async-trait", "broadcast-service", @@ -1307,9 +1307,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" dependencies = [ "iana-time-zone", "js-sys", @@ -1332,7 +1332,7 @@ dependencies = [ [[package]] name = "circuits-prover" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "circuits-utils", "tempfile", @@ -1341,7 +1341,7 @@ dependencies = [ [[package]] name = "circuits-utils" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "dirs", ] @@ -1359,9 +1359,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.53" +version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" +checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" dependencies = [ "clap_builder", "clap_derive", @@ -1369,9 +1369,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.53" +version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" +checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" dependencies = [ "anstream", "anstyle", @@ -1388,14 +1388,14 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "clap_lex" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" [[package]] name = "cobs" @@ -1433,7 +1433,7 @@ dependencies = [ [[package]] name = "common-http-client" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "broadcast-service", "chain-service", @@ -1578,7 +1578,7 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "cryptarchia-engine" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "cfg_eval", "nomos-utils", @@ -1592,7 +1592,7 @@ dependencies = [ [[package]] name = "cryptarchia-sync" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "bytes", "cryptarchia-engine", @@ -1663,7 +1663,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1697,7 +1697,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1711,7 +1711,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1722,7 +1722,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1733,7 +1733,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1751,15 +1751,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "data-encoding-macro" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47ce6c96ea0102f01122a185683611bd5ac8d99e62bc59dd12e6bda344ee673d" +checksum = "8142a83c17aa9461d637e649271eae18bf2edd00e91f2e105df36c3c16355bdb" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -1767,12 +1767,12 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976" +checksum = "7ab67060fc6b8ef687992d439ca0fa36e7ed17e9a0b16b25b601e8757df720de" dependencies = [ "data-encoding", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1825,7 +1825,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1835,7 +1835,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1848,29 +1848,29 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "derive_more" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" dependencies = [ "derive_more-impl", ] [[package]] name = "derive_more-impl" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ "convert_case 0.10.0", "proc-macro2", "quote", "rustc_version", - "syn 2.0.111", + "syn 2.0.114", "unicode-xid", ] @@ -1915,7 +1915,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1996,7 +1996,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2076,7 +2076,7 @@ checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2149,9 +2149,9 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "find-msvc-tools" -version = "0.1.5" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" +checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41" [[package]] name = "fnv" @@ -2192,7 +2192,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2282,7 +2282,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2345,9 +2345,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", @@ -2409,7 +2409,7 @@ dependencies = [ [[package]] name = "groth16" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "ark-bn254 0.4.0", "ark-ec 0.4.2", @@ -2447,7 +2447,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.12.1", + "indexmap 2.13.0", "slab", "tokio", "tokio-util", @@ -2466,7 +2466,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.4.0", - "indexmap 2.12.1", + "indexmap 2.13.0", "slab", "tokio", "tokio-util", @@ -2718,7 +2718,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2 0.6.1", "system-configuration", "tokio", "tower-service", @@ -2909,9 +2909,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", "hashbrown 0.16.1", @@ -2974,9 +2974,9 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" dependencies = [ "memchr", "serde", @@ -3037,9 +3037,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "jf-crhf" @@ -3078,9 +3078,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.83" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" dependencies = [ "once_cell", "wasm-bindgen", @@ -3113,7 +3113,7 @@ dependencies = [ [[package]] name = "key-management-system-keys" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "async-trait", "bytes", @@ -3138,17 +3138,17 @@ dependencies = [ [[package]] name = "key-management-system-macros" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "key-management-system-service" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "async-trait", "key-management-system-keys", @@ -3184,7 +3184,7 @@ dependencies = [ [[package]] name = "kzgrs" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "ark-bls12-381", "ark-ec 0.4.2", @@ -3203,7 +3203,7 @@ dependencies = [ [[package]] name = "kzgrs-backend" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "ark-ff 0.4.2", "ark-poly 0.4.2", @@ -3224,9 +3224,9 @@ checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" [[package]] name = "lazy-regex" -version = "3.4.2" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "191898e17ddee19e60bccb3945aa02339e81edd4a8c50e21fd4d48cdecda7b29" +checksum = "c5c13b6857ade4c8ee05c3c3dc97d2ab5415d691213825b90d3211c425c1f907" dependencies = [ "lazy-regex-proc_macros", "once_cell", @@ -3235,14 +3235,14 @@ dependencies = [ [[package]] name = "lazy-regex-proc_macros" -version = "3.4.2" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c35dc8b0da83d1a9507e12122c80dea71a9c7c613014347392483a83ea593e04" +checksum = "32a95c68db5d41694cea563c86a4ba4dc02141c16ef64814108cb23def4d5438" dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3256,9 +3256,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.178" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "libloading" @@ -3293,9 +3293,9 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ "bitflags 2.10.0", "libc", @@ -3398,13 +3398,13 @@ dependencies = [ [[package]] name = "match-lookup" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1265724d8cb29dbbc2b0f06fffb8bf1a8c0cf73a78eede9ba73a4a66c52a981e" +checksum = "757aee279b8bdbb9f9e676796fd459e4207a1f986e87886700abf589f5abf771" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.114", ] [[package]] @@ -3421,7 +3421,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3491,7 +3491,7 @@ dependencies = [ [[package]] name = "mmr" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "ark-ff 0.4.2", "groth16", @@ -3609,7 +3609,7 @@ dependencies = [ [[package]] name = "nomos-blend-crypto" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "blake2", "groth16", @@ -3627,7 +3627,7 @@ dependencies = [ [[package]] name = "nomos-blend-message" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "blake2", "derivative", @@ -3649,7 +3649,7 @@ dependencies = [ [[package]] name = "nomos-blend-proofs" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "ed25519-dalek", "generic-array 1.3.5", @@ -3664,7 +3664,7 @@ dependencies = [ [[package]] name = "nomos-core" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "ark-ff 0.4.2", "async-trait", @@ -3694,7 +3694,7 @@ dependencies = [ [[package]] name = "nomos-da-messages" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "blake2", "futures", @@ -3707,7 +3707,7 @@ dependencies = [ [[package]] name = "nomos-http-api-common" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "axum", "governor", @@ -3722,7 +3722,7 @@ dependencies = [ [[package]] name = "nomos-ledger" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "cryptarchia-engine", "groth16", @@ -3745,7 +3745,7 @@ dependencies = [ [[package]] name = "nomos-network" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "async-trait", "cryptarchia-sync", @@ -3761,7 +3761,7 @@ dependencies = [ [[package]] name = "nomos-storage" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "async-trait", "bytes", @@ -3780,7 +3780,7 @@ dependencies = [ [[package]] name = "nomos-utils" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "async-trait", "blake2", @@ -3934,7 +3934,7 @@ checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3987,7 +3987,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -4016,7 +4016,7 @@ checksum = "969ccca8ffc4fb105bd131a228107d5c9dd89d9d627edf3295cbe979156f9712" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -4049,7 +4049,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -4113,7 +4113,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -4158,7 +4158,7 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "pol" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "circuits-prover", "circuits-utils", @@ -4186,7 +4186,7 @@ dependencies = [ [[package]] name = "poq" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "circuits-prover", "circuits-utils", @@ -4201,14 +4201,14 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.11.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" [[package]] name = "poseidon2" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "ark-bn254 0.4.0", "ark-ff 0.4.2", @@ -4280,14 +4280,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" dependencies = [ "unicode-ident", ] @@ -4300,7 +4300,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "version_check", ] @@ -4365,7 +4365,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -4396,7 +4396,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.5.10", + "socket2 0.6.1", "thiserror 2.0.17", "tokio", "tracing", @@ -4433,16 +4433,16 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.5.10", + "socket2 0.6.1", "tracing", "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.42" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" dependencies = [ "proc-macro2", ] @@ -4471,7 +4471,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -4491,7 +4491,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -4500,14 +4500,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", ] @@ -4518,7 +4518,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -4545,7 +4545,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "libredox", "thiserror 2.0.17", ] @@ -4567,7 +4567,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -4607,9 +4607,9 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "reqwest" -version = "0.12.26" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b4c14b2d9afca6a60277086b0cc6a6ae0b568f6f7916c943a8cdc79f8be240f" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64", "bytes", @@ -4642,7 +4642,7 @@ dependencies = [ "tokio-native-tls", "tokio-rustls", "tokio-util", - "tower 0.5.2", + "tower 0.5.3", "tower-http", "tower-service", "url", @@ -4671,7 +4671,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", @@ -4686,7 +4686,7 @@ dependencies = [ "anyhow", "borsh", "bytemuck", - "derive_more 2.1.0", + "derive_more 2.1.1", "elf", "lazy_static", "postcard", @@ -4763,7 +4763,7 @@ dependencies = [ "anyhow", "bit-vec", "bytemuck", - "derive_more 2.1.0", + "derive_more 2.1.1", "paste", "risc0-binfmt", "risc0-core", @@ -4779,7 +4779,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80f2723fedace48c6c5a505bd8f97ac4e1712bc4cb769083e10536d862b66987" dependencies = [ "bytemuck", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -4830,7 +4830,7 @@ dependencies = [ "hex-literal 0.4.1", "metal", "paste", - "rand_core 0.9.3", + "rand_core 0.9.5", "risc0-core", "risc0-zkvm-platform", "serde", @@ -4851,7 +4851,7 @@ dependencies = [ "borsh", "bytemuck", "bytes", - "derive_more 2.1.0", + "derive_more 2.1.1", "hex", "lazy-regex", "prost", @@ -4883,7 +4883,7 @@ checksum = "cfaa10feba15828c788837ddde84b994393936d8f5715228627cfe8625122a40" dependencies = [ "bytemuck", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "getrandom 0.3.4", "libm", "num_enum", @@ -4942,9 +4942,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40a0376c50d0358279d9d643e4bf7b7be212f1f4ff1da9070a7b54d22ef75c88" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ "const-oid", "digest", @@ -4962,9 +4962,9 @@ dependencies = [ [[package]] name = "ruint" -version = "1.17.0" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68df0380e5c9d20ce49534f292a36a7514ae21350726efe1865bdb1fa91d278" +checksum = "c141e807189ad38a07276942c6623032d3753c8859c146104ac2e4d68865945a" dependencies = [ "borsh", "proptest", @@ -4999,9 +4999,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ "bitflags 2.10.0", "errno", @@ -5012,9 +5012,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.35" +version = "0.23.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" dependencies = [ "once_cell", "ring", @@ -5053,9 +5053,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" [[package]] name = "rzup" @@ -5099,9 +5099,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289" +checksum = "54e910108742c57a770f492731f99be216a52fadd361b06c8fb59d74ccc267d2" dependencies = [ "dyn-clone", "ref-cast", @@ -5194,6 +5194,7 @@ dependencies = [ "chrono", "common", "futures", + "indexer", "key-management-system-service", "log", "mempool", @@ -5289,20 +5290,20 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", "serde_core", + "zmij", ] [[package]] @@ -5347,9 +5348,9 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.12.1", + "indexmap 2.13.0", "schemars 0.9.0", - "schemars 1.1.0", + "schemars 1.2.0", "serde_core", "serde_json", "serde_with_macros", @@ -5365,7 +5366,7 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -5381,7 +5382,7 @@ dependencies = [ [[package]] name = "services-utils" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "async-trait", "futures", @@ -5423,10 +5424,11 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.7" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -5514,7 +5516,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac" dependencies = [ "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -5563,7 +5565,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -5585,9 +5587,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.111" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", @@ -5611,25 +5613,25 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "system-configuration" -version = "0.5.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.10.0", "core-foundation", "system-configuration-sys", ] [[package]] name = "system-configuration-sys" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" dependencies = [ "core-foundation-sys", "libc", @@ -5637,9 +5639,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.23.0" +version = "3.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" dependencies = [ "fastrand", "getrandom 0.3.4", @@ -5698,7 +5700,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -5709,7 +5711,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -5723,30 +5725,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.44" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" [[package]] name = "time-macros" -version = "0.2.24" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" dependencies = [ "num-conv", "time-core", @@ -5788,9 +5790,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.48.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ "bytes", "libc", @@ -5811,7 +5813,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -5848,9 +5850,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.17" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", @@ -5882,9 +5884,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.4+spec-1.0.0" +version = "0.7.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe3cea6b2aa3b910092f6abd4053ea464fab5f9c170ba5e9a6aead16ec4af2b6" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" dependencies = [ "serde_core", ] @@ -5895,7 +5897,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "serde", "serde_spanned", "toml_datetime 0.6.11", @@ -5909,17 +5911,17 @@ version = "0.23.10+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ - "indexmap 2.12.1", - "toml_datetime 0.7.4+spec-1.0.0", + "indexmap 2.13.0", + "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "winnow", ] [[package]] name = "toml_parser" -version = "1.0.5+spec-1.0.0" +version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c03bee5ce3696f31250db0bbaff18bc43301ce0e8db2ed1f07cbb2acf89984c" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" dependencies = [ "winnow", ] @@ -5943,9 +5945,9 @@ dependencies = [ [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", @@ -5970,7 +5972,7 @@ dependencies = [ "http-body", "iri-string", "pin-project-lite", - "tower 0.5.2", + "tower 0.5.3", "tower-layer", "tower-service", ] @@ -6005,9 +6007,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -6023,14 +6025,14 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "tracing-core" -version = "0.1.35" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -6142,9 +6144,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.7" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", @@ -6167,7 +6169,7 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "utxotree" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "ark-ff 0.4.2", "groth16", @@ -6253,9 +6255,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.106" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" dependencies = [ "cfg-if", "once_cell", @@ -6266,11 +6268,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.56" +version = "0.4.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" dependencies = [ "cfg-if", + "futures-util", "js-sys", "once_cell", "wasm-bindgen", @@ -6279,9 +6282,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.106" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6289,22 +6292,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.106" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.106" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" dependencies = [ "unicode-ident", ] @@ -6324,9 +6327,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.83" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" dependencies = [ "js-sys", "wasm-bindgen", @@ -6344,9 +6347,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" +checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" dependencies = [ "rustls-pki-types", ] @@ -6403,7 +6406,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -6414,7 +6417,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -6626,7 +6629,7 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "witness-generator" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "circuits-utils", "tempfile", @@ -6680,28 +6683,28 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.31" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.31" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -6721,7 +6724,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "synstructure", ] @@ -6736,13 +6739,13 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -6775,13 +6778,13 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "zksign" version = "0.1.0" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git#b89238be3ad8111b9975e1023b87d8672d0edd74" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git#044259f74527bffb2724e132203f10253de58541" dependencies = [ "circuits-prover", "circuits-utils", @@ -6793,3 +6796,9 @@ dependencies = [ "thiserror 2.0.17", "witness-generator", ] + +[[package]] +name = "zmij" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea" diff --git a/indexer/src/config.rs b/indexer/src/config.rs index 3c7a75fc..1ab102f8 100644 --- a/indexer/src/config.rs +++ b/indexer/src/config.rs @@ -1,8 +1,6 @@ -use nomos_core::mantle::ops::channel::ChannelId; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct IndexerConfig { pub resubscribe_interval: u64, - pub channel_id: ChannelId, } diff --git a/indexer/src/lib.rs b/indexer/src/lib.rs index f797ce1b..8fd2c9c5 100644 --- a/indexer/src/lib.rs +++ b/indexer/src/lib.rs @@ -1,25 +1,29 @@ +use std::sync::Arc; + use anyhow::Result; use bedrock_client::{BasicAuthCredentials, BedrockClient}; -use common::block::{BlockHash, HashableBlockData}; +use common::block::HashableBlockData; use futures::StreamExt; use log::info; use nomos_core::mantle::{ Op, SignedMantleTx, ops::channel::{ChannelId, inscribe::InscriptionOp}, }; -use tokio::sync::mpsc::Sender; +use tokio::sync::{RwLock, mpsc::Sender}; use url::Url; -use crate::{config::IndexerConfig, state::IndexerState}; +use crate::{config::IndexerConfig, message::IndexerToSequencerMessage, state::IndexerState}; pub mod config; +pub mod message; pub mod state; pub struct IndexerCore { pub bedrock_client: BedrockClient, - pub bedrock_url: Url, - pub channel_sender: Sender, + pub channel_sender: Sender, pub config: IndexerConfig, + pub bedrock_url: Url, + pub channel_id: ChannelId, pub state: IndexerState, } @@ -27,17 +31,19 @@ impl IndexerCore { pub fn new( addr: &str, auth: Option, - sender: Sender, + sender: Sender, config: IndexerConfig, + channel_id: ChannelId, ) -> Result { Ok(Self { bedrock_client: BedrockClient::new(auth)?, bedrock_url: Url::parse(addr)?, channel_sender: sender, config, + channel_id, // No state setup for now, future task. state: IndexerState { - latest_seen_block: 0, + latest_seen_block: Arc::new(RwLock::new(0)), }, }) } @@ -63,16 +69,29 @@ impl IndexerCore { .get_block_by_id(self.bedrock_url.clone(), header_id) .await? { - info!("Extracted L1 block at height {} with data {l1_block:#?}", block_info.height); + info!("Extracted L1 block at height {}", block_info.height); - let l2_blocks_parsed = parse_blocks( - l1_block.into_transactions().into_iter(), - &self.config.channel_id, - ); + let l2_blocks_parsed = + parse_blocks(l1_block.into_transactions().into_iter(), &self.channel_id); for l2_block in l2_blocks_parsed { + // State modification, will be updated in future + { + let mut guard = self.state.latest_seen_block.write().await; + if l2_block.block_id > *guard { + *guard = l2_block.block_id; + } + } + // Sending data into sequencer, may need to be expanded. - self.channel_sender.send(l2_block.block_hash()).await?; + let message = IndexerToSequencerMessage::BlockObserved { + l1_block_id: block_info.height, + l2_block_height: l2_block.block_id, + }; + + self.channel_sender.send(message.clone()).await?; + + info!("Sent message {:#?} to sequencer", message); } } } @@ -96,7 +115,6 @@ pub fn parse_blocks( inscription, .. }) if channel_id == decoded_channel_id => { - // Assuming, that it is how block will be inscribed on l1 borsh::from_slice::(inscription).ok() } _ => None, diff --git a/indexer/src/message.rs b/indexer/src/message.rs new file mode 100644 index 00000000..195696ad --- /dev/null +++ b/indexer/src/message.rs @@ -0,0 +1,7 @@ +#[derive(Debug, Clone)] +pub enum IndexerToSequencerMessage { + BlockObserved { + l1_block_id: u64, + l2_block_height: u64, + }, +} diff --git a/indexer/src/state.rs b/indexer/src/state.rs index 74301688..b2aa48a5 100644 --- a/indexer/src/state.rs +++ b/indexer/src/state.rs @@ -1,5 +1,9 @@ +use std::sync::Arc; + +use tokio::sync::RwLock; + #[derive(Debug)] pub struct IndexerState { // Only one field for now, for testing. - pub latest_seen_block: u64, + pub latest_seen_block: Arc>, } diff --git a/integration_tests/configs/sequencer/sequencer_config.json b/integration_tests/configs/sequencer/bedrock_local_attached/sequencer_config.json similarity index 93% rename from integration_tests/configs/sequencer/sequencer_config.json rename to integration_tests/configs/sequencer/bedrock_local_attached/sequencer_config.json index 5f36c0d5..7212ce36 100644 --- a/integration_tests/configs/sequencer/sequencer_config.json +++ b/integration_tests/configs/sequencer/bedrock_local_attached/sequencer_config.json @@ -155,13 +155,13 @@ 37, 37 ], - "bedrock_addr": "http://127.0.0.1:8080", - "bedrock_auth": [ - "user", - "password" - ], - "indexer_config": { - "resubscribe_interval": 1000, - "channel_id": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" + "bedrock_config": { + "channel_id": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a", + "node_url": "http://127.0.0.1:8080", + "user": "user", + "password": null, + "indexer_config": { + "resubscribe_interval": 1000 + } } } diff --git a/integration_tests/configs/sequencer/detached/sequencer_config.json b/integration_tests/configs/sequencer/detached/sequencer_config.json new file mode 100644 index 00000000..575d3de3 --- /dev/null +++ b/integration_tests/configs/sequencer/detached/sequencer_config.json @@ -0,0 +1,158 @@ +{ + "home": "", + "override_rust_log": null, + "genesis_id": 1, + "is_genesis_random": true, + "max_num_tx_in_block": 20, + "mempool_max_size": 10000, + "block_create_timeout_millis": 10000, + "port": 0, + "initial_accounts": [ + { + "account_id": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", + "balance": 10000 + }, + { + "account_id": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", + "balance": 20000 + } + ], + "initial_commitments": [ + { + "npk": [ + 63, + 202, + 178, + 231, + 183, + 82, + 237, + 212, + 216, + 221, + 215, + 255, + 153, + 101, + 177, + 161, + 254, + 210, + 128, + 122, + 54, + 190, + 230, + 151, + 183, + 64, + 225, + 229, + 113, + 1, + 228, + 97 + ], + "account": { + "program_owner": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "balance": 10000, + "data": [], + "nonce": 0 + } + }, + { + "npk": [ + 192, + 251, + 166, + 243, + 167, + 236, + 84, + 249, + 35, + 136, + 130, + 172, + 219, + 225, + 161, + 139, + 229, + 89, + 243, + 125, + 194, + 213, + 209, + 30, + 23, + 174, + 100, + 244, + 124, + 74, + 140, + 47 + ], + "account": { + "program_owner": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "balance": 20000, + "data": [], + "nonce": 0 + } + } + ], + "signing_key": [ + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 37 + ] +} diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index 3602e9eb..af8758e4 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -38,7 +38,7 @@ static LOGGER: LazyLock<()> = LazyLock::new(env_logger::init); pub struct TestContext { sequencer_server_handle: ServerHandle, sequencer_loop_handle: JoinHandle>, - indexer_loop_handle: JoinHandle>, + indexer_loop_handle: Option>>, sequencer_client: SequencerClient, wallet: WalletCore, _temp_sequencer_dir: TempDir, @@ -46,12 +46,25 @@ pub struct TestContext { } impl TestContext { - /// Create new test context. + /// Create new test context in detached mode. Default. pub async fn new() -> Result { let manifest_dir = env!("CARGO_MANIFEST_DIR"); let sequencer_config_path = - PathBuf::from(manifest_dir).join("configs/sequencer/sequencer_config.json"); + PathBuf::from(manifest_dir).join("configs/sequencer/detached/sequencer_config.json"); + + let sequencer_config = SequencerConfig::from_path(&sequencer_config_path) + .context("Failed to create sequencer config from file")?; + + Self::new_with_sequencer_config(sequencer_config).await + } + + /// Create new test context in local bedrock node attached mode. + pub async fn new_bedrock_local_attached() -> Result { + let manifest_dir = env!("CARGO_MANIFEST_DIR"); + + let sequencer_config_path = PathBuf::from(manifest_dir) + .join("configs/sequencer/bedrock_local_attached/sequencer_config.json"); let sequencer_config = SequencerConfig::from_path(&sequencer_config_path) .context("Failed to create sequencer config from file")?; @@ -69,10 +82,15 @@ impl TestContext { debug!("Test context setup"); - let (sequencer_server_handle, sequencer_addr, sequencer_loop_handle, temp_sequencer_dir, indexer_loop_handle) = - Self::setup_sequencer(sequencer_config) - .await - .context("Failed to setup sequencer")?; + let ( + sequencer_server_handle, + sequencer_addr, + sequencer_loop_handle, + temp_sequencer_dir, + indexer_loop_handle, + ) = Self::setup_sequencer(sequencer_config) + .await + .context("Failed to setup sequencer")?; // Convert 0.0.0.0 to 127.0.0.1 for client connections // When binding to port 0, the server binds to 0.0.0.0: @@ -103,7 +121,13 @@ impl TestContext { async fn setup_sequencer( mut config: SequencerConfig, - ) -> Result<(ServerHandle, SocketAddr, JoinHandle>, TempDir, JoinHandle>)> { + ) -> Result<( + ServerHandle, + SocketAddr, + JoinHandle>, + TempDir, + Option>>, + )> { let temp_sequencer_dir = tempfile::tempdir().context("Failed to create temp dir for sequencer home")?; @@ -123,7 +147,7 @@ impl TestContext { sequencer_addr, sequencer_loop_handle, temp_sequencer_dir, - indexer_loop_handle + indexer_loop_handle, )) } @@ -191,7 +215,12 @@ impl Drop for TestContext { } = self; sequencer_loop_handle.abort(); - indexer_loop_handle.abort(); + match indexer_loop_handle { + Some(handle) => { + handle.abort(); + } + None => {} + }; // Can't wait here as Drop can't be async, but anyway stop signal should be sent sequencer_server_handle.stop(true).now_or_never(); diff --git a/integration_tests/tests/indexer.rs b/integration_tests/tests/indexer.rs index b30499d5..d82e8960 100644 --- a/integration_tests/tests/indexer.rs +++ b/integration_tests/tests/indexer.rs @@ -6,17 +6,17 @@ use tokio::test; #[test] async fn indexer_run_local_node() -> Result<()> { println!("Waiting 20 seconds for L1 node to start producing"); - tokio::time::sleep(std::time::Duration::from_secs(20)).await; + tokio::time::sleep(std::time::Duration::from_secs(2)).await; - let ctx = TestContext::new().await?; + let ctx = TestContext::new_bedrock_local_attached().await?; info!("Let's observe behaviour"); - tokio::time::sleep(std::time::Duration::from_secs(30)).await; + tokio::time::sleep(std::time::Duration::from_secs(300)).await; let gen_id = ctx.sequencer_client().get_genesis_id().await.unwrap(); info!("btw, gen id is {gen_id:?}"); Ok(()) -} \ No newline at end of file +} diff --git a/integration_tests/tests/tps.rs b/integration_tests/tests/tps.rs index e03dc5de..87f7e45a 100644 --- a/integration_tests/tests/tps.rs +++ b/integration_tests/tests/tps.rs @@ -1,7 +1,6 @@ use std::time::{Duration, Instant}; use anyhow::Result; -use indexer::config::IndexerConfig; use integration_tests::TestContext; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use log::info; @@ -186,12 +185,6 @@ impl TpsTestManager { initial_accounts: initial_public_accounts, initial_commitments: vec![initial_commitment], signing_key: [37; 32], - bedrock_addr: "0.0.0.0".to_string(), - bedrock_auth: ("".to_string(), "".to_string()), - indexer_config: IndexerConfig { - resubscribe_interval: 100, - channel_id: [42; 32].into(), - }, bedrock_config: None, } } diff --git a/sequencer_core/src/config.rs b/sequencer_core/src/config.rs index 396a89e9..3ef692d0 100644 --- a/sequencer_core/src/config.rs +++ b/sequencer_core/src/config.rs @@ -6,6 +6,7 @@ use std::{ use anyhow::Result; use indexer::config::IndexerConfig; +use nomos_core::mantle::ops::channel::ChannelId; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, Clone)] @@ -48,12 +49,6 @@ pub struct SequencerConfig { pub initial_commitments: Vec, /// Sequencer own signing key pub signing_key: [u8; 32], - /// Bedrock addr - pub bedrock_addr: String, - /// Bedrock auth - pub bedrock_auth: (String, String), - /// Indexer config - pub indexer_config: IndexerConfig, /// Bedrock configuration options pub bedrock_config: Option, } @@ -61,9 +56,15 @@ pub struct SequencerConfig { #[derive(Clone, Serialize, Deserialize)] pub struct BedrockConfig { /// Bedrock channel ID - pub channel_id: [u8; 32], + pub channel_id: ChannelId, /// Bedrock Url pub node_url: String, + /// Bedrock user + pub user: String, + /// Bedrock password(optional) + pub password: Option, + /// Indexer config + pub indexer_config: IndexerConfig, } impl SequencerConfig { diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 245990ad..9aeb7302 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -5,10 +5,11 @@ use anyhow::Result; use common::PINATA_BASE58; use common::{ HashType, - block::{BlockHash, HashableBlockData}, + block::HashableBlockData, transaction::{EncodedTransaction, NSSATransaction}, }; use config::SequencerConfig; +use indexer::message::IndexerToSequencerMessage; use log::warn; use mempool::{MemPool, MemPoolHandle}; use serde::{Deserialize, Serialize}; @@ -28,7 +29,7 @@ pub struct SequencerCore { chain_height: u64, // No logic here for now #[allow(unused)] - receiver: Receiver, + receiver: Option>, block_settlement_client: Option, } @@ -50,7 +51,7 @@ impl SequencerCore { /// Start Sequencer from configuration and construct transaction sender pub fn start_from_config( config: SequencerConfig, - receiver: Receiver, + receiver: Option>, ) -> (Self, MemPoolHandle) { let hashable_data = HashableBlockData { block_id: config.genesis_id, @@ -275,7 +276,6 @@ mod tests { use base58::{FromBase58, ToBase58}; use common::test_utils::sequencer_sign_key_for_testing; - use indexer::config::IndexerConfig; use nssa::PrivateKey; use super::*; @@ -305,12 +305,6 @@ mod tests { initial_accounts, initial_commitments: vec![], signing_key: *sequencer_sign_key_for_testing().value(), - bedrock_addr: "0.0.0.0".to_string(), - bedrock_auth: ("".to_string(), "".to_string()), - indexer_config: IndexerConfig { - resubscribe_interval: 100, - channel_id: [42; 32].into(), - }, bedrock_config: None, } } @@ -357,9 +351,7 @@ mod tests { async fn common_setup_with_config( config: SequencerConfig, ) -> (SequencerCore, MemPoolHandle) { - let (_, receiver) = tokio::sync::mpsc::channel(100); - - let (mut sequencer, mempool_handle) = SequencerCore::start_from_config(config, receiver); + let (mut sequencer, mempool_handle) = SequencerCore::start_from_config(config, None); let tx = common::test_utils::produce_dummy_empty_transaction(); mempool_handle.push(tx).await.unwrap(); @@ -374,9 +366,7 @@ mod tests { #[test] fn test_start_from_config() { let config = setup_sequencer_config(); - let (_, receiver) = tokio::sync::mpsc::channel(100); - let (sequencer, _mempool_handle) = - SequencerCore::start_from_config(config.clone(), receiver); + let (sequencer, _mempool_handle) = SequencerCore::start_from_config(config.clone(), None); assert_eq!(sequencer.chain_height, config.genesis_id); assert_eq!(sequencer.sequencer_config.max_num_tx_in_block, 10); @@ -435,9 +425,7 @@ mod tests { let initial_accounts = vec![initial_acc1, initial_acc2]; let config = setup_sequencer_config_variable_initial_accounts(initial_accounts); - let (_, receiver) = tokio::sync::mpsc::channel(100); - let (sequencer, _mempool_handle) = - SequencerCore::start_from_config(config.clone(), receiver); + let (sequencer, _mempool_handle) = SequencerCore::start_from_config(config.clone(), None); let acc1_account_id = config.initial_accounts[0] .account_id @@ -773,9 +761,8 @@ mod tests { // from `acc_1` to `acc_2`. The block created with that transaction will be kept stored in // the temporary directory for the block storage of this test. { - let (_, receiver) = tokio::sync::mpsc::channel(100); let (mut sequencer, mempool_handle) = - SequencerCore::start_from_config(config.clone(), receiver); + SequencerCore::start_from_config(config.clone(), None); let signing_key = PrivateKey::try_new([1; 32]).unwrap(); let tx = common::test_utils::create_transaction_native_token_transfer( @@ -800,9 +787,7 @@ mod tests { // Instantiating a new sequencer from the same config. This should load the existing block // with the above transaction and update the state to reflect that. - let (_, receiver) = tokio::sync::mpsc::channel(100); - let (sequencer, _mempool_handle) = - SequencerCore::start_from_config(config.clone(), receiver); + let (sequencer, _mempool_handle) = SequencerCore::start_from_config(config.clone(), None); let balance_acc_1 = sequencer.state.get_account_by_id(&acc1_account_id).balance; let balance_acc_2 = sequencer.state.get_account_by_id(&acc2_account_id).balance; diff --git a/sequencer_rpc/src/lib.rs b/sequencer_rpc/src/lib.rs index d41dbbd3..d66392c8 100644 --- a/sequencer_rpc/src/lib.rs +++ b/sequencer_rpc/src/lib.rs @@ -23,7 +23,7 @@ pub struct JsonHandler { sequencer_state: Arc>, // No functionality for now. #[allow(unused)] - indexer_state: Arc>, + indexer_state: Option>>, mempool_handle: MemPoolHandle, } diff --git a/sequencer_rpc/src/net_utils.rs b/sequencer_rpc/src/net_utils.rs index dc1f287b..8803831e 100644 --- a/sequencer_rpc/src/net_utils.rs +++ b/sequencer_rpc/src/net_utils.rs @@ -47,7 +47,7 @@ pub fn new_http_server( config: RpcConfig, seuquencer_core: Arc>, mempool_handle: MemPoolHandle, - indexer_core: Arc>, + indexer_core: Option>>, ) -> io::Result<(actix_web::dev::Server, SocketAddr)> { let RpcConfig { addr, diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index 6f89d9e6..05c6342d 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -345,7 +345,7 @@ mod tests { use indexer::{IndexerCore, config::IndexerConfig}; use sequencer_core::{ SequencerCore, - config::{AccountInitialData, SequencerConfig}, + config::{AccountInitialData, BedrockConfig, SequencerConfig}, }; use serde_json::Value; use tempfile::tempdir; @@ -390,31 +390,37 @@ mod tests { initial_accounts, initial_commitments: vec![], signing_key: *sequencer_sign_key_for_testing().value(), - bedrock_addr: "http://127.0.0.1:8080".to_string(), - bedrock_auth: ("".to_string(), "".to_string()), - indexer_config: IndexerConfig { - resubscribe_interval: 100, + bedrock_config: Some(BedrockConfig { channel_id: [42; 32].into(), - }, - bedrock_config: None, + node_url: "http://localhost:8080".to_string(), + user: "user".to_string(), + password: None, + indexer_config: IndexerConfig { + resubscribe_interval: 100, + }, + }), } } async fn components_for_tests() -> (JsonHandler, Vec, EncodedTransaction) { let config = sequencer_config_for_tests(); + let bedrock_config = config.bedrock_config.clone().unwrap(); + let (sender, receiver) = tokio::sync::mpsc::channel(100); let indexer_core = IndexerCore::new( - &config.bedrock_addr, + &bedrock_config.node_url, Some(BasicAuthCredentials::new( - config.bedrock_auth.0.clone(), - Some(config.bedrock_auth.1.clone()), + bedrock_config.user.clone(), + bedrock_config.password.clone(), )), sender, - config.indexer_config.clone(), + bedrock_config.indexer_config.clone(), + bedrock_config.channel_id.into(), ) .unwrap(); + let (mut sequencer_core, mempool_handle) = - SequencerCore::start_from_config(config, receiver); + SequencerCore::start_from_config(config, Some(receiver)); let initial_accounts = sequencer_core.sequencer_config().initial_accounts.clone(); let signing_key = nssa::PrivateKey::try_new([1; 32]).unwrap(); @@ -445,7 +451,7 @@ mod tests { ( JsonHandler { sequencer_state: sequencer_core, - indexer_state: indexer_core, + indexer_state: Some(indexer_core), mempool_handle, }, initial_accounts, diff --git a/sequencer_runner/src/lib.rs b/sequencer_runner/src/lib.rs index 72929c4a..b65675c4 100644 --- a/sequencer_runner/src/lib.rs +++ b/sequencer_runner/src/lib.rs @@ -22,37 +22,51 @@ struct Args { pub async fn startup_sequencer( app_config: SequencerConfig, -) -> Result<(ServerHandle, SocketAddr, JoinHandle>, JoinHandle>)> { +) -> Result<( + ServerHandle, + SocketAddr, + JoinHandle>, + Option>>, +)> { let block_timeout = app_config.block_create_timeout_millis; let port = app_config.port; // ToDo: Maybe make buffer size configurable. - let (sender, receiver) = tokio::sync::mpsc::channel(100); + let (indexer_core, receiver) = if let Some(bedrock_config) = app_config.bedrock_config.clone() { + let (sender, receiver) = tokio::sync::mpsc::channel(100); - let indexer_core = IndexerCore::new( - &app_config.bedrock_addr, - Some(BasicAuthCredentials::new( - app_config.bedrock_auth.0.clone(), - Some(app_config.bedrock_auth.1.clone()), - )), - sender, - app_config.indexer_config.clone(), - )?; + let indexer_core = IndexerCore::new( + &bedrock_config.node_url, + Some(BasicAuthCredentials::new( + bedrock_config.user.clone(), + bedrock_config.password.clone(), + )), + sender, + bedrock_config.indexer_config.clone(), + bedrock_config.channel_id.into(), + )?; - info!("Indexer core set up"); + info!("Indexer core set up"); + + (Some(indexer_core), Some(receiver)) + } else { + info!("Bedrock config not provided, skipping indexer setup"); + + (None, None) + }; let (sequencer_core, mempool_handle) = SequencerCore::start_from_config(app_config, receiver); info!("Sequencer core set up"); - let indexer_core_wrapped = Arc::new(Mutex::new(indexer_core)); + let indexer_core_wrapped = indexer_core.map(|core| Arc::new(Mutex::new(core))); let seq_core_wrapped = Arc::new(Mutex::new(sequencer_core)); let (http_server, addr) = new_http_server( RpcConfig::with_port(port), Arc::clone(&seq_core_wrapped), mempool_handle, - Arc::clone(&indexer_core_wrapped), + indexer_core_wrapped.clone(), )?; info!("HTTP server started"); let http_server_handle = http_server.handle(); @@ -80,18 +94,25 @@ pub async fn startup_sequencer( } }); - let indexer_loop_handle = tokio::spawn(async move { - { - let indexer_guard = indexer_core_wrapped.lock().await; - let res = indexer_guard.subscribe_parse_block_stream().await; + let indexer_loop_handle = indexer_core_wrapped.map(|indexer_core_wrapped| { + tokio::spawn(async move { + { + let indexer_guard = indexer_core_wrapped.lock().await; + let res = indexer_guard.subscribe_parse_block_stream().await; - info!("Indexer loop res is {res:#?}"); - } + info!("Indexer loop res is {res:#?}"); + } - Ok(()) + Ok(()) + }) }); - Ok((http_server_handle, addr, main_loop_handle, indexer_loop_handle)) + Ok(( + http_server_handle, + addr, + main_loop_handle, + indexer_loop_handle, + )) } pub async fn main_runner() -> Result<()> { @@ -114,7 +135,10 @@ pub async fn main_runner() -> Result<()> { let (_, _, main_loop_handle, indexer_loop_handle) = startup_sequencer(app_config).await?; main_loop_handle.await??; - indexer_loop_handle.await??; + + if indexer_loop_handle.is_some() { + indexer_loop_handle.unwrap().await??; + } Ok(()) } From b96865ab89c48437cbf9804d34587f47b2c59f1a Mon Sep 17 00:00:00 2001 From: Pravdyvy Date: Fri, 16 Jan 2026 16:15:21 +0200 Subject: [PATCH 07/18] fix: indexer update --- Cargo.lock | 12 +++ Cargo.toml | 1 + common/src/rpc_primitives/requests.rs | 4 + common/src/sequencer_client.rs | 25 +++++- indexer/Cargo.toml | 1 + indexer/src/config.rs | 2 + indexer/src/lib.rs | 85 +++++++++++-------- .../sequencer_config.json | 6 +- integration_tests/src/lib.rs | 9 +- integration_tests/tests/indexer.rs | 12 ++- sequencer_core/Cargo.toml | 2 +- sequencer_core/src/block_settlement_client.rs | 5 +- sequencer_rpc/src/process.rs | 38 +++++++-- sequencer_runner/src/lib.rs | 2 +- 14 files changed, 144 insertions(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8646b5d8..e2392385 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2893,6 +2893,7 @@ dependencies = [ "serde_json", "sha2", "tokio", + "tokio-retry", "url", ] @@ -5826,6 +5827,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-retry" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f57eb36ecbe0fc510036adff84824dd3c24bb781e21bfa67b69d556aa85214f" +dependencies = [ + "pin-project", + "rand 0.8.5", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.4" diff --git a/Cargo.toml b/Cargo.toml index 4a4dc2ef..3fe9c16b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,6 +80,7 @@ borsh = "1.5.7" base58 = "0.2.0" itertools = "0.14.0" url = "2.5.4" +tokio-retry = "0.3.0" common-http-client = { git = "https://github.com/logos-blockchain/logos-blockchain.git" } key-management-system-service = { git = "https://github.com/logos-blockchain/logos-blockchain.git" } diff --git a/common/src/rpc_primitives/requests.rs b/common/src/rpc_primitives/requests.rs index 71641936..62460209 100644 --- a/common/src/rpc_primitives/requests.rs +++ b/common/src/rpc_primitives/requests.rs @@ -73,6 +73,9 @@ pub struct GetProofForCommitmentRequest { #[derive(Serialize, Deserialize, Debug)] pub struct GetProgramIdsRequest {} +#[derive(Serialize, Deserialize, Debug)] +pub struct GetLastSeenL2BlockAtIndexerRequest {} + parse_request!(HelloRequest); parse_request!(RegisterAccountRequest); parse_request!(SendTxRequest); @@ -87,6 +90,7 @@ parse_request!(GetAccountsNoncesRequest); parse_request!(GetProofForCommitmentRequest); parse_request!(GetAccountRequest); parse_request!(GetProgramIdsRequest); +parse_request!(GetLastSeenL2BlockAtIndexerRequest); #[derive(Serialize, Deserialize, Debug)] pub struct HelloResponse { diff --git a/common/src/sequencer_client.rs b/common/src/sequencer_client.rs index 0cb03f6f..b33c22a5 100644 --- a/common/src/sequencer_client.rs +++ b/common/src/sequencer_client.rs @@ -18,9 +18,10 @@ use crate::{ GetAccountRequest, GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse, GetBlockRangeDataRequest, GetBlockRangeDataResponse, GetInitialTestnetAccountsResponse, GetLastBlockRequest, GetLastBlockResponse, - GetProgramIdsRequest, GetProgramIdsResponse, GetProofForCommitmentRequest, - GetProofForCommitmentResponse, GetTransactionByHashRequest, - GetTransactionByHashResponse, SendTxRequest, SendTxResponse, + GetLastSeenL2BlockAtIndexerRequest, GetProgramIdsRequest, GetProgramIdsResponse, + GetProofForCommitmentRequest, GetProofForCommitmentResponse, + GetTransactionByHashRequest, GetTransactionByHashResponse, SendTxRequest, + SendTxResponse, }, }, transaction::{EncodedTransaction, NSSATransaction}, @@ -347,4 +348,22 @@ impl SequencerClient { Ok(resp_deser) } + + /// Get last seen l2 block at indexer + pub async fn get_last_seen_l2_block_at_indexer( + &self, + ) -> Result { + let last_req = GetLastSeenL2BlockAtIndexerRequest {}; + + let req = serde_json::to_value(last_req).unwrap(); + + let resp = self + .call_method_with_payload("get_last_seen_l2_block_at_indexer", req) + .await + .unwrap(); + + let resp_deser = serde_json::from_value(resp).unwrap(); + + Ok(resp_deser) + } } diff --git a/indexer/Cargo.toml b/indexer/Cargo.toml index 6d05bed5..b3ad6f3d 100644 --- a/indexer/Cargo.toml +++ b/indexer/Cargo.toml @@ -31,3 +31,4 @@ indicatif = { version = "0.18.3", features = ["improved_unicode"] } risc0-zkvm.workspace = true url.workspace = true nomos-core.workspace = true +tokio-retry.workspace = true diff --git a/indexer/src/config.rs b/indexer/src/config.rs index 1ab102f8..d37bb423 100644 --- a/indexer/src/config.rs +++ b/indexer/src/config.rs @@ -3,4 +3,6 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct IndexerConfig { pub resubscribe_interval: u64, + pub start_delay: u64, + pub limit_retry: usize, } diff --git a/indexer/src/lib.rs b/indexer/src/lib.rs index 8fd2c9c5..9b713eee 100644 --- a/indexer/src/lib.rs +++ b/indexer/src/lib.rs @@ -10,6 +10,7 @@ use nomos_core::mantle::{ ops::channel::{ChannelId, inscribe::InscriptionOp}, }; use tokio::sync::{RwLock, mpsc::Sender}; +use tokio_retry::Retry; use url::Url; use crate::{config::IndexerConfig, message::IndexerToSequencerMessage, state::IndexerState}; @@ -49,54 +50,66 @@ impl IndexerCore { } pub async fn subscribe_parse_block_stream(&self) -> Result<()> { - let mut stream_pinned = Box::pin( - self.bedrock_client - .0 - .get_lib_stream(self.bedrock_url.clone()) - .await?, - ); + loop { + let mut stream_pinned = Box::pin( + self.bedrock_client + .0 + .get_lib_stream(self.bedrock_url.clone()) + .await?, + ); - info!("Block stream joined"); + info!("Block stream joined"); - while let Some(block_info) = stream_pinned.next().await { - let header_id = block_info.header_id; + while let Some(block_info) = stream_pinned.next().await { + let header_id = block_info.header_id; - info!("Observed L1 block at height {}", block_info.height); + info!("Observed L1 block at height {}", block_info.height); - if let Some(l1_block) = self - .bedrock_client - .0 - .get_block_by_id(self.bedrock_url.clone(), header_id) + // Simple retry strategy on requests + let strategy = + tokio_retry::strategy::FibonacciBackoff::from_millis(self.config.start_delay) + .take(self.config.limit_retry); + + if let Some(l1_block) = Retry::spawn(strategy, || { + self.bedrock_client + .0 + .get_block_by_id(self.bedrock_url.clone(), header_id) + }) .await? - { - info!("Extracted L1 block at height {}", block_info.height); + { + info!("Extracted L1 block at height {}", block_info.height); - let l2_blocks_parsed = - parse_blocks(l1_block.into_transactions().into_iter(), &self.channel_id); + let l2_blocks_parsed = + parse_blocks(l1_block.into_transactions().into_iter(), &self.channel_id); - for l2_block in l2_blocks_parsed { - // State modification, will be updated in future - { - let mut guard = self.state.latest_seen_block.write().await; - if l2_block.block_id > *guard { - *guard = l2_block.block_id; + for l2_block in l2_blocks_parsed { + // State modification, will be updated in future + { + let mut guard = self.state.latest_seen_block.write().await; + if l2_block.block_id > *guard { + *guard = l2_block.block_id; + } } + + // Sending data into sequencer, may need to be expanded. + let message = IndexerToSequencerMessage::BlockObserved { + l1_block_id: block_info.height, + l2_block_height: l2_block.block_id, + }; + + self.channel_sender.send(message.clone()).await?; + + info!("Sent message {:#?} to sequencer", message); } - - // Sending data into sequencer, may need to be expanded. - let message = IndexerToSequencerMessage::BlockObserved { - l1_block_id: block_info.height, - l2_block_height: l2_block.block_id, - }; - - self.channel_sender.send(message.clone()).await?; - - info!("Sent message {:#?} to sequencer", message); } } - } - Ok(()) + // Refetch stream after delay + tokio::time::sleep(std::time::Duration::from_millis( + self.config.resubscribe_interval, + )) + .await; + } } } diff --git a/integration_tests/configs/sequencer/bedrock_local_attached/sequencer_config.json b/integration_tests/configs/sequencer/bedrock_local_attached/sequencer_config.json index 7212ce36..80013751 100644 --- a/integration_tests/configs/sequencer/bedrock_local_attached/sequencer_config.json +++ b/integration_tests/configs/sequencer/bedrock_local_attached/sequencer_config.json @@ -156,12 +156,14 @@ 37 ], "bedrock_config": { - "channel_id": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a", + "channel_id": "0101010101010101010101010101010101010101010101010101010101010101", "node_url": "http://127.0.0.1:8080", "user": "user", "password": null, "indexer_config": { - "resubscribe_interval": 1000 + "resubscribe_interval": 1000, + "start_delay": 1000, + "limit_retry": 10 } } } diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index af8758e4..a2afb11b 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -215,12 +215,9 @@ impl Drop for TestContext { } = self; sequencer_loop_handle.abort(); - match indexer_loop_handle { - Some(handle) => { - handle.abort(); - } - None => {} - }; + if let Some(handle) = indexer_loop_handle { + handle.abort(); + } // Can't wait here as Drop can't be async, but anyway stop signal should be sent sequencer_server_handle.stop(true).now_or_never(); diff --git a/integration_tests/tests/indexer.rs b/integration_tests/tests/indexer.rs index d82e8960..12e011ff 100644 --- a/integration_tests/tests/indexer.rs +++ b/integration_tests/tests/indexer.rs @@ -6,17 +6,21 @@ use tokio::test; #[test] async fn indexer_run_local_node() -> Result<()> { println!("Waiting 20 seconds for L1 node to start producing"); - tokio::time::sleep(std::time::Duration::from_secs(2)).await; + tokio::time::sleep(std::time::Duration::from_secs(30)).await; let ctx = TestContext::new_bedrock_local_attached().await?; info!("Let's observe behaviour"); - tokio::time::sleep(std::time::Duration::from_secs(300)).await; + tokio::time::sleep(std::time::Duration::from_secs(600)).await; - let gen_id = ctx.sequencer_client().get_genesis_id().await.unwrap(); + let gen_id = ctx + .sequencer_client() + .get_last_seen_l2_block_at_indexer() + .await + .unwrap(); - info!("btw, gen id is {gen_id:?}"); + info!("Last seen L2 block at indexer is {}", gen_id.last_block); Ok(()) } diff --git a/sequencer_core/Cargo.toml b/sequencer_core/Cargo.toml index 85e36632..4ef1e8f6 100644 --- a/sequencer_core/Cargo.toml +++ b/sequencer_core/Cargo.toml @@ -21,7 +21,7 @@ log.workspace = true tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } bedrock_client.workspace = true key-management-system-service.workspace = true -nomos-core.workspace=true +nomos-core.workspace = true rand.workspace = true reqwest.workspace = true borsh.workspace = true diff --git a/sequencer_core/src/block_settlement_client.rs b/sequencer_core/src/block_settlement_client.rs index 1964f37f..ca10695d 100644 --- a/sequencer_core/src/block_settlement_client.rs +++ b/sequencer_core/src/block_settlement_client.rs @@ -26,7 +26,7 @@ impl BlockSettlementClient { .expect("Signing key should load or be created successfully"); let bedrock_node_url = Url::parse(&config.node_url).expect("Bedrock URL should be a valid URL"); - let bedrock_channel_id = ChannelId::from(config.channel_id); + let bedrock_channel_id = config.channel_id; let bedrock_client = BedrockClient::new(None).expect("Bedrock client should be able to initialize"); Self { @@ -78,7 +78,8 @@ impl BlockSettlementClient { pub async fn post_and_wait(&self, block_data: &HashableBlockData) -> Result { let msg_id: MsgId = { let mut this = [0; 32]; - this[0..8].copy_from_slice(&block_data.block_id.to_le_bytes()); + // Bandaid solution + this[0..8].copy_from_slice(&(block_data.block_id - 2).to_le_bytes()); this.into() }; diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index 05c6342d..2c0ed866 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -16,10 +16,10 @@ use common::{ GetBlockDataRequest, GetBlockDataResponse, GetBlockRangeDataRequest, GetBlockRangeDataResponse, GetGenesisIdRequest, GetGenesisIdResponse, GetInitialTestnetAccountsRequest, GetLastBlockRequest, GetLastBlockResponse, - GetProgramIdsRequest, GetProgramIdsResponse, GetProofForCommitmentRequest, - GetProofForCommitmentResponse, GetTransactionByHashRequest, - GetTransactionByHashResponse, HelloRequest, HelloResponse, SendTxRequest, - SendTxResponse, + GetLastSeenL2BlockAtIndexerRequest, GetProgramIdsRequest, GetProgramIdsResponse, + GetProofForCommitmentRequest, GetProofForCommitmentResponse, + GetTransactionByHashRequest, GetTransactionByHashResponse, HelloRequest, HelloResponse, + SendTxRequest, SendTxResponse, }, }, transaction::{EncodedTransaction, NSSATransaction}, @@ -44,6 +44,7 @@ pub const GET_ACCOUNTS_NONCES: &str = "get_accounts_nonces"; pub const GET_ACCOUNT: &str = "get_account"; pub const GET_PROOF_FOR_COMMITMENT: &str = "get_proof_for_commitment"; pub const GET_PROGRAM_IDS: &str = "get_program_ids"; +pub const GET_LAST_SEEN_L2_BLOCK_AT_INDEXER: &str = "get_last_seen_l2_block_at_indexer"; pub const HELLO_FROM_SEQUENCER: &str = "HELLO_FROM_SEQUENCER"; @@ -314,6 +315,27 @@ impl JsonHandler { respond(response) } + async fn process_get_last_seen_l2_block_at_indexer( + &self, + request: Request, + ) -> Result { + let _get_last_req = GetLastSeenL2BlockAtIndexerRequest::parse(Some(request.params))?; + + let last_block = { + if let Some(indexer_state) = &self.indexer_state { + let state = indexer_state.lock().await; + + *state.state.latest_seen_block.read().await + } else { + 0 + } + }; + + let response = GetLastBlockResponse { last_block }; + + respond(response) + } + pub async fn process_request_internal(&self, request: Request) -> Result { match request.method.as_ref() { HELLO => self.process_temp_hello(request).await, @@ -329,6 +351,10 @@ impl JsonHandler { GET_TRANSACTION_BY_HASH => self.process_get_transaction_by_hash(request).await, GET_PROOF_FOR_COMMITMENT => self.process_get_proof_by_commitment(request).await, GET_PROGRAM_IDS => self.process_get_program_ids(request).await, + GET_LAST_SEEN_L2_BLOCK_AT_INDEXER => { + self.process_get_last_seen_l2_block_at_indexer(request) + .await + } _ => Err(RpcErr(RpcError::method_not_found(request.method))), } } @@ -397,6 +423,8 @@ mod tests { password: None, indexer_config: IndexerConfig { resubscribe_interval: 100, + start_delay: 1000, + limit_retry: 10, }, }), } @@ -415,7 +443,7 @@ mod tests { )), sender, bedrock_config.indexer_config.clone(), - bedrock_config.channel_id.into(), + bedrock_config.channel_id, ) .unwrap(); diff --git a/sequencer_runner/src/lib.rs b/sequencer_runner/src/lib.rs index b65675c4..16303db7 100644 --- a/sequencer_runner/src/lib.rs +++ b/sequencer_runner/src/lib.rs @@ -43,7 +43,7 @@ pub async fn startup_sequencer( )), sender, bedrock_config.indexer_config.clone(), - bedrock_config.channel_id.into(), + bedrock_config.channel_id, )?; info!("Indexer core set up"); From 342809c8308b0816f1584f63017ae4d28bc380e4 Mon Sep 17 00:00:00 2001 From: Pravdyvy Date: Fri, 16 Jan 2026 16:19:59 +0200 Subject: [PATCH 08/18] fix: machete fix for indexer --- Cargo.lock | 16 ---------------- indexer/Cargo.toml | 16 ---------------- 2 files changed, 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e2392385..ebd947ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2869,29 +2869,13 @@ name = "indexer" version = "0.1.0" dependencies = [ "anyhow", - "async-stream", - "base58", - "base64", "bedrock_client", "borsh", - "bytemuck", - "clap", "common", - "env_logger", "futures", - "hex", - "indicatif", - "itertools 0.14.0", - "key_protocol", "log", "nomos-core", - "nssa", - "nssa_core", - "rand 0.8.5", - "risc0-zkvm", "serde", - "serde_json", - "sha2", "tokio", "tokio-retry", "url", diff --git a/indexer/Cargo.toml b/indexer/Cargo.toml index b3ad6f3d..fd8f7382 100644 --- a/indexer/Cargo.toml +++ b/indexer/Cargo.toml @@ -4,31 +4,15 @@ version = "0.1.0" edition = "2024" [dependencies] -nssa_core.workspace = true -nssa.workspace = true common.workspace = true bedrock_client.workspace = true -key_protocol.workspace = true anyhow.workspace = true -serde_json.workspace = true -env_logger.workspace = true log.workspace = true serde.workspace = true tokio.workspace = true -clap.workspace = true -base64.workspace = true -bytemuck.workspace = true borsh.workspace = true -base58.workspace = true -hex.workspace = true -rand.workspace = true -itertools.workspace = true -sha2.workspace = true futures.workspace = true -async-stream = "0.3.6" -indicatif = { version = "0.18.3", features = ["improved_unicode"] } -risc0-zkvm.workspace = true url.workspace = true nomos-core.workspace = true tokio-retry.workspace = true From f3dcda346cc016436515f05deca5dc7cfbc10bdd Mon Sep 17 00:00:00 2001 From: Pravdyvy Date: Mon, 19 Jan 2026 13:55:31 +0200 Subject: [PATCH 09/18] fix: ci test 1 --- .github/workflows/ci.yml | 27 ------------------- indexer/src/lib.rs | 5 ++-- indexer/src/state.rs | 2 +- integration_tests/tests/indexer.rs | 8 +++--- sequencer_core/src/block_settlement_client.rs | 5 ++-- sequencer_rpc/src/lib.rs | 6 ++--- sequencer_rpc/src/net_utils.rs | 4 +-- sequencer_rpc/src/process.rs | 7 +++-- .../configs/debug/sequencer_config.json | 11 ++++++-- sequencer_runner/src/lib.rs | 16 +++++------ 10 files changed, 34 insertions(+), 57 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 800b0422..72794bdf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -127,33 +127,6 @@ jobs: RUST_LOG: "info" run: cargo test -p integration_tests -- --exact private::private_transfer_to_owned_account - indexer-test: - runs-on: ubuntu-latest - timeout-minutes: 60 - steps: - - uses: actions/checkout@v5 - with: - ref: ${{ github.head_ref }} - - - uses: ./.github/actions/install-system-deps - - - uses: ./.github/actions/install-risc0 - - - name: Install active toolchain - run: rustup install - - - name: Test indexer run - env: - RUST_LOG: "info" - run: | - git clone https://github.com/logos-blockchain/logos-blockchain.git - cd logos-blockchain - chmod 777 ./scripts/setup-nomos-circuits.sh && ./scripts/setup-nomos-circuits.sh - cargo build --all-features --all-targets - CONSENSUS_SLOT_TIME=5 POL_PROOF_DEV_MODE=true target/debug/nomos-node nodes/nomos-node/config-one-node.yaml --dev-mode-reset-chain-clock > /dev/null 2>&1 - cd .. - cargo test -p integration_tests -- --exact indexer_run_local_node - artifacts: runs-on: ubuntu-latest timeout-minutes: 60 diff --git a/indexer/src/lib.rs b/indexer/src/lib.rs index 9b713eee..b7d70dab 100644 --- a/indexer/src/lib.rs +++ b/indexer/src/lib.rs @@ -3,8 +3,8 @@ use std::sync::Arc; use anyhow::Result; use bedrock_client::{BasicAuthCredentials, BedrockClient}; use common::block::HashableBlockData; -use futures::StreamExt; -use log::info; +use futures::{StreamExt, TryFutureExt}; +use log::{info, warn}; use nomos_core::mantle::{ Op, SignedMantleTx, ops::channel::{ChannelId, inscribe::InscriptionOp}, @@ -74,6 +74,7 @@ impl IndexerCore { self.bedrock_client .0 .get_block_by_id(self.bedrock_url.clone(), header_id) + .inspect_err(|err| warn!("Block fetching failed with err: {err:#?}")) }) .await? { diff --git a/indexer/src/state.rs b/indexer/src/state.rs index b2aa48a5..bd05971f 100644 --- a/indexer/src/state.rs +++ b/indexer/src/state.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use tokio::sync::RwLock; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct IndexerState { // Only one field for now, for testing. pub latest_seen_block: Arc>, diff --git a/integration_tests/tests/indexer.rs b/integration_tests/tests/indexer.rs index 12e011ff..120a85c1 100644 --- a/integration_tests/tests/indexer.rs +++ b/integration_tests/tests/indexer.rs @@ -5,14 +5,11 @@ use tokio::test; #[test] async fn indexer_run_local_node() -> Result<()> { - println!("Waiting 20 seconds for L1 node to start producing"); - tokio::time::sleep(std::time::Duration::from_secs(30)).await; - let ctx = TestContext::new_bedrock_local_attached().await?; info!("Let's observe behaviour"); - tokio::time::sleep(std::time::Duration::from_secs(600)).await; + tokio::time::sleep(std::time::Duration::from_secs(180)).await; let gen_id = ctx .sequencer_client() @@ -20,6 +17,9 @@ async fn indexer_run_local_node() -> Result<()> { .await .unwrap(); + // Checking, that some blocks are landed on bedrock + assert!(gen_id.last_block > 0); + info!("Last seen L2 block at indexer is {}", gen_id.last_block); Ok(()) diff --git a/sequencer_core/src/block_settlement_client.rs b/sequencer_core/src/block_settlement_client.rs index 2a82e47a..16b33107 100644 --- a/sequencer_core/src/block_settlement_client.rs +++ b/sequencer_core/src/block_settlement_client.rs @@ -87,9 +87,8 @@ impl BlockSettlementClient { .post_transaction(self.bedrock_node_url.clone(), tx.clone()) .await?; - match tx.mantle_tx.ops.first() { - Some(Op::ChannelInscribe(inscribe)) => self.last_message_id = inscribe.id(), - _ => {} + if let Some(Op::ChannelInscribe(inscribe)) = tx.mantle_tx.ops.first() { + self.last_message_id = inscribe.id() } Ok(block_data.block_id) diff --git a/sequencer_rpc/src/lib.rs b/sequencer_rpc/src/lib.rs index d66392c8..4f39f957 100644 --- a/sequencer_rpc/src/lib.rs +++ b/sequencer_rpc/src/lib.rs @@ -8,7 +8,7 @@ use common::{ rpc_primitives::errors::{RpcError, RpcErrorKind}, transaction::EncodedTransaction, }; -use indexer::IndexerCore; +use indexer::state::IndexerState; use mempool::MemPoolHandle; pub use net_utils::*; use sequencer_core::SequencerCore; @@ -21,9 +21,9 @@ use self::types::err_rpc::RpcErr; // ToDo: Add necessary fields pub struct JsonHandler { sequencer_state: Arc>, - // No functionality for now. + // No meaningfull functionality for now. #[allow(unused)] - indexer_state: Option>>, + indexer_state: Option, mempool_handle: MemPoolHandle, } diff --git a/sequencer_rpc/src/net_utils.rs b/sequencer_rpc/src/net_utils.rs index 8803831e..0198a8dc 100644 --- a/sequencer_rpc/src/net_utils.rs +++ b/sequencer_rpc/src/net_utils.rs @@ -7,7 +7,7 @@ use common::{ transaction::EncodedTransaction, }; use futures::{Future, FutureExt}; -use indexer::IndexerCore; +use indexer::state::IndexerState; use log::info; use mempool::MemPoolHandle; use sequencer_core::SequencerCore; @@ -47,7 +47,7 @@ pub fn new_http_server( config: RpcConfig, seuquencer_core: Arc>, mempool_handle: MemPoolHandle, - indexer_core: Option>>, + indexer_core: Option, ) -> io::Result<(actix_web::dev::Server, SocketAddr)> { let RpcConfig { addr, diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index 2c0ed866..797cbe52 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -323,9 +323,9 @@ impl JsonHandler { let last_block = { if let Some(indexer_state) = &self.indexer_state { - let state = indexer_state.lock().await; + let last_seen_block = indexer_state.latest_seen_block.read().await; - *state.state.latest_seen_block.read().await + *last_seen_block } else { 0 } @@ -474,12 +474,11 @@ mod tests { .unwrap(); let sequencer_core = Arc::new(Mutex::new(sequencer_core)); - let indexer_core = Arc::new(Mutex::new(indexer_core)); ( JsonHandler { sequencer_state: sequencer_core, - indexer_state: Some(indexer_core), + indexer_state: Some(indexer_core.state.clone()), mempool_handle, }, initial_accounts, diff --git a/sequencer_runner/configs/debug/sequencer_config.json b/sequencer_runner/configs/debug/sequencer_config.json index ad43ba65..d7cce5d0 100644 --- a/sequencer_runner/configs/debug/sequencer_config.json +++ b/sequencer_runner/configs/debug/sequencer_config.json @@ -156,7 +156,14 @@ 37 ], "bedrock_config": { - "channel_id": [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], - "node_url": "http://localhost:8080" + "channel_id": "0101010101010101010101010101010101010101010101010101010101010101", + "node_url": "http://localhost:8080", + "user": "user", + "password": null, + "indexer_config": { + "resubscribe_interval": 1000, + "start_delay": 1000, + "limit_retry": 10 + } } } diff --git a/sequencer_runner/src/lib.rs b/sequencer_runner/src/lib.rs index 16303db7..ffb95806 100644 --- a/sequencer_runner/src/lib.rs +++ b/sequencer_runner/src/lib.rs @@ -6,7 +6,7 @@ use bedrock_client::BasicAuthCredentials; use clap::Parser; use common::rpc_primitives::RpcConfig; use indexer::IndexerCore; -use log::info; +use log::{error, info}; use sequencer_core::{SequencerCore, config::SequencerConfig}; use sequencer_rpc::new_http_server; use tokio::{sync::Mutex, task::JoinHandle}; @@ -59,14 +59,14 @@ pub async fn startup_sequencer( info!("Sequencer core set up"); - let indexer_core_wrapped = indexer_core.map(|core| Arc::new(Mutex::new(core))); + let indexer_state_wrapped = indexer_core.as_ref().map(|core| core.state.clone()); let seq_core_wrapped = Arc::new(Mutex::new(sequencer_core)); let (http_server, addr) = new_http_server( RpcConfig::with_port(port), Arc::clone(&seq_core_wrapped), mempool_handle, - indexer_core_wrapped.clone(), + indexer_state_wrapped, )?; info!("HTTP server started"); let http_server_handle = http_server.handle(); @@ -94,13 +94,11 @@ pub async fn startup_sequencer( } }); - let indexer_loop_handle = indexer_core_wrapped.map(|indexer_core_wrapped| { + let indexer_loop_handle = indexer_core.map(|indexer_core| { tokio::spawn(async move { - { - let indexer_guard = indexer_core_wrapped.lock().await; - let res = indexer_guard.subscribe_parse_block_stream().await; - - info!("Indexer loop res is {res:#?}"); + match indexer_core.subscribe_parse_block_stream().await { + Ok(()) => unreachable!(), + Err(err) => error!("Indexer loop failed with error: {err:#?}"), } Ok(()) From b143beef37db04174135738e94e9af8ae66b0abf Mon Sep 17 00:00:00 2001 From: Pravdyvy Date: Mon, 19 Jan 2026 14:10:16 +0200 Subject: [PATCH 10/18] fix: ci fix 1 --- Cargo.lock | 1 - artifacts/program_methods/amm.bin | Bin 460028 -> 460004 bytes .../authenticated_transfer.bin | Bin 379876 -> 379900 bytes artifacts/program_methods/pinata.bin | Bin 382256 -> 382264 bytes artifacts/program_methods/pinata_token.bin | Bin 390164 -> 390140 bytes .../privacy_preserving_circuit.bin | Bin 470812 -> 470820 bytes artifacts/program_methods/token.bin | Bin 418452 -> 418488 bytes artifacts/test_program_methods/burner.bin | Bin 376680 -> 376704 bytes .../test_program_methods/chain_caller.bin | Bin 390400 -> 390408 bytes artifacts/test_program_methods/claimer.bin | Bin 375604 -> 375596 bytes .../test_program_methods/data_changer.bin | Bin 378312 -> 378304 bytes .../test_program_methods/extra_output.bin | Bin 375676 -> 375668 bytes artifacts/test_program_methods/minter.bin | Bin 375616 -> 375580 bytes .../test_program_methods/missing_output.bin | Bin 375768 -> 375764 bytes .../modified_transfer.bin | Bin 379156 -> 379164 bytes .../test_program_methods/nonce_changer.bin | Bin 375696 -> 375700 bytes artifacts/test_program_methods/noop.bin | Bin 375392 -> 375412 bytes .../program_owner_changer.bin | Bin 375616 -> 375620 bytes .../simple_balance_transfer.bin | Bin 377508 -> 377500 bytes integration_tests/Cargo.toml | 1 - 20 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ebd947ec..1e7135fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2939,7 +2939,6 @@ dependencies = [ "env_logger", "futures", "hex", - "indexer", "key_protocol", "log", "nssa", diff --git a/artifacts/program_methods/amm.bin b/artifacts/program_methods/amm.bin index 354e6556b683b6d7ce832c9cfacefc12589ceacd..b908a30cb6a27c978ea8f75d8b4a19d12e501211 100644 GIT binary patch delta 79525 zcmZ794Sbi=`@r#Yf43fxq|yV!)`KQP2q6q13`<2a=?P0i7*g>a4I#wh8$t*nM6n@$ zLkRtU=4S{+R4hUxgxLRc-S;^=*UtU=|Niqn*L5E5bD#U+d+(vGH|4CmDQ8wrH1LjH zdq$Pd9d$)<^kh{{@iEb3Ra=XXj2>P*aLDf6qYhOi7rYr|SLIGTGBS%tPkie5==!R5 ziw}#gts1=ez&6Fkd{_2SCKojOMws^+}2FaLk}JGb!vhb=$2`-V=fwlh_&vQ1`Q zB#Ap6d|Xe{sr3yT7SCV))ppT^i!19-Y8`E}xbE}sBC6D^IzHNP=jvUkcm4LJ>iTU> zW>#Epg{xQ9fA!F+p8G zR8_7%F=Y;|s#`rhbMO_>_L+)(qHc?qeRXq`s#sZ7{B@61;U|mBzkV_+ReM8K?)ttd zQ(0BSm%?kSCa>?^W>ZtscNG=aRLyt)T|2d^&i%K!s%q={J(C=BMODGK`=rceRVDIe zQq@fPa$(g{`Eo(kM)`7nRnB*O8DCW-U&d5TlP{yH7Rr~is#eLD5moIP_%gg|pnN&4 zs!YC|S~XX`6jiN|FDF!Ol`qFt6>Q+kF;ykb^w5;gV z=48CRPBwK&Z+3$RP8RAMXBh->gQWU`=@$#eZ-ja&Ga{`Sp-!#w0^o% z>%yqh^{qJ2txeZQB4Wp6n%YFWq^7@I-K%XhC@WKZN;D;9e$1>mCE9P7(eYAPoz?qw zGre~db!yGBipwfiWhM=eI%mqZBfIdcOv853K`B$0$!!;Pscyf0bX6+aP(5RZs4HJH z^LC87Mh%&o9iy+J^_e*xqyMG~v#U!xMR&GJ75iXoYz6Qajb=J@K(Cqx~iRPBM)ZBL52r!vD&jtSbuP0SPxiFQtztW4<;IgICJW(|pUOT9ThQ&%i=x;)dbI65Z!J+pjR)MMw`k<)uG zi^kpD%4GG*~zRqT*=x>Su>USy5*HAyN0t`=>=GW$u>$+IMI)F7y0p z{MS=MDeE#c>R!FWu;{XE&WKFq2 zowjRbdgczv>e=I=RL@>fij{3LxzcmRqnW|yL_KyZJbdxCS4Ta24apjJTXySC_xECi zTuhRjhcYwHk+nJ?v*a9^?KAVn$n3n7skkp1kSRDT>XE8wn<+jkn$RZhqVTFr?O9RxHp!`U zQD#k?(K?e|67}7=VoTOuQP%XnM`c}X3K=`&it`FfGlPkzDw;CoCDAph!i|~DCDG9- z^L=K(+0l@s<=U~CS!YM5r_Ab1!`ZB|+J`bZqvVLK%nTS6?U8wV4Cg`nvC;mSm1Cm* z)g0iPQf*9pQ0}R&8y_7Q*{jy6nRe$z-=}J?$c%n6>Q$X{esl!OdvtY4X>@3mD(rIO zoC#6&oC&D~wRtPrg%!cUnMjcjCt!(bF8m*Vpi_)o<;S^D;u?UBhjD63m$%Yj+FG9&n}ew&K(Om1PG8OZ;N zhv%8)L-Nevp?RhQ#G`mDdR z)0=-Yrb9<&CY222@GZs+*e=hkl$~NwAL82fd8Wp?|DVRx|D9`!I2IDW1W(?9S+w=* z@q!(hNt?gqFJtC#{M!fYX@+5>&OgdKHVN2)Fv|XiRaq*J-A%OuV@>Y*~$~PiOjGgd1@g) zO0zbeqF@FEc1p~TxI?=P{*hq*WkUVAd9!l4v|@);v?`N2J8lOFRoQyh1ann z$JzS3c3=R^0Bb#NZxlWsZ%6-e!Gjc3s)RLoD?Zy+=&@ted=ZcVjmK*l&=?zk44=;c z+p4VdqP(GQ-N6HKo$) zJ4a@G55MI8LqAK&a|a;m5}AeAP53dm=qT@(CEhbRqH;jzG446L=9!Il_y_J9nT`AQ zG`Y6lCcMbkKg}Gq8wX%_mYm&@)p!*Xlx-{QzB@b00NoP04KKj5grvi^xjafSz_B*} z#LUOvWL?%{_8xf@$i{-%pYybj_wjgge&&L;S$&T?n*CqYE6=PVQ<^)Nd7GS{XI9we zyLaalqV75yuVNl&_U4qd@reDMy+`%uYqLg1c{L;#@543T?#uqWL}qhAo++`(vopij zXPpy$TK&TMtbMc7ANS(QyT3nMhV_n2_5uFv`wFkawYGZ4JviNu@yBKuE*#{K#of4A zc_p4rzB_h1_lZnDA3x2MP%!_%JTrjRD?49>^}$N*&9NBB1(3X5?i2}Rcb;5xj( z`n&@;33-xt*TDt2SowS0>*&1ZJHg=xav>eWk+TQ-FI;rIo9Uq`bL&Bz78J;pTV~(` zT(11q!I9a68FHs%uR>M|9iDFU&%-6;HxH=#(Z;NyQM9T0&tI~pM(Kfhk=b$zPY!lQ zFFKU#=IPuE?GDxB8Cd$4869vKw;r5p{SfYda$bDoB>q2KU*zM_Ku!x)e9;Kkd7nt^}5qXG}vsXGi63fG^YoLbRn|z|*y=#x<5RS|oSFIfudJ`qtMXYo7toL0kvq9O%~bcOdb~n;F6|VO z?&;f_GRl*!wOMnL`)~Q$*tAwT8@J|StMj+P zers%Mr!4vV2KoD|xU_#@5sz$clL{k(3TFisMk!1F%pm`E6_*a~RF?ez1o>|i`TiM4 zW7Atfgnbk!>1C=wDl`TaHmkT)_(NIpd!5p9kNaT1H8%BCmi#kX=BLd_l^`9Qtt=I8 zZdt+Hs^XGAOIh+?4f1PMT=L&k&Nk`BrcFVGUsZxs_+42#*yYrgd%PR=TVqq6vg98Z ztGEp4N@dBP8{|Kz;*$TcvgE&`@>&0_&3h_AD*T_aRQN?z zko@0NT=KUlOa89hk;|H=q_xS#ers&%>7C|E*w{2UsBn@`pk8CsDaw+6S&)B)ic9`g z%98&;kpEC~JU;&$o8~tcn0P?%;(q0McF^2AaD(y(SnuKgRDBu1`^7xolJ6cpK2~uV z&|j{8a{Xy-{!t0ifEnT^Oe*xoy2E@Gm;AkyCBHbxAFAS#f4X(tzf_nSRJbOnaILcB zKNjRaq2kiPLS@N+FUbGDB%bWQRHzFo{1jAZRB_4QtSlXLJgwyn?S%c-*wjr~@(+pg zUH`1=fhs{dI8s?EjK(#W`!z8Rx4XjoJlt7%0`7IPy%X~)tqS+!*)rKu=5CymCLw;& zKtin)V3+VF?up}P2jV|kyZ9z79XS7r^&0sd`>nC*Pi5Jmorm(uq{Eed4|b(sxpFS< zuR7?7E0p)Zy2CxO-x`~EdmgvfmOYTi(VMaK=gx{xhDPbQ!4A}thm$jh$!8e*M2-to zgEHciaouD;;NoBaLsh;U!qb(d{*`#8sy}5Y$A6aEqpO1kD^vs0U{?kx`EJ0|Ra`ol zkK1152lzN1p!_5rq5O23f_XH^+bfQ9%6y8;Rl?`EW~y&+HQsoNecmI#?J#3D<9I;$ z06YyJVA~so7peG7xJ)^{gn|-P@D=Ws_8opB6)L>fDSg-m*?6=0I6Hem^oI^OszDZbtWewz#Bxk|r!+9Ua48#MH zSGK#H&YJ}a+@dPMG9%6pU|CfCYy;n7Sw!wL!PqnSjKCThot1R(2G$>DvPbYfjrPx_ zzMN&pr~#*C)s7AJ=vkMe-=r-0PY3ynd|a--jZKSvL45oDG^p^o zic9`#W$7T|C5t{J+49n*d24KHqb&J*HRs3I|JG(7l^`ALrz{nQH&>8WTbmIoF8OCE zOa8PVKds`Df1R`RFBR^mV1+uZ=HcAy{AunBQM`g($h_^qjr+JMexzL@DM_iW|_a7HsK*9N^ z_Ke>OOTt}v7Is&*T3n%K++j%CckmYllT^Y#c#g6e z!G%OQ3pXgY#@#A?huh%XAw5ldyT|?UKDeXxIk+%Q!EUzTW(r2(QPwZucGvp`YjCOZ zD|jjS?#lKpF22F%Z@}LX-@~@onYSpjRlF-sZ&d|5%WIY!eFMAVY!1OV+rVIJ$i~|q zEQc)FQsxvahs=2hKD*d^81BG;T>OkP`TQeO6J`T%_x%~66 z%!u;@EHmI-hKoLSZe=b$ll51u3N9rQ0_t>TiuPFeD!ku7&18~csV|7}!(ROl5{=%eD&L0@IbKR(Dm zQN<}pk;pAT&NPH!X#y>aBIs7W|oReewDK1FADM(tGML9s2qR(|0t;NiAs

^EM)C`(4MB1^e=b2QVQ0QP#Pr-F1L0S-p55Z+3(v?V^3}p zVizyK>+oO-WI$uAU3@&go(|<1Qu@0M*Wk3fy}m?2!Oiw5m6T5BBz6sS!9~P7+YWBA zcJbTravJPrJ9r6?Cf~)E;xgs`;GA33{r?TAFwA}{fD!(PC*kkK%5# z{At~4Tw)h*o2H=R4u4*sXYCRuNQFE7fXeW!D({Q&;Mv}n;=9xgUXE8OPsSUS(^Dzf zq6)6TJ=nu!OPOnNsd6Qrtb8M$p?ov0SH2a?jJft^VRcB;riuc;H8yR3RumrsIfinK z&cJdA;tLO+fn^Wm7|Jny56cX6i<11_C45JW8Jlc98p{s$wfPTY*`Z{O@cDlo1+qtO z(eyc+??F<*c>AK9WphJvjWxHqA1 zh?%lvOPROuAmYx;u?)!heO!j+m9Vt;o3)E?!7@PSzi~Id3oAb|#+EYwQcy=i3P}Td z@~%XjY`loXGGga_vFwra{#bUv`9Q1>$pGxP#-@Wtb4Zw>S**YKnA}f+9D)w^7}a4p z1a8$&v9EOBP+SbCAO;xN^rtf^7KfX3Lkz5X>ejSni^fH&Qr zXL4yU{&`gEWH0zpPTb)E|2&X7FR_ca!bNBJHM1`skK>=3qs5W9*8}SQe>Mf#BqSRz z2=HJ!a1EB>$;90v%ix77J{Rvh!hhU;2iK|i3fzhK4m23wjPT|M(!PVO6l9aY495w5 z&S#N4=;H;rRt?|`JWa(*@I2))_;>Q%=l_{_nTp?mSEW_K-4yg-0NdLEypGL0KY+LK zd^LbZT&Uu|<2A(H6z7#Pl+VH|snFIA=mtFEAwQs7a2p03 zUy3=VFXCw`{tBL_T#J_}zg5cl_dOlB1~!qP*TAp1K~?x2n}_`X{>1H+x8lPYkUNe0 zOyD8*5ue`|uTHwASR zw4p@ypxD|a48^hroKMHH$eho_atNJEu&jFLbFiFM&SSBx8SAt;mjXF2T|z0Av%q;G zmh;;AA}q()`4TLL%()!vOYfD~Z;ee;l;h9;cT=#22HKJ(Gw?d@Hs3Frw*$Y62a)eS zi2RD@lOI2T(84Jb6DOTUW@zBk@iN!G-2cv^VD6*7!_j!D^10RvX;Ci4O+h@H-PQSR z@Jdy`9p0q8BkuQD(jV(TGF>PrwFTl`aK$3OM`s1`(SgU|IjVjs9`>|JPy~Xcq#7xtRK*Yc#!g?xJda*yij?Xb<#ikcx{kSiECAbo3LR`BwJ)|!=06@ zaE|gEENjT+-yitl#I}D1@F)edRD~z;O66y9gYpu*N%H9G`E(dx`zhG( za(+FB1n0}JoHq5gfyG$%*fsDQmKl*D$YVFZ${X)-U+b%|?BD?FHfjgtvAk!R0=-J} z1Mh`v)GF?WJ1_RD`arx=`A|HAW1ig1TA7pZ2(<=I!R^!xr-x9GuL_3Q1{g3~D{}_c zhhQZ38$Ygx^&#kWG2fh~!+s=1saEC!EIU|eKj>tz^w%Md^DA4QQ6MAQB`Gkwa13P+ z;`5XSF2OT#wry~<8h}jUG^}Uf+Q5}Kdx@X1oA3hqOJ<1AUyCW2{DM!Y!5fud4g5yn zxA0b#{~liUqHpg5T(4ZOE%(3AbOBz4H>nC=<5ktZ!EbR+jrR|MHwFF`7peR$%3OaV z^EU<4RD!vrrL*ut6>l4OJG@-QJK#0SJK?R$JL3T_#XBI^|H$l4!HA?FcCWyD1}?zm zDt|v*r+g4Dd)d#>VSx*q9p8WWeJ~1Us0xGeI^~mb#VfwS(*mCncqE>y^3TCrl*i-Q zOKC5;|3zkkD`5X+MlK3`30@)<;*DSY!W)&R;sLMvctzmr1JA&P6T5gjEa$oN4tSArNBr(cegCH*_bgwb8_rkW1?wx}ZrE>p(+TS<;l1bb zN{35xXM5%Q4$F0=fl6|7>VF>Z5!0OKgQKM2S_gShoGb6sxw!a#uWslw6E_VXgX54`Uxtoo{a$0t_1H22%Y32M5 zmb1e7Pb{l?zU^Sf1q^^S(%-u4MC#+ww!OzD^7DUkOuE|+H<0iycJJ#8%36;2jlgGK z*fPE;@XZ&sjQ3K9Ozs_pm$Lr!Dm|72?ZJ4RTE!>hZvXMC{50H8`Ha9NfzQE%RsQ%i z1+!Jb1iVoBqQI90z5>^({Hb`Ias}R^d_C?^;_iMalU_u@Ot%I&jlRIM-5S8HFXNd{ zc|TmQT!M86V*-!IxwU@ACg8!ZH#==EqM*SSn9BlB4m=fic%!)iQxSMN9>4(OHN_4* zW6cs{OPS}e>`=0C|6fAEcnbPZA{UactdoS4`3B1jIj_euL(UC&KHi4{so$wQv5R-X zGGor&@j4t|*wR!OWD8uv@z`*T+?DN8YZt#9%Q1AGjP-?Ss^m9sjZN2JePMcqhf+CY znw_X%1Pw^|h))Ij!yw1~gB_ z<+1${KOnjOXPL)Tf;8|3?xyzeEnK3!9P2%PU)7fm{)_b^?|3;kGqp&&2HqLhNIbd!@dV@wm=9S-J@7O} z=w33Nj2oyhh^V{+y4N~R#}5X67;jMncpSHV)1Ng9aRE;Hr-A2efot%^z%Su4H-!vg z9WJGTau$&cXwVgjUHuaR7vY&|07G!iGWGudbP852^CLXVI=-3E!An8>wZO0At*ZXp zxc^(ez4vj2a$W4SPxv@USc&JU3afFqcYOXgc)ap=fj0*J8JDa4&3IN?75quTI^}<{ zOnI^~$yX+8!Z{nyQlIVG;MppFTfA^zUw?Z%U&TA%bT9Sud7Y$!O6Y=DDtE{Fw9CPM z;|H0rKJD6a+DV7*`Qjuj{Y6xgv+lObxc^HB?z|j4l_wrnZ7~UQVY&^=Y0}TS^)$W} zt3Dgvgk_K0+Xh!)IV2S}fBn^5xR`-l8_&N6lV4yx@tSnY3eS+B8|b0-P|oWkus%e` z1U^pkm-{tx60T4##tW2(r-Oo#fzQUZs=`=2<6Ymu`FMqLS>Q_om*X`mKYbMi{onHq zUV|H$qGaRy{}MmjyAlslz7dxy-;DJdxfT13U)RHGjik-qlezgYqEfQtm~X?)My9A& zlz2RrDPLyejT|BwkXtkRa|mSs&X-}?ffLA=MYaUXfMplNRcb)-`~PQy5kIdIs9_Fyp%PuO??07{&gP(n<>bRyHA<7 z@yh@D8F(KrcZ-bt-*K-GeEe@bnYjC~+WV@+G{=@Q`FJ+*WJ{U7@IrBN|4o^FC@_US zVLvP*bQStz8G!S_cqQJ30(s~hYwhCa;;)IvS4QHqtX;ec|4dwd{vdAPHCx~kUdN3j zL^i(B+QomyGGoraU|Dp@*2?^b^&;Ma{l<@UVivJ|{@@w#*b1)AH0aLb8?Y?8Rn(H} z!kbu*d8Pe0U34u&W5%+H$2Su!Q@oS)2UrFa?*Q)+yIx0qoZO6BnSbK}+5Y9U*?CIK zW4e3b9=KQ?^FFxqDF5>Ur{Ps9egb9a5S~$fLc#w{p%5KLqd%jar?kK;x#JXC2)7VkYn79QAJ$&`r@4b<;ibuuzQi& ziBB}*WQ)ws(>VURU{?|fR6-BjU%3w+q+EbUEANNPl@GEWWCt)kh|fp|1-IZz)xaz~ zTlp?rqkOORY}-Nmt6Ro91@40DRsHlX6l_!lxwzmXKSjN9k#gU_`v%@0my=&$2UKb8 zru?Rs=I1{tm`4ToL1Lq|tI!yDGhU_!^e5g_?+5%Z?)M$qp?l|Z3Ja_-+V-W=3M z#id{H>NH9Q_z(&SdQl^UlsV8z}Mo1D*pytze;`nzlDOF)xLvSf$s`D2N$XQ`vcFzqgDJ- zoPCbFH}D5|an3os|97|FzbP2;r5}K)WRI0w1>QFB_IRes?}!I|<=g8TI7ggT3A6xPU!&J2(dCuJHpp52pvKf{7GpPYQe)o~H6A2cC*&t9S(- z$N<{KD~tyYT=BIZz@kdl-yBu&0twnL2YwYVRmZSF;-mc{?Q}h_WK{eJoUP&$@aDCC z02f`)`qu@Q1qoN+A{ua0_z*5%XWx8s)x6fC6R z6iVd0Kh)YK9FFBQbS}hlnkHK-a}1VM?c&Gb9OVce=@efCESaTB4N8Yfge7%cJbv{)`au> zxC9?!^MAK?@jtOFQs=E$9#Z2i&84=9f<+W0m)ch5{247DvoFAYYizm@>&NT~m+)IK zJQWWlNj@pv&s#5fiq5zGjfWh0gmXT0I&Vyf7ZZ=)|4&jK$aDHkJeO6TY>~Mm@N8VC z;`iVM>wW$Mc$M-affslu_y4CTSmvgL8F>aTSAGub4<1Xf-x`~$v7V7fF6B?FGQdJs zrOe2GX7E!L3@D#U;+LE2)4%NTClq9VYrn(6vODgk#7QTSIVtcdxHI`KJ`@)ykHE#s zXIuA@0nq+kE}qYS-JJ>JqL4gm! z)4sRgY^KROaj~kO34AXeui_8lxeaOG;d}}%XN23>5q^MIsS5SDjzyUr$6J|yY`iE+ zj_Dz{w9G#u@KJb+YVSBaKTU`3=5h%IlQ#GPU4fUW_(OQ3@(P^K3?v)Bl3^XMa%SYT znJwdI1RjagTUCSCQ&3EU1+*xubemffyAIk1-Vw_oaPcmIyW@6a{adj?IA8hVTe<(| z{@@!ZCqetFz|-&um47XsOM|T$fh?+pxDt1>{uB?!ZiZ90QD4RPzK!#*TqTSkVZKV3 zj+f%dHuwzg_mdy+V!RM%b9X5~`6Re2&_p)S=IVf{;{mteULBpbgK zi{(0CoirK*;xPl=oJNW8YNrG zJdfopaDD;HS>RlQ*Yxv#1;0w%oh9E|yZjAU7Pa$6yfQh&a{p^(ex{(zhUE_o{DS?~ z*z_CL_xJBQ@>f<_#REu^`}sbX@RLwnTDgA3KAro&EXsI5y!-7`9>v#{nORAE=9Th_ZEa*U7UOw+~ zbIU*DdN!7`YF8V70Lxi*u=N(VgR=kf0J6&+$$9BM@1Jc=m@P761D}gcqrWa(fVU`L zjB|eR@$$e|Sxf(H{NNY``VgeC-}s{uSRaDxRa|!9DLhbhxG3;qJXytS65IY6z$+BY zPzkkop7L9GmGXOmKM4FkTsz+X3df#zavCdNhx`Ak?*BK&1%AqI#wEXc-yZl*JWa(j zcsZ*)UK5;Euj6_Ze;aRBeqWqc1$9BfM>u=4AHYhyOnEh~SNAGGaHS zkKumGbvRe~FT6hxM}qbac(RIj4%`(lQSlr+OAY9Fym6~< zzX(_U<2@uD6r3LTOuST87=`E2fqUY)3AbfcyBS)7+eJO>nafYj;BG3u4wtKVdP7j~ zQ{YBCLsj@4*DC*w>y^!2E!`?`TioFD(`I`L`ltMeI|l9=cxOCFM~nWcD`n)2`PT;+~;b9Az8 zeR==i)fU8eGr1J&1bl7aO1zK;JJOEa@1MnT;Yl`b-*_dKo0-H{S-bdGSk4;RSpWQl zBL#9=C0oj@$8y>^H%NRx?;mh6@m3^A2RmgFyZml=IPrEiezdiVAB)Ej-%k3M1}?S* zF5yyKmL$aS`>kDk9#(5!r43CZP{|w+$Ti_Bt$8uUZ zuf}p3Ij_O`DR(WFHRIynVp%iJ8?dYi=Z#p_jP%dOZz543izL}n<`*o-*!edscQfZL zSng)de`9_7{uld=Z@tcGdHWuHJHN=pg)7~TkF)ZGv&$@g=96O_Ur2bO$)zOH07Ugf938EaPLqaB;WZQrV1`5VPj`MW#w2_ zZL+1zl~`7_^Ax;EU5Kv6vPfOL0=LEIQXp&ONoyB>I!(bORbdg9Rq7HJ<5|itVwpl0 ze+kPmbzX{VmH&g~5V`mpc#U%UEebZNg5_AI*j0ER%Q1BRFP1~*{2`V@+>xc>UU4S0S$0O_9&f23eRcRvHa z;AN$L267(ev6?+hw#ejJy8)L6@v8z)!~dZ@_r&xVmKn46|HwS$3gR9j^9&xQI$VrL zE7#x|%C81~Bk)^zzRG_O*E66rYli(#navc;*`-JG9{!1!Pw+F)>k;mL_;8zlDlS#= zDY!=YQ9M|=4v$d&8xNSk&;Plb%^vf4h}_i=V6VXa0v~{9s{8@Cfezg3`*FAtM|Qxs z;oLmmeii;@LfR+1M!`xo!VTE;@D+ZtE}=zPqz69QGJa^_!*OR-|7iTH8qkG!K)R>z z;8F@Us{!1POH}+}>k|5v0elw3zYP2}E>rct#TzH~jDONv4tc?2tiNGpzTk2S7N`nS zaE)@>dbu6IYeD?Yz;EN_s{Z@98v}5M{P)LL|C4(88Tgxo3T5+nVmIYSSkpfnzqT9r zI6Pa`KMBw6?b|QLtCWX7&iO9|H8dwvnh6r-27VB4QVq<yI5|^p^=|L0}=lc#$z=PE>D#!WC z58?sJ@8S7-`uZPOPqs6<(-SS@JGXS&>`K8>)j$utO1Tdnp*lPb=k)a*o?-324R=ov ze<1KfxL zWlpy;lg)3rKFw2de?Ne3cymz?v&K&G<#?frPr<8{ z)41({>hpgk1=Cdr&*DJ``VN-h!OAaL_p*EZdl3IS@V~fR)z5l{)A~U5`M)g%<{;nU z_ISw;8r2wE*_8Q(VW_KR5m4XS~TBz&qC z;SqQtYarQp;J~sboCgO!IdCz~Il|`;$8*$aT#=^WT?#mB;?wFWoKXp%;Kx-wdXDGz z;vS~XPT?>-pwM@4CazQ-6?k0W^m!C4P!%TPo9HlQ2Xr^SQ4Q#IJVSXSUU{q^KqEHC zdH;@YQ9F?LyfL?7?oG18X;VbO-KxPW@mBFAV%#;3asT%6|#3 zX*T!&*C<%mT);0H;VsI`aj(I?!~YYX=>0#uQGLE&g=!K12! zt@ttJK1;Y8p5*tq0N< z1IuaW8Yl@oCh&N?QRPp-ONRLR7h!osYrg+q<_h8-csCz-DqbcPY`g-m818*N9>^P! zWJ{Ub@#vvGJ{!+dz6UQjll%WNdm;Iff-NdxEiN188)(24%0J>o%D+hdSv|~_?BvpW z#EZs!$PCgv|4W$(xKIuFBD{IHy8mBB!R*t0hm-NJGrX_H^OUc{E9iiy_PB$m@&D8@ zUx`1)DI3qKPWCvNA^t@zJn(!z|0i3@Y!@VS2;2!TXUbdy-EhfB?_F_)au58O8o()d zAT#9Z55=p}B)CPEra-39B~%8!Dez3ZK;_?ohn4vHcjMX0_u+PD`}jPZE>Z=LQc$V< zBrf75(O!&5j$u6>sNRbGiwl(V`4~NZwC`YVEU)R3EoJ)QZ}17Wy^%Gne<^SYXOkce zI*-QEq4PK_19CnOUx^1(AOoCb?c!BfUb{KpjpenT^F1}3|MD8l70e~!Q#^(OY49Cu z7k>}))~Y%G|FFE}a`8GWZ@HX5!t$2P`4c=@`Li?yHL740UatHVUa9;ImbYB4!Sz_) zayd8PUzC5q^3uu0f5P&P$vNFffxO#w1)H(F+jaf}%e!Fbzi<&ggaVnN-Y+F~@qApT zz9X_1zMgzp6_S6twarhPGbwnSgdJ@{rL}ADMl3Iroo~kSGTHf7+<>zvkPd3BUHldN z1M!rNe`}q@dH=tGf*(}_onKDu8t95Qsrb>>E`BWjRmCS+yZB}JcjE3s^?-F8m!JQ8 zh=RXKa3fq{?Hc$1|D!ti%i6{N!A4#A@?S~p;(OsN6+hit;;euE*-Z*sli)^JY3&-g z5pSm&c;4E@U%>5Ee2uk>uf;nOclUz!OA{ykGk_f_kWaU+LTB7bHF%`8iyw{UMWXYu zSYA>&561G6%K0QbSostz@09HQH)V!Uut@zx<1j4mY+M6pV0kCxJQB;tb?39Oe0X&p zjpfs_^EfO|(az^#d5X68e{PQy$YZxlD8usD?0hkn$7bhCu{h`(Z4PXfFOJmS;fc1z4T|ou9(;Nz3^eykerd z|3628Jh8ZhC0HIPoU5@sP&mJg<+Gymt61*$&b4@z@|##*zq|O`cvza(@2=oo3d*eH zr(joLzcn^}fc5tUzv72V<$FNOxp2sjaCGAPg!0*MGan4Z|5Nql`-Hy+?f;J5{L>Hr zKyc8()}VpzueKau4)z;={|D;<_E2#dz>!!#9}Iex{&m6eBrIh{y3wj!%P+yRd7v1C z<(0~7)=8&)R15qzp06H2-p5On>+nkDk6&f~r9i&5BOM&@TFZn1fe*u5R0D;$-x#^K z$rhPo@igTVt;_9G_LD*U*>q6wJf5c-sKzVC`VN-jP0FuhnXzO`nPph7p?9#~_-DAW zK1AtD@8mBYu}A&Ll11}>s)8J|@3C~~4#C#{v>ZTG+tS(CjPnED26s?ykNbP4O($D0 zfO>KW&TE-qCI-F;*R#j&W;F+QxX?dEzk$nq2j-o?@8OxvaX$ZkK*1`t=>Ei|LHL7ylf~lsm7+deyJNers%6i}kAi zwmDA!vdXjGY`Mp618;|y(P3L!l|4KV=bzuh_7Ryw10RkDsrb=&f%5UVK`i?(O%}NV z>mh-MVN>cmJQFWh9);UY@bPhhO9M~D`Q#`4Gk{4HEKm(xj_Z`C1WpIO4sTKUH{wOi zn0u^$&N|*dW^f5+Ms5ETR8vr({#xD3c!fH~uVQ_SYq8%No8H9w7{7N1e+P^y?iD2$ zw%%OmWQLYeNiKAc;C1Km{y)C5QSdtj(qa5@Je4v7s-k#6xm1wf@pxNxC~Iad)_dF# z_y?>9{FACLciTo>l)km6-H9x-StUpZJ2KRq3;Z$d61Y1qQ1RXHeC3{aiE@76y>VJ6 z^rK*zs&F74IMEN_P+X*ZWZ*%8kH;k{zX;bW4_U_gTc-+6CqetHz@zYHl|K%bmH7dd z;%Ukk2EH`#<;z%qGgXBtB(%NIH<-rVlq>NnwJ2}IUn<{>^)bH{`;EVThxHWzjSrdz}9?%PcYjA%x;8*d2i~NsnZN*DfJRQBo6OSrrjq9l3 zu5^PXj@!wA7}m{r9qw$s0&h_r?C`cRxfl10|5mKzpN1!2;%D>>yvjRmN?I0}F@eY9 zZkPH7Cg7RZcwdAoC;9vTJ-A$X8NQDJ<=6rLglll}){W2q-QM9+O2Mu+;b`2@oRBhQ zc#CS_ZroXQP>WaLgKYgDBz}qOAZ5C6Y-bZc*v5~-D_ni~{9i^vFADay33uaRE`fM0 z9kMBSH(edU2 zjsY{W0xwq$d>FVMXW!-r^ch~pfT_y=@ze9~^PSOIKE4f}sodTfb zxzsPBqr|F#;{u<6+g|4L%klU-`~a>BJPi*dKkZ&VKTd&MD3XnzRK{{0aDE!gb-;NM zmg|7?Vl3AI=NGYD2b^ERWq4l-WQNuzPWE4(0l%d{&Qn)m1D5mDc_Wt7)cI#Dr>XNV zSWZ*t->{sf&RejYWzK)&VUyJ7|9>fv)66AAE0PO|b2hG2@ith_YZu=Z%X#g*J(lZ& za|hg6)=0eZ6BM{tS`~Dmpuci=JV-eQ%UR(X*d5DhL5Dm2d3rM*pnN-?Q|05c@dD+0 zaINwKc)9W;c%||JJnb&uUixVY=BR?_u^!e&;JKgAPu-< zI56;0fd}EaD*pt$PWcp^Ki9W6H1G&*x&NI-!Dv-sG+uYVZ{S><^MLmSc#!hNxJJ1= z@Ku4Q;mtOm_0KODQc(P$@8AYJOZgUD_>hm!!Zpfw1->`%{dlv=e;9A%EGU%EzjB_h zprG^--@%7?zVau5zX<##u2cDI1AmMA&G+s9(CqmB6PceV7^V__#o3Sg3R`f#@;`x7 zAGD0O!X+wyTRh+~-`)gr}Fdg ztmk}#d*Fr2dj;+n_<%ar|58<900|AshvTivN8@GB`woxC^~yzohXfvm&0=5w%sN?r zs-T1fxiTdiPdK=MHR0ZD-em3KGx71noo~lm)px(|#ImMb{4QLgJSRnC* z0cqe?*Fct8%KL%%TA!7?#VX)|MRuS+mE^6~OIR+=8|_=KMfdTCN*GW!ae2Sch-JX7 ztke6?<u`StTq5n8 zC~f+Fm=s{P$m|<}@qFjK8vensHvc%wR`GXmd&XD|b8m8P=PCc6#Oa`W+(F80u}%h@GJj(kK)lK4|9>SRA^)F${?eiz$ zjmnn?p5iU%Uu3SPpk0k`;5uBSd?TKxJTveefoJ17m46T3r2GJ`d0G04??1c@ZZ4pV z0WApp6kZiqNaBm|M&%dqz*qbZyo^UE|0nP==eU15e20PxRbd5QzSKAPA>O3?N#HL6 ze~GhS_4U`{ZpsaKJWl#&06*FS**}?qUjqMzWf3JCs~Rsq$@_1-RK@?r-3om?`iM)l zif7|b%hmh;HWYlO61K%(C~uFyRPKP+D0jkND|f+bmAm70$~pL3x&OO8+MR;$R6-Bj zpxhg8P|nBSEANH%X}k~iTVvCHSf9q7?}^OUX&Ok8CD-OND3CqkN*w!MEPLR*8p|HI z{M>t^c*^7Nl2LywmKk#KN3raXtKWdXRo;txL7HRGT;W0rWDi}1>$n%l9y+&wkb48p zvI8u}a)_Mo#BvDT0P3;KpsU|?9^Y$b(e=Jk{40D>+2U z{qgcE?$7;ta08K%PM!?AIl=bv_ZxB6U6)%W29c_n(w0ra)G0vZc&WEUVV} zbUa!4Oe|-OiLaYXG zOyJ{ix`RqMiGtdz?fsh5@^ZXP#i!tU+^msZr;+Ir{7Yb&-=IJ6%4C%Q&w`G zryk(%|FEj#zwg6&KjdNl#t$==q80hvFdNGuk!2=b8)-`%Zy4q zEfpT5K&H$ke1m1mTm!xNyE<~r;`5mNQY?ooeh9@+VL4gA&55Y^7j|hBB;N$Qzm46bhQ!d7v#c}`4z;FuMHTVuk20kb7SlmnHpC9-F z{1t~Je$U5BxeIT`x$%7RGbMN?AAZx_Y{3r{6j6|G-Q`O@I$?M1J_^_U;0JhI;FAKM zg4d}0p?Ky-Uw;JNnCA1p>tH$st5k>2;7zK+;=nb5U%}=_-$5;Ir~DSqQGO5S|ETW& zA5btrCDh|G<=mvegF-De+;|{&q{Mlk}YL^l?3JA@iM%NJtTQwC3g9} zupDFOK6o8=_lnc3U3@s+a-`26fzz}4`GT`3_=N`I^PWX>gSBhmCM=7{c_!}6A={1u zxe``eyZFm^cj9~4_Z}^J!U#DIo{XoL8RA_B0bXk+wRp^dokvivKd4r;;Fc3D;m*l+M>;R&BE@@mA#<@vsUXzZv(s z*85hx?R4*1X$nTFf+{?%(kI-F_08iR?6=0Ixme#jj^vq8){wgt=RX$3r)@6BRGt~H zz%qbh8j(wLx`qN7Ko1h6;4dr#*wcF8<9q{wJse>xT!Uo~>#S?B?BTaIKgAz+n8g6{ zZ2ZAB{DfnKyWU@zw%~f@o?p{}@+o+; z@>Mwd23Mc^|9lD-{pve-BJeYTpTm#R;O-__bYECQwv_o2%K(#&zYB_GfX?f%3^3m0 z^Z$1g$Ov7+_gF^g{3F(DU=#Kmzt@BH8u(qsWy(8!!14-Y&t@Y#5Y${&lDZ|NcXK>sv(J_Xr-#s#sHJ?zB4hZvIhe zyfd}stoaE`hw-HvAH!K7JFuILS2lOZj?&*l_-^9-{flHu-={#&KwaREaITu6m3Y!$ zJ*X{PWLD!@%HQCUzkU2WJXv|8b-e%5Kx2@w8P8>e@g8%`cVC-~IO#BDdf+*-2XXgY zTCH8Y7)yQUp;#Y+(=nUvpD8($0(}VH9q+ri=Joo?OE9`?yl@GuR)gB#$@4Km|?I2|i z!O}sprOZIA_xMQcx5lQUaf_e-KUO8k9*)I&0Otq30MAwfyg2Zsc$JD@8F&g#54go2 zg+T|aIrx4%9 z#xJpU@p3GO+?s#?hl07P!o$|C!lPK$g!2L%AELN`51+VKv5!9^@tOXi^D}E#e--|T zc=FxwH2?ljLsH-pw#D5!W-NhtN)NPl@c~$lsqSIO-*H3B8R(4dCfEPQrmhs|8Q9q;#J9_1ah*EtP7Hi9ZkOezoPYTYmu=^L1}@y* zyQJCi{U} z?UW~?c!a~U6HikO$P_*vbnv8#%M3mpbg)RprT!N|{V#1i-hXM}>!5*kK?6H{-*OK- zV!t&u?S%Cnc2jW~z%fDnF28x0Pt_&KOqT;dxR|oYgR9pt|R8aq!IPUr< z;klrJB|!sU1r2Yl8+Vg9e@r8hBpCrTz;+{TdaQ0jv$`fBS>(pM(uT0~><| zx^8Sag*#)vH8$;v^$g~!xD4PVtWVqGjqJZJ7)nA}bBnFb>8b(Q!!xn&VCr#ETz?RC z;)hg~FCE^9%T#+etGKjxYnlSx;4GCO4ZMQOR0FT6xHRxO*7cXExYYj{m#O-{sJPTm z|3-msV2etS273P3vVlFY-x{0t#JYZgic9@7@Je;1ENSVqIfsHZDq%d{s5}9;>*z1F z7vTZQmtnn!S75(!>BV}0<9<&DG@7JTD$UytRY6Alc+lXJDlSv@bkN`;6_@&71ogjE zajE~cuAkpkkG;!^*Zp#E_xE(170)o1-@nIe@S4O|&C zFh#|sfvZ&mQolmQrT$Yv{by8M>Obe}%k?LV*QS2|q=B!32EI{oX<)r?Agh_M23tSrp8;%C3DQ8btm4wZt60~sRdK2R z1J;-7O@V)HU(-M^~_q=P@P?%)Eh-O}JZ=2339TUEYv*yk6n?dsl85O`m#``iB) zxBlV-)7W$%3A)3Xx%@++G}y~_IDoj@q{DG|tLm^c@I>69lUpPFl?`0k+57S|1^Hcl z!4#}Vcs2H0V^amz1ALIr4KjcN`?+Dd%9jB?6SVi7ipvbAmjn$~<6f(CO(DH@uKKWAYD?%K-Z_6*|8J%dciF;)R05AI9?^ zNq)nkqx}BcrxYx_IM2vG#U=?~;tlo53y2;04sMfF*eTD9wjJL3Tk zuE##Fwa?l|$~c3Of9<*c`Okm;|3ClN+c@wYIZGw*WTZj51b^|98M9 z5orY5;Aj5<7w<3gZ(hmr2an>xUws*SR8n}yQLylJt-k%`3wQkrRk1g;a=kYQCXPje z!RuRn<~JV<{PzTc_K_(WImN;ie%9(cT)zJgfX6=E>U-?iV*Jy`0Y?N5LH=?CL&xI> z=e|{RCL4rD0Gsdkd9+0EAAkq2;z|a-x(E~QZ{<}mGk*VxXu-f`v(a)3|2JTB2lQac zp&tP5`zW@!#JA-nsO`h8zE#Hl7zFlWBn0kToA-Jd_|r@J`>q}?_Q=4Cmtw+cGV#t4 zAOO4-?;9DpX*F6lZkt-MZs7-r|8#9%T;l&KU~?hCTo*Fieq_;gAo4pvPC2@I`>lC6!akJ%2Y~bIIhP@^gNEfBq#F6^CvDJe-;S zzH-3RcwoN0=7AD^_3I!5e>^2LzXrVOy{*1SN+H|+dT;=rS5p2}z|*&I30C$mzYCU^ z1buEZz5(gRDVaL<4e0-W%~; zfZsax`9Z+u`-Q6UKL%{BdQX%bUB3nTH+p;VJKjbrKez>Y3n{Ml{GLm|LL5HkKO3JP z0^A2xtl&=qz8Jsb4Tj`e@I%1Q11>%%eJ=stI_-1172lAEf(7W#WnyA0?7z9ST3NPJ zE`^jriXSUkb}?XcCDY7l2)qxlx#Rg2%wXVW0h>-H2zL&TTm}}SEvMS!55VS5=ipJm z(>eH->`ibmZk{@9-VfLmqt7cR*nByp8U((%gzpAyx?C$$`ZD0@GIQw_{rPo%S&sjo zfY16rt-ehq{5)WD#q;MSoDE+&(=fadu>E(fj^6({;OQ&4dk3WcPjT9nLf8(mZKeta z4h*3T@pizS(+v+-N8rduTYaM?hi(UKZrfc~5RmnK4-d|IxRu}EH!Qs?21fuJJvFdO zX4>|@ydLJZe@g9s0C?t--<_Ja(@Y54cIg? zJyyck+zvx@3^-t5bN)Yu2c~K@Q3~Cy@0iK*?*g7KG#A_f)BOKieG?_Zn*rbQe5-F& z34a>!Bmdm$yQ5sts&|4T&rU7ya=`LmiqkSb|38ce7aNbKM6mu{K=_?j{-soA#eWX? zg6CR&2TO$G?=}sJQ^)gRz!!o5r~3SlAcQZ#M=TeV0{+SOrU19Td=^^TXqyBPaN(gCO`9AhLxRlq(*&7kUf0nqV7X(~!8eobY{sO-JMfCCeXq-%L~d`|qD=ijM*|-y@biR!;EX zeUMTZo`*^TRvrS&uE(!pom^1-3Bcw{r`9hnV5;Hq9Go&l?*eSTpr|rTPXjhzKvcn- zK8)k`vs0G!V}Nl-H0vCv;X@!`KZ?<$FeIM@Z0>&DQcn0&z~<)C`r`@$Zv6;^4z|47 z^JO0eZ=Zq7RkHZSk3qBGz*Ls-u8+e`z%+lVT;MxDiPQBM{nn=kc8(-84j7jSb$Fs2 z&pkW3=7u)aC;pOLVEZBn-N>Ol4r3~0tT#O~u+3(n;|UQsVc>X<8wE!md}iS9kFgyV z`9UbdBnraBOS%5cw+Gt#;qMHbKA1|HI4+Yhi`|fW`tY|0HtOS^8~78Oy0M7eDDjmO zD@9}T(%DCzd~P7^AM%6P^J70?t}kQ3Dx zTR+5yTYfa~*(LRBV)tD|+P3S5jsl@dx++m=c;D|4o`r$%K|&l-FZCl4Ztfeq+5ELH z4tDR^-HurrB_3xUldhClpHPX!|3aE1)OTc?E@Uv9GdPlL}7+tHoj8{=IKU^ z8%Ilh+d0-!y~VQ@FZY5l4wNIJzzb6zRVtxhdq3HavCz~a%bEp? zm&$X|_TLd=2gM%K(cU-OYZ#hMNicU8hFdI@79*dtY0u_SDQ<*+_6zfj7h+-KIrQ+V z1x;Yorgwt$>f?#Kwozb}K7SKAb9>`B4n3G<7@OYFFCS0dv?AK6uAST`9UeODz)h3B zx7Ty`1qa?5>+2$NioR|US%ecMR$fXYFO@u0k<|B|Ku*mPg>x%OxF?nHc;qUnLO+l} zkcgB~nYJM_ps6&|jiVV~$Y}1IF|}aKvU}gYU`MoPZ_=Ja?4^synZG^zY3>7H##!b@ zae*a7GNAAjDDx98eUBy)=YEt*FV9+?aGRg&|f~8VIX_A1#A@sx8g(`$N^d)U~j?c!C#zyAuSK~-l9do-g9COXX z%^voMxpU^uG9O(gIia&q{gDrmrFzdwGB}uev2aAp;9;kMiuDU8lhHX3?Ll(toQGfoTnKRBnd-8sS4R@07wW5r$w`Z6D6GDBoQ&vuhKZHUc&_3iQl73k0d*56^}vA0<34o- zvlM^#fMp5FXaKj>oB!bMRoKpOzS=+3%fW7e%F2GFO7tJdp zh%jdkpKr8&{1meCRSjaN7p)+ZnTp_kCUMMgItVZD7sBVZ+tJZR=C~c>F=J>}s}CK0 zo-wv|D0n{W5N>>j;rPzqfyiej1a5w#%5C(jB%RQr>4im=4d7g#|LcL_b&a$LsfUKi zYwB#0ZEVurYlt<+W%%orWG6zBnVLAIZRgI`mFZF-rLO|`hAi@YD2$&*9^971Mbb+N z8ac?+=+7)CYv)m|p*gB`Xf-)apJS0lTN=^xJme@D*)&=oSWQN^H;rl=ZK_1TNI>%o zLXWN?E9NkEWDQw2=i!BG$m$h!$3pIs>Pyy;k&(KODb=^FAxr1r`^p+JwuMp{CFEbY z?Em_v(LqGp;E&=wsx>+{iX+0uFb3`MxBrtvQS~4m?9n zKj&3t9SnkSH+NyYL23`^6t481T8q1D2d@P=YdPa`XB z*jg3_DoR7fQsst6t~!lu?bp$1P?jf8C;OJgiV06RPz$ai#fzQR_pS#+lSIV67omXS z2ZC~`Au+@H!86F<+>ieD47f&fUV!w~JcVcv>kqFdgUe^XP|WUjnLZbD^WNNvKEJ+h zqL=Wr%N%|_N0$%PJRd?n>zVV&nP4~46cLW9FfbCr6JgYNSigM(Id1vvkBYT=`g%y| z-1lBHPF8k#g?4!*S9LShTx>b#=AlA$K?&t8sGp1S+zoZhHB4AtyHb;BG}Kg>5Jca(EtE2|$P&BPrK zCj!cKZV)95M}-WSAK}2@Oty0;vb6Y(gLCVW4<17iunDzi{Dx&qu4~VxRljgHS@-JM zPxBSz>4w5T*}H3BM0Xsxw&wlUw#n*x4&=e-3=Tx7RZ5r=A*2^L2!5Od)lP}EQz?;n zZWmK_k{pfW5$hNhn9N%9*iLZSJhT%~G!HdF!nQotY94FSr#%j3`coUp#&yj&k=y+F zz|vFp?+v0|yRT_SekdJZq$!RT<-mZSNy(-`&x@mo$I6LZj(WDfh?12j&wQvqM9HdU zGoKa55Z7BNSvGt4%NRcU*-A#9$~@#%6-AW{`y5K@6(*{)a-LGqA(YDnBIAfF;f7um zg}xUCUL3TY=|$zJX*68CilybyHC-_?BanI7_w;7G2(^l_S>sqfwXIF$qUbk^+^*E} zGEy}q;zqQ2$Uo)iHokzYRQ0KOFGN51P3ae|G`j|BdUNCWg; zD48BP?L0De&_;Mjg_j~yWGLhERA2Epd7lkK6uSXzF?v2+p2Yg-)E8M)WT*u!eXWD2^aa@Ia4<9LaF=n3+sA%!O~gSMp#Zeo&d)*F9mjp$qVS}U~s zEppkWrix-)cb^^4ykaWfj`c1Ls1ljPb#6bfQD zby2qu1VaS(#V3ifQOswNi)3UH24ExAw|s|8>M#5QIeA;)a9^R*#tmHt2NS&sxdCnL zdf^2f%&Y=Q18^McLSKy|s2+WaY_Nq(J!AyAjL|0K`?0?2DU#SJY8f%Aqd24^&Xm-T zKSlnZ?fEF5(gX(84UA+JPnD1%kT^iEE2)>l+ZKTzCFq?poV_FcnB{RIh#NgPa{t`O1aR@kfn|r7f-2!M@V;i zDo!FA2KxQalSeOuyeIG#7%~i~=BCJjmd9p8w@$h1bwd1!7s&mY1lJTzV{TjzPq~}B zN^6f3b{BV(o_2$Yi9INfP44&7J$ol%IKE5nKBrL^{jOB$_OFQ0pZ^}&oyAIUbik!( z3ky)dLuR@+7P+)5_FgeKz%bIqRu}>^Pf^Y&aw|yBnb7YQvzdv75WTUsk;_m$579PE zN*qVAbVZ2jK^*BH{1Z{*sSI3n;Gv06`Dy6W?n^oH#(yS@j~R!L6^F3L33FhG6W;xW zyp3^ub{pe7l?!(F zGq6KM*3d5aiW$*>pt-TEyPS6xG5;Fo!Ux}VZOs1N4I}$JQeieP=PZZj=C48 zO81{&$su%Yrw&KX3+|H_Cn(ci`mgY{*-KkLiTJ&*CPC36lRhrF>y`LlUB}ux8>lLfEU1}4j}LeR_T~YZ`m$Q{FS;9 zLwX9$gJ>)6agpWW)pe0W5NV1c5Ji;0k@0dj>$87BZqS=wAcNc7C{0sbC!lcT(ASI> zs(jW)p{$(q8nM>rf1M=yOFt(|wh70yEF+MVG1SVdc-V-&v!uC7V`zWxHlHSFuY_)+ z7Ko~W>Xq!$u-D44x!17)^@Ak8%zy-IoVsj2p`Xtqs+*xl)^_A)?&9ZS$m+UH+vOoz zOT=U{Il1S?q(DU*n-Z(7posT9bEN|z7g847bzKu==#M`^whkdf;rj{Fz)&ORM0B(M zv}avpa~8xtMc+F5eN6kEzU?S^-lj+`;BHKSNZd(TlV{^J$`F~}eI$utq|s9- z6uNep-t!Y{m44l?$v4MwUjxP~3291wFXllhA;^0&F1UlR7z>mfjU@M-YX#%j1BCAg z`w(YCqD1%M#uA^JIlFf6+Ryx*0Xhs)fx8h1&T$K=G6yr7yXtzosvJlSJ;j#Kk0C=I z9L0bJcYj-fQ>p%i_b2o{j)K##N zL6Xv>G$`{k3o9*^wPucj+w)ZYv!d+ZIirxULvsL~qyVJN0y=(rejG34CVFC1%)Zoqv2l$g=7fvDDDaTT8$*9>=n;C8w2Lg1yLJ5X;J zu+Bry#0!xRgj*&NAiI?sz&hG#8QmmA2KZjfny}GP;l$?t9fEq)v87&o zoRtotF%Yff$Qti2j7y2V>HsT^a*Yz`J5R7KwUKjo{1`@%nyVfT&%JG%q0}G6sMz&r4tbG4X9!hBTIOgj_y)&ylwM+=*6e98H@s zlDzPf(a0L}irIC?$Rj6OqvMIW%7tch+>G(#I8Do0>&9Jtc63UgjJ{)3AxWiyVkP%~3v@Y7gnw%9sv9PN+-{YjCFHMs$; z7}^y}AUMV7h$_xg-%oQanTX)j3e%jGgc3njcUnrdY&xTP>3P=BQG;P)UB4tRkCqw~ z`Wq)(=Pa%J0BZ8aY#wV~m||Ypodw$BX@<0lU2DvFzo&mRXdSS@)YyY+GgOY?jc|RF zZC$yIGMTCaii%VEA=04rQdnp^qqG^^CamBWe)WY*pP( zIcBF!vbP3>erS(%iXK{GJ>2Nmb*DqWxWu~BHl0B*EzE^NBK+j~&SC2c+fM|djELfJ zL0QjN`io1gmJJUWxdW8g(D=z=Y|PUU{k0M61RJFy>IR{g;_frdTA*9Q)>VVZ#)dx5 zya=8lsulXZ!k)^eLWA+QTrQ?x*#;-Npc%-U|lhoRHW50bL7m3b zMZsx`t}ww8L)>9caj2nyS<)56Xyx)@EKo^IBVN#jObm>N!aW{bn-!>J=DbEC0R{*) zPbURe1KgtP@EYwa)R7T_4WSU+`UcG<(+PubfL3nYT8~n0EStV$g|*g3CCWoLeZmE9 zxH}%xx2>?+Ho{*VL<;3xn5ra9^%quHr`x!K?K!xjg>C|HMy2|vE3EZ42*rK;Sm2Oy zB7`0VUL>l}km*J$jm+7d7I+N-Q3wvgw*kXhffosq*bh;2Qi1XKM2w`UMiuPSUrpU+@CE_D=mGy@H z43QDOvjAMhP9;@<#5`n?9FL-q!BIH%vCXoerm;`Cs@K$_K+Ng|yWh5R&rPN>=I|Y3 z`j@M%>^03;D<8Rru)H#cWRfp%`2))DcnEtv{fjl$p$xq*J~Ax02a6mVT2o5v+1Q`# zl~#-4D=37^5aGJ0VFHk;!-$8^KBn$pE}fY3uZRss7|yR6nVsLBB%%tg z>WF|q`*g?H#oNd79+vj*8z$TBM4!BmSo+{vYfD!5Qg3Vb{~OrnWrg?IU5p!7@BfB- zP;5a~Tnu={R8*zwg)ZcbX_DYqY15iL(YKFTPKKNCXkWlZ_y`#?DXZ9^E(k4jpfQfE z@(VR#>|6|4Z7^MlUr#7%F;up*34_}`qOVw2gF^q~Y1ZVXMov`8-#QEje~i%iKhLnf zqcdThaO9(>Tg&_PJx9rjN4~$_I=;UL&%fgHEAad)F3m*&&;R^mk2_VrXWU{o@>K9a z%vZ*Ql*NvxzdUZaLnsXjm|KNz7PP(~mep_GU_GdZH&|;nxM=(hi|i~?in!HRY6JW} zbMARmd2nk`cA(O_uII5sJNH7_~sF0!I5%!$+ccR6hsnXq35yy@`;3Rk>?%f zh!bPnZQ*dBBJ?_y=oMqeSA|0Z4_cs83GSi2!CIS9fhHYCB3wsy6qk3pk1r%NO>jRx z5Rn_ixIq~yl%oP9qH)NfN<>xME(Nq^!UBOxP4Eo1nEQ@AL*FkVbzHeb!bnAklKoD; zh%&Uup=^O$UZ9;ZIDb9TP;Oow4KUHgT~T-(V)qUDM;nn$KKK^gtX)GbTYqJvbw3RvC`@-_18#Y=pp8j_y)GC6M~OS2yr8-fL22RZ5uDpoXLBj|H7Ii5 z&z887gzu<9A7P05C4sBI#H_b2tsDN^NT}(MTPt9OB+~AVQ3z1FN}*6a1(uh%)_y`E=X_S$P-zI!fhyd}5pmfU%{ z(U3bkbcz-}f5KG*qE%(92AmYFD61RLH(Iv5&%piLMf;VFnDkb(S6SXAeWTr%kGkaP zQ=_u77R!%~{#Dk0`4LS=8MCRh;*RIn7O3 zPPWM`iX?IGqfY5$S~a<8^YX=O);Eu4ET2_`=z1h2& zve~Att+D}Mbxf7Mv3%NB zPi3V_%gXY;?V75XS60Lqb4S_qZ@V-#vUi2Il`VGvT{@?%%Kdl6?6SIV4@z<>ZY=Bm z-NC7fblC{`Qc^ZozFbqbTE1LWwpG4NEz8}+mnmgM^5xR968SQzY^i)1U$#!Zj4Nxg znJ=Tu`pB0H%8KR7@Un&SWoX%2`EpKKoqQQo)_n_K&Mq4vUy91+%9qoYuikQan@ra6 zsUDf?tmv3j;klWX+0p2x1LFO7Ff%MDhcv!er2h08N*v!nY`g{RJsx@YF+MEj*G zCf~g^N=Lmi#Zh#2RFPR7Mdx+sGP6h2dTi-4&0FO}&B}73-CH#=O)^vBCSS_*OhrfS zy)vuI3Fe!HPyf;?=LC~UX6@2UNh*3e+AmX(6&)DmW(H(MgUgraM2Ds_TboAh4|r>J zIcuTprc+*S)nq`_YIY9CyNPM@Xk^BltXJARYUFE0dFN(PzpPAQi|G1P#nwzki|EMq zrC(%qiK3ZZPKc6K@ye@yJr%G$e zySIxDiK1h4`wODIGgTd;7MZFpQMc%XOkEd_SD#GL0nsJpY7mU;f;{C@ad`H8^UQd4EuJM&@_81BL~S!q4UUR3`%qTC$B<}hcB=Hi%&ei&k*SJd<*SEA$EGqf?~jhi%)cP&m@<7c zt1gHp9vF|I;<>TeIR&kn=a^0h49x0O@NlYA*C^F0=M9s|i^up_rvHUf>9|bsg;Ce` z=8&vzQP#|^CuB`Fh2(K*iSsHR%q%0GGDl|CT_}sJV`jvt=)}yCBcqX-PG6@E%2bU^ z?U^}ZG&5G(Dl=eobl84{HT1)L7L_Ly)p&E z8AEBaOwsUYV$)<`*JM@?kJ?d*CCge_7iToNXGFBOEt{0d9U&u1W%`d`AyoXDnLZ-A zHf6SEwvS+*S(b}NMdzkU$7JS>j0UC57nzMC8CAu@oS^@oQJI=duM1dA?~IOGXLcVG z9hRvX9rY^bxZjd$8jrhTOnKF~=!nQ(&t_*@TpWF$DlE*5dMfH%o;yA|p7q|fe8hz4 z82;nTn-@%s$`?#bEvd+_Y?{v*pKK9dHUzFKAKf+U?CiZ?BiMoXNym3GC-HR&-oO0q zgR?d@iMD2*IU?)W-B*pyH{1K>n3|JAeQfP9lz zm~VRWzX9jun>7RT&4fYuW;5k2DeJ@k3WnsHwv_cBoNqFF9-ehlW{=~tT4l~ZB&&IO zbW|3%nyr~Fy|a#uR+V=-I&0HCskJ7vdsSBZJ$rtcXNnkB%0%YFF2?jMKe{UGjA-Cq zJB{geOee!JGf^sK&Wa*avOdo&$|5%vneO~A_nSO3YLCPp;9`}(M;7_NNmN$5xTrTAHTgngTt8k@*}iKDLwD+s1PaGN!I!hNJSC|IOMvirSXn zTb=cHcKWy9jA^+SGm}aNa{LZs+P26yHPn`YevB)2&o`^AkNDG=>c8zy6Tbpa--Fq; z^*_N&_GE@_{>s0MnZxmO6H)rNF(rLEnYJ>zR4Q%$pkM;S%d-{w)=>fHS`T3+^LFN$ zDb_jv7_-)J=xm1@@VXQOw0@=Dm}dXvnM&)aOw#C00O4a(X%de_Lz!FI|_3GUrI-)yiQ?$@04!~i;5_uDNpZJT+& zgok3*MLYuqyGLgAZuy4&HuN8vM<`gJj?uSx74Aj_89>1vky)bRm*9R3$j!jBxI(!W zZ)Amzwe=5g$pDxE)_UCDm3TaEPXBR1IR&#+!k@SfkF*u~>=`v&1Y|&I{0##dZR2m^ z@eDvNMH0{1D>9ei-K_iL8F*Lg+wdaX!Ia;zF6-hbe`>49Ola+o;VXC!&b5msFSGZT zSq}|7bMMG3Y@cuH?An^$CNiaMNweO&Er+(y_wzg6*3(bal=hLiiuf*e9AB2_tk0@X zrE_R^Tt~kI*W=aXxdV{DPh^&2H{oM((Fxw4NxV~XMCE{1Fzy8%^37H|{Bt@)X6qrH zOrGs`|NSDf%-0`eMpH0rf0mTpk)3!Q6O?T$^xdBwWq@u8J&TuMSwhlbK^~7&3~-Fi zpOpFJ>#V6A=N^zxfov?8!;G17p!cb`&q0|<-(+dR)BU73?k9m{awYK@A z+eJp&+Gyj;na4f{aZ1{FKKnbjOZjKtWDSe*Ye*h&FxPUsFN5}t%=Yg2W`s>%kvZqv ztP7*x%U6Dzbx3x4duOh+hxxN*YM01lAMVetfAB_JVXGf{0H^y&{@6^#h5h`oScwNH z|AFU|?~dKk2S%o+j}J04C|G<%zUj^Cm7RY9>w~pl4~|72E?{=&uRl04|DnNASQh*C zLn5=Hx|8V@JKLO5zViF5hjP;G*s-1`cZ#oDl6T=jk(qu9lW2EjNlzBaartJNZFd`% z`=Ja}#&OJ{QGDNYo`vNe+QP=Gu-rSHa}VRXi2Ee*w7Hmq=_llyrMAL<@GKIFtlJ$P znJT=*`bIo~CwzCEtHcA8oAioI=M(cA?gZx_!F949N6sGTeU9X;IMvPc;FNiif~6G5 zm0M=u2Ru#rtD_=w05jxH$HGEZ3LTzn^KZl>$Zr@>`D3+NgZbE5{^u`QGotkH{K)J$ zizf#=qqiQzb@N>Ag?5Lw;W=3Pml+*$EVmw(?|AEIe+Ume zni<9Jke`bye16)zK|!f6FkNNMs0M~(d6;z#RQKZ~I^FNy{j$3kTsHm zKZF-y9{S=n{}rCs5KpH}r&A-dwxJ+pF2beCPvATTSZMdSOMmu|0qkiToPaOEa@xyD z^)z0m2KW>1LVM@ic+b-!)13GyaW)mEW6UA_k!ESE1C=cjm)HxCizN7QBQ5v6}UkV8hGiA_9$fxU>S z9#^~?x8&aD?u9SmHN<5g((qwjSyGq!HGCx3=T+D}KX&B$JO{h0!u?#v+7>m`?`XcH zU>XH(q#e$V%x82U7gFh9RQb0%vnEH;r%)z+cOJyc1M-PsJsFt+I6RXOLf~;*wvlEcxBjXEvUqL$Kd! z>km_w3Ks_XV^mx^xJX&@?+WtoR&mKsFHi+i;q9Qp8Wooc?<-6Gjv)VU6_@;flqJ90 zS&eo$Z4RcuZ?*M@Doce68dor*Ra`n4r!4t*2Kn<_|6diC{Qpyy z{J&j(a{Xyy{!s~1AsXoSUn(4c^$Z=P;*#H8S@H)4`9oA(^3Su5`U@N-b%7ZsQM-;||;R)ZSP&_392we{_kCI6T> z-}TR`K29Y_2ZhQ~VKiQKrN3K_!!54z9*oxKR_FHZJU&^vW`wr%nNz1GK9_&ZK8s&W4 zOLfp0mnt8Kb%$NC-)id*8qC8D?KNW$A1m`)RKpjONYp382dzy zd#DCw#Ao5E>3+Zig8>Xt`Em%)QAM7@*|40nbu# z>EJQk>>5A7CAhcp(|D-zvuO$z(O`3#0giDEo~9B$$E#-e2EW8x&$7>ZUYU`UROMdr;{P_Cc#2lg$q=UnhrNX%l6{OWB=6n^G z{1M8Me_fDYs^XGA(^>kL3J+4SR-IN4aJ$%A75btGe{Zq=)-aA45dnzsi zSZf{czf{;9RQMsN@RPFSw>YoyfcC(CO#2T0reKOn_y;dg zj)rm}QO?Gjm7C(WvwVlU;=F;K%Z{UUBL+c)?U zo}j!MuO{DJ**4(;H~IYU@h0L2*!K43Ey{cqZ;R7)s$gGv&2qDEU_YGAAsA~LIL#We zrA!f)LzZkQb2gSk<~#_G9N>KpZpnaLeCYXn{+B6o1;a^@DRRC5n?t=v<3bf5hh@fG z{&*}i;yek<3^-qki#~DAF;mWG{S8nBQ%R6j>MC4?^=Wqv_8U*l%CgGu4e}SNxSVzm zDNFw9bWq`Sl^_+~RF(?sgZ!^mT=KtFmi*MP#ygOM{l@42W~x9cbO|aHsJL{{Og(@x`oTM!Iqk{agDlYjK zD@*=NmCyQbVs26iQsEY5sqna}Ao)+Kxa2QYmi!Nc{Et*z@~gd*&;P#%75?-I%v5cC zow9V0JEHNF?vMS(D;H(SKQ72GY>3DAAEvaSAh{in#*4WU#_xx@U)^J!bP}0+@lxWs z6v$6&d}rN=))yvr4Ya{U#9P}A z=32Y>zwjCwY->As8IL00#b3q6$`v^GHg*4hODYVp-wI%aKjA4jelw2Sjp7N3OS9|X zBs`rsPucMvU54kX{Cn|y%!J1AO1z!=M_K=bHx5$w|F)y)kUelSaw3)vlPzUV#v7IU zV`?C%-D2met0q7!LBy{Wh^_CtPwu{*HIvQ z$69(>S>StjAyh`#pBQaUsF({ z8vGV-&iD>D<00qzRlnCbR=tYvjVp-9Gs1b^7mvE%*FO<&RP`^#)k!`-vPFdj6x31R z-h{p-X3CN+W!}O4h&#WBWkAkraWR%x!qVRF)-L`hmH|4~;kJe1`20_qdJ3vYNKqsW zbmd)%*j4C(WyH=svFwra;aGOS`ADn}$mT1Z3@Y4=w>^+= z@@P;VDE?!e>;*r{iCaGCp9iuoPVC}MaM5{w&Gf|MaQstqv^X4heo)>2FQ6csgk<9d z0q#!+uE9(3bmDH2Ex=1v`~iH(Q2%jz4X#r04{$5ud(dEfGs4>+O#2RYQjkpoGaM%r zjAxNNQ%=l|PrrHbE$*QHfKhJua^U^hE}H?djd2k