diff --git a/mm2src/coins/qrc20.rs b/mm2src/coins/qrc20.rs index 92f74fad59..2631f3724d 100644 --- a/mm2src/coins/qrc20.rs +++ b/mm2src/coins/qrc20.rs @@ -59,7 +59,7 @@ use rpc::v1::types::{ use script::{Builder as ScriptBuilder, Opcode, Script, TransactionInputSigner}; use script_pubkey::generate_contract_call_script_pubkey; use serde_json::{self as json, Value as Json}; -use serialization::{deserialize, serialize, CoinVariant}; +use serialization::{deserialize, serialize}; use std::collections::{HashMap, HashSet}; use std::convert::TryInto; use std::num::TryFromIntError; @@ -731,7 +731,7 @@ impl UtxoCommonOps for Qrc20Coin { } async fn get_current_mtp(&self) -> UtxoRpcResult { - utxo_common::get_current_mtp(&self.utxo, CoinVariant::Qtum).await + utxo_common::get_current_mtp(&self.utxo).await } fn is_unspent_mature(&self, output: &RpcTransaction) -> bool { diff --git a/mm2src/coins/utxo.rs b/mm2src/coins/utxo.rs index fe4ca0d337..c58bad636d 100644 --- a/mm2src/coins/utxo.rs +++ b/mm2src/coins/utxo.rs @@ -83,7 +83,9 @@ use rpc::v1::types::{Bytes as BytesJson, Transaction as RpcTransaction, H256 as use script::{Builder, Script, SignatureVersion, TransactionInputSigner}; use secp256k1::Signature as SecpSignature; use serde_json::{self as json, Value as Json}; -use serialization::{deserialize, serialize, serialize_with_flags, Error as SerError, SERIALIZE_TRANSACTION_WITNESS}; +use serialization::{ + deserialize, serialize, serialize_with_flags, ChainVariant, Error as SerError, SERIALIZE_TRANSACTION_WITNESS, +}; use spv_validation::conf::SPVConf; use spv_validation::helpers_validation::SPVError; use spv_validation::storage::BlockHeaderStorageError; @@ -626,6 +628,8 @@ pub struct UtxoCoinConf { pub derivation_path: Option, /// The average time in seconds needed to mine a new block for this coin. pub avg_blocktime: Option, + /// How to interpret block headers for this coin (BTC, Qtum, RVN, etc.). + pub chain_variant: ChainVariant, } pub struct UtxoCoinFields { diff --git a/mm2src/coins/utxo/bch.rs b/mm2src/coins/utxo/bch.rs index caea216d58..891b0391e3 100644 --- a/mm2src/coins/utxo/bch.rs +++ b/mm2src/coins/utxo/bch.rs @@ -42,7 +42,7 @@ use mm2_metrics::MetricsArc; use mm2_number::MmNumber; use rpc::v1::types::H264 as H264Json; use serde_json::{self as json, Value as Json}; -use serialization::{deserialize, CoinVariant}; +use serialization::deserialize; use std::sync::MutexGuard; pub type BchUnspentMap = HashMap; @@ -825,8 +825,7 @@ impl UtxoCommonOps for BchCoin { } async fn get_current_mtp(&self) -> UtxoRpcResult { - // BCH uses the same coin variant as BTC for block header deserialization - utxo_common::get_current_mtp(&self.utxo_arc, CoinVariant::BTC).await + utxo_common::get_current_mtp(&self.utxo_arc).await } fn is_unspent_mature(&self, output: &RpcTransaction) -> bool { diff --git a/mm2src/coins/utxo/qtum.rs b/mm2src/coins/utxo/qtum.rs index b444deb6f1..da98e1c8de 100644 --- a/mm2src/coins/utxo/qtum.rs +++ b/mm2src/coins/utxo/qtum.rs @@ -50,7 +50,6 @@ use mm2_metrics::MetricsArc; use mm2_number::MmNumber; use rpc::v1::types::H264 as H264Json; use serde::Serialize; -use serialization::CoinVariant; use utxo_signer::UtxoSignerOps; #[derive(Debug, Display)] @@ -438,7 +437,7 @@ impl UtxoCommonOps for QtumCoin { } async fn get_current_mtp(&self) -> UtxoRpcResult { - utxo_common::get_current_mtp(&self.utxo_arc, CoinVariant::Qtum).await + utxo_common::get_current_mtp(&self.utxo_arc).await } fn is_unspent_mature(&self, output: &RpcTransaction) -> bool { diff --git a/mm2src/coins/utxo/rpc_clients.rs b/mm2src/coins/utxo/rpc_clients.rs index 6e43abe6b6..3a024c313f 100644 --- a/mm2src/coins/utxo/rpc_clients.rs +++ b/mm2src/coins/utxo/rpc_clients.rs @@ -22,7 +22,7 @@ use mm2_err_handle::prelude::*; use mm2_number::{BigDecimal, MmNumber}; use rpc::v1::types::{Bytes as BytesJson, Transaction as RpcTransaction, H256 as H256Json}; use script::Script; -use serialization::{deserialize, serialize, serialize_with_flags, CoinVariant, SERIALIZE_TRANSACTION_WITNESS}; +use serialization::{deserialize, serialize, serialize_with_flags, ChainVariant, SERIALIZE_TRANSACTION_WITNESS}; use std::collections::HashMap; use std::fmt; @@ -193,6 +193,15 @@ impl UtxoRpcClientEnum { UtxoRpcClientEnum::Electrum(_) => false, } } + + /// Returns how block headers/transactions should be interpreted for this client. + /// Delegates to the underlying concrete client, which stores the configured ChainVariant. + pub fn chain_variant(&self) -> ChainVariant { + match self { + UtxoRpcClientEnum::Native(ref c) => c.chain_variant(), + UtxoRpcClientEnum::Electrum(ref c) => c.chain_variant(), + } + } } /// Generic unspent info required to build transactions, we need this separate type because native @@ -389,12 +398,7 @@ pub trait UtxoRpcClientOps: fmt::Debug + Send + Sync + 'static { ) -> Box, Error = String> + Send>; /// Get median time past for `count` blocks in the past including `starting_block` - fn get_median_time_past( - &self, - starting_block: u64, - count: NonZeroU64, - coin_variant: CoinVariant, - ) -> UtxoRpcFut; + fn get_median_time_past(&self, starting_block: u64, count: NonZeroU64) -> UtxoRpcFut; /// Returns block time in seconds since epoch (Jan 1 1970 GMT). async fn get_block_timestamp(&self, height: u64) -> Result>; @@ -692,6 +696,7 @@ impl ConcurrentRequestMap { pub struct NativeClientImpl { /// Name of coin the rpc client is intended to work with pub coin_ticker: String, + pub chain_variant: ChainVariant, /// The uri to send requests to pub uri: String, /// Value of Authorization header, e.g. "Basic base64(user:password)" @@ -707,6 +712,7 @@ impl Default for NativeClientImpl { fn default() -> Self { NativeClientImpl { coin_ticker: "TEST".to_string(), + chain_variant: ChainVariant::Standard, uri: "".to_string(), auth: "".to_string(), event_handlers: vec![], @@ -730,6 +736,9 @@ pub trait UtxoJsonRpcClientInfo: JsonRpcClient { /// Name of coin the rpc client is intended to work with fn coin_name(&self) -> &str; + /// How to interpret headers/transactions for the coin. + fn chain_variant(&self) -> ChainVariant; + /// Generate client info from coin name fn client_info(&self) -> String { format!("coin: {}", self.coin_name()) @@ -740,6 +749,10 @@ impl UtxoJsonRpcClientInfo for NativeClientImpl { fn coin_name(&self) -> &str { self.coin_ticker.as_str() } + + fn chain_variant(&self) -> ChainVariant { + self.chain_variant + } } impl JsonRpcClient for NativeClientImpl { @@ -992,12 +1005,7 @@ impl UtxoRpcClientOps for NativeClient { Box::new(fut.boxed().compat()) } - fn get_median_time_past( - &self, - starting_block: u64, - count: NonZeroU64, - _coin_variant: CoinVariant, - ) -> UtxoRpcFut { + fn get_median_time_past(&self, starting_block: u64, count: NonZeroU64) -> UtxoRpcFut { let selfi = self.clone(); let fut = async move { let starting_block_hash = selfi.get_block_hash(starting_block).compat().await?; diff --git a/mm2src/coins/utxo/rpc_clients/electrum_rpc/client.rs b/mm2src/coins/utxo/rpc_clients/electrum_rpc/client.rs index 958746d403..197e8ff426 100644 --- a/mm2src/coins/utxo/rpc_clients/electrum_rpc/client.rs +++ b/mm2src/coins/utxo/rpc_clients/electrum_rpc/client.rs @@ -36,7 +36,7 @@ use mm2_number::BigDecimal; use mocktopus::macros::*; use rpc::v1::types::{Bytes as BytesJson, Transaction as RpcTransaction, H256 as H256Json}; use serialization::{ - deserialize, serialize, serialize_with_flags, CoinVariant, CompactInteger, Reader, SERIALIZE_TRANSACTION_WITNESS, + deserialize, serialize, serialize_with_flags, ChainVariant, CompactInteger, Reader, SERIALIZE_TRANSACTION_WITNESS, }; use spv_validation::helpers_validation::SPVError; use spv_validation::storage::BlockHeaderStorageOps; @@ -84,6 +84,7 @@ pub struct ElectrumClientSettings { pub struct ElectrumClientImpl { client_name: String, coin_ticker: String, + chain_variant: ChainVariant, pub connection_manager: ConnectionManager, next_id: AtomicU64, negotiate_version: bool, @@ -112,6 +113,7 @@ impl ElectrumClientImpl { streaming_manager: StreamingManager, abortable_system: AbortableQueue, mut event_handlers: Vec>, + chain_variant: ChainVariant, ) -> Result { let connection_manager = ConnectionManager::try_new( client_settings.servers, @@ -127,6 +129,7 @@ impl ElectrumClientImpl { Ok(ElectrumClientImpl { client_name: client_settings.client_name, coin_ticker: client_settings.coin_ticker, + chain_variant, connection_manager, next_id: 0.into(), negotiate_version: client_settings.negotiate_version, @@ -148,6 +151,7 @@ impl ElectrumClientImpl { streaming_manager: StreamingManager, abortable_system: AbortableQueue, event_handlers: Vec>, + chain_variant: ChainVariant, ) -> Result, String> { let client_impl = Arc::new(ElectrumClientImpl::try_new( client_settings, @@ -155,6 +159,7 @@ impl ElectrumClientImpl { streaming_manager, abortable_system, event_handlers, + chain_variant, )?); // Initialize the connection manager. client_impl @@ -227,6 +232,10 @@ impl ElectrumClientImpl { &self.block_headers_storage } + pub fn chain_variant(&self) -> ChainVariant { + self.chain_variant + } + pub fn weak_spawner(&self) -> WeakSpawner { self.abortable_system.weak_spawner() } @@ -239,6 +248,7 @@ impl ElectrumClientImpl { abortable_system: AbortableQueue, event_handlers: Vec>, protocol_version: OrdRange, + chain_variant: ChainVariant, ) -> Result, String> { let client_impl = Arc::new(ElectrumClientImpl { protocol_version, @@ -248,6 +258,7 @@ impl ElectrumClientImpl { streaming_manager, abortable_system, event_handlers, + chain_variant, )? }); // Initialize the connection manager. @@ -274,6 +285,10 @@ impl UtxoJsonRpcClientInfo for ElectrumClient { fn coin_name(&self) -> &str { self.coin_ticker.as_str() } + + fn chain_variant(&self) -> ChainVariant { + self.chain_variant + } } impl JsonRpcClient for ElectrumClient { @@ -316,6 +331,7 @@ impl ElectrumClient { block_headers_storage: BlockHeaderStorage, streaming_manager: StreamingManager, abortable_system: AbortableQueue, + chain_variant: ChainVariant, ) -> Result { let client = ElectrumClient(ElectrumClientImpl::try_new_arc( client_settings, @@ -323,6 +339,7 @@ impl ElectrumClient { streaming_manager, abortable_system, event_handlers, + chain_variant, )?); Ok(client) @@ -752,7 +769,7 @@ impl ElectrumClient { from_height: u64, to_height: u64, ) -> UtxoRpcFut<(HashMap, Vec)> { - let coin_name = self.coin_ticker.clone(); + let chain_variant = self.chain_variant; if from_height == 0 || to_height < from_height { return Box::new(futures01::future::err( UtxoRpcError::Internal("Invalid values for from/to parameters".to_string()).into(), @@ -774,8 +791,7 @@ impl ElectrumClient { let mut serialized = serialize(&len).take(); serialized.extend(headers.hex.0); drop_mutability!(serialized); - let mut reader = - Reader::new_with_coin_variant(serialized.as_slice(), coin_name.as_str().into()); + let mut reader = Reader::new_with_chain_variant(serialized.as_slice(), chain_variant); let maybe_block_headers = reader.read_list::(); let block_headers = match maybe_block_headers { Ok(headers) => headers, @@ -1089,12 +1105,7 @@ impl UtxoRpcClientOps for ElectrumClient { Box::new(fut.boxed().compat()) } - fn get_median_time_past( - &self, - starting_block: u64, - count: NonZeroU64, - coin_variant: CoinVariant, - ) -> UtxoRpcFut { + fn get_median_time_past(&self, starting_block: u64, count: NonZeroU64) -> UtxoRpcFut { let from = if starting_block <= count.get() { 0 } else { @@ -1102,6 +1113,7 @@ impl UtxoRpcClientOps for ElectrumClient { }; let coin_name = self.coin_ticker.clone(); + let chain_variant = self.chain_variant; let requested_count = count.get(); Box::new( @@ -1115,7 +1127,7 @@ impl UtxoRpcClientOps for ElectrumClient { let len = CompactInteger::from(res_count); let mut serialized = serialize(&len).take(); serialized.extend(res.hex.0); - let mut reader = Reader::new_with_coin_variant(serialized.as_slice(), coin_variant); + let mut reader = Reader::new_with_chain_variant(serialized.as_slice(), chain_variant); let headers = reader.read_list::().map_to_mm(|e| UtxoRpcError::InvalidResponse(format!( "blockchain.block.headers: failed to parse list of {} headers (coin={}, from={}, requested_count={}): {}", diff --git a/mm2src/coins/utxo/utxo_block_header_storage/mod.rs b/mm2src/coins/utxo/utxo_block_header_storage/mod.rs index 908a850bd2..ead89cecc8 100644 --- a/mm2src/coins/utxo/utxo_block_header_storage/mod.rs +++ b/mm2src/coins/utxo/utxo_block_header_storage/mod.rs @@ -14,6 +14,7 @@ use mm2_core::mm_ctx::MmArc; #[cfg(all(test, not(target_arch = "wasm32")))] use mocktopus::macros::*; use primitives::hash::H256; +use serialization::ChainVariant; use spv_validation::storage::{BlockHeaderStorageError, BlockHeaderStorageOps}; use std::collections::HashMap; use std::fmt::{Debug, Formatter}; @@ -30,7 +31,11 @@ impl Debug for BlockHeaderStorage { impl BlockHeaderStorage { #[cfg(all(not(test), not(target_arch = "wasm32")))] - pub(crate) fn new_from_ctx(ctx: MmArc, ticker: String) -> Result { + pub(crate) fn new_from_ctx( + ctx: MmArc, + ticker: String, + chain_variant: ChainVariant, + ) -> Result { #[cfg(not(feature = "new-db-arch"))] let maybe_sqlite_connection = ctx.sqlite_connection.get(); #[cfg(feature = "new-db-arch")] @@ -41,20 +46,29 @@ impl BlockHeaderStorage { Ok(BlockHeaderStorage { inner: Box::new(SqliteBlockHeadersStorage { ticker, + chain_variant, conn: sqlite_connection.clone(), }), }) } #[cfg(target_arch = "wasm32")] - pub(crate) fn new_from_ctx(ctx: MmArc, ticker: String) -> Result { + pub(crate) fn new_from_ctx( + ctx: MmArc, + ticker: String, + chain_variant: ChainVariant, + ) -> Result { Ok(BlockHeaderStorage { - inner: Box::new(IDBBlockHeadersStorage::new(&ctx, ticker)), + inner: Box::new(IDBBlockHeadersStorage::new(&ctx, ticker, chain_variant)), }) } #[cfg(all(test, not(target_arch = "wasm32")))] - pub(crate) fn new_from_ctx(ctx: MmArc, ticker: String) -> Result { + pub(crate) fn new_from_ctx( + ctx: MmArc, + ticker: String, + chain_variant: ChainVariant, + ) -> Result { use db_common::sqlite::rusqlite::Connection; use std::sync::{Arc, Mutex}; @@ -65,7 +79,11 @@ impl BlockHeaderStorage { .unwrap_or_else(|| Arc::new(Mutex::new(Connection::open_in_memory().unwrap()))); Ok(BlockHeaderStorage { - inner: Box::new(SqliteBlockHeadersStorage { ticker, conn }), + inner: Box::new(SqliteBlockHeadersStorage { + ticker, + chain_variant, + conn, + }), }) } @@ -149,7 +167,7 @@ mod block_headers_storage_tests { pub(crate) async fn test_add_block_headers_impl(for_coin: &str) { let ctx = mm_ctx_with_custom_db(); - let storage = BlockHeaderStorage::new_from_ctx(ctx, for_coin.to_string()) + let storage = BlockHeaderStorage::new_from_ctx(ctx, for_coin.to_string(), ChainVariant::Standard) .unwrap() .into_inner(); storage.init().await.unwrap(); @@ -163,7 +181,7 @@ mod block_headers_storage_tests { pub(crate) async fn test_get_block_header_impl(for_coin: &str) { let ctx = mm_ctx_with_custom_db(); - let storage = BlockHeaderStorage::new_from_ctx(ctx, for_coin.to_string()) + let storage = BlockHeaderStorage::new_from_ctx(ctx, for_coin.to_string(), ChainVariant::Standard) .unwrap() .into_inner(); storage.init().await.unwrap(); @@ -188,7 +206,7 @@ mod block_headers_storage_tests { pub(crate) async fn test_get_last_block_header_with_non_max_bits_impl(for_coin: &str) { let ctx = mm_ctx_with_custom_db(); - let storage = BlockHeaderStorage::new_from_ctx(ctx, for_coin.to_string()) + let storage = BlockHeaderStorage::new_from_ctx(ctx, for_coin.to_string(), ChainVariant::Standard) .unwrap() .into_inner(); storage.init().await.unwrap(); @@ -223,7 +241,7 @@ mod block_headers_storage_tests { pub(crate) async fn test_get_last_block_height_impl(for_coin: &str) { let ctx = mm_ctx_with_custom_db(); - let storage = BlockHeaderStorage::new_from_ctx(ctx, for_coin.to_string()) + let storage = BlockHeaderStorage::new_from_ctx(ctx, for_coin.to_string(), ChainVariant::Standard) .unwrap() .into_inner(); storage.init().await.unwrap(); @@ -251,7 +269,7 @@ mod block_headers_storage_tests { pub(crate) async fn test_remove_headers_from_storage_impl(for_coin: &str) { let ctx = mm_ctx_with_custom_db(); - let storage = BlockHeaderStorage::new_from_ctx(ctx, for_coin.to_string()) + let storage = BlockHeaderStorage::new_from_ctx(ctx, for_coin.to_string(), ChainVariant::Standard) .unwrap() .into_inner(); storage.init().await.unwrap(); @@ -305,7 +323,7 @@ mod native_tests { fn test_init_collection() { let for_coin = "init_collection"; let ctx = mm_ctx_with_custom_db(); - let storage = BlockHeaderStorage::new_from_ctx(ctx, for_coin.to_string()) + let storage = BlockHeaderStorage::new_from_ctx(ctx, for_coin.to_string(), ChainVariant::Standard) .unwrap() .into_inner(); @@ -363,7 +381,7 @@ mod wasm_test { #[wasm_bindgen_test] async fn test_storage_init() { let ctx = mm_ctx_with_custom_db(); - let storage = IDBBlockHeadersStorage::new(&ctx, "RICK".to_string()); + let storage = IDBBlockHeadersStorage::new(&ctx, "RICK".to_string(), ChainVariant::RICK); register_wasm_log(); diff --git a/mm2src/coins/utxo/utxo_block_header_storage/sql_block_header_storage.rs b/mm2src/coins/utxo/utxo_block_header_storage/sql_block_header_storage.rs index 3f04e2d068..57115a405d 100644 --- a/mm2src/coins/utxo/utxo_block_header_storage/sql_block_header_storage.rs +++ b/mm2src/coins/utxo/utxo_block_header_storage/sql_block_header_storage.rs @@ -9,7 +9,7 @@ use db_common::{ sqlite::CHECK_TABLE_EXISTS_SQL, }; use primitives::hash::H256; -use serialization::Reader; +use serialization::{ChainVariant, Reader}; use spv_validation::storage::{BlockHeaderStorageError, BlockHeaderStorageOps}; use std::collections::HashMap; use std::convert::TryInto; @@ -96,6 +96,7 @@ fn remove_headers_from_to_height_sql(for_coin: &str) -> Result>, } @@ -204,7 +205,7 @@ impl BlockHeaderStorageOps for SqliteBlockHeadersStorage { coin: coin.clone(), reason: e.to_string(), })?; - let mut reader = Reader::new_with_coin_variant(serialized, coin.as_str().into()); + let mut reader = Reader::new_with_chain_variant(serialized, self.chain_variant); let header: BlockHeader = reader .read() @@ -275,7 +276,7 @@ impl BlockHeaderStorageOps for SqliteBlockHeadersStorage { })?; if let Some(header_raw) = maybe_header_raw { - let header = BlockHeader::try_from_string_with_coin_variant(header_raw, coin.as_str().into()).map_err( + let header = BlockHeader::try_from_string_with_chain_variant(header_raw, self.chain_variant).map_err( |e: serialization::Error| BlockHeaderStorageError::DecodeError { coin, reason: e.to_string(), @@ -349,6 +350,7 @@ impl SqliteBlockHeadersStorage { pub fn in_memory(ticker: String) -> Self { SqliteBlockHeadersStorage { ticker, + chain_variant: ChainVariant::Standard, conn: Arc::new(Mutex::new(Connection::open_in_memory().unwrap())), } } diff --git a/mm2src/coins/utxo/utxo_block_header_storage/wasm/indexeddb_block_header_storage.rs b/mm2src/coins/utxo/utxo_block_header_storage/wasm/indexeddb_block_header_storage.rs index 292f3ac2b8..e77e6a81db 100644 --- a/mm2src/coins/utxo/utxo_block_header_storage/wasm/indexeddb_block_header_storage.rs +++ b/mm2src/coins/utxo/utxo_block_header_storage/wasm/indexeddb_block_header_storage.rs @@ -11,7 +11,7 @@ use mm2_db::indexed_db::{ use mm2_err_handle::prelude::*; use num_traits::ToPrimitive; use primitives::hash::H256; -use serialization::Reader; +use serialization::{ChainVariant, Reader}; use spv_validation::storage::{BlockHeaderStorageError, BlockHeaderStorageOps}; use std::collections::HashMap; @@ -48,13 +48,15 @@ impl IDBBlockHeadersInner { pub struct IDBBlockHeadersStorage { pub db: SharedDb, pub ticker: String, + pub chain_variant: ChainVariant, } impl IDBBlockHeadersStorage { - pub fn new(ctx: &MmArc, ticker: String) -> Self { + pub fn new(ctx: &MmArc, ticker: String, chain_variant: ChainVariant) -> Self { Self { db: ConstructibleDb::new(ctx).into_shared(), ticker, + chain_variant, } } @@ -126,7 +128,7 @@ impl BlockHeaderStorageOps for IDBBlockHeadersStorage { coin: self.ticker.clone(), reason: e.to_string(), })?; - let mut reader = Reader::new_with_coin_variant(serialized, self.ticker.as_str().into()); + let mut reader = Reader::new_with_chain_variant(serialized, self.chain_variant); let header: BlockHeader = reader .read() @@ -258,7 +260,7 @@ impl BlockHeaderStorageOps for IDBBlockHeadersStorage { coin: ticker.clone(), reason: e.to_string(), })?; - let mut reader = Reader::new_with_coin_variant(serialized, ticker.as_str().into()); + let mut reader = Reader::new_with_chain_variant(serialized, self.chain_variant); let header: BlockHeader = reader .read() diff --git a/mm2src/coins/utxo/utxo_builder/utxo_arc_builder.rs b/mm2src/coins/utxo/utxo_builder/utxo_arc_builder.rs index fdc7534f3d..da41012b4c 100644 --- a/mm2src/coins/utxo/utxo_builder/utxo_arc_builder.rs +++ b/mm2src/coins/utxo/utxo_builder/utxo_arc_builder.rs @@ -24,7 +24,7 @@ use mocktopus::macros::*; use rand::Rng; use script::Script; use serde_json::Value as Json; -use serialization::Reader; +use serialization::{ChainVariant, Reader}; use spv_validation::conf::SPVConf; use spv_validation::helpers_validation::{validate_headers, SPVError}; use spv_validation::storage::{BlockHeaderStorageError, BlockHeaderStorageOps}; @@ -385,7 +385,10 @@ pub(crate) async fn block_header_utxo_loop( let last_height_in_storage = match storage.get_last_block_height().await { Ok(Some(height)) => height, Ok(None) => { - if let Err(err) = validate_and_store_starting_header(&client, ticker, storage, &spv_conf).await { + if let Err(err) = + validate_and_store_starting_header(&client, ticker, storage, &spv_conf, client.chain_variant()) + .await + { sync_status_loop_handle.notify_on_permanent_error(err); break; } @@ -705,6 +708,7 @@ async fn validate_and_store_starting_header( ticker: &str, storage: &dyn BlockHeaderStorageOps, spv_conf: &SPVConf, + chain_variant: ChainVariant, ) -> MmResult<(), StartingHeaderValidationError> { let height = spv_conf.starting_block_header.height; let header_bytes = client @@ -713,7 +717,7 @@ async fn validate_and_store_starting_header( .await .map_to_mm(|err| StartingHeaderValidationError::RpcError(err.to_string()))?; - let mut reader = Reader::new_with_coin_variant(&header_bytes, ticker.into()); + let mut reader = Reader::new_with_chain_variant(&header_bytes, chain_variant); let header = reader .read() .map_to_mm(|err| StartingHeaderValidationError::DecodeErr { diff --git a/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs b/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs index 76ea3cb849..356caeff9d 100644 --- a/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs +++ b/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs @@ -38,6 +38,7 @@ use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use secp256k1::PublicKey; use serde_json::{self as json, Value as Json}; +use serialization::ChainVariant; use spv_validation::conf::SPVConf; use spv_validation::helpers_validation::SPVError; use spv_validation::storage::{BlockHeaderStorageError, BlockHeaderStorageOps}; @@ -385,7 +386,9 @@ where // all spawned futures related to this `UTXO` coin will be aborted as well. let abortable_system: AbortableQueue = builder.ctx().abortable_system.create_subsystem()?; - let rpc_client = builder.rpc_client(abortable_system.create_subsystem()?).await?; + let rpc_client = builder + .rpc_client(abortable_system.create_subsystem()?, conf.chain_variant) + .await?; let tx_fee = builder.tx_fee(&rpc_client).await?; let decimals = builder.decimals(&rpc_client).await?; let dust_amount = builder.dust_amount(); @@ -474,7 +477,9 @@ where // all spawned futures related to this `UTXO` coin will be aborted as well. let abortable_system: AbortableQueue = builder.ctx().abortable_system.create_subsystem()?; - let rpc_client = builder.rpc_client(abortable_system.create_subsystem()?).await?; + let rpc_client = builder + .rpc_client(abortable_system.create_subsystem()?, conf.chain_variant) + .await?; let tx_fee = builder.tx_fee(&rpc_client).await?; let decimals = builder.decimals(&rpc_client).await?; let dust_amount = builder.dust_amount(); @@ -662,7 +667,11 @@ pub trait UtxoCoinBuilderCommonOps { } } - async fn rpc_client(&self, abortable_system: AbortableQueue) -> UtxoCoinBuildResult { + async fn rpc_client( + &self, + abortable_system: AbortableQueue, + chain_variant: ChainVariant, + ) -> UtxoCoinBuildResult { match self.activation_params().mode.clone() { UtxoRpcMode::Native => { #[cfg(target_arch = "wasm32")] @@ -671,7 +680,7 @@ pub trait UtxoCoinBuilderCommonOps { } #[cfg(not(target_arch = "wasm32"))] { - let native = self.native_client()?; + let native = self.native_client(chain_variant)?; Ok(UtxoRpcClientEnum::Native(native)) } }, @@ -684,6 +693,7 @@ pub trait UtxoCoinBuilderCommonOps { .electrum_client( abortable_system, ElectrumBuilderArgs::default(), + chain_variant, servers, (min_connected, max_connected), ) @@ -699,6 +709,7 @@ pub trait UtxoCoinBuilderCommonOps { &self, abortable_system: AbortableQueue, args: ElectrumBuilderArgs, + chain_variant: ChainVariant, servers: Vec, (min_connected, max_connected): (Option, Option), ) -> UtxoCoinBuildResult { @@ -714,7 +725,7 @@ pub trait UtxoCoinBuilderCommonOps { } let storage_ticker = self.ticker().replace('-', "_"); - let block_headers_storage = BlockHeaderStorage::new_from_ctx(self.ctx().clone(), storage_ticker) + let block_headers_storage = BlockHeaderStorage::new_from_ctx(self.ctx().clone(), storage_ticker, chain_variant) .map_to_mm(|e| UtxoCoinBuildError::Internal(e.to_string()))?; if !block_headers_storage.is_initialized_for().await? { block_headers_storage.init().await?; @@ -739,12 +750,13 @@ pub trait UtxoCoinBuilderCommonOps { block_headers_storage, ctx.event_stream_manager.clone(), abortable_system, + chain_variant, ) .map_to_mm(UtxoCoinBuildError::Internal) } #[cfg(not(target_arch = "wasm32"))] - fn native_client(&self) -> UtxoCoinBuildResult { + fn native_client(&self, chain_variant: ChainVariant) -> UtxoCoinBuildResult { use base64::engine::general_purpose::URL_SAFE; use base64::Engine; @@ -773,6 +785,7 @@ pub trait UtxoCoinBuilderCommonOps { event_handlers, request_id: 0u64.into(), list_unspent_concurrent_map: ConcurrentRequestMap::new(), + chain_variant, }); Ok(NativeClient(client)) diff --git a/mm2src/coins/utxo/utxo_builder/utxo_conf_builder.rs b/mm2src/coins/utxo/utxo_builder/utxo_conf_builder.rs index d803326bcc..07fb224a18 100644 --- a/mm2src/coins/utxo/utxo_builder/utxo_conf_builder.rs +++ b/mm2src/coins/utxo/utxo_builder/utxo_conf_builder.rs @@ -12,8 +12,9 @@ use keys::NetworkAddressPrefixes; use mm2_err_handle::prelude::*; use script::SignatureVersion; use serde_json::{self as json, Value as Json}; +use serialization::ChainVariant; use spv_validation::conf::SPVConf; -use std::convert::TryInto; +use std::convert::{TryFrom, TryInto}; use std::num::NonZeroU64; use std::sync::atomic::AtomicBool; @@ -36,6 +37,8 @@ pub enum UtxoConfError { InvalidAddressFormat(String), InvalidDecimals(String), InvalidProtocolData(String), + #[display(fmt = "Invalid 'protocol.chain_variant' value: {_0}")] + InvalidChainVariant(String), } impl From for UtxoConfError { @@ -117,6 +120,7 @@ impl<'a> UtxoConfBuilder<'a> { let derivation_path = self.derivation_path()?; let avg_blocktime = self.avg_blocktime(); let spv_conf = self.spv_conf()?; + let chain_variant = self.chain_variant()?; Ok(UtxoCoinConf { ticker: self.ticker.to_owned(), @@ -149,6 +153,7 @@ impl<'a> UtxoConfBuilder<'a> { spv_conf, derivation_path, avg_blocktime, + chain_variant, }) } @@ -340,6 +345,16 @@ impl<'a> UtxoConfBuilder<'a> { fn avg_blocktime(&self) -> Option { self.conf["avg_blocktime"].as_u64() } + + fn chain_variant(&self) -> UtxoConfResult { + let chain_variant = match self.conf["protocol"]["chain_variant"].as_str() { + None => ChainVariant::Standard, + Some(other) => ChainVariant::try_from(other) + .map_err(|_| MmError::new(UtxoConfError::InvalidChainVariant(other.to_owned())))?, + }; + + Ok(chain_variant) + } } /// 'txfee' coins param config values diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index 3e4e2edaa6..d46667051b 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -64,7 +64,7 @@ use rpc_clients::NativeClientImpl; use script::{Builder, Opcode, Script, ScriptAddress, TransactionInputSigner, UnsignedTransactionInput}; use secp256k1::{PublicKey, Signature as SecpSignature}; use serde_json::{self as json}; -use serialization::{deserialize, serialize, serialize_with_flags, CoinVariant, SERIALIZE_TRANSACTION_WITNESS}; +use serialization::{deserialize, serialize, serialize_with_flags, SERIALIZE_TRANSACTION_WITNESS}; use std::cmp::Ordering; use std::collections::hash_map::{Entry, HashMap}; use std::convert::TryFrom; @@ -417,10 +417,10 @@ pub fn checked_address_from_str(coin: &T, address: &str) -> Mm Ok(addr) } -pub async fn get_current_mtp(coin: &UtxoCoinFields, coin_variant: CoinVariant) -> UtxoRpcResult { +pub async fn get_current_mtp(coin: &UtxoCoinFields) -> UtxoRpcResult { let current_block = coin.rpc_client.get_block_count().compat().await?; coin.rpc_client - .get_median_time_past(current_block, coin.conf.mtp_block_count, coin_variant) + .get_median_time_past(current_block, coin.conf.mtp_block_count) .compat() .await } @@ -5711,11 +5711,14 @@ fn test_check_all_utxo_inputs_signed_by_pub_overwintered() { use common::block_on; // We need a running electrum client for this test to test the functionality of fetching a tx from the network, parsing it, and using its input amount for sig_hash calculations. - let client = UtxoRpcClientEnum::Electrum(electrum_client_for_test(&[ - "electrum3.cipig.net:10001", - "electrum1.cipig.net:10001", - "electrum2.cipig.net:10001", - ])); + let client = UtxoRpcClientEnum::Electrum(electrum_client_for_test( + &[ + "electrum3.cipig.net:10001", + "electrum1.cipig.net:10001", + "electrum2.cipig.net:10001", + ], + ChainVariant::Standard, + )); let mut fields = utxo_coin_fields_for_test(client, None, false); fields.conf.ticker = "KMD".to_owned(); let coin = utxo_coin_from_fields(fields); diff --git a/mm2src/coins/utxo/utxo_common_tests.rs b/mm2src/coins/utxo/utxo_common_tests.rs index 0eeed36194..3c9af239bb 100644 --- a/mm2src/coins/utxo/utxo_common_tests.rs +++ b/mm2src/coins/utxo/utxo_common_tests.rs @@ -21,6 +21,7 @@ use crypto::HDPathToAccount; use itertools::Itertools; use keys::prefixes::*; use mm2_test_helpers::for_tests::mm_ctx_with_custom_db; +use serialization::ChainVariant; use std::convert::TryFrom; use std::num::NonZeroUsize; use std::str::FromStr; @@ -137,6 +138,7 @@ pub(super) fn utxo_coin_fields_for_test( spv_conf: None, derivation_path: None, avg_blocktime: None, + chain_variant: ChainVariant::Standard, }, decimals: TEST_COIN_DECIMALS, dust_amount: UTXO_DUST_AMOUNT, diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index 9c31818bb9..fa7d621e3d 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -223,7 +223,7 @@ impl UtxoCommonOps for UtxoStandardCoin { } async fn get_current_mtp(&self) -> UtxoRpcResult { - utxo_common::get_current_mtp(&self.utxo_arc, self.ticker().into()).await + utxo_common::get_current_mtp(&self.utxo_arc).await } fn is_unspent_mature(&self, output: &RpcTransaction) -> bool { diff --git a/mm2src/coins/utxo/utxo_tests.rs b/mm2src/coins/utxo/utxo_tests.rs index 7a2fbb214c..2ec224e48e 100644 --- a/mm2src/coins/utxo/utxo_tests.rs +++ b/mm2src/coins/utxo/utxo_tests.rs @@ -56,7 +56,7 @@ use mm2_test_helpers::for_tests::{ }; use mocktopus::mocking::*; use rpc::v1::types::H256 as H256Json; -use serialization::{deserialize, CoinVariant, CompactInteger, Reader}; +use serialization::{deserialize, ChainVariant, CompactInteger, Reader}; use spv_validation::conf::{BlockHeaderValidationParams, SPVBlockHeader}; use spv_validation::storage::BlockHeaderStorageOps; use spv_validation::work::DifficultyAlgorithm; @@ -72,7 +72,7 @@ use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; #[cfg(not(target_arch = "wasm32"))] const TAKER_PAYMENT_SPEND_SEARCH_INTERVAL: f64 = 1.; -pub fn electrum_client_for_test(servers: &[&str]) -> ElectrumClient { +pub fn electrum_client_for_test(servers: &[&str], chain_variant: ChainVariant) -> ElectrumClient { let ctx = MmCtxBuilder::default().into_mm_arc(); let servers: Vec<_> = servers.iter().map(|server| json!({ "url": server })).collect(); let req = json!({ @@ -95,9 +95,9 @@ pub fn electrum_client_for_test(servers: &[&str]) -> ElectrumClient { collect_metrics: false, }; - let servers = servers.into_iter().map(|s| json::from_value(s).unwrap()).collect(); + let servers: Vec = servers.into_iter().map(|s| json::from_value(s).unwrap()).collect(); let abortable_system = AbortableQueue::default(); - block_on(builder.electrum_client(abortable_system, args, servers, (None, None))).unwrap() + block_on(builder.electrum_client(abortable_system, args, chain_variant, servers, (None, None))).unwrap() } /// Returned client won't work by default, requires some mocks to be usable @@ -161,7 +161,7 @@ where #[test] fn test_extract_secret() { - let client = electrum_client_for_test(MARTY_ELECTRUM_ADDRS); + let client = electrum_client_for_test(MARTY_ELECTRUM_ADDRS, ChainVariant::MORTY); let coin = utxo_coin_for_test(client.into(), None, false); let tx_hex = hex::decode("0400008085202f890125236f423b7f585e6a86d8a6c45c6805bbd5823851a57a00f6dcd3a41dc7487500000000d8483045022100ce7246314170b7c84df41a9d987dad5b572cfca5c27ee738d2682ce147c460a402206fa477fc27bec62600b13ea8a3f81fbad1fa9adad28bc1fa5c212a12ecdccd7f01205c62072b57b6473aeee6d35270c8b56d86975e6d6d4245b25425d771239fae32004c6b630476ac3765b1752103242d9cb2168968d785f6914c494c303ff1c27ba0ad882dbc3c15cfa773ea953cac6782012088a914f95ae6f5fb6a4c4e69b00b4c1dbc0698746c0f0288210210e0f210673a2024d4021270bb711664a637bb542317ed9be5ad592475320c0cac68ffffffff0128230000000000001976a9142c445a7af3da3feb2ba7d5f2a32002c772acc1e188ac76ac3765000000000000000000000000000000").unwrap(); @@ -174,7 +174,7 @@ fn test_extract_secret() { #[test] fn test_send_maker_spends_taker_payment_recoverable_tx() { - let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS); + let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS, ChainVariant::RICK); let coin = utxo_coin_for_test(client.into(), None, false); let tx_hex = hex::decode("0100000001de7aa8d29524906b2b54ee2e0281f3607f75662cbc9080df81d1047b78e21dbc00000000d7473044022079b6c50820040b1fbbe9251ced32ab334d33830f6f8d0bf0a40c7f1336b67d5b0220142ccf723ddabb34e542ed65c395abc1fbf5b6c3e730396f15d25c49b668a1a401209da937e5609680cb30bff4a7661364ca1d1851c2506fa80c443f00a3d3bf7365004c6b6304f62b0e5cb175210270e75970bb20029b3879ec76c4acd320a8d0589e003636264d01a7d566504bfbac6782012088a9142fb610d856c19fd57f2d0cffe8dff689074b3d8a882103f368228456c940ac113e53dad5c104cf209f2f102a409207269383b6ab9b03deac68ffffffff01d0dc9800000000001976a9146d9d2b554d768232320587df75c4338ecc8bf37d88ac40280e5c").unwrap(); let secret = hex::decode("9da937e5609680cb30bff4a7661364ca1d1851c2506fa80c443f00a3d3bf7365").unwrap(); @@ -197,7 +197,7 @@ fn test_send_maker_spends_taker_payment_recoverable_tx() { #[test] fn test_generate_transaction() { - let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS); + let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS, ChainVariant::RICK); let coin = utxo_coin_for_test(client.into(), None, false); let unspents = vec![UnspentInfo { value: 10000000000, @@ -291,7 +291,7 @@ fn test_generate_transaction() { #[test] fn test_addresses_from_script() { - let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS); + let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS, ChainVariant::RICK); let coin = utxo_coin_for_test(client.into(), None, false); // P2PKH let script: Script = "76a91405aab5342166f8594baf17a7d9bef5d56744332788ac".into(); @@ -480,6 +480,7 @@ fn test_wait_for_payment_spend_timeout_electrum() { let block_headers_storage = BlockHeaderStorage { inner: Box::new(SqliteBlockHeadersStorage { ticker: TEST_COIN_NAME.into(), + chain_variant: ChainVariant::Standard, conn: Arc::new(Mutex::new(Connection::open_in_memory().unwrap())), }), }; @@ -500,6 +501,7 @@ fn test_wait_for_payment_spend_timeout_electrum() { block_headers_storage, StreamingManager::default(), abortable_system, + ChainVariant::Standard, ) .expect("Expected electrum_client_impl constructed without a problem"); let client = UtxoRpcClientEnum::Electrum(client); @@ -525,7 +527,7 @@ fn test_wait_for_payment_spend_timeout_electrum() { #[test] fn test_search_for_swap_tx_spend_electrum_was_spent() { let secret = hex::decode("a1c44607b870cd714a75d5243347fa36debcd3a91ff1f50b79f52d83238a0b2d").unwrap(); - let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS); + let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS, ChainVariant::RICK); let coin = utxo_coin_for_test( client.into(), Some("spice describe gravity federal blast come thank unfair canal monkey style afraid"), @@ -560,7 +562,7 @@ fn test_search_for_swap_tx_spend_electrum_was_spent() { #[test] fn test_search_for_swap_tx_spend_electrum_was_refunded() { let secret_hash = hex::decode("7a752434d4564c11b9333743122dab3a0aa21bd9").unwrap(); - let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS); + let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS, ChainVariant::RICK); let coin = utxo_coin_for_test( client.into(), Some("spice describe gravity federal blast come thank unfair canal monkey style afraid"), @@ -1013,7 +1015,7 @@ fn test_withdraw_rick_rewards_none() { #[test] fn test_utxo_lock() { // send several transactions concurrently to check that they are not using same inputs - let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS); + let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS, ChainVariant::RICK); let coin = utxo_coin_for_test(client.into(), None, false); let output = TransactionOutput { value: 1000000, @@ -1032,7 +1034,7 @@ fn test_utxo_lock() { #[test] fn test_spv_proof() { - let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS); + let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS, ChainVariant::RICK); // https://doc.explorer.dexstats.info/tx/a3ebedbe20f82e43708f276152cf7dfb03a6050921c8f266e48c00ab66e891fb let tx_str = "0400008085202f8901e15182af2c252bcfbd58884f3bdbd4d85ed036e53cfe2fd1f904ecfea10cb9f2010000006b483045022100d2435e0c9211114271ac452dc47fd08d3d2dc4bdd484d5750ee6bbda41056d520220408bfb236b7028b6fde0e59a1b6522949131a611584cce36c3df1e934c1748630121022d7424c741213a2b9b49aebdaa10e84419e642a8db0a09e359a3d4c850834846ffffffff02a09ba104000000001976a914054407d1a2224268037cfc7ca3bc438d082bedf488acdd28ce9157ba11001976a914046922483fab8ca76b23e55e9d338605e2dbab6088ac03d63665000000000000000000000000000000"; @@ -1067,7 +1069,7 @@ fn get_tx_details_coinbase_transaction() { /// https://marty.explorer.dexstats.info/tx/ae3220b868c677c77f8c9bdbc49b42da512260b45af695e672b1c5090815566c const TX_HASH: &str = "ae3220b868c677c77f8c9bdbc49b42da512260b45af695e672b1c5090815566c"; - let client = electrum_client_for_test(MARTY_ELECTRUM_ADDRS); + let client = electrum_client_for_test(MARTY_ELECTRUM_ADDRS, ChainVariant::MORTY); let coin = utxo_coin_for_test( client.into(), Some("spice describe gravity federal blast come thank unfair canal monkey style afraid"), @@ -1080,7 +1082,7 @@ fn get_tx_details_coinbase_transaction() { #[test] fn test_electrum_rpc_client_error() { - let client = electrum_client_for_test(&["electrum1.cipig.net:10060"]); + let client = electrum_client_for_test(&["electrum1.cipig.net:10060"], ChainVariant::Standard); let empty_hash = H256Json::default(); let err = block_on_f01(client.get_verbose_transaction(&empty_hash)).unwrap_err(); @@ -1459,26 +1461,32 @@ fn test_generate_tx_fee_is_correct_when_dynamic_fee_is_larger_than_relay() { #[test] fn test_get_median_time_past_from_electrum_kmd() { - let client = electrum_client_for_test(&[ - "electrum1.cipig.net:10001", - "electrum2.cipig.net:10001", - "electrum3.cipig.net:10001", - ]); + let client = electrum_client_for_test( + &[ + "electrum1.cipig.net:10001", + "electrum2.cipig.net:10001", + "electrum3.cipig.net:10001", + ], + ChainVariant::Standard, + ); - let mtp = block_on_f01(client.get_median_time_past(1773390, KMD_MTP_BLOCK_COUNT, CoinVariant::Standard)).unwrap(); + let mtp = block_on_f01(client.get_median_time_past(1773390, KMD_MTP_BLOCK_COUNT)).unwrap(); // the MTP is block time of 1773385 in this case assert_eq!(1583159915, mtp); } #[test] fn test_get_median_time_past_from_electrum_btc() { - let client = electrum_client_for_test(&[ - "electrum1.cipig.net:10000", - "electrum2.cipig.net:10000", - "electrum3.cipig.net:10000", - ]); + let client = electrum_client_for_test( + &[ + "electrum1.cipig.net:10000", + "electrum2.cipig.net:10000", + "electrum3.cipig.net:10000", + ], + ChainVariant::BTC, + ); - let mtp = block_on_f01(client.get_median_time_past(632858, KMD_MTP_BLOCK_COUNT, CoinVariant::Standard)).unwrap(); + let mtp = block_on_f01(client.get_median_time_past(632858, KMD_MTP_BLOCK_COUNT)).unwrap(); assert_eq!(1591173041, mtp); } @@ -1502,7 +1510,7 @@ fn test_get_median_time_past_from_native_has_median_in_get_block() { ) }); - let mtp = block_on_f01(client.get_median_time_past(632858, KMD_MTP_BLOCK_COUNT, CoinVariant::Standard)).unwrap(); + let mtp = block_on_f01(client.get_median_time_past(632858, KMD_MTP_BLOCK_COUNT)).unwrap(); assert_eq!(1591173041, mtp); } @@ -1545,7 +1553,7 @@ fn test_get_median_time_past_from_native_does_not_have_median_in_get_block() { MockResult::Return(Box::new(futures01::future::ok(block))) }); - let mtp = block_on_f01(client.get_median_time_past(632858, KMD_MTP_BLOCK_COUNT, CoinVariant::Standard)).unwrap(); + let mtp = block_on_f01(client.get_median_time_past(632858, KMD_MTP_BLOCK_COUNT)).unwrap(); assert_eq!(1591173041, mtp); } @@ -1675,7 +1683,7 @@ fn test_network_info_negative_time_offset() { #[test] fn test_unavailable_electrum_proto_version() { ElectrumClientImpl::try_new_arc.mock_safe( - |client_settings, block_headers_storage, streaming_manager, abortable_system, event_handlers| { + |client_settings, block_headers_storage, streaming_manager, abortable_system, event_handlers, chain_variant| { MockResult::Return(ElectrumClientImpl::with_protocol_version( client_settings, block_headers_storage, @@ -1683,6 +1691,7 @@ fn test_unavailable_electrum_proto_version() { abortable_system, event_handlers, OrdRange::new(1.8, 1.9).unwrap(), + chain_variant, )) }, ); @@ -1756,7 +1765,7 @@ fn test_spam_rick() { fn test_one_unavailable_electrum_proto_version() { // First mock with an unrealistically high version requirement that no server would support ElectrumClientImpl::try_new_arc.mock_safe( - |client_settings, block_headers_storage, streaming_manager, abortable_system, event_handlers| { + |client_settings, block_headers_storage, streaming_manager, abortable_system, event_handlers, chain_variant| { MockResult::Return(ElectrumClientImpl::with_protocol_version( client_settings, block_headers_storage, @@ -1764,12 +1773,13 @@ fn test_one_unavailable_electrum_proto_version() { abortable_system, event_handlers, OrdRange::new(7.4, 7.4).unwrap(), + chain_variant, )) }, ); // Try to connect with the high version requirement - should fail - let client = electrum_client_for_test(&["electrum1.cipig.net:10000"]); + let client = electrum_client_for_test(&["electrum1.cipig.net:10000"], ChainVariant::BTC); // When an electrum server doesn't support our protocol version range, it gets removed by the client, // wait a little bit to make sure this is the case. block_on(Timer::sleep(2.)); @@ -1784,7 +1794,7 @@ fn test_one_unavailable_electrum_proto_version() { // Now reset the mock to a supported version ElectrumClientImpl::try_new_arc.mock_safe( - |client_settings, block_headers_storage, streaming_manager, abortable_system, event_handlers| { + |client_settings, block_headers_storage, streaming_manager, abortable_system, event_handlers, chain_variant| { MockResult::Return(ElectrumClientImpl::with_protocol_version( client_settings, block_headers_storage, @@ -1792,6 +1802,7 @@ fn test_one_unavailable_electrum_proto_version() { abortable_system, event_handlers, OrdRange::new(1.4, 1.4).unwrap(), + chain_variant, )) }, ); @@ -2080,7 +2091,7 @@ fn test_get_mature_unspent_ordered_map_from_cache_impl( ) { const TX_HASH: &str = "b43f9ed47f7b97d4766b6f1614136fa0c55b9a52c97342428333521fa13ad714"; let tx_hash: H256Json = <[u8; 32]>::from_hex(TX_HASH).unwrap().into(); - let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS); + let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS, ChainVariant::RICK); let mut verbose = block_on_f01(client.get_verbose_transaction(&tx_hash)).unwrap(); verbose.confirmations = cached_confs; verbose.height = cached_height; @@ -2780,7 +2791,7 @@ fn test_qtum_is_unspent_mature() { #[ignore] // TODO it fails at least when fee is 2055837 sat per kbyte, need to investigate fn test_get_sender_trade_fee_dynamic_tx_fee() { - let rpc_client = electrum_client_for_test(&["electrum1.cipig.net:10071"]); + let rpc_client = electrum_client_for_test(&["electrum1.cipig.net:10071"], ChainVariant::Qtum); let mut coin_fields = utxo_coin_fields_for_test( UtxoRpcClientEnum::Electrum(rpc_client), Some("bob passphrase max taker vol with dynamic trade fee"), @@ -2819,7 +2830,7 @@ fn test_get_sender_trade_fee_dynamic_tx_fee() { // TODO: remove when we disable such old style txns #[test] fn test_validate_old_fee_tx() { - let rpc_client = electrum_client_for_test(MARTY_ELECTRUM_ADDRS); + let rpc_client = electrum_client_for_test(MARTY_ELECTRUM_ADDRS, ChainVariant::MORTY); let coin = utxo_coin_for_test(UtxoRpcClientEnum::Electrum(rpc_client), None, false); let tx_bytes = hex::decode("0400008085202f8901033aedb3c3c02fc76c15b393c7b1f638cfa6b4a1d502e00d57ad5b5305f12221000000006a473044022074879aabf38ef943eba7e4ce54c444d2d6aa93ac3e60ea1d7d288d7f17231c5002205e1671a62d8c031ac15e0e8456357e54865b7acbf49c7ebcba78058fd886b4bd012103242d9cb2168968d785f6914c494c303ff1c27ba0ad882dbc3c15cfa773ea953cffffffff0210270000000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac4802d913000000001976a914902053231ef0541a7628c11acac40d30f2a127bd88ac008e3765000000000000000000000000000000").unwrap(); let taker_fee_tx = coin.tx_enum_from_bytes(&tx_bytes).unwrap(); @@ -2839,7 +2850,7 @@ fn test_validate_old_fee_tx() { #[test] fn test_validate_fee_wrong_sender() { - let rpc_client = electrum_client_for_test(MARTY_ELECTRUM_ADDRS); + let rpc_client = electrum_client_for_test(MARTY_ELECTRUM_ADDRS, ChainVariant::MORTY); let coin = utxo_coin_for_test(UtxoRpcClientEnum::Electrum(rpc_client), None, false); // https://marty.explorer.dexstats.info/tx/99349d1c72ef396ecb39ab2989b888b02e22382249271c79cda8139825adc468 let tx_bytes = hex::decode("0400008085202f8901033aedb3c3c02fc76c15b393c7b1f638cfa6b4a1d502e00d57ad5b5305f12221000000006a473044022074879aabf38ef943eba7e4ce54c444d2d6aa93ac3e60ea1d7d288d7f17231c5002205e1671a62d8c031ac15e0e8456357e54865b7acbf49c7ebcba78058fd886b4bd012103242d9cb2168968d785f6914c494c303ff1c27ba0ad882dbc3c15cfa773ea953cffffffff0210270000000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac4802d913000000001976a914902053231ef0541a7628c11acac40d30f2a127bd88ac008e3765000000000000000000000000000000").unwrap(); @@ -2862,7 +2873,7 @@ fn test_validate_fee_wrong_sender() { #[test] fn test_validate_fee_min_block() { - let rpc_client = electrum_client_for_test(MARTY_ELECTRUM_ADDRS); + let rpc_client = electrum_client_for_test(MARTY_ELECTRUM_ADDRS, ChainVariant::MORTY); let coin = utxo_coin_for_test(UtxoRpcClientEnum::Electrum(rpc_client), None, false); // https://marty.explorer.dexstats.info/tx/99349d1c72ef396ecb39ab2989b888b02e22382249271c79cda8139825adc468 let tx_bytes = hex::decode("0400008085202f8901033aedb3c3c02fc76c15b393c7b1f638cfa6b4a1d502e00d57ad5b5305f12221000000006a473044022074879aabf38ef943eba7e4ce54c444d2d6aa93ac3e60ea1d7d288d7f17231c5002205e1671a62d8c031ac15e0e8456357e54865b7acbf49c7ebcba78058fd886b4bd012103242d9cb2168968d785f6914c494c303ff1c27ba0ad882dbc3c15cfa773ea953cffffffff0210270000000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac4802d913000000001976a914902053231ef0541a7628c11acac40d30f2a127bd88ac008e3765000000000000000000000000000000").unwrap(); @@ -2886,11 +2897,14 @@ fn test_validate_fee_min_block() { #[test] // https://github.com/KomodoPlatform/atomicDEX-API/issues/857 fn test_validate_fee_bch_70_bytes_signature() { - let rpc_client = electrum_client_for_test(&[ - "electrum1.cipig.net:10055", - "electrum2.cipig.net:10055", - "electrum3.cipig.net:10055", - ]); + let rpc_client = electrum_client_for_test( + &[ + "electrum1.cipig.net:10055", + "electrum2.cipig.net:10055", + "electrum3.cipig.net:10055", + ], + ChainVariant::BTC, + ); let coin = utxo_coin_for_test(UtxoRpcClientEnum::Electrum(rpc_client), None, false); // https://blockchair.com/bitcoin-cash/transaction/ccee05a6b5bbc6f50d2a65a5a3a04690d3e2d81082ad57d3ab471189f53dd70d let tx_bytes = hex::decode("0100000002cae89775f264e50f14238be86a7184b7f77bfe26f54067b794c546ec5eb9c91a020000006b483045022100d6ed080f722a0637a37552382f462230cc438984bc564bdb4b7094f06cfa38fa022062304a52602df1fbb3bebac4f56e1632ad456f62d9031f4983f07e546c8ec4d8412102ae7dc4ef1b49aadeff79cfad56664105f4d114e1716bc4f930cb27dbd309e521ffffffff11f386a6fe8f0431cb84f549b59be00f05e78f4a8a926c5e023a0d5f9112e8200000000069463043021f17eb93ed20a6f2cd357eabb41a4ec6329000ddc6d5b42ecbe642c5d41b206a022026bc4920c4ce3af751283574baa8e4a3efd4dad0d8fe6ba3ddf5d75628d36fda412102ae7dc4ef1b49aadeff79cfad56664105f4d114e1716bc4f930cb27dbd309e521ffffffff0210270000000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac57481c00000000001976a914bac11ce4cd2b1df2769c470d09b54f86df737e3c88ac035b4a60").unwrap(); @@ -2954,22 +2968,28 @@ fn firo_verbose_block_deserialize() { fn firo_lelantus_tx() { // https://explorer.firo.org/tx/06ed4b75010edcf404a315be70903473f44050c978bc37fbcee90e0b49114ba8 let tx_hash = "06ed4b75010edcf404a315be70903473f44050c978bc37fbcee90e0b49114ba8".into(); - let electrum = electrum_client_for_test(&[ - "electrumx01.firo.org:50001", - "electrumx02.firo.org:50001", - "electrumx03.firo.org:50001", - ]); + let electrum = electrum_client_for_test( + &[ + "electrumx01.firo.org:50001", + "electrumx02.firo.org:50001", + "electrumx03.firo.org:50001", + ], + ChainVariant::Standard, + ); let _tx = block_on_f01(electrum.get_verbose_transaction(&tx_hash)).unwrap(); } #[test] fn firo_lelantus_tx_details() { // https://explorer.firo.org/tx/06ed4b75010edcf404a315be70903473f44050c978bc37fbcee90e0b49114ba8 - let electrum = electrum_client_for_test(&[ - "electrumx01.firo.org:50001", - "electrumx02.firo.org:50001", - "electrumx03.firo.org:50001", - ]); + let electrum = electrum_client_for_test( + &[ + "electrumx01.firo.org:50001", + "electrumx02.firo.org:50001", + "electrumx03.firo.org:50001", + ], + ChainVariant::Standard, + ); let coin = utxo_coin_for_test(electrum.into(), None, false); let tx_details = get_tx_details_eq_for_both_versions( @@ -2999,22 +3019,28 @@ fn firo_lelantus_tx_details() { fn firo_spark_tx() { // https://explorer.firo.org/tx/c50e5a3f16744ac86bacae28d9251a29bf754d250592bce16a953cd961b584d5 let tx_hash = "c50e5a3f16744ac86bacae28d9251a29bf754d250592bce16a953cd961b584d5".into(); - let electrum = electrum_client_for_test(&[ - "electrumx01.firo.org:50001", - "electrumx02.firo.org:50001", - "electrumx03.firo.org:50001", - ]); + let electrum = electrum_client_for_test( + &[ + "electrumx01.firo.org:50001", + "electrumx02.firo.org:50001", + "electrumx03.firo.org:50001", + ], + ChainVariant::Standard, + ); let _tx = block_on_f01(electrum.get_verbose_transaction(&tx_hash)).unwrap(); } #[test] fn firo_spark_tx_details() { // https://explorer.firo.org/tx/c50e5a3f16744ac86bacae28d9251a29bf754d250592bce16a953cd961b584d5 - let electrum = electrum_client_for_test(&[ - "electrumx01.firo.org:50001", - "electrumx02.firo.org:50001", - "electrumx03.firo.org:50001", - ]); + let electrum = electrum_client_for_test( + &[ + "electrumx01.firo.org:50001", + "electrumx02.firo.org:50001", + "electrumx03.firo.org:50001", + ], + ChainVariant::Standard, + ); let coin = utxo_coin_for_test(electrum.into(), None, false); let tx_details = get_tx_details_eq_for_both_versions( @@ -3138,13 +3164,15 @@ fn test_generate_tx_doge_fee() { #[test] fn doge_mtp() { - let electrum = electrum_client_for_test(&[ - "electrum1.cipig.net:10060", - "electrum2.cipig.net:10060", - "electrum3.cipig.net:10060", - ]); - let mtp = block_on_f01(electrum.get_median_time_past(3631820, NonZeroU64::new(11).unwrap(), CoinVariant::Standard)) - .unwrap(); + let electrum = electrum_client_for_test( + &[ + "electrum1.cipig.net:10060", + "electrum2.cipig.net:10060", + "electrum3.cipig.net:10060", + ], + ChainVariant::Standard, + ); + let mtp = block_on_f01(electrum.get_median_time_past(3631820, NonZeroU64::new(11).unwrap())).unwrap(); assert_eq!(mtp, 1614849084); } @@ -3228,99 +3256,118 @@ fn test_parse_fixed_dingo_txfee_config() { #[test] fn firo_mtp() { - let electrum = electrum_client_for_test(&[ - "electrumx01.firo.org:50001", - "electrumx02.firo.org:50001", - "electrumx03.firo.org:50001", - ]); - let mtp = block_on_f01(electrum.get_median_time_past(356730, NonZeroU64::new(11).unwrap(), CoinVariant::Standard)) - .unwrap(); + let electrum = electrum_client_for_test( + &[ + "electrumx01.firo.org:50001", + "electrumx02.firo.org:50001", + "electrumx03.firo.org:50001", + ], + ChainVariant::Standard, + ); + let mtp = block_on_f01(electrum.get_median_time_past(356730, NonZeroU64::new(11).unwrap())).unwrap(); assert_eq!(mtp, 1616492629); } #[test] fn verus_mtp() { - let electrum = electrum_client_for_test(&["el0.verus.io:17485", "el1.verus.io:17485", "el2.verus.io:17485"]); - let mtp = block_on_f01(electrum.get_median_time_past(1480113, NonZeroU64::new(11).unwrap(), CoinVariant::Standard)) - .unwrap(); + let electrum = electrum_client_for_test( + &["el0.verus.io:17485", "el1.verus.io:17485", "el2.verus.io:17485"], + ChainVariant::Standard, + ); + let mtp = block_on_f01(electrum.get_median_time_past(1480113, NonZeroU64::new(11).unwrap())).unwrap(); assert_eq!(mtp, 1618579909); } #[test] fn sys_mtp() { - let electrum = electrum_client_for_test(&[ - "electrum1.cipig.net:10064", - "electrum2.cipig.net:10064", - "electrum3.cipig.net:10064", - ]); - let mtp = block_on_f01(electrum.get_median_time_past(1006678, NonZeroU64::new(11).unwrap(), CoinVariant::Standard)) - .unwrap(); + let electrum = electrum_client_for_test( + &[ + "electrum1.cipig.net:10064", + "electrum2.cipig.net:10064", + "electrum3.cipig.net:10064", + ], + ChainVariant::Standard, + ); + let mtp = block_on_f01(electrum.get_median_time_past(1006678, NonZeroU64::new(11).unwrap())).unwrap(); assert_eq!(mtp, 1620019628); } #[test] fn btc_mtp() { - let electrum = electrum_client_for_test(&[ - "electrum1.cipig.net:10000", - "electrum2.cipig.net:10000", - "electrum3.cipig.net:10000", - ]); - let mtp = block_on_f01(electrum.get_median_time_past(681659, NonZeroU64::new(11).unwrap(), CoinVariant::Standard)) - .unwrap(); + let electrum = electrum_client_for_test( + &[ + "electrum1.cipig.net:10000", + "electrum2.cipig.net:10000", + "electrum3.cipig.net:10000", + ], + ChainVariant::BTC, + ); + let mtp = block_on_f01(electrum.get_median_time_past(681659, NonZeroU64::new(11).unwrap())).unwrap(); assert_eq!(mtp, 1620019527); } #[test] fn rvn_mtp() { - let electrum = electrum_client_for_test(&[ - "electrum1.cipig.net:10051", - "electrum2.cipig.net:10051", - "electrum3.cipig.net:10051", - ]); - let mtp = - block_on_f01(electrum.get_median_time_past(1968120, NonZeroU64::new(11).unwrap(), CoinVariant::RVN)).unwrap(); + let electrum = electrum_client_for_test( + &[ + "electrum1.cipig.net:10051", + "electrum2.cipig.net:10051", + "electrum3.cipig.net:10051", + ], + ChainVariant::RVN, + ); + let mtp = block_on_f01(electrum.get_median_time_past(1968120, NonZeroU64::new(11).unwrap())).unwrap(); assert_eq!(mtp, 1633946264); } #[test] fn pivx_mtp() { - let electrum = electrum_client_for_test(&["electrum01.chainster.org:50001", "electrum02.chainster.org:50001"]); - let mtp = - block_on_f01(electrum.get_median_time_past(5014894, NonZeroU64::new(11).unwrap(), CoinVariant::PIVX)).unwrap(); + let electrum = electrum_client_for_test( + &["electrum01.chainster.org:50001", "electrum02.chainster.org:50001"], + ChainVariant::PIVX, + ); + let mtp = block_on_f01(electrum.get_median_time_past(5014894, NonZeroU64::new(11).unwrap())).unwrap(); assert_eq!(mtp, 1754356500); } #[test] fn qtum_mtp() { - let electrum = electrum_client_for_test(&[ - "electrum1.cipig.net:10050", - "electrum2.cipig.net:10050", - "electrum3.cipig.net:10050", - ]); - let mtp = - block_on_f01(electrum.get_median_time_past(681659, NonZeroU64::new(11).unwrap(), CoinVariant::Qtum)).unwrap(); + let electrum = electrum_client_for_test( + &[ + "electrum1.cipig.net:10050", + "electrum2.cipig.net:10050", + "electrum3.cipig.net:10050", + ], + ChainVariant::Qtum, + ); + let mtp = block_on_f01(electrum.get_median_time_past(681659, NonZeroU64::new(11).unwrap())).unwrap(); assert_eq!(mtp, 1598854128); } #[test] fn zer_mtp() { - let electrum = electrum_client_for_test(&[ - "electrum1.cipig.net:10065", - "electrum2.cipig.net:10065", - "electrum3.cipig.net:10065", - ]); - let mtp = block_on_f01(electrum.get_median_time_past(1130915, NonZeroU64::new(11).unwrap(), CoinVariant::Standard)) - .unwrap(); + let electrum = electrum_client_for_test( + &[ + "electrum1.cipig.net:10065", + "electrum2.cipig.net:10065", + "electrum3.cipig.net:10065", + ], + ChainVariant::Standard, + ); + let mtp = block_on_f01(electrum.get_median_time_past(1130915, NonZeroU64::new(11).unwrap())).unwrap(); assert_eq!(mtp, 1623240214); } #[test] fn test_tx_details_kmd_rewards() { - let electrum = electrum_client_for_test(&[ - "electrum1.cipig.net:10001", - "electrum2.cipig.net:10001", - "electrum3.cipig.net:10001", - ]); + let electrum = electrum_client_for_test( + &[ + "electrum1.cipig.net:10001", + "electrum2.cipig.net:10001", + "electrum3.cipig.net:10001", + ], + ChainVariant::Standard, + ); let mut fields = utxo_coin_fields_for_test(electrum.into(), None, false); fields.conf.ticker = "KMD".to_owned(); fields.derivation_method = DerivationMethod::SingleAddress( @@ -3354,11 +3401,14 @@ fn test_tx_details_kmd_rewards() { fn test_tx_details_kmd_rewards_claimed_by_other() { const TX_HASH: &str = "f09e8894959e74c1e727ffa5a753a30bf2dc6d5d677cc1f24b7ee5bb64e32c7d"; - let electrum = electrum_client_for_test(&[ - "electrum1.cipig.net:10001", - "electrum2.cipig.net:10001", - "electrum3.cipig.net:10001", - ]); + let electrum = electrum_client_for_test( + &[ + "electrum1.cipig.net:10001", + "electrum2.cipig.net:10001", + "electrum3.cipig.net:10001", + ], + ChainVariant::Standard, + ); let mut fields = utxo_coin_fields_for_test(electrum.into(), None, false); fields.conf.ticker = "KMD".to_owned(); fields.derivation_method = DerivationMethod::SingleAddress( @@ -3385,7 +3435,7 @@ fn test_tx_details_kmd_rewards_claimed_by_other() { fn test_tx_details_bch_no_rewards() { const TX_HASH: &str = "eb13d926f15cbb896e0bcc7a1a77a4ec63504e57a1524c13a7a9b80f43ecb05c"; - let electrum = electrum_client_for_test(T_BCH_ELECTRUMS); + let electrum = electrum_client_for_test(T_BCH_ELECTRUMS, ChainVariant::BTC); let coin = utxo_coin_for_test(electrum.into(), None, false); let tx_details = get_tx_details_eq_for_both_versions(&coin, TX_HASH); @@ -3402,11 +3452,14 @@ fn test_update_kmd_rewards() { // 535ffa3387d3fca14f4a4d373daf7edf00e463982755afce89bc8c48d8168024 const OUTDATED_TX_DETAILS: &str = r#"{"tx_hex":"0400008085202f8901afcadb73880bc1c9e7ce96b8274c2e2a4547415e649f425f98791685be009b73020000006b483045022100b8fbb77efea482b656ad16fc53c5a01d289054c2e429bf1d7bab16c3e822a83602200b87368a95c046b2ce6d0d092185138a3f234a7eb0d7f8227b196ef32358b93f012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff01dd15c293000000001976a91483762a373935ca241d557dfce89171d582b486de88ac99fe9960000000000000000000000000000000","tx_hash":"535ffa3387d3fca14f4a4d373daf7edf00e463982755afce89bc8c48d8168024","from":["RMGJ9tRST45RnwEKHPGgBLuY3moSYP7Mhk"],"to":["RMGJ9tRST45RnwEKHPGgBLuY3moSYP7Mhk"],"total_amount":"24.68539379","spent_by_me":"24.68539379","received_by_me":"24.78970333","my_balance_change":"0.10430954","block_height":2387532,"timestamp":1620705483,"fee_details":{"type":"Utxo","amount":"-0.10430954"},"coin":"KMD","internal_id":"535ffa3387d3fca14f4a4d373daf7edf00e463982755afce89bc8c48d8168024"}"#; - let electrum = electrum_client_for_test(&[ - "electrum1.cipig.net:10001", - "electrum2.cipig.net:10001", - "electrum3.cipig.net:10001", - ]); + let electrum = electrum_client_for_test( + &[ + "electrum1.cipig.net:10001", + "electrum2.cipig.net:10001", + "electrum3.cipig.net:10001", + ], + ChainVariant::Standard, + ); let mut fields = utxo_coin_fields_for_test(electrum.into(), None, false); fields.conf.ticker = "KMD".to_owned(); fields.derivation_method = DerivationMethod::SingleAddress( @@ -5104,7 +5157,7 @@ fn test_electrum_balance_deserializing() { #[test] fn test_electrum_display_balances() { - let rpc_client = electrum_client_for_test(DOC_ELECTRUM_ADDRS); + let rpc_client = electrum_client_for_test(DOC_ELECTRUM_ADDRS, ChainVariant::RICK); block_on(utxo_common_tests::test_electrum_display_balances(&rpc_client)); } @@ -5112,7 +5165,7 @@ fn test_electrum_display_balances() { fn test_for_non_existent_tx_hex_utxo_electrum() { // This test shouldn't wait till timeout! let timeout = wait_until_sec(120); - let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS); + let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS, ChainVariant::RICK); let coin = utxo_coin_for_test( client.into(), Some("spice describe gravity federal blast come thank unfair canal monkey style afraid"), @@ -5197,7 +5250,7 @@ fn test_native_display_balances() { #[test] fn test_message_hash() { - let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS); + let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS, ChainVariant::RICK); let coin = utxo_coin_for_test( client.into(), Some("spice describe gravity federal blast come thank unfair canal monkey style afraid"), @@ -5211,7 +5264,7 @@ fn test_message_hash() { #[test] fn test_sign_verify_message() { - let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS); + let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS, ChainVariant::RICK); let coin = utxo_coin_for_test( client.into(), Some("spice describe gravity federal blast come thank unfair canal monkey style afraid"), @@ -5232,7 +5285,7 @@ fn test_sign_verify_message() { #[test] fn test_sign_verify_message_segwit() { - let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS); + let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS, ChainVariant::RICK); let coin = utxo_coin_for_test( client.into(), Some("spice describe gravity federal blast come thank unfair canal monkey style afraid"), @@ -5259,7 +5312,7 @@ fn test_sign_verify_message_segwit() { #[test] fn test_tx_enum_from_bytes() { - let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS); + let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS, ChainVariant::RICK); let coin = utxo_coin_for_test(client.into(), None, false); let tx_hex = hex::decode("01000000017b1eabe0209b1fe794124575ef807057c77ada2138ae4fa8d6c4de0398a14f3f00000000494830450221008949f0cb400094ad2b5eb399d59d01c14d73d8fe6e96df1a7150deb388ab8935022079656090d7f6bac4c9a94e0aad311a4268e082a725f8aeae0573fb12ff866a5f01ffffffff01f0ca052a010000001976a914cbc20a7664f2f69e5355aa427045bc15e7c6c77288ac00000000").unwrap(); @@ -5277,7 +5330,7 @@ fn test_tx_enum_from_bytes() { #[test] fn test_hd_utxo_tx_history() { - let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS); + let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS, ChainVariant::RICK); block_on(utxo_common_tests::test_hd_utxo_tx_history_impl(client)); } @@ -5492,7 +5545,7 @@ fn rick_blocker_5() -> BlockHeader { let header = "0400000028a4f1aa8be606c8bf8195b2e95d478a83314ff9ad7b017457d9e58d00d1710bb43f41db65677e3fdb83ddbd8cfb4a7ad2e110f74bc19726dc949576e003a1ecfbc2f4300c01f0b7820d00e3347c8da4ee614674376cbc45359daa54f9b5493e381b405d0f0f0f2001003cfb15008ad9f4fab1ff4076f8919f743193f007c0db28f5106e003b0000fd400500acba878991f600ed8c022758be9ff9752ef175e7530324df4d1b87f5a03ca5c2c3fce10b08743bd5ba03912703b8f305f7dd382487d437d9b1823cdc11a00f59a20b235ef57502a0a7ad6fc7d3d242e8f4477a01fb8834ac4dc6e2e40e4909f9edc0db07c0f98df40e5a61327311b005c98a727694ebaabcb366b92dda4af9e3f6e72c5461dd81d6daccbd1fca8ec17597df7585947b54deb83554859776b5bcefadfa566ff12c04ac624f9416e76beccec35694ae0ed11dc17a911f114225be62cf5b971628f364f57d8348d95fdc415b0d2a7a477ea130d3320108739edf761f85f81efd6c0e4eafa8166b05bd74af7928b0786b63ae499dba38065be13e7541b7f4e26727d0fa6887e265e09709b940ca87295ce5984de7d4058b5d340b162935fa46ee20cac955379e3c8fa1ff92fb354bb2a0fedf697b683a5875f4ed2bcef984d296b0c1e07a52920f1dd5a60140c7c1245a52ed196df3292db8bfff52923b0a8615b6a99a5fcf1e5f461f01a04b1c3bb517fe16553e1f8e8aa20bd3cc2cac6d3242a2ce373737b57cec4637907fd236e0d44d91d59533484ec23634b93645c10a858d83805d731f300aa27a162e172216d7fc21170b4d232767e4c66f9a871224f13480e89c2edb0e6e1ef5cf75d9203839cc0282fd7852319232057f30793bb5552d94ebf3ffcc67b73f44e80c3de79b9d8d7f0175939722054bc2ddfb84288dff8c7554f191d6ee1b65c40b75d4435712d4e88c64d6379ab7e578bcd8117501504faa7a3be3a6a2826fd7a3e5e9efb1d3642937f3a35be5793be8e1d4acf9dd2dcd356d6e4c7d0c8b87587b8ad901b9ce71792ae0bdae27811b52300e6809e4691bfc7f738252e7c197e228cce5fda6130f8f518e5059530b731fe8afbf51308aa8da3bd31b1d1eb22cca1a896aed281397925265cd861a7eadb80124363dec8cb508aea7c277f04b9841888dd932471349e651ce2622a59065932f463ffce6b19a975d6914336ab49394afd17dfb9a448157007ea1437b1483587bc7de0dec5103cafad76704e91e9ea2b0b9a8570b935d5c65478e7195b08161be4625b8d5fd3658e6164cf2d6898ecbf1f14945fdd75bb991a3d9ffac713a3a7a81a31a765b9c37a578976aa15e66c97c957f4651dc5fc492c2111d8724d375a8293a36e0ddcf2a01facf30401d8677611522882e1447e4c8be5fa9ad073fb3fdcc6f673981484089090fe4c05bfaae173503e0f99c7407b297852d216463924d365d26b4cd63401a46bd7ed969ddb235044eb2373645144976c7f713720c0238ade9d3aae1d2b153e82d093232d4b12b2108ec564ae0e855e09252f1434c28d90bb298ab6d1750498bf90d93c8797901911548b81af1ba185be52c0dff9c1b11812941d2d527c95c4382879298f364077710b5efd56d1bf39148aedc4fcd9e8bddb4c36a3f901dc11f9493d1fbdfe80c88fa8866c1465c939c0d71cb57e78822b5fc3023578aa2d6b9cd3ebaa54f22876b935f251183d8a68459cab30cd19bcb4e4c1e1a5a83e4687a4795dc23732e81b9f024f70db96e412831d26e61d4fa292a95648e0b614d9a148cd852df1bf26a34ea971e63f8c634133ab7b13ac8045f6d6e20af2313b38d12cb8cee54a7aba7a7cd7e8b1b5e0b0931d4665a0bb36b63f325161b571fdd4f159f470e443e9b0cfb193bf4eea5fa9715dc6132cb8ed97f7f097837471a5147d14f2066cd3dcd50460d70180a7a24e2b5b9ab20caf952d2ea1b51747afec975f76d0313a98e444f20938bf709530960f9fbf5af9857cbe3410d37f3cba10ff57642861586b7c1b1c57019602f1529df9d6e45ca2f7663519c58915e9e299d5beee73cb4553238566844f571374d3f6a247dd8ecbbc893"; - BlockHeader::try_from_string_with_coin_variant(header.to_string(), "RICK".into()).unwrap() + BlockHeader::try_from_string_with_chain_variant(header.to_string(), ChainVariant::RICK).unwrap() } #[cfg(not(target_arch = "wasm32"))] @@ -5510,7 +5563,7 @@ fn test_block_header_utxo_loop_with_reorg() { for (idx, header) in rick_headers.into_iter().enumerate() { rick_headers_map.insert( (idx + 2) as u64, - BlockHeader::try_from_string_with_coin_variant(header, "RICK".into()).unwrap(), + BlockHeader::try_from_string_with_chain_variant(header, ChainVariant::RICK).unwrap(), ); } @@ -5643,7 +5696,7 @@ fn test_block_header_utxo_loop_with_reorg() { #[test] fn test_electrum_v14_block_hash() { - let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS); + let client = electrum_client_for_test(DOC_ELECTRUM_ADDRS, ChainVariant::RICK); // First verify BlockHeader hash implementation works correctly with a known reference block let headers = @@ -5656,7 +5709,7 @@ fn test_electrum_v14_block_hash() { .into_iter() .chain(headers.hex.0) .collect::>(); - let headers = Reader::new_with_coin_variant(&serialized, CoinVariant::RICK) + let headers = Reader::new_with_chain_variant(&serialized, ChainVariant::RICK) .read_list::() .expect("Failed to deserialize headers"); @@ -5687,7 +5740,7 @@ fn test_electrum_v14_block_hash() { .into_iter() .chain(headers.hex.0) .collect::>(); - let headers = Reader::new_with_coin_variant(&serialized, CoinVariant::RICK) + let headers = Reader::new_with_chain_variant(&serialized, ChainVariant::RICK) .read_list::() .expect("Failed to deserialize headers"); @@ -5716,8 +5769,8 @@ fn test_electrum_v14_block_hash() { #[ignore = "This is a utility test for debugging header deserialization and must be run explicitly"] fn test_scan_and_deserialize_block_headers() { // ========================== CONFIGURATION ========================== - /// The ticker of the coin to test (e.g., "NMC", "CHTA", "RVN"). - const COIN_TICKER: &str = "PIVX"; + /// Header layout for the configured coin ticker. + const CHAIN_VARIANT: ChainVariant = ChainVariant::PIVX; /// A list of active Electrum servers for the specified coin. const ELECTRUM_URLS: &[&str] = &["electrum01.chainster.org:50001", "electrum02.chainster.org:50001"]; /// The block height to start scanning from. @@ -5728,7 +5781,7 @@ fn test_scan_and_deserialize_block_headers() { const CHUNK_SIZE: u64 = 100; // =================================================================== - let client = electrum_client_for_test(ELECTRUM_URLS); + let client = electrum_client_for_test(ELECTRUM_URLS, CHAIN_VARIANT); let mut current_height = START_HEIGHT; loop { @@ -5755,7 +5808,7 @@ fn test_scan_and_deserialize_block_headers() { // This is the correct approach, inspired by your original test. // We create a single reader for the entire raw byte stream of concatenated headers. let raw_chunk_bytes = &headers_res.hex.0; - let mut reader = Reader::new_with_coin_variant(raw_chunk_bytes, COIN_TICKER.into()); + let mut reader = Reader::new_with_chain_variant(raw_chunk_bytes, CHAIN_VARIANT); // We loop exactly `count` times, reading one header in each iteration. // The `read` method will correctly consume a variable number of bytes depending on the header's content. diff --git a/mm2src/coins/utxo/utxo_wasm_tests.rs b/mm2src/coins/utxo/utxo_wasm_tests.rs index f6b1306fdd..e982fbb208 100644 --- a/mm2src/coins/utxo/utxo_wasm_tests.rs +++ b/mm2src/coins/utxo/utxo_wasm_tests.rs @@ -1,4 +1,4 @@ -use super::rpc_clients::{ElectrumClient, UtxoRpcClientOps}; +use super::rpc_clients::{ElectrumClient, ElectrumConnectionSettings, UtxoRpcClientOps}; use super::utxo_builder::{UtxoArcBuilder, UtxoCoinBuilderCommonOps}; use super::utxo_standard::UtxoStandardCoin; use super::*; @@ -7,7 +7,7 @@ use crate::{IguanaPrivKey, PrivKeyBuildPolicy}; use hex::FromHex; use mm2_core::mm_ctx::MmCtxBuilder; use mm2_test_helpers::for_tests::DOC_ELECTRUM_ADDRS; -use serialization::deserialize; +use serialization::{deserialize, ChainVariant}; use wasm_bindgen_test::*; wasm_bindgen_test_configure!(run_in_browser); @@ -40,10 +40,10 @@ pub async fn electrum_client_for_test(servers: &[&str]) -> ElectrumClient { collect_metrics: false, }; - let servers = servers.into_iter().map(|s| json::from_value(s).unwrap()).collect(); + let servers: Vec = servers.into_iter().map(|s| json::from_value(s).unwrap()).collect(); let abortable_system = AbortableQueue::default(); builder - .electrum_client(abortable_system, args, servers, (None, None)) + .electrum_client(abortable_system, args, ChainVariant::Standard, servers, (None, None)) .await .unwrap() } diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 0cb179b756..f95c0fa4dd 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -69,7 +69,6 @@ use mocktopus::macros::*; use rpc::v1::types::{Bytes as BytesJson, Transaction as RpcTransaction, H256 as H256Json, H264 as H264Json}; use script::{Builder as ScriptBuilder, Opcode, Script, TransactionInputSigner}; use serde_json::Value as Json; -use serialization::CoinVariant; use std::collections::{HashMap, HashSet}; use std::convert::TryInto; use std::iter; @@ -996,7 +995,7 @@ impl UtxoCoinBuilder for ZCoinBuilder<'_> { #[cfg(not(target_arch = "wasm32"))] ZcoinRpcMode::Native => init_native_client( &self, - self.native_client().map_mm_err()?, + self.native_client(utxo_arc.conf.chain_variant).map_mm_err()?, blocks_db, locked_notes_db.clone(), ) @@ -1967,7 +1966,7 @@ impl UtxoCommonOps for ZCoin { } async fn get_current_mtp(&self) -> UtxoRpcResult { - utxo_common::get_current_mtp(&self.utxo_arc, CoinVariant::Standard).await + utxo_common::get_current_mtp(&self.utxo_arc).await } fn is_unspent_mature(&self, output: &RpcTransaction) -> bool { diff --git a/mm2src/mm2_bitcoin/chain/src/block_header.rs b/mm2src/mm2_bitcoin/chain/src/block_header.rs index b0eb0aad75..190441c1f7 100644 --- a/mm2src/mm2_bitcoin/chain/src/block_header.rs +++ b/mm2src/mm2_bitcoin/chain/src/block_header.rs @@ -8,7 +8,7 @@ use hash::H256; use hex::FromHex; use primitives::bytes::Bytes; use primitives::U256; -use ser::{deserialize, serialize, CoinVariant, Deserializable, Reader, Serializable, Stream}; +use ser::{deserialize, serialize, ChainVariant, Deserializable, Reader, Serializable, Stream}; use std::io; use transaction::{deserialize_tx, TxType}; use {OutPoint, Transaction}; @@ -233,14 +233,14 @@ impl Deserializable for BlockHeader { let merkle_root_hash = reader.read()?; // This is needed to deserialize coin like LBC correctly. - let claim_trie_root = if version == BIP9_NO_SOFT_FORK_BLOCK_HEADER_VERSION && reader.coin_variant().is_lbc() { + let claim_trie_root = if version == BIP9_NO_SOFT_FORK_BLOCK_HEADER_VERSION && reader.chain_variant().is_lbc() { Some(reader.read()?) } else { None }; - let is_zcash_style = (version == 4 && !reader.coin_variant().is_btc() && !reader.coin_variant().is_ppc()) - || reader.coin_variant().is_kmd_assetchain(); + let is_zcash_style = (version == 4 && !reader.chain_variant().is_btc() && !reader.chain_variant().is_ppc()) + || reader.chain_variant().is_kmd_assetchain(); let mut hash_final_sapling_root = if is_zcash_style { Some(reader.read()?) } else { None }; let time = reader.read()?; let bits = if is_zcash_style { @@ -250,7 +250,7 @@ impl Deserializable for BlockHeader { }; let nonce = if is_zcash_style { BlockHeaderNonce::H256(reader.read()?) - } else if (version == KAWPOW_VERSION && reader.coin_variant().is_rvn()) + } else if (version == KAWPOW_VERSION && reader.chain_variant().is_rvn()) || (version == MTP_POW_VERSION && time >= PROG_POW_SWITCH_TIME) { BlockHeaderNonce::U32(0) @@ -258,7 +258,7 @@ impl Deserializable for BlockHeader { BlockHeaderNonce::U32(reader.read()?) }; // A PIVX header is a standard header with a `hash_final_sapling_root` added after the nonce. - hash_final_sapling_root = if reader.coin_variant().is_pivx() { + hash_final_sapling_root = if reader.chain_variant().is_pivx() { Some(reader.read()?) } else { hash_final_sapling_root @@ -272,7 +272,7 @@ impl Deserializable for BlockHeader { // https://en.bitcoin.it/wiki/Merged_mining_specification#Merged_mining_coinbase // AuxPoW is only for AuxPoW coins (Dogecoin, Namecoin, Syscoin, etc.). // BTC-like variants (BTC, BCH, NAV, ...) must NOT interpret bit 8 as AuxPoW. - let aux_pow = if (version & AUXPOW_VERSION_FLAG) != 0 && !reader.coin_variant().is_btc() { + let aux_pow = if (version & AUXPOW_VERSION_FLAG) != 0 && !reader.chain_variant().is_btc() { let coinbase_tx = deserialize_tx(reader, TxType::StandardWithWitness)?; let parent_block_hash = reader.read()?; let coinbase_branch = reader.read()?; @@ -302,7 +302,7 @@ impl Deserializable for BlockHeader { }; let (hash_state_root, hash_utxo_root, prevout_stake, vch_block_sig_dlgt) = - if version == BIP9_NO_SOFT_FORK_BLOCK_HEADER_VERSION && reader.coin_variant().is_qtum() { + if version == BIP9_NO_SOFT_FORK_BLOCK_HEADER_VERSION && reader.chain_variant().is_qtum() { ( Some(reader.read()?), Some(reader.read()?), @@ -314,7 +314,7 @@ impl Deserializable for BlockHeader { }; // https://github.com/RavenProject/Ravencoin/blob/61c790447a5afe150d9892705ac421d595a2df60/src/primitives/block.h#L67 - let (n_height, n_nonce_u64, mix_hash) = if version == KAWPOW_VERSION && reader.coin_variant().is_rvn() { + let (n_height, n_nonce_u64, mix_hash) = if version == KAWPOW_VERSION && reader.chain_variant().is_rvn() { (Some(reader.read()?), Some(reader.read()?), Some(reader.read()?)) } else { (None, None, None) @@ -346,11 +346,11 @@ impl Deserializable for BlockHeader { } impl BlockHeader { - pub fn try_from_string_with_coin_variant(header: String, coin_variant: CoinVariant) -> Result { + pub fn try_from_string_with_chain_variant(header: String, chain_variant: ChainVariant) -> Result { let buffer = &header .from_hex::>() .map_err(|e| ser::Error::Custom(e.to_string()))? as &[u8]; - let mut reader = Reader::new_with_coin_variant(buffer, coin_variant); + let mut reader = Reader::new_with_chain_variant(buffer, chain_variant); reader.read::() } @@ -409,7 +409,7 @@ mod tests { }; use hex::FromHex; use primitives::bytes::Bytes; - use ser::{deserialize, serialize, serialize_list, CoinVariant, Error as ReaderError, Reader, Stream}; + use ser::{deserialize, serialize, serialize_list, ChainVariant, Error as ReaderError, Reader, Stream}; const AUX_POW_VERSION_DOGE: u32 = 6422788; @@ -1063,7 +1063,7 @@ mod tests { 115, 127, 165, 240, 245, 7, 151, 6, 193, 202, 139, 227, 48, 79, 12, 178, 233, 104, 176, 129, 136, 171, 201, 184, 15, 6, 37, 118, 246, 130, 5, 177, 140, 190, 58, 38, 213, 98, 92, 42, 1, 26, 63, 91, 195, 195, ]; - let mut reader = Reader::new_with_coin_variant(headers_bytes, CoinVariant::LBC); + let mut reader = Reader::new_with_chain_variant(headers_bytes, ChainVariant::LBC); let headers = reader.read_list::().unwrap(); for header in headers.iter() { assert_eq!(header.version, BIP9_NO_SOFT_FORK_BLOCK_HEADER_VERSION); @@ -2154,7 +2154,7 @@ mod tests { 226, 1, 77, 51, 114, 115, 8, 152, 211, 49, 161, 62, 190, 80, 119, 154, 30, 193, 226, 46, 248, 169, 69, 226, 86, 134, 101, 238, 115, 14, 63, 174, 123, 30, 7, 123, 174, 60, 13, 100, 49, 23, 123, ]; - let mut reader = Reader::new_with_coin_variant(headers_bytes, CoinVariant::Qtum); + let mut reader = Reader::new_with_chain_variant(headers_bytes, ChainVariant::Qtum); let headers = reader.read_list::().unwrap(); for header in headers.iter() { assert_eq!(header.version, BIP9_NO_SOFT_FORK_BLOCK_HEADER_VERSION); @@ -2489,7 +2489,7 @@ mod tests { 252, 71, 214, 56, 220, 173, 79, 220, 196, 15, 211, ]; - let mut reader = Reader::new_with_coin_variant(headers_bytes, CoinVariant::RVN); + let mut reader = Reader::new_with_chain_variant(headers_bytes, ChainVariant::RVN); let headers = reader.read_list::().unwrap(); for header in headers.iter() { assert_eq!(header.version, KAWPOW_VERSION); @@ -2503,7 +2503,7 @@ mod tests { // https://live.blockcypher.com/btc/block/0000000000000000097336f8439779072501753e2f48b8798c66188139f2d9cf/ let header = "04000000462a79dfa51b541648ee55df74cdc14b9ea7feb932e912060000000000000000374c1707a72691be50070bc5029d586e9200d672c6c3dfd29d267bf6b2b01b9e0ace395654a91118923bd9d5"; let header_bytes = &header.from_hex::>().unwrap() as &[u8]; - let mut reader = Reader::new_with_coin_variant(header_bytes, CoinVariant::BTC); + let mut reader = Reader::new_with_chain_variant(header_bytes, ChainVariant::BTC); let header = reader.read::().unwrap(); assert_eq!(header.version, 4); let serialized = serialize(&header); @@ -2515,7 +2515,7 @@ mod tests { // https://live.blockcypher.com/btc/block/000000000000000006e35d6675fb0fec767a5f3b346261a5160f6e2a8d258070/ let header = "00000030af7e7389ca428b05d8902fcdc148e70974524d39cb56bc0100000000000000007ce0cd0c9c648d1b585d29b9ab23ebc987619d43925b3c768d7cb4bc097cfb821441c05614a107187aef1ee1"; let header_bytes = &header.from_hex::>().unwrap() as &[u8]; - let mut reader = Reader::new_with_coin_variant(header_bytes, CoinVariant::BTC); + let mut reader = Reader::new_with_chain_variant(header_bytes, ChainVariant::BTC); let header = reader.read::().unwrap(); assert_eq!(header.version, KAWPOW_VERSION); let serialized = serialize(&header); @@ -2527,7 +2527,7 @@ mod tests { // https://explorer.bitcoinunlimited.info/block/000000000000000001fa10bec90256a006203df5347de869d6500814f27668f1 let header = "0000003075135a61aad9ebe8db6a4e9c5e3ee6febd92a6788ee1860100000000000000007098ff568e4c66422bc62b5e3106fc16c08f64c91d7c6d5cd0519f1fade0d7332106286694a10218f925a695"; let header_bytes = &header.from_hex::>().unwrap() as &[u8]; - let mut reader = Reader::new_with_coin_variant(header_bytes, CoinVariant::BTC); + let mut reader = Reader::new_with_chain_variant(header_bytes, ChainVariant::BTC); let header = reader.read::().unwrap(); assert_eq!(header.version, KAWPOW_VERSION); assert_eq!( @@ -2593,7 +2593,7 @@ mod tests { 53, 161, 162, 247, 132, 187, 50, 235, 188, 174, 70, 185, 245, 211, 141, 119, 79, 178, 153, 254, 11, 140, 176, 126, 250, 146, 57, 162, 99, 45, 233, 12, 28, 0, 0, 0, 0, ]; - let mut reader = Reader::new_with_coin_variant(&serialized_headers, CoinVariant::PPC); + let mut reader = Reader::new_with_chain_variant(&serialized_headers, ChainVariant::PPC); let headers = reader.read_list::().unwrap(); let serialized_from_deserialized = serialize_list(&headers); assert_eq!(serialized_from_deserialized.take(), serialized_headers); @@ -2668,7 +2668,7 @@ mod tests { 116, 80, 28, 198, 158, 251, 91, 106, 67, 68, 64, 116, 254, 225, 22, 100, 27, 178, 157, 165, 108, 43, 74, 127, 69, 105, 145, 252, 146, 178, ]; - let mut reader = Reader::new_with_coin_variant(&header_bytes, "RICK".into()); + let mut reader = Reader::new_with_chain_variant(&header_bytes, ChainVariant::RICK); let header = reader.read::().unwrap(); assert_eq!(header.version, 1); let serialized = serialize(&header); @@ -2745,7 +2745,7 @@ mod tests { 177, 201, 167, 14, 130, 112, 23, 34, 136, 129, 229, 62, 122, 148, 56, 32, 94, 62, 254, 254, 207, 15, 102, 197, 30, 99, 165, 167, 45, 90, 134, 148, 30, 190, 180, 68, ]; - let mut reader = Reader::new_with_coin_variant(&header_bytes, "RICK".into()); + let mut reader = Reader::new_with_chain_variant(&header_bytes, ChainVariant::RICK); let header = reader.read::().unwrap(); assert_eq!(header.version, 4); let serialized = serialize(&header); @@ -2821,7 +2821,7 @@ mod tests { 116, 80, 28, 198, 158, 251, 91, 106, 67, 68, 64, 116, 254, 225, 22, 100, 27, 178, 157, 165, 108, 43, 74, 127, 69, 105, 145, 252, 146, 178, ]; - let mut reader = Reader::new_with_coin_variant(&header_bytes, "MORTY".into()); + let mut reader = Reader::new_with_chain_variant(&header_bytes, ChainVariant::MORTY); let header = reader.read::().unwrap(); assert_eq!(header.version, 1); let serialized = serialize(&header); @@ -2899,7 +2899,7 @@ mod tests { 18, 144, 31, 139, 113, 34, 195, 127, 249, 240, 148, 137, 108, 183, 210, 82, 68, 79, 47, 159, 196, 184, 61, 124, 219, 155, ]; - let mut reader = Reader::new_with_coin_variant(&header_bytes, "MORTY".into()); + let mut reader = Reader::new_with_chain_variant(&header_bytes, ChainVariant::MORTY); let header = reader.read::().unwrap(); assert_eq!(header.version, 4); let serialized = serialize(&header); @@ -2922,7 +2922,7 @@ mod tests { fn test_pivx_sapling_header() { let header_hex = "0b000000097d36aeeb2585e6c08226f8f48cb91213708fcad603cb67be76efa5b3b31c0baf86a77624fd298be0f5a7b908d17d3d83edf8f681de2913b2584fb92380e152594229684411051b00000000c801eff496c2720766cdbf2ec20b5436b37350e2945f85a7feb8a4b4a12d4323"; let header_bytes = &header_hex.from_hex::>().unwrap() as &[u8]; - let mut reader = Reader::new_with_coin_variant(header_bytes, CoinVariant::PIVX); + let mut reader = Reader::new_with_chain_variant(header_bytes, ChainVariant::PIVX); let header: BlockHeader = reader.read().unwrap(); // Sapling root must be present @@ -2953,7 +2953,7 @@ mod tests { let header_bytes: Vec = header_hex.from_hex().unwrap(); // Treat NAV as BTC-style (no AuxPoW parsing) - let mut reader = Reader::new_with_coin_variant(header_bytes.as_slice(), CoinVariant::BTC); + let mut reader = Reader::new_with_chain_variant(header_bytes.as_slice(), ChainVariant::BTC); let header: BlockHeader = reader.read().unwrap(); assert_eq!(header.version, 0x7bf5ffff); diff --git a/mm2src/mm2_bitcoin/serialization/src/lib.rs b/mm2src/mm2_bitcoin/serialization/src/lib.rs index 07e290b7e7..b1e9cf06c7 100644 --- a/mm2src/mm2_bitcoin/serialization/src/lib.rs +++ b/mm2src/mm2_bitcoin/serialization/src/lib.rs @@ -13,7 +13,7 @@ pub use primitives::{bytes, compact, hash}; pub use compact_integer::{parse_compact_int, CompactInteger}; pub use list::List; -pub use reader::{deserialize, deserialize_iterator, CoinVariant, Deserializable, Error, ReadIterator, Reader}; +pub use reader::{deserialize, deserialize_iterator, ChainVariant, Deserializable, Error, ReadIterator, Reader}; pub use stream::{ serialize, serialize_list, serialize_with_flags, serialized_list_size, serialized_list_size_with_flags, Serializable, Stream, SERIALIZE_TRANSACTION_WITNESS, diff --git a/mm2src/mm2_bitcoin/serialization/src/reader.rs b/mm2src/mm2_bitcoin/serialization/src/reader.rs index 431cd6becf..0c12ae90b9 100644 --- a/mm2src/mm2_bitcoin/serialization/src/reader.rs +++ b/mm2src/mm2_bitcoin/serialization/src/reader.rs @@ -1,12 +1,8 @@ use compact_integer::CompactInteger; use derive_more::Display; +use std::convert::TryFrom; use std::{io, marker}; -const BTC_FORKS: &[&str] = &["BTC", "BCH", "NAV", "RIC"]; -const PIVX_FORKS: &[&str] = &["PIVX", "DOGEC"]; -const QTUM_FORKS: &[&str] = &["QTUM", "RUNES"]; -const RVN_FORKS: &[&str] = &["RVN", "AIPG", "XNA", "EVR", "MEWC", "AVN"]; - pub fn deserialize(buffer: R) -> Result where R: io::Read, @@ -56,8 +52,8 @@ pub trait Deserializable { T: io::Read; } -#[derive(Debug)] -pub enum CoinVariant { +#[derive(Debug, Clone, Copy)] +pub enum ChainVariant { // Todo: https://github.com/KomodoPlatform/atomicDEX-API/issues/1345 BTC, Qtum, @@ -73,55 +69,45 @@ pub enum CoinVariant { PIVX, } -impl CoinVariant { +impl ChainVariant { pub fn is_btc(&self) -> bool { - matches!(self, CoinVariant::BTC) + matches!(self, ChainVariant::BTC) } pub fn is_qtum(&self) -> bool { - matches!(self, CoinVariant::Qtum) + matches!(self, ChainVariant::Qtum) } pub fn is_lbc(&self) -> bool { - matches!(self, CoinVariant::LBC) + matches!(self, ChainVariant::LBC) } pub fn is_ppc(&self) -> bool { - matches!(self, CoinVariant::PPC) + matches!(self, ChainVariant::PPC) } pub fn is_kmd_assetchain(&self) -> bool { - matches!(self, CoinVariant::RICK | CoinVariant::MORTY) + matches!(self, ChainVariant::RICK | ChainVariant::MORTY) } pub fn is_rvn(&self) -> bool { - matches!(self, CoinVariant::RVN) + matches!(self, ChainVariant::RVN) } pub fn is_pivx(&self) -> bool { - matches!(self, CoinVariant::PIVX) + matches!(self, ChainVariant::PIVX) } } -fn ticker_matches(ticker: &str, with: &str) -> bool { - ticker == with || ticker.contains(&format!("{with}-")) || ticker.contains(&format!("{with}_")) -} - -impl From<&str> for CoinVariant { - fn from(ticker: &str) -> Self { - match ticker { - // "BTC", "BTC-segwit", "tBTC", "tBTC-segwit", "BCH", "tBCH", etc.. - t if BTC_FORKS.iter().any(|ticker| ticker_matches(t, ticker)) => CoinVariant::BTC, - // "QTUM", "QTUM-segwit", "tQTUM", "tQTUM-segwit", etc.. - t if QTUM_FORKS.iter().any(|ticker| ticker_matches(t, ticker)) => CoinVariant::Qtum, - // "LBC", "LBC-segwit", etc.. - t if ticker_matches(t, "LBC") => CoinVariant::LBC, - // "PPC", "PPC-segwit", etc.. - t if ticker_matches(t, "PPC") => CoinVariant::PPC, - // "RICK" - t if ticker_matches(t, "RICK") => CoinVariant::RICK, - // "MORTY" - t if ticker_matches(t, "MORTY") => CoinVariant::MORTY, - // `RVN`, `AIPG`, etc.. - t if RVN_FORKS.iter().any(|ticker| ticker_matches(t, ticker)) => CoinVariant::RVN, - // PIVX family ("PIVX", "DOGEC", …) - t if PIVX_FORKS.iter().any(|ticker| ticker_matches(t, ticker)) => CoinVariant::PIVX, - _ => CoinVariant::Standard, +impl TryFrom<&str> for ChainVariant { + type Error = String; + + fn try_from(value: &str) -> Result { + match value { + "BTC" => Ok(ChainVariant::BTC), + "QTUM" => Ok(ChainVariant::Qtum), + "LBC" => Ok(ChainVariant::LBC), + "PPC" => Ok(ChainVariant::PPC), + "RICK" => Ok(ChainVariant::RICK), + "MORTY" => Ok(ChainVariant::MORTY), + "RVN" => Ok(ChainVariant::RVN), + "PIVX" => Ok(ChainVariant::PIVX), + _ => Err(format!("Unknown chain variant: {}", value)), } } } @@ -131,7 +117,7 @@ impl From<&str> for CoinVariant { pub struct Reader { buffer: T, peeked: Option, - coin_variant: CoinVariant, + chain_variant: ChainVariant, } impl<'a> Reader<&'a [u8]> { @@ -140,16 +126,16 @@ impl<'a> Reader<&'a [u8]> { Reader { buffer, peeked: None, - coin_variant: CoinVariant::Standard, + chain_variant: ChainVariant::Standard, } } /// Convenient way of creating for slice of bytes - pub fn new_with_coin_variant(buffer: &'a [u8], coin_variant: CoinVariant) -> Self { + pub fn new_with_chain_variant(buffer: &'a [u8], chain_variant: ChainVariant) -> Self { Reader { buffer, peeked: None, - coin_variant, + chain_variant, } } } @@ -184,7 +170,15 @@ where Reader { buffer: read, peeked: None, - coin_variant: CoinVariant::Standard, + chain_variant: ChainVariant::Standard, + } + } + + pub fn from_read_with_chain_variant(read: R, chain_variant: ChainVariant) -> Self { + Reader { + buffer: read, + peeked: None, + chain_variant, } } @@ -255,8 +249,8 @@ where } } - pub fn coin_variant(&self) -> &CoinVariant { - &self.coin_variant + pub fn chain_variant(&self) -> &ChainVariant { + &self.chain_variant } } diff --git a/mm2src/mm2_bitcoin/spv_validation/src/work.rs b/mm2src/mm2_bitcoin/spv_validation/src/work.rs index fae1e6fdd5..2a411179b4 100644 --- a/mm2src/mm2_bitcoin/spv_validation/src/work.rs +++ b/mm2src/mm2_bitcoin/spv_validation/src/work.rs @@ -177,6 +177,7 @@ pub(crate) mod tests { use lazy_static::lazy_static; use primitives::hash::H256; use serde::Deserialize; + use serialization::ChainVariant; use std::collections::HashMap; const BLOCK_HEADERS_STR: &str = include_str!("./for_tests/workTestVectors.json"); @@ -200,7 +201,11 @@ pub(crate) mod tests { .get(coin) .unwrap() .iter() - .map(|h| (h.height, h.hex.as_str().into())) + .map(|h| { + let header = BlockHeader::try_from_string_with_chain_variant(h.hex.clone(), ChainVariant::Standard) + .expect("valid block header in test data"); + (h.height, header) + }) .collect() }