mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-05 14:53:06 +00:00
refactor: split block polling
This commit is contained in:
parent
2d34925725
commit
91c898f19c
@ -21,6 +21,8 @@ hex = "0.4.3"
|
|||||||
rand.workspace = true
|
rand.workspace = true
|
||||||
itertools = "0.14.0"
|
itertools = "0.14.0"
|
||||||
sha2.workspace = true
|
sha2.workspace = true
|
||||||
|
futures.workspace = true
|
||||||
|
async-stream = "0.3.6"
|
||||||
|
|
||||||
[dependencies.key_protocol]
|
[dependencies.key_protocol]
|
||||||
path = "../key_protocol"
|
path = "../key_protocol"
|
||||||
|
|||||||
@ -9,9 +9,7 @@ use serde::Serialize;
|
|||||||
use crate::{
|
use crate::{
|
||||||
WalletCore,
|
WalletCore,
|
||||||
cli::{SubcommandReturnValue, WalletSubcommand},
|
cli::{SubcommandReturnValue, WalletSubcommand},
|
||||||
helperfunctions::{
|
helperfunctions::{AccountPrivacyKind, HumanReadableAccount, parse_addr_with_privacy_prefix},
|
||||||
AccountPrivacyKind, HumanReadableAccount, parse_addr_with_privacy_prefix, parse_block_range,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const TOKEN_DEFINITION_TYPE: u8 = 0;
|
const TOKEN_DEFINITION_TYPE: u8 = 0;
|
||||||
@ -278,7 +276,6 @@ impl WalletSubcommand for AccountSubcommand {
|
|||||||
new_subcommand.handle_subcommand(wallet_core).await
|
new_subcommand.handle_subcommand(wallet_core).await
|
||||||
}
|
}
|
||||||
AccountSubcommand::SyncPrivate {} => {
|
AccountSubcommand::SyncPrivate {} => {
|
||||||
let last_synced_block = wallet_core.last_synced_block;
|
|
||||||
let curr_last_block = wallet_core
|
let curr_last_block = wallet_core
|
||||||
.sequencer_client
|
.sequencer_client
|
||||||
.get_last_block()
|
.get_last_block()
|
||||||
@ -298,13 +295,7 @@ impl WalletSubcommand for AccountSubcommand {
|
|||||||
|
|
||||||
println!("Stored persistent data at {path:#?}");
|
println!("Stored persistent data at {path:#?}");
|
||||||
} else {
|
} else {
|
||||||
parse_block_range(
|
wallet_core.sync_to_block(curr_last_block).await?;
|
||||||
last_synced_block + 1,
|
|
||||||
curr_last_block,
|
|
||||||
wallet_core.sequencer_client.clone(),
|
|
||||||
wallet_core,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(SubcommandReturnValue::SyncedToBlock(curr_last_block))
|
Ok(SubcommandReturnValue::SyncedToBlock(curr_last_block))
|
||||||
|
|||||||
@ -1,8 +1,5 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use common::sequencer_client::SequencerClient;
|
|
||||||
use nssa::program::Program;
|
use nssa::program::Program;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -16,7 +13,7 @@ use crate::{
|
|||||||
token::TokenProgramAgnosticSubcommand,
|
token::TokenProgramAgnosticSubcommand,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
helperfunctions::{fetch_config, parse_block_range},
|
helperfunctions::fetch_config,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod account;
|
pub mod account;
|
||||||
@ -164,29 +161,20 @@ pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValu
|
|||||||
|
|
||||||
pub async fn execute_continuous_run() -> Result<()> {
|
pub async fn execute_continuous_run() -> Result<()> {
|
||||||
let config = fetch_config().await?;
|
let config = fetch_config().await?;
|
||||||
let seq_client = Arc::new(SequencerClient::new(config.sequencer_addr.clone())?);
|
|
||||||
let mut wallet_core = WalletCore::start_from_config_update_chain(config.clone()).await?;
|
let mut wallet_core = WalletCore::start_from_config_update_chain(config.clone()).await?;
|
||||||
|
|
||||||
let mut latest_block_num = seq_client.get_last_block().await?.last_block;
|
|
||||||
let mut curr_last_block = latest_block_num;
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
parse_block_range(
|
let latest_block_num = wallet_core
|
||||||
curr_last_block,
|
.sequencer_client
|
||||||
latest_block_num,
|
.get_last_block()
|
||||||
seq_client.clone(),
|
.await?
|
||||||
&mut wallet_core,
|
.last_block;
|
||||||
)
|
wallet_core.sync_to_block(latest_block_num).await?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
curr_last_block = latest_block_num + 1;
|
|
||||||
|
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(
|
tokio::time::sleep(std::time::Duration::from_millis(
|
||||||
config.seq_poll_timeout_millis,
|
config.seq_poll_timeout_millis,
|
||||||
))
|
))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
latest_block_num = seq_client.get_last_block().await?.last_block;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,21 +1,16 @@
|
|||||||
use std::{path::PathBuf, str::FromStr, sync::Arc};
|
use std::{path::PathBuf, str::FromStr};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
|
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
|
||||||
use common::{
|
use key_protocol::key_protocol_core::NSSAUserData;
|
||||||
block::HashableBlockData, sequencer_client::SequencerClient, transaction::NSSATransaction,
|
use nssa::Account;
|
||||||
};
|
|
||||||
use key_protocol::{
|
|
||||||
key_management::key_tree::traits::KeyNode as _, key_protocol_core::NSSAUserData,
|
|
||||||
};
|
|
||||||
use nssa::{Account, privacy_preserving_transaction::message::EncryptedAccountData};
|
|
||||||
use nssa_core::account::Nonce;
|
use nssa_core::account::Nonce;
|
||||||
use rand::{RngCore, rngs::OsRng};
|
use rand::{RngCore, rngs::OsRng};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
HOME_DIR_ENV_VAR, WalletCore,
|
HOME_DIR_ENV_VAR,
|
||||||
config::{
|
config::{
|
||||||
InitialAccountData, InitialAccountDataPrivate, InitialAccountDataPublic,
|
InitialAccountData, InitialAccountDataPrivate, InitialAccountDataPublic,
|
||||||
PersistentAccountDataPrivate, PersistentAccountDataPublic, PersistentStorage, WalletConfig,
|
PersistentAccountDataPrivate, PersistentAccountDataPublic, PersistentStorage, WalletConfig,
|
||||||
@ -230,125 +225,6 @@ impl From<Account> for HumanReadableAccount {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn parse_block_range(
|
|
||||||
start: u64,
|
|
||||||
stop: u64,
|
|
||||||
seq_client: Arc<SequencerClient>,
|
|
||||||
wallet_core: &mut WalletCore,
|
|
||||||
) -> Result<()> {
|
|
||||||
for block_id in start..(stop + 1) {
|
|
||||||
let block =
|
|
||||||
borsh::from_slice::<HashableBlockData>(&seq_client.get_block(block_id).await?.block)?;
|
|
||||||
|
|
||||||
for tx in block.transactions {
|
|
||||||
let nssa_tx = NSSATransaction::try_from(&tx)?;
|
|
||||||
|
|
||||||
if let NSSATransaction::PrivacyPreserving(tx) = nssa_tx {
|
|
||||||
let mut affected_accounts = vec![];
|
|
||||||
|
|
||||||
for (acc_account_id, (key_chain, _)) in
|
|
||||||
&wallet_core.storage.user_data.default_user_private_accounts
|
|
||||||
{
|
|
||||||
let view_tag = EncryptedAccountData::compute_view_tag(
|
|
||||||
key_chain.nullifer_public_key.clone(),
|
|
||||||
key_chain.incoming_viewing_public_key.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
for (ciph_id, encrypted_data) in tx
|
|
||||||
.message()
|
|
||||||
.encrypted_private_post_states
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
{
|
|
||||||
if encrypted_data.view_tag == view_tag {
|
|
||||||
let ciphertext = &encrypted_data.ciphertext;
|
|
||||||
let commitment = &tx.message.new_commitments[ciph_id];
|
|
||||||
let shared_secret = key_chain
|
|
||||||
.calculate_shared_secret_receiver(encrypted_data.epk.clone());
|
|
||||||
|
|
||||||
let res_acc = nssa_core::EncryptionScheme::decrypt(
|
|
||||||
ciphertext,
|
|
||||||
&shared_secret,
|
|
||||||
commitment,
|
|
||||||
ciph_id as u32,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(res_acc) = res_acc {
|
|
||||||
println!(
|
|
||||||
"Received new account for account_id {acc_account_id:#?} with account object {res_acc:#?}"
|
|
||||||
);
|
|
||||||
|
|
||||||
affected_accounts.push((*acc_account_id, res_acc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for keys_node in wallet_core
|
|
||||||
.storage
|
|
||||||
.user_data
|
|
||||||
.private_key_tree
|
|
||||||
.key_map
|
|
||||||
.values()
|
|
||||||
{
|
|
||||||
let acc_account_id = keys_node.account_id();
|
|
||||||
let key_chain = &keys_node.value.0;
|
|
||||||
|
|
||||||
let view_tag = EncryptedAccountData::compute_view_tag(
|
|
||||||
key_chain.nullifer_public_key.clone(),
|
|
||||||
key_chain.incoming_viewing_public_key.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
for (ciph_id, encrypted_data) in tx
|
|
||||||
.message()
|
|
||||||
.encrypted_private_post_states
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
{
|
|
||||||
if encrypted_data.view_tag == view_tag {
|
|
||||||
let ciphertext = &encrypted_data.ciphertext;
|
|
||||||
let commitment = &tx.message.new_commitments[ciph_id];
|
|
||||||
let shared_secret = key_chain
|
|
||||||
.calculate_shared_secret_receiver(encrypted_data.epk.clone());
|
|
||||||
|
|
||||||
let res_acc = nssa_core::EncryptionScheme::decrypt(
|
|
||||||
ciphertext,
|
|
||||||
&shared_secret,
|
|
||||||
commitment,
|
|
||||||
ciph_id as u32,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(res_acc) = res_acc {
|
|
||||||
println!(
|
|
||||||
"Received new account for account_id {acc_account_id:#?} with account object {res_acc:#?}"
|
|
||||||
);
|
|
||||||
|
|
||||||
affected_accounts.push((acc_account_id, res_acc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (affected_account_id, new_acc) in affected_accounts {
|
|
||||||
wallet_core
|
|
||||||
.storage
|
|
||||||
.insert_private_account_data(affected_account_id, new_acc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wallet_core.last_synced_block = block_id;
|
|
||||||
wallet_core.store_persistent_data().await?;
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"Block at id {block_id} with timestamp {} parsed",
|
|
||||||
block.timestamp
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@ -9,9 +9,12 @@ use common::{
|
|||||||
transaction::{EncodedTransaction, NSSATransaction},
|
transaction::{EncodedTransaction, NSSATransaction},
|
||||||
};
|
};
|
||||||
use config::WalletConfig;
|
use config::WalletConfig;
|
||||||
use key_protocol::key_management::key_tree::chain_index::ChainIndex;
|
use key_protocol::key_management::key_tree::{chain_index::ChainIndex, traits::KeyNode as _};
|
||||||
use log::info;
|
use log::info;
|
||||||
use nssa::{Account, AccountId, PrivacyPreservingTransaction, program::Program};
|
use nssa::{
|
||||||
|
Account, AccountId, PrivacyPreservingTransaction,
|
||||||
|
privacy_preserving_transaction::message::EncryptedAccountData, program::Program,
|
||||||
|
};
|
||||||
use nssa_core::{Commitment, MembershipProof, SharedSecretKey, program::InstructionData};
|
use nssa_core::{Commitment, MembershipProof, SharedSecretKey, program::InstructionData};
|
||||||
pub use privacy_preserving_tx::PrivacyPreservingAccount;
|
pub use privacy_preserving_tx::PrivacyPreservingAccount;
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
@ -293,4 +296,91 @@ impl WalletCore {
|
|||||||
shared_secrets,
|
shared_secrets,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn sync_to_block(&mut self, block_id: u64) -> Result<()> {
|
||||||
|
use futures::TryStreamExt as _;
|
||||||
|
|
||||||
|
if self.last_synced_block >= block_id {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let poller = self.poller.clone();
|
||||||
|
let mut blocks =
|
||||||
|
std::pin::pin!(poller.poll_block_range(self.last_synced_block + 1..=block_id));
|
||||||
|
|
||||||
|
while let Some(block) = blocks.try_next().await? {
|
||||||
|
for tx in block.transactions {
|
||||||
|
let nssa_tx = NSSATransaction::try_from(&tx)?;
|
||||||
|
self.sync_private_accounts_with_tx(nssa_tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.last_synced_block = block.block_id;
|
||||||
|
self.store_persistent_data().await?;
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Block at id {} with timestamp {} parsed",
|
||||||
|
block.block_id, block.timestamp,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_private_accounts_with_tx(&mut self, tx: NSSATransaction) {
|
||||||
|
let NSSATransaction::PrivacyPreserving(tx) = tx else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let private_account_key_chains = self
|
||||||
|
.storage
|
||||||
|
.user_data
|
||||||
|
.default_user_private_accounts
|
||||||
|
.iter()
|
||||||
|
.map(|(acc_account_id, (key_chain, _))| (*acc_account_id, key_chain))
|
||||||
|
.chain(
|
||||||
|
self.storage
|
||||||
|
.user_data
|
||||||
|
.private_key_tree
|
||||||
|
.key_map
|
||||||
|
.values()
|
||||||
|
.map(|keys_node| (keys_node.account_id(), &keys_node.value.0)),
|
||||||
|
);
|
||||||
|
|
||||||
|
let affected_accounts = private_account_key_chains
|
||||||
|
.flat_map(|(acc_account_id, key_chain)| {
|
||||||
|
let view_tag = EncryptedAccountData::compute_view_tag(
|
||||||
|
key_chain.nullifer_public_key.clone(),
|
||||||
|
key_chain.incoming_viewing_public_key.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
tx.message()
|
||||||
|
.encrypted_private_post_states
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(move |(_, encrypted_data)| encrypted_data.view_tag == view_tag)
|
||||||
|
.filter_map(|(ciph_id, encrypted_data)| {
|
||||||
|
let ciphertext = &encrypted_data.ciphertext;
|
||||||
|
let commitment = &tx.message.new_commitments[ciph_id];
|
||||||
|
let shared_secret =
|
||||||
|
key_chain.calculate_shared_secret_receiver(encrypted_data.epk.clone());
|
||||||
|
|
||||||
|
nssa_core::EncryptionScheme::decrypt(
|
||||||
|
ciphertext,
|
||||||
|
&shared_secret,
|
||||||
|
commitment,
|
||||||
|
ciph_id as u32,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map(move |res_acc| (acc_account_id, res_acc))
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
for (affected_account_id, new_acc) in affected_accounts {
|
||||||
|
println!(
|
||||||
|
"Received new account for account_id {affected_account_id:#?} with account object {new_acc:#?}"
|
||||||
|
);
|
||||||
|
self.storage
|
||||||
|
.insert_private_account_data(affected_account_id, new_acc);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use common::sequencer_client::SequencerClient;
|
use common::{block::HashableBlockData, sequencer_client::SequencerClient};
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
|
||||||
use crate::config::WalletConfig;
|
use crate::config::WalletConfig;
|
||||||
@ -66,4 +66,18 @@ impl TxPoller {
|
|||||||
|
|
||||||
anyhow::bail!("Transaction not found in preconfigured amount of blocks");
|
anyhow::bail!("Transaction not found in preconfigured amount of blocks");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn poll_block_range(
|
||||||
|
&self,
|
||||||
|
range: std::ops::RangeInclusive<u64>,
|
||||||
|
) -> impl futures::Stream<Item = Result<HashableBlockData>> {
|
||||||
|
async_stream::stream! {
|
||||||
|
for block_id in range {
|
||||||
|
let block = borsh::from_slice::<HashableBlockData>(
|
||||||
|
&self.client.get_block(block_id).await?.block,
|
||||||
|
)?;
|
||||||
|
yield Ok(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user