Skip to content

Commit

Permalink
Fix ARRR activation. More info to activation statuses. Check point bl…
Browse files Browse the repository at this point in the history
…ock #1427 (#1439)

* WIP.

* WIP. Added more info to BuildingWalletDb status. Added check_point_block.

* Temporary ignore RUSTSEC-2020-0159.

* Add TemporaryError variant to SyncStatus #1427.

* consensus_params -> protocol_info

* Review fixes.

Co-authored-by: Artem Vitae <artem@vitae.com>
  • Loading branch information
artemii235 and Artem Vitae committed Aug 10, 2022
1 parent 7cf104a commit 0f6c726
Show file tree
Hide file tree
Showing 12 changed files with 217 additions and 90 deletions.
2 changes: 2 additions & 0 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@ notice = "warn"
# RUSTSEC-2021-0113 is related to metrics-util crate that is not actively used for now despite being still present in deps tree
# RUSTSEC-2020-0071 is related to time crate, which is used only by chrono in our deps tree, remove when https://github.com/chronotope/chrono/issues/700 is resolved
# RUSTSEC-2022-0040 is related to owning-ref, which seems unmaintained. We need to find a way to get rid of it. https://github.com/KomodoPlatform/atomicDEX-API/issues/1429
# RUSTSEC-2020-0159 is related to chrono, updated in dev
ignore = [
"RUSTSEC-2021-0113",
"RUSTSEC-2020-0071",
"RUSTSEC-2022-0040",
"RUSTSEC-2020-0159",
#"RUSTSEC-0000-0000",
]
# Threshold for security vulnerabilities, any vulnerability with a CVSS score
Expand Down
6 changes: 2 additions & 4 deletions mm2src/coins/lp_coins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ cfg_native! {
use futures::AsyncWriteExt;
use std::io;
use zcash_primitives::transaction::Transaction as ZTransaction;
use z_coin::ZcoinConsensusParams;
use z_coin::ZcoinProtocolInfo;
}

cfg_wasm32! {
Expand Down Expand Up @@ -2110,9 +2110,7 @@ pub enum CoinProtocol {
decimals: u8,
},
#[cfg(not(target_arch = "wasm32"))]
ZHTLC {
consensus_params: ZcoinConsensusParams,
},
ZHTLC(ZcoinProtocolInfo),
}

pub type RpcTransportEventHandlerShared = Arc<dyn RpcTransportEventHandler + Send + Sync + 'static>;
Expand Down
66 changes: 42 additions & 24 deletions mm2src/coins/z_coin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ mod z_coin_errors;
pub use z_coin_errors::*;

#[cfg(all(test, feature = "zhtlc-native-tests"))]
mod z_coin_tests;
mod z_coin_native_tests;

