feat: first indexer integration test

This commit is contained in:
Pravdyvy 2026-02-10 14:03:56 +02:00
parent 36407c1d43
commit 56ff66ccc1
13 changed files with 733 additions and 703 deletions

1
Cargo.lock generated
View File

@ -3449,6 +3449,7 @@ dependencies = [
"hex",
"indexer_core",
"indexer_service",
"indexer_service_rpc",
"key_protocol",
"log",
"nssa",

View File

@ -40,9 +40,6 @@ pub struct GetBlockRangeDataRequest {
#[derive(Serialize, Deserialize, Debug)]
pub struct GetGenesisIdRequest {}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetGenesisBlockRequest {}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetLastBlockRequest {}
@ -91,7 +88,6 @@ parse_request!(GetAccountsNoncesRequest);
parse_request!(GetProofForCommitmentRequest);
parse_request!(GetAccountRequest);
parse_request!(GetProgramIdsRequest);
parse_request!(GetGenesisBlockRequest);
#[derive(Serialize, Deserialize, Debug)]
pub struct HelloResponse {
@ -180,11 +176,6 @@ pub struct GetGenesisIdResponse {
pub genesis_id: u64,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetGenesisBlockResponse {
pub genesis_block_borsh_ser: Vec<u8>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetLastBlockResponse {
pub last_block: u64,

View File

@ -14,7 +14,6 @@ use super::rpc_primitives::requests::{
};
use crate::{
HashType,
block::Block,
config::BasicAuth,
error::{SequencerClientError, SequencerRpcError},
rpc_primitives::{
@ -22,11 +21,10 @@ use crate::{
requests::{
GetAccountRequest, GetAccountResponse, GetAccountsNoncesRequest,
GetAccountsNoncesResponse, GetBlockRangeDataRequest, GetBlockRangeDataResponse,
GetGenesisBlockRequest, GetGenesisBlockResponse, GetInitialTestnetAccountsResponse,
GetLastBlockRequest, GetLastBlockResponse, GetProgramIdsRequest, GetProgramIdsResponse,
GetProofForCommitmentRequest, GetProofForCommitmentResponse,
GetTransactionByHashRequest, GetTransactionByHashResponse, SendTxRequest,
SendTxResponse,
GetInitialTestnetAccountsResponse, GetLastBlockRequest, GetLastBlockResponse,
GetProgramIdsRequest, GetProgramIdsResponse, GetProofForCommitmentRequest,
GetProofForCommitmentResponse, GetTransactionByHashRequest,
GetTransactionByHashResponse, SendTxRequest, SendTxResponse,
},
},
transaction::NSSATransaction,
@ -273,24 +271,6 @@ impl SequencerClient {
Ok(resp_deser)
}
/// Get genesis block from sequencer
///
/// ToDo: Error handling
pub async fn get_genesis_block(&self) -> Result<Block, SequencerClientError> {
let genesis_req = GetGenesisBlockRequest {};
let req = serde_json::to_value(genesis_req).unwrap();
let resp = self
.call_method_with_payload("get_genesis_block", req)
.await
.unwrap();
let resp_deser = serde_json::from_value::<GetGenesisBlockResponse>(resp).unwrap();
Ok(borsh::from_slice(&resp_deser.genesis_block_borsh_ser).unwrap())
}
/// Get initial testnet accounts from sequencer
pub async fn get_initial_testnet_accounts(
&self,

View File

@ -31,9 +31,14 @@ pub struct IndexerConfig {
pub initial_accounts: Vec<AccountInitialData>,
/// List of initial commitments
pub initial_commitments: Vec<CommitmentsInitialData>,
/// Sequencers signing key
///
/// ToDo: Remove it after introducing bedrock block parsing.
/// Currently can not be removed, because indexer must start
/// chain BEFORE sequencer.
pub signing_key: [u8; 32],
pub resubscribe_interval_millis: u64,
pub bedrock_client_config: ClientConfig,
pub sequencer_client_config: ClientConfig,
pub channel_id: ChannelId,
}

View File

@ -1,8 +1,8 @@
use anyhow::Result;
use bedrock_client::BedrockClient;
use common::block::{Block, HashableBlockData};
// ToDo: Remove after testnet
use common::PINATA_BASE58;
use common::{block::Block, sequencer_client::SequencerClient};
use common::{HashType, PINATA_BASE58};
use futures::StreamExt;
use log::info;
use logos_blockchain_core::mantle::{
@ -19,19 +19,23 @@ pub mod state;
#[derive(Clone)]
pub struct IndexerCore {
pub bedrock_client: BedrockClient,
pub sequencer_client: SequencerClient,
pub config: IndexerConfig,
pub store: IndexerStore,
}
impl IndexerCore {
pub async fn new(config: IndexerConfig) -> Result<Self> {
let sequencer_client = SequencerClient::new_with_auth(
config.sequencer_client_config.addr.clone(),
config.sequencer_client_config.auth.clone(),
)?;
// ToDo: replace with correct startup
let hashable_data = HashableBlockData {
block_id: 1,
transactions: vec![],
prev_block_hash: HashType([0; 32]),
timestamp: 0,
};
let start_block = sequencer_client.get_genesis_block().await?;
let signing_key = nssa::PrivateKey::try_new(config.signing_key).unwrap();
let channel_genesis_msg_id = [0; 32];
let start_block = hashable_data.into_pending_block(&signing_key, channel_genesis_msg_id);
let initial_commitments: Vec<nssa_core::Commitment> = config
.initial_commitments
@ -66,7 +70,6 @@ impl IndexerCore {
config.bedrock_client_config.addr.clone(),
config.bedrock_client_config.auth.clone().map(Into::into),
)?,
sequencer_client,
config,
// ToDo: Implement restarts
store: IndexerStore::open_db_with_genesis(&home, Some((start_block, state)))?,

View File

@ -17,6 +17,7 @@ indexer_core.workspace = true
wallet-ffi.workspace = true
serde_json.workspace = true
token_core.workspace = true
indexer_service_rpc.workspace = true
url.workspace = true
anyhow.workspace = true

View File

@ -12,8 +12,13 @@ use wallet::config::{
InitialAccountData, InitialAccountDataPrivate, InitialAccountDataPublic, WalletConfig,
};
pub fn indexer_config(bedrock_addr: SocketAddr) -> Result<IndexerConfig> {
pub fn indexer_config(
bedrock_addr: SocketAddr,
home: PathBuf,
initial_data: &InitialData,
) -> Result<IndexerConfig> {
Ok(IndexerConfig {
home,
resubscribe_interval_millis: 1000,
bedrock_client_config: ClientConfig {
addr: addr_to_url(UrlProtocol::Http, bedrock_addr)
@ -24,6 +29,9 @@ pub fn indexer_config(bedrock_addr: SocketAddr) -> Result<IndexerConfig> {
max_retries: 10,
},
},
initial_accounts: initial_data.sequencer_initial_accounts(),
initial_commitments: initial_data.sequencer_initial_commitments(),
signing_key: [37; 32],
channel_id: bedrock_channel_id(),
})
}

View File

@ -10,6 +10,7 @@ use indexer_service::IndexerHandle;
use log::{debug, error, warn};
use nssa::{AccountId, PrivacyPreservingTransaction};
use nssa_core::Commitment;
use sequencer_core::indexer_client::{IndexerClient, IndexerClientTrait};
use sequencer_runner::SequencerHandle;
use tempfile::TempDir;
use testcontainers::compose::DockerCompose;
@ -33,10 +34,12 @@ static LOGGER: LazyLock<()> = LazyLock::new(env_logger::init);
// NOTE: Order of fields is important for proper drop order.
pub struct TestContext {
sequencer_client: SequencerClient,
indexer_client: IndexerClient,
wallet: WalletCore,
sequencer_handle: SequencerHandle,
indexer_handle: IndexerHandle,
bedrock_compose: DockerCompose,
_temp_indexer_dir: TempDir,
_temp_sequencer_dir: TempDir,
_temp_wallet_dir: TempDir,
}
@ -62,7 +65,7 @@ impl TestContext {
let (bedrock_compose, bedrock_addr) = Self::setup_bedrock_node().await?;
let indexer_handle = Self::setup_indexer(bedrock_addr)
let (indexer_handle, temp_indexer_dir) = Self::setup_indexer(bedrock_addr, &initial_data)
.await
.context("Failed to setup Indexer")?;
@ -81,15 +84,22 @@ impl TestContext {
let sequencer_url = config::addr_to_url(config::UrlProtocol::Http, sequencer_handle.addr())
.context("Failed to convert sequencer addr to URL")?;
let indexer_url = config::addr_to_url(config::UrlProtocol::Ws, indexer_handle.addr())
.context("Failed to convert indexer addr to URL")?;
let sequencer_client =
SequencerClient::new(sequencer_url).context("Failed to create sequencer client")?;
let indexer_client = IndexerClient::new(&indexer_url)
.await
.context("Failed to create indexer client")?;
Ok(Self {
sequencer_client,
indexer_client,
wallet,
bedrock_compose,
sequencer_handle,
indexer_handle,
_temp_indexer_dir: temp_indexer_dir,
_temp_sequencer_dir: temp_sequencer_dir,
_temp_wallet_dir: temp_wallet_dir,
})
@ -158,13 +168,26 @@ impl TestContext {
Ok((compose, addr))
}
async fn setup_indexer(bedrock_addr: SocketAddr) -> Result<IndexerHandle> {
let indexer_config =
config::indexer_config(bedrock_addr).context("Failed to create Indexer config")?;
async fn setup_indexer(
bedrock_addr: SocketAddr,
initial_data: &config::InitialData,
) -> Result<(IndexerHandle, TempDir)> {
let temp_indexer_dir =
tempfile::tempdir().context("Failed to create temp dir for indexer home")?;
debug!("Using temp indexer home at {:?}", temp_indexer_dir.path());
let indexer_config = config::indexer_config(
bedrock_addr,
temp_indexer_dir.path().to_owned(),
initial_data,
)
.context("Failed to create Indexer config")?;
indexer_service::run_server(indexer_config, 0)
.await
.context("Failed to run Indexer Service")
.map(|handle| (handle, temp_indexer_dir))
}
async fn setup_sequencer(
@ -245,6 +268,11 @@ impl TestContext {
&self.sequencer_client
}
/// Get reference to the indexer client.
pub fn indexer_client(&self) -> &IndexerClient {
&self.indexer_client
}
/// Get existing public account IDs in the wallet.
pub fn existing_public_accounts(&self) -> Vec<AccountId> {
self.wallet
@ -270,9 +298,11 @@ impl Drop for TestContext {
sequencer_handle,
indexer_handle,
bedrock_compose,
_temp_indexer_dir: _,
_temp_sequencer_dir: _,
_temp_wallet_dir: _,
sequencer_client: _,
indexer_client: _,
wallet: _,
} = self;

View File

@ -0,0 +1,36 @@
use anyhow::Result;
use indexer_service_rpc::RpcClient;
use integration_tests::TestContext;
use log::info;
use tokio::test;
// use wallet::cli::{Command, config::ConfigSubcommand};
#[test]
async fn indexer_test_run() -> Result<()> {
let ctx = TestContext::new().await?;
// RUN OBSERVATION
info!("LETS TAKE A LOOK");
tokio::time::sleep(std::time::Duration::from_secs(100)).await;
let last_block_seq = ctx
.sequencer_client()
.get_last_block()
.await
.unwrap()
.last_block;
info!("Last block on seq now is {last_block_seq}");
let last_block_indexer = ctx
.indexer_client()
.get_last_finalized_block_id()
.await
.unwrap();
info!("Last block on ind now is {last_block_indexer}");
assert!(last_block_indexer > 1);
Ok(())
}

View File

@ -639,7 +639,6 @@ async fn create_token_with_private_definition_and_supply() -> Result<()> {
};
// Create token with both private definition and supply
let name = "A NAME".to_string();
let total_supply = 37;
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_account_id: format_private_account_id(definition_account_id),
@ -799,7 +798,6 @@ async fn shielded_token_transfer() -> Result<()> {
};
// Create token
let name = "A NAME".to_string();
let total_supply = 37;
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_account_id: format_public_account_id(definition_account_id),
@ -913,7 +911,6 @@ async fn deshielded_token_transfer() -> Result<()> {
};
// Create token with private supply
let name = "A NAME".to_string();
let total_supply = 37;
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_account_id: format_public_account_id(definition_account_id),
@ -1014,8 +1011,6 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> {
};
// Create token
let name = "A NAME".to_string();
let total_supply = 37;
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_account_id: format_private_account_id(definition_account_id),
supply_account_id: format_private_account_id(supply_account_id),

File diff suppressed because it is too large Load Diff

View File

@ -129,10 +129,10 @@ impl<BC: BlockSettlementClientTrait, IC: IndexerClientTrait> SequencerCore<BC, I
let block_settlement_client = BC::new(&config.bedrock_config, bedrock_signing_key)
.expect("Failed to initialize Block Settlement Client");
let (_, msg_id) = block_settlement_client
.create_inscribe_tx(&genesis_block)
.expect("Inscription transaction with genesis block should be constructible");
let last_bedrock_msg_id = msg_id.into();
// let (_, msg_id) = block_settlement_client
// .create_inscribe_tx(&genesis_block)
// .expect("Inscription transaction with genesis block should be constructible");
// let last_bedrock_msg_id = msg_id.into();
let indexer_client = IC::new(&config.indexer_rpc_url)
.await
@ -146,7 +146,7 @@ impl<BC: BlockSettlementClientTrait, IC: IndexerClientTrait> SequencerCore<BC, I
sequencer_config: config,
block_settlement_client,
indexer_client,
last_bedrock_msg_id,
last_bedrock_msg_id: channel_genesis_msg_id,
};
(sequencer_core, mempool_handle)

View File

@ -12,12 +12,12 @@ use common::{
GetAccountBalanceRequest, GetAccountBalanceResponse, GetAccountRequest,
GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse,
GetBlockDataRequest, GetBlockDataResponse, GetBlockRangeDataRequest,
GetBlockRangeDataResponse, GetGenesisBlockRequest, GetGenesisBlockResponse,
GetGenesisIdRequest, GetGenesisIdResponse, GetInitialTestnetAccountsRequest,
GetLastBlockRequest, GetLastBlockResponse, GetProgramIdsRequest, GetProgramIdsResponse,
GetProofForCommitmentRequest, GetProofForCommitmentResponse,
GetTransactionByHashRequest, GetTransactionByHashResponse, HelloRequest, HelloResponse,
SendTxRequest, SendTxResponse,
GetBlockRangeDataResponse, GetGenesisIdRequest, GetGenesisIdResponse,
GetInitialTestnetAccountsRequest, GetLastBlockRequest, GetLastBlockResponse,
GetProgramIdsRequest, GetProgramIdsResponse, GetProofForCommitmentRequest,
GetProofForCommitmentResponse, GetTransactionByHashRequest,
GetTransactionByHashResponse, HelloRequest, HelloResponse, SendTxRequest,
SendTxResponse,
},
},
transaction::{NSSATransaction, transaction_pre_check},
@ -37,7 +37,6 @@ pub const SEND_TX: &str = "send_tx";
pub const GET_BLOCK: &str = "get_block";
pub const GET_BLOCK_RANGE: &str = "get_block_range";
pub const GET_GENESIS: &str = "get_genesis";
pub const GET_GENESIS_BLOCK: &str = "get_genesis_block";
pub const GET_LAST_BLOCK: &str = "get_last_block";
pub const GET_ACCOUNT_BALANCE: &str = "get_account_balance";
pub const GET_TRANSACTION_BY_HASH: &str = "get_transaction_by_hash";
@ -164,25 +163,6 @@ impl<BC: BlockSettlementClientTrait, IC: IndexerClientTrait> JsonHandler<BC, IC>
respond(response)
}
async fn process_get_genesis_block(&self, request: Request) -> Result<Value, RpcErr> {
let _get_genesis_req = GetGenesisBlockRequest::parse(Some(request.params))?;
let genesis_block = {
let state = self.sequencer_state.lock().await;
let gen_id = state.block_store().genesis_id();
state.block_store().get_block_at_id(gen_id)?
};
let response = GetGenesisBlockResponse {
genesis_block_borsh_ser: borsh::to_vec(&genesis_block)
.expect("Block must serialize correctly"),
};
respond(response)
}
async fn process_get_last_block(&self, request: Request) -> Result<Value, RpcErr> {
let _get_last_block_req = GetLastBlockRequest::parse(Some(request.params))?;
@ -326,7 +306,6 @@ impl<BC: BlockSettlementClientTrait, IC: IndexerClientTrait> JsonHandler<BC, IC>
GET_BLOCK => self.process_get_block_data(request).await,
GET_BLOCK_RANGE => self.process_get_block_range_data(request).await,
GET_GENESIS => self.process_get_genesis(request).await,
GET_GENESIS_BLOCK => self.process_get_genesis_block(request).await,
GET_LAST_BLOCK => self.process_get_last_block(request).await,
GET_INITIAL_TESTNET_ACCOUNTS => self.get_initial_testnet_accounts(request).await,
GET_ACCOUNT_BALANCE => self.process_get_account_balance(request).await,