/// `ZP2SHSpendError` compatible `TransactionErr` handling macro.
macro_rules! try_ztx_s {
Expand Down Expand Up @@ -119,6 +119,20 @@ pub struct ZcoinConsensusParams {
b58_script_address_prefix: [u8; 2],
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CheckPointBlockInfo {
height: u32,
hash: H256Json,
time: u32,
sapling_tree: BytesJson,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ZcoinProtocolInfo {
consensus_params: ZcoinConsensusParams,
check_point_block: Option<CheckPointBlockInfo>,
}

impl Parameters for ZcoinConsensusParams {
fn activation_height(&self, nu: NetworkUpgrade) -> Option<BlockHeight> {
match nu {
Expand Down Expand Up @@ -696,22 +710,12 @@ pub async fn z_coin_from_conf_and_params(
ticker: &str,
conf: &Json,
params: &ZcoinActivationParams,
consensus_params: ZcoinConsensusParams,
protocol_info: ZcoinProtocolInfo,
secp_priv_key: &[u8],
) -> Result<ZCoin, MmError<ZCoinBuildError>> {
let z_key = ExtendedSpendingKey::master(secp_priv_key);
let db_dir = ctx.dbdir();
z_coin_from_conf_and_params_with_z_key(
ctx,
ticker,
conf,
params,
secp_priv_key,
db_dir,
z_key,
consensus_params,
)
.await
z_coin_from_conf_and_params_with_z_key(ctx, ticker, conf, params, secp_priv_key, db_dir, z_key, protocol_info).await
}

pub struct ZCoinBuilder<'a> {
Expand All @@ -723,7 +727,7 @@ pub struct ZCoinBuilder<'a> {
secp_priv_key: &'a [u8],
db_dir_path: PathBuf,
z_spending_key: ExtendedSpendingKey,
consensus_params: ZcoinConsensusParams,
protocol_info: ZcoinProtocolInfo,
}

impl<'a> UtxoCoinBuilderCommonOps for ZCoinBuilder<'a> {
Expand Down Expand Up @@ -755,15 +759,21 @@ impl<'a> UtxoCoinWithIguanaPrivKeyBuilder for ZCoinBuilder<'a> {
.default_address()
.map_err(|_| MmError::new(ZCoinBuildError::GetAddressError))?;

let dex_fee_addr = decode_payment_address(self.consensus_params.hrp_sapling_payment_address(), DEX_FEE_Z_ADDR)
.expect("DEX_FEE_Z_ADDR is a valid z-address")
.expect("DEX_FEE_Z_ADDR is a valid z-address");
let dex_fee_addr = decode_payment_address(
self.protocol_info.consensus_params.hrp_sapling_payment_address(),
DEX_FEE_Z_ADDR,
)
.expect("DEX_FEE_Z_ADDR is a valid z-address")
.expect("DEX_FEE_Z_ADDR is a valid z-address");

let z_tx_prover = async_blocking(LocalTxProver::with_default_location)
.await
.or_mm_err(|| ZCoinBuildError::ZCashParamsNotFound)?;

let my_z_addr_encoded = encode_payment_address(self.consensus_params.hrp_sapling_payment_address(), &my_z_addr);
let my_z_addr_encoded = encode_payment_address(
self.protocol_info.consensus_params.hrp_sapling_payment_address(),
&my_z_addr,
);

let evk = ExtendedFullViewingKey::from(&self.z_spending_key);
let (sync_state_connector, light_wallet_db) = match &self.z_coin_params.mode {
Expand All @@ -782,7 +792,15 @@ impl<'a> UtxoCoinWithIguanaPrivKeyBuilder for ZCoinBuilder<'a> {
.or_mm_err(|| ZCoinBuildError::EmptyLightwalletdUris)?,
)?;

init_light_client(uri, cache_db_path, wallet_db_path, self.consensus_params.clone(), evk).await?
init_light_client(
uri,
cache_db_path,
wallet_db_path,
self.protocol_info.consensus_params.clone(),
self.protocol_info.check_point_block,
evk,
)
.await?
},
};

Expand All @@ -794,7 +812,7 @@ impl<'a> UtxoCoinWithIguanaPrivKeyBuilder for ZCoinBuilder<'a> {
z_spending_key: self.z_spending_key,
z_tx_prover: Arc::new(z_tx_prover),
light_wallet_db,
consensus_params: self.consensus_params,
consensus_params: self.protocol_info.consensus_params,
sync_state_connector,
};

Expand All @@ -817,7 +835,7 @@ impl<'a> ZCoinBuilder<'a> {
secp_priv_key: &'a [u8],
db_dir_path: PathBuf,
z_spending_key: ExtendedSpendingKey,
consensus_params: ZcoinConsensusParams,
protocol_info: ZcoinProtocolInfo,
) -> ZCoinBuilder<'a> {
let utxo_mode = match &z_coin_params.mode {
ZcoinRpcMode::Native => UtxoRpcMode::Native,
Expand Down Expand Up @@ -846,7 +864,7 @@ impl<'a> ZCoinBuilder<'a> {
secp_priv_key,
db_dir_path,
z_spending_key,
consensus_params,
protocol_info,
}
}
}
Expand All @@ -860,7 +878,7 @@ async fn z_coin_from_conf_and_params_with_z_key(
secp_priv_key: &[u8],
db_dir_path: PathBuf,
z_spending_key: ExtendedSpendingKey,
consensus_params: ZcoinConsensusParams,
protocol_info: ZcoinProtocolInfo,
) -> Result<ZCoin, MmError<ZCoinBuildError>> {
let builder = ZCoinBuilder::new(
ctx,
Expand All @@ -870,7 +888,7 @@ async fn z_coin_from_conf_and_params_with_z_key(
secp_priv_key,
db_dir_path,
z_spending_key,
consensus_params,
protocol_info,
);
builder.build().await
}
Expand Down
9 changes: 7 additions & 2 deletions mm2src/coins/z_coin/z_coin_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,20 @@ use zcash_primitives::transaction::builder::Error as ZTxBuilderError;
#[non_exhaustive]
pub enum UpdateBlocksCacheErr {
GrpcError(tonic::Status),
DbError(SqliteError),
BlocksDbError(SqliteError),
ZcashSqliteError(ZcashClientError),
}

impl From<tonic::Status> for UpdateBlocksCacheErr {
fn from(err: tonic::Status) -> Self { UpdateBlocksCacheErr::GrpcError(err) }
}

impl From<SqliteError> for UpdateBlocksCacheErr {
fn from(err: SqliteError) -> Self { UpdateBlocksCacheErr::DbError(err) }
fn from(err: SqliteError) -> Self { UpdateBlocksCacheErr::BlocksDbError(err) }
}

impl From<ZcashClientError> for UpdateBlocksCacheErr {
fn from(err: ZcashClientError) -> Self { UpdateBlocksCacheErr::ZcashSqliteError(err) }
}

#[derive(Debug, Display)]
Expand Down
File renamed without changes.
96 changes: 66 additions & 30 deletions mm2src/coins/z_coin/z_rpc.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{z_coin_errors::*, ZcoinConsensusParams};
use super::{z_coin_errors::*, CheckPointBlockInfo, ZcoinConsensusParams};
use crate::utxo::utxo_common;
use common::executor::Timer;
use common::log::{debug, error, info};
use common::log::{debug, error, info, LogOnError};
use common::{async_blocking, spawn_abortable, AbortOnDropHandle};
use db_common::sqlite::rusqlite::{params, Connection, Error as SqliteError, NO_PARAMS};
use db_common::sqlite::{query_single_row, run_optimization_pragmas};
Expand All @@ -23,8 +23,9 @@ use zcash_client_backend::data_api::error::Error as ChainError;
use zcash_client_backend::data_api::{BlockSource, WalletRead, WalletWrite};
use zcash_client_backend::proto::compact_formats::CompactBlock;
use zcash_client_sqlite::error::SqliteClientError as ZcashClientError;
use zcash_client_sqlite::wallet::init::{init_accounts_table, init_wallet_db};
use zcash_client_sqlite::wallet::init::{init_accounts_table, init_blocks_table, init_wallet_db};
use zcash_client_sqlite::WalletDb;
use zcash_primitives::block::BlockHash;
use zcash_primitives::consensus::BlockHeight;
use zcash_primitives::transaction::TxId;
use zcash_primitives::zip32::ExtendedFullViewingKey;
Expand Down Expand Up @@ -103,7 +104,7 @@ impl BlockDb {
Ok(())
}

fn get_latest_block(&self) -> Result<i64, MmError<SqliteError>> {
fn get_latest_block(&self) -> Result<u32, MmError<SqliteError>> {
Ok(query_single_row(
&self.0,
"SELECT height FROM compactblocks ORDER BY height DESC LIMIT 1",
Expand Down Expand Up @@ -147,6 +148,7 @@ pub(super) async fn init_light_client(
cache_db_path: PathBuf,
wallet_db_path: PathBuf,
consensus_params: ZcoinConsensusParams,
check_point_block: Option<CheckPointBlockInfo>,
evk: ExtendedFullViewingKey,
) -> Result<(AsyncMutex<SaplingSyncConnector>, WalletDbShared), MmError<ZcoinLightClientInitError>> {
let blocks_db =
Expand All @@ -162,6 +164,15 @@ pub(super) async fn init_light_client(
init_wallet_db(&db).map_to_mm(ZcoinLightClientInitError::WalletDbInitFailure)?;
if db.get_extended_full_viewing_keys()?.is_empty() {
init_accounts_table(&db, &[evk])?;
if let Some(check_point) = check_point_block {
init_blocks_table(
&db,
BlockHeight::from_u32(check_point.height),
BlockHash(check_point.hash.0),
check_point.time,
&check_point.sapling_tree.0,
)?;
}
}
Ok(db)
}
Expand Down Expand Up @@ -235,7 +246,11 @@ pub enum SyncStatus {
current_scanned_block: u64,
latest_block: u64,
},
BuildingWalletDb,
BuildingWalletDb {
current_scanned_block: u64,
latest_block: u64,
},
TemporaryError(String),
Finished {
block_number: u64,
},
Expand All @@ -257,46 +272,52 @@ pub struct SaplingSyncLoopHandle {

impl SaplingSyncLoopHandle {
fn notify_blocks_cache_status(&mut self, current_scanned_block: u64, latest_block: u64) {
if self
.sync_status_notifier
self.sync_status_notifier
.try_send(SyncStatus::UpdatingBlocksCache {
current_scanned_block,
latest_block,
})
.is_err()
{
debug!("No one seems interested in SyncStatus");
}
.debug_log_with_msg("No one seems interested in SyncStatus");
}

fn notify_building_wallet_db(&mut self) {
if self
.sync_status_notifier
.try_send(SyncStatus::BuildingWalletDb)
.is_err()
{
debug!("No one seems interested in SyncStatus");
}
fn notify_building_wallet_db(&mut self, current_scanned_block: u64, latest_block: u64) {
self.sync_status_notifier
.try_send(SyncStatus::BuildingWalletDb {
current_scanned_block,
latest_block,
})
.debug_log_with_msg("No one seems interested in SyncStatus");
}

fn notify_on_error(&mut self, error: String) {
self.sync_status_notifier
.try_send(SyncStatus::TemporaryError(error))
.debug_log_with_msg("No one seems interested in SyncStatus");
}

fn notify_sync_finished(&mut self) {
if self
.sync_status_notifier
self.sync_status_notifier
.try_send(SyncStatus::Finished {
block_number: self.current_block.into(),
})
.is_err()
{
debug!("No one seems interested in SyncStatus");
}
.debug_log_with_msg("No one seems interested in SyncStatus");
}

async fn update_blocks_cache(&mut self) -> Result<(), MmError<UpdateBlocksCacheErr>> {
let request = tonic::Request::new(ChainSpec {});
let current_blockchain_block = self.grpc_client.get_latest_block(request).await?;
let current_block_in_db = block_in_place(|| self.blocks_db.get_latest_block())?;
let extrema = block_in_place(|| self.wallet_db.lock().block_height_extrema())?;

let mut from_block = self
.consensus_params
.sapling_activation_height
.max(current_block_in_db + 1) as u64;

if let Some((_, max_in_wallet)) = extrema {
from_block = from_block.max(max_in_wallet.into());
}

let from_block = current_block_in_db as u64 + 1;
let current_block: u64 = current_blockchain_block.into_inner().height;

if current_block >= from_block {
Expand Down Expand Up @@ -327,7 +348,9 @@ impl SaplingSyncLoopHandle {
/// Scans cached blocks, validates the chain and updates WalletDb.
/// For more notes on the process, check https://github.com/zcash/librustzcash/blob/master/zcash_client_backend/src/data_api/chain.rs#L2
fn scan_blocks(&mut self) -> Result<(), MmError<ZcashClientError>> {
let wallet_guard = self.wallet_db.lock();
// required to avoid immutable borrow of self
let wallet_db_arc = self.wallet_db.clone();
let wallet_guard = wallet_db_arc.lock();
let mut wallet_ops = wallet_guard.get_update_ops().expect("get_update_ops always returns Ok");

if let Err(e) = validate_chain(
Expand All @@ -349,7 +372,20 @@ impl SaplingSyncLoopHandle {
}
}

scan_cached_blocks(&self.consensus_params, &self.blocks_db, &mut wallet_ops, None)?;
let current_block = BlockHeight::from_u32(self.blocks_db.get_latest_block()?);
loop {
match wallet_ops.block_height_extrema()? {
Some((_, max_in_wallet)) => {
if max_in_wallet >= current_block {
break;
} else {
self.notify_building_wallet_db(max_in_wallet.into(), current_block.into());
}
},
None => self.notify_building_wallet_db(0, current_block.into()),
}
scan_cached_blocks(&self.consensus_params, &self.blocks_db, &mut wallet_ops, Some(1000))?;
}
Ok(())
}

Expand Down Expand Up @@ -408,14 +444,14 @@ async fn light_wallet_db_sync_loop(mut sync_handle: SaplingSyncLoopHandle) {
loop {
if let Err(e) = sync_handle.update_blocks_cache().await {
error!("Error {} on blocks cache update", e);
sync_handle.notify_on_error(e.to_string());
Timer::sleep(10.).await;
continue;
}

sync_handle.notify_building_wallet_db();

if let Err(e) = block_in_place(|| sync_handle.scan_blocks()) {
error!("Error {} on scan_blocks", e);
sync_handle.notify_on_error(e.to_string());
Timer::sleep(10.).await;
continue;
}
Expand Down
Loading

0 comments on commit 0f6c726

Please sign in to comment.