diff --git a/Cargo.lock b/Cargo.lock index 90712913b..9a35453f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1506,6 +1506,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "dashmap" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +dependencies = [ + "cfg-if", + "hashbrown 0.12.3", + "lock_api", + "once_cell", + "parking_lot_core 0.9.7", +] + [[package]] name = "data-encoding" version = "2.3.3" @@ -4851,6 +4864,7 @@ dependencies = [ "mockall", "mockall_double", "orderbook-primitives", + "orderbook-rpc", "parity-scale-codec", "parking_lot 0.12.1", "polkadex-primitives", @@ -4867,6 +4881,7 @@ dependencies = [ "sc-network-gossip", "sc-network-sync", "sc-network-test", + "sc-rpc", "sc-utils", "serde", "serde_json", @@ -4906,6 +4921,7 @@ dependencies = [ "scale-info", "serde", "serde_json", + "serde_with", "sp-api", "sp-application-crypto", "sp-core", @@ -8486,6 +8502,31 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "serial_test" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d" +dependencies = [ + "dashmap", + "futures 0.3.28", + "lazy_static", + "log", + "parking_lot 0.12.1", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + [[package]] name = "sha-1" version = "0.9.8" @@ -10029,6 +10070,7 @@ dependencies = [ "sc-utils", "serde", "serde_json", + "serial_test", "sp-api", "sp-application-crypto", "sp-arithmetic", diff --git a/clients/orderbook/Cargo.toml b/clients/orderbook/Cargo.toml index b8d6f2ae3..20a5cb37c 100644 --- a/clients/orderbook/Cargo.toml +++ b/clients/orderbook/Cargo.toml @@ -60,3 +60,5 @@ env_logger = "0.10.0" mockall = "0.11.1" testing_logger = "0.1.1" mockall_double = "0.3.0" +orderbook-rpc = {path="rpc"} +sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.37" } diff --git a/clients/orderbook/rpc/src/lib.rs b/clients/orderbook/rpc/src/lib.rs index 5cf491866..3f989385d 100644 --- a/clients/orderbook/rpc/src/lib.rs +++ b/clients/orderbook/rpc/src/lib.rs @@ -14,7 +14,8 @@ use jsonrpsee::{ use log::info; use orderbook::DbRef; use orderbook_primitives::{ - types::{AccountAsset, ObMessage, ObRecoveryState}, + recovery::ObRecoveryState, + types::{AccountAsset, ObMessage}, ObApi, }; use parking_lot::RwLock; @@ -23,7 +24,6 @@ use reference_trie::ExtensionLayout; use rust_decimal::Decimal; use sp_api::ProvideRuntimeApi; use sp_arithmetic::traits::SaturatedConversion; -use sp_blockchain::HeaderBackend; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; use std::sync::Arc; use trie_db::{TrieDBMut, TrieDBMutBuilder, TrieMut}; @@ -90,17 +90,22 @@ pub trait OrderbookApi { } /// Implements the OrderbookApi RPC trait for interacting with Orderbook. -pub struct OrderbookRpc { +pub struct OrderbookRpc { tx: UnboundedSender, _executor: SubscriptionTaskExecutor, last_successful_block_number_snapshot_created: Arc>, memory_db: DbRef, working_state_root: Arc>, - client: Arc, + runtime: Arc, _marker: std::marker::PhantomData, } -impl OrderbookRpc { +impl OrderbookRpc +where + Block: BlockT, + Runtime: Send + Sync + ProvideRuntimeApi, + Runtime::Api: ObApi, +{ /// Creates a new Orderbook Rpc handler instance. pub fn new( _executor: SubscriptionTaskExecutor, @@ -108,7 +113,7 @@ impl OrderbookRpc { last_successful_block_number_snapshot_created: Arc>, memory_db: DbRef, working_state_root: Arc>, - client: Arc, + runtime: Arc, ) -> Self { Self { tx, @@ -116,26 +121,13 @@ impl OrderbookRpc { last_successful_block_number_snapshot_created, memory_db, working_state_root, - client, + runtime, _marker: Default::default(), } } -} - -#[async_trait] -impl OrderbookApiServer for OrderbookRpc -where - Block: BlockT, - Client: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, - Client::Api: ObApi, -{ - async fn submit_action(&self, message: ObMessage) -> RpcResult<()> { - let mut tx = self.tx.clone(); - tx.send(message).await?; - Ok(()) - } - async fn get_orderbook_recovery_state(&self) -> RpcResult> { + /// Returns the serialized offchain state based on the last finalized snapshot summary + pub async fn get_orderbook_recovery_state_inner(&self) -> RpcResult> { let last_finalized_block_guard = self.last_successful_block_number_snapshot_created.read(); let last_finalized_block = *last_finalized_block_guard; @@ -143,26 +135,28 @@ where let mut memory_db = memory_db_guard.clone(); let worker_state_root_guard = self.working_state_root.read(); let mut worker_state_root = *worker_state_root_guard; - + info!(target:"orderbook-rpc","Getting all registered accounts at last finalized snapshot"); // get all accounts let all_register_accounts = self - .client + .runtime .runtime_api() .get_all_accounts_and_proxies(&BlockId::number(last_finalized_block.saturated_into())) .map_err(|err| JsonRpseeError::Custom(err.to_string() + "failed to get accounts"))?; + info!(target:"orderbook-rpc","main accounts found: {:?}, Getting last finalized snapshot summary",all_register_accounts.len()); // get snapshot summary let last_snapshot_summary = self - .client + .runtime .runtime_api() .get_latest_snapshot(&BlockId::number(last_finalized_block.saturated_into())) .map_err(|err| { JsonRpseeError::Custom(err.to_string() + "failed to get snapshot summary") })?; + info!(target:"orderbook-rpc","Getting allowlisted asset ids"); // Get all allow listed AssetIds let allowlisted_asset_ids = self - .client + .runtime .runtime_api() .get_allowlisted_assets(&BlockId::number(last_finalized_block.saturated_into())) .map_err(|err| { @@ -196,7 +190,7 @@ where } Ok(()) }; - + info!(target:"orderbook-rpc","Loading balances from trie to result..."); for (user_main_account, list_of_proxy_accounts) in all_register_accounts { for asset in allowlisted_asset_ids.clone() { let account_asset = AccountAsset::new(user_main_account.clone(), asset); @@ -208,8 +202,27 @@ where ob_recovery_state.snapshot_id = last_snapshot_summary.snapshot_id; ob_recovery_state.state_change_id = last_snapshot_summary.state_change_id; ob_recovery_state.worker_nonce = last_snapshot_summary.worker_nonce; - + info!(target:"orderbook-rpc","Serializing Orderbook snapshot state"); let serialize_ob_recovery_state = serde_json::to_vec(&ob_recovery_state)?; + info!(target:"orderbook-rpc","Orderbook snapshot state exported"); Ok(serialize_ob_recovery_state) } } + +#[async_trait] +impl OrderbookApiServer for OrderbookRpc +where + Block: BlockT, + Runtime: Send + Sync + 'static + ProvideRuntimeApi, + Runtime::Api: ObApi, +{ + async fn submit_action(&self, message: ObMessage) -> RpcResult<()> { + let mut tx = self.tx.clone(); + tx.send(message).await?; + Ok(()) + } + + async fn get_orderbook_recovery_state(&self) -> RpcResult> { + self.get_orderbook_recovery_state_inner().await + } +} diff --git a/clients/orderbook/src/error.rs b/clients/orderbook/src/error.rs index 9dfd0d26b..42de2e25c 100644 --- a/clients/orderbook/src/error.rs +++ b/clients/orderbook/src/error.rs @@ -39,10 +39,6 @@ pub enum Error { // SnapshotSigningFailed, #[error("Failed to submit snapshot to runtime")] FailedToSubmitSnapshotToRuntime, - #[error("Main account already registered")] - MainAlreadyRegistered, - #[error("Proxy account already registered")] - ProxyAlreadyRegistered, #[error("Offchain storage not available")] OffchainStorageNotAvailable, #[error("Signature verification Failed")] diff --git a/clients/orderbook/src/tests/mod.rs b/clients/orderbook/src/tests/mod.rs index 40d2d27d9..6ac0b9133 100644 --- a/clients/orderbook/src/tests/mod.rs +++ b/clients/orderbook/src/tests/mod.rs @@ -1,3 +1,4 @@ +pub mod rpc; pub mod sync; use crate::protocol_standard_name; @@ -11,7 +12,8 @@ use orderbook_primitives::{ }; use parking_lot::{Mutex, RwLock}; use polkadex_primitives::{ - ocex::TradingPairConfig, withdrawal::Withdrawal, AccountId, BlockNumber, + ingress::IngressMessages, ocex::TradingPairConfig, withdrawal::Withdrawal, AccountId, AssetId, + BlockNumber, }; use primitive_types::H256; use reference_trie::RefHasher; @@ -40,6 +42,8 @@ pub(crate) struct TestApi { pub operator_key: Option, pub trading_config: Vec<(TradingPair, TradingPairConfig)>, pub withdrawals: Arc>>>>, + pub ingress_messages: Vec>, + pub allowlisted_assets: Vec, } impl TestApi { @@ -139,6 +143,14 @@ impl TestApi { pub fn read_trading_pair_configs(&self) -> Vec<(TradingPair, TradingPairConfig)> { self.trading_config.clone() } + + pub fn get_ingress_messages(&self) -> Vec> { + self.ingress_messages.clone() + } + + pub fn get_allowlisted_assets(&self) -> Vec { + self.allowlisted_assets.clone() + } } sp_api::mock_impl_runtime_apis! { @@ -154,7 +166,7 @@ impl ObApi for RuntimeApi { } /// Return the ingress messages at the given block - fn ingress_messages() -> Vec> { Vec::new() } + fn ingress_messages() -> Vec> { self.inner.get_ingress_messages() } /// Submits the snapshot to runtime fn submit_snapshot(summary: SnapshotSummary) -> Result<(), ()> { @@ -196,6 +208,10 @@ impl ObApi for RuntimeApi { fn read_trading_pair_configs() -> Vec<(TradingPair, TradingPairConfig)>{ self.inner.read_trading_pair_configs() } + /// Returns the allowlisted asset ids + fn get_allowlisted_assets() -> Vec { + self.inner.get_allowlisted_assets() + } } } diff --git a/clients/orderbook/src/tests/rpc.rs b/clients/orderbook/src/tests/rpc.rs new file mode 100644 index 000000000..829c83b83 --- /dev/null +++ b/clients/orderbook/src/tests/rpc.rs @@ -0,0 +1,202 @@ +use crate::tests::{ + generate_and_finalize_blocks, initialize_orderbook, make_ob_ids, ObTestnet, TestApi, +}; +use futures::{future::BoxFuture, SinkExt, StreamExt}; +use memory_db::MemoryDB; +use orderbook_primitives::{ + crypto::AuthorityId, + types::{AccountAsset, ObMessage, UserActions}, +}; +use orderbook_rpc::OrderbookRpc; +use parking_lot::RwLock; +use polkadex_primitives::{ingress::IngressMessages, AssetId}; +use rust_decimal::{prelude::FromPrimitive, Decimal}; +use sc_client_api::BlockchainEvents; +use sc_keystore::LocalKeystore; +use sc_network_test::TestNetFactory; +use sp_arithmetic::traits::SaturatedConversion; +use sp_core::Pair; +use sp_keyring::AccountKeyring; +use sp_keystore::CryptoStore; +use std::{collections::HashMap, sync::Arc}; + +#[tokio::test] +pub async fn test_orderbook_rpc() { + sp_tracing::try_init_simple(); + + let (orderbook_operator, _) = sp_core::ecdsa::Pair::generate(); + let mut testnet = ObTestnet::new(3, 0); + let peers = &[ + (AccountKeyring::Alice, true), + (AccountKeyring::Bob, true), + (AccountKeyring::Charlie, true), + ]; + + let active: Vec = + make_ob_ids(&peers.iter().map(|(k, _)| k.clone()).collect::>()); + + let main = AccountKeyring::Alice; + let proxy1 = AccountKeyring::Bob; + let proxy2 = AccountKeyring::Charlie; + + let runtime = Arc::new(TestApi { + active, + latest_snapshot_nonce: Arc::new(Default::default()), + snapshots: Arc::new(Default::default()), + unprocessed: Arc::new(Default::default()), + main_to_proxy_mapping: HashMap::from([( + main.to_account_id(), + vec![proxy1.to_account_id(), proxy2.to_account_id()], + )]), + pending_snapshot: None, + operator_key: Some(orderbook_operator.public()), + trading_config: vec![], + withdrawals: Arc::new(Default::default()), + ingress_messages: vec![ + IngressMessages::RegisterUser(main.to_account_id(), proxy1.to_account_id()), + IngressMessages::Deposit( + main.to_account_id(), + AssetId::Polkadex, + Decimal::from_f64(1.456).unwrap(), + ), + IngressMessages::AddProxy(main.to_account_id(), proxy2.to_account_id()), + ], + allowlisted_assets: vec![AssetId::Polkadex], + }); + + let peer_id = 0; + let (sender, receiver) = futures::channel::mpsc::unbounded(); + testnet.peers[peer_id].data.peer_rpc_link = Some(sender.clone()); + testnet.peers[peer_id].data.is_validator = true; + testnet.peers[peer_id].data.last_successful_block_number_snapshot_created = + Arc::new(RwLock::new(0_u32.saturated_into())); + testnet.peers[peer_id].data.memory_db = Arc::new(RwLock::new(MemoryDB::default())); + testnet.peers[peer_id].data.working_state_root = Arc::new(RwLock::new([0; 32])); + + let key = AccountKeyring::Dave; + + // Generate the crypto material with test keys, + // we have to use file based keystore, + // in memory keystore doesn't seem to work here + let keystore = + Some(Arc::new(LocalKeystore::open(format!("keystore-{:?}", peer_id), None).unwrap())); + let (pair, seed) = + orderbook_primitives::crypto::Pair::from_string_with_seed(&key.to_seed(), None).unwrap(); + // Insert the key + keystore + .as_ref() + .unwrap() + .insert_unknown(orderbook_primitives::KEY_TYPE, &key.to_seed(), pair.public().as_ref()) + .await + .unwrap(); + // Check if the key is present or not + keystore + .as_ref() + .unwrap() + .key_pair::(&pair.public()) + .unwrap(); + + let sync_oracle = testnet.peers[peer_id].network_service().clone(); + + let rpc_handle = OrderbookRpc::new( + Arc::new(DummyTaskExecutor), + sender, + testnet.peers[peer_id] + .data + .last_successful_block_number_snapshot_created + .clone(), + testnet.peers[peer_id].data.memory_db.clone(), + testnet.peers[peer_id].data.working_state_root.clone(), + runtime.clone(), + ); + let worker_params = crate::worker::WorkerParams { + client: testnet.peers[peer_id].client().as_client(), + backend: testnet.peers[peer_id].client().as_backend(), + runtime, + sync_oracle, + is_validator: true, + network: testnet.peers[peer_id].network_service().clone(), + protocol_name: "/ob/1".into(), + message_sender_link: receiver, + metrics: None, + _marker: Default::default(), + last_successful_block_number_snapshot_created: testnet.peers[peer_id] + .data + .last_successful_block_number_snapshot_created + .clone(), + memory_db: testnet.peers[peer_id].data.memory_db.clone(), + working_state_root: testnet.peers[peer_id].data.working_state_root.clone(), + keystore, + }; + + let mut finality_stream_future = testnet.peers[peer_id] + .client() + .as_client() + .finality_notification_stream() + .fuse(); + + let mut worker = crate::worker::ObWorker::<_, _, _, _, _, _>::new(worker_params); + + // Send the RPC with Ob message + let mut message = ObMessage { + worker_nonce: 1, + stid: 10, + action: UserActions::BlockImport(1), + signature: Default::default(), + }; + message.signature = orderbook_operator.sign_prehashed(&message.sign_data()); + // Generate one block + generate_and_finalize_blocks(1, &mut testnet, 1).await; + let next_finalized_blk = finality_stream_future.next().await.unwrap(); + + // Progress the worker's chain + worker.handle_finality_notification(&next_finalized_blk).await.unwrap(); + + worker.process_new_user_action(&message).await.unwrap(); + + let result: Vec = rpc_handle.get_orderbook_recovery_state_inner().await.unwrap(); + + let offchain_state: orderbook_primitives::recovery::ObRecoveryState = + serde_json::from_slice(&result).unwrap(); + // Assert everything. + + assert_eq!(offchain_state.worker_nonce, 0); // We didn't generate any snapshot yet. + assert_eq!(offchain_state.state_change_id, 0); // We didn't generate any snapshot yet. + assert_eq!(offchain_state.snapshot_id, 0); // We didn't generate any snapshot yet. + assert_eq!(offchain_state.account_ids.len(), 1); + assert_eq!( + offchain_state.account_ids.get(&main.to_account_id()).unwrap(), + &vec![proxy1.to_account_id(), proxy2.to_account_id()] + ); + assert_eq!( + offchain_state + .balances + .get(&AccountAsset { main: main.to_account_id(), asset: AssetId::Polkadex }) + .cloned() + .unwrap(), + Decimal::from_f64(1.456).unwrap() + ); +} + +#[derive(Clone)] +pub struct DummyTaskExecutor; + +impl sp_core::traits::SpawnNamed for DummyTaskExecutor { + fn spawn_blocking( + &self, + name: &'static str, + group: Option<&'static str>, + future: BoxFuture<'static, ()>, + ) { + todo!() + } + + fn spawn( + &self, + name: &'static str, + group: Option<&'static str>, + future: BoxFuture<'static, ()>, + ) { + todo!() + } +} diff --git a/clients/orderbook/src/tests/sync.rs b/clients/orderbook/src/tests/sync.rs index f1e4bf8de..ab183ad5e 100644 --- a/clients/orderbook/src/tests/sync.rs +++ b/clients/orderbook/src/tests/sync.rs @@ -46,6 +46,8 @@ pub async fn test_orderbook_snapshot() { operator_key: Some(orderbook_operator.public()), trading_config: vec![], withdrawals: Arc::new(Default::default()), + ingress_messages: vec![], + allowlisted_assets: vec![], }); let ob_peers = peers diff --git a/clients/orderbook/src/worker.rs b/clients/orderbook/src/worker.rs index 84fd26fe7..7a956eb7b 100644 --- a/clients/orderbook/src/worker.rs +++ b/clients/orderbook/src/worker.rs @@ -1242,8 +1242,8 @@ pub fn register_main( ) -> Result<(), Error> { info!(target: "orderbook", "Registering main account: {:?}", main); if trie.contains(&main.encode())? { - error!(target: "orderbook", "Main account already registered: {:?}", main); - return Err(Error::MainAlreadyRegistered) + warn!(target: "orderbook", "Main account already registered: {:?}", main); + return Ok(()) } let account_info = AccountInfo { proxies: vec![proxy] }; trie.insert(&main.encode(), &account_info.encode())?; @@ -1273,7 +1273,8 @@ pub fn add_proxy( info!(target: "orderbook", "Main account found: {:?}", main); let mut account_info = AccountInfo::decode(&mut &data[..])?; if account_info.proxies.contains(&proxy) { - return Err(Error::ProxyAlreadyRegistered) + warn!(target: "orderbook", "Proxy account already registered: {:?}", proxy); + return Ok(()) } account_info.proxies.push(proxy); trie.insert(&main.encode(), &account_info.encode())?; diff --git a/clients/orderbook/src/worker_tests.rs b/clients/orderbook/src/worker_tests.rs index d48a79d27..ed423d4f5 100644 --- a/clients/orderbook/src/worker_tests.rs +++ b/clients/orderbook/src/worker_tests.rs @@ -44,19 +44,6 @@ pub fn register_main_will_store_successfully() { assert_eq!(account_info_in_db.proxies, vec![alice_proxy]); } -// Try to re register main account and assert expected error -#[test] -pub fn register_main_with_the_same_account_will_return_main_already_registered_error() { - let mut working_state_root = [0u8; 32]; - let mut memory_db: MemoryDB, Vec> = Default::default(); - let mut trie: TrieDBMut = - TrieDBMutBuilder::new(&mut memory_db, &mut working_state_root).build(); - let (alice_main, alice_proxy) = get_alice_main_and_proxy_account(); - assert!(register_main(&mut trie, alice_main.clone(), alice_proxy.clone()).is_ok()); - let result = register_main(&mut trie, alice_main.clone(), alice_proxy.clone()); - assert_eq!(result, Err(Error::MainAlreadyRegistered).into()); -} - // add proxy account and assert changes in db #[test] pub fn add_proxy_will_store_it_successfully() { @@ -74,31 +61,6 @@ pub fn add_proxy_will_store_it_successfully() { assert_eq!(account_info_in_db.proxies, vec![alice_proxy, alice_new_proxy_account]); } -// Try to add a duplicate proxy account and assert expected error -#[test] -pub fn add_proxy_with_the_same_proxy_account_will_return_proxy_already_registered_error() { - let mut working_state_root = [0u8; 32]; - let mut memory_db: MemoryDB, Vec> = Default::default(); - let mut trie: TrieDBMut = - TrieDBMutBuilder::new(&mut memory_db, &mut working_state_root).build(); - let (alice_main, alice_proxy) = get_alice_main_and_proxy_account(); - assert!(register_main(&mut trie, alice_main.clone(), alice_proxy.clone()).is_ok()); - let result = add_proxy(&mut trie, alice_main.clone(), alice_proxy.clone()); - assert_eq!(result, Err(Error::ProxyAlreadyRegistered).into()); -} - -// Try to add a proxy account when main account is not registered and assert expected error -#[test] -pub fn add_proxy_with_not_registered_main_account_will_return_main_account_not_found_error() { - let mut working_state_root = [0u8; 32]; - let mut memory_db: MemoryDB, Vec> = Default::default(); - let mut trie: TrieDBMut = - TrieDBMutBuilder::new(&mut memory_db, &mut working_state_root).build(); - let (alice_main, alice_proxy) = get_alice_main_and_proxy_account(); - let result = add_proxy(&mut trie, alice_main.clone(), alice_proxy.clone()); - assert_eq!(result, Err(Error::MainAccountNotFound).into()); -} - // remove proxy account and assert changes in db #[test] pub fn remove_proxy_will_remove_it_from_the_storage_successfully() { diff --git a/clients/thea/Cargo.toml b/clients/thea/Cargo.toml index a581a50e5..43382bb4d 100644 --- a/clients/thea/Cargo.toml +++ b/clients/thea/Cargo.toml @@ -54,3 +54,4 @@ substrate-test-runtime-client = {git = "https://github.com/paritytech/substrate" mockall = "0.11.1" testing_logger = "0.1.1" mockall_double = "0.3.0" +serial_test = "2.0.0" diff --git a/clients/thea/src/tests/deposit.rs b/clients/thea/src/tests/deposit.rs index ab18c90e7..fe001bf93 100644 --- a/clients/thea/src/tests/deposit.rs +++ b/clients/thea/src/tests/deposit.rs @@ -74,6 +74,7 @@ impl ForeignConnector for DummyForeignConnector { } #[tokio::test] +#[serial_test::serial] pub async fn test_foreign_deposit() { sp_tracing::try_init_simple(); diff --git a/clients/thea/src/tests/mod.rs b/clients/thea/src/tests/mod.rs index 2bcfd6fe6..79bfd6ef2 100644 --- a/clients/thea/src/tests/mod.rs +++ b/clients/thea/src/tests/mod.rs @@ -32,6 +32,7 @@ pub mod deposit; pub mod withdrawal; #[derive(Clone, Default)] +// This is the mock of native runtime state pub(crate) struct TestApi { authorities: BTreeMap>, validator_set_id: ValidatorSetId, diff --git a/clients/thea/src/tests/withdrawal.rs b/clients/thea/src/tests/withdrawal.rs index d5e2be767..dffb89738 100644 --- a/clients/thea/src/tests/withdrawal.rs +++ b/clients/thea/src/tests/withdrawal.rs @@ -86,6 +86,7 @@ impl ForeignConnector for DummyForeignConnector { } #[tokio::test] +#[serial_test::serial] pub async fn test_withdrawal() { sp_tracing::try_init_simple(); diff --git a/pallets/thea-message-handler/src/lib.rs b/pallets/thea-message-handler/src/lib.rs index 66d2cd67f..65dfa7ae3 100644 --- a/pallets/thea-message-handler/src/lib.rs +++ b/pallets/thea-message-handler/src/lib.rs @@ -199,7 +199,7 @@ impl Pallet { // Find who all signed this payload let signed_auths_indexes: Vec = return_set_bits(bitmap); - + // TODO: Super majority check here. // Create a vector of public keys of everyone who signed let auths = >::get(payload.validator_set_id); let mut signatories: Vec = vec![]; diff --git a/pallets/thea/src/lib.rs b/pallets/thea/src/lib.rs index 754894f55..daf75cac1 100644 --- a/pallets/thea/src/lib.rs +++ b/pallets/thea/src/lib.rs @@ -213,7 +213,8 @@ impl Pallet { // Find who all signed this payload let signed_auths_indexes: Vec = return_set_bits(bitmap); - + // TODO: Check if we have 2/3rd authorities signed on this. + // TODO: Make, > indexed by network as key1 and validator setid as key2 // Create a vector of public keys of everyone who signed let auths: Vec = >::get(payload.network).to_vec(); let mut signatories: Vec = vec![]; diff --git a/primitives/orderbook/Cargo.toml b/primitives/orderbook/Cargo.toml index 84a7ef80d..e6f095376 100644 --- a/primitives/orderbook/Cargo.toml +++ b/primitives/orderbook/Cargo.toml @@ -19,11 +19,13 @@ polkadex-primitives = { workspace = true } chrono = { version = "0.4.23", optional = true } rand = { version = "0.8.5", optional = true } serde = { version = "1.0.152", optional = true, default-features = false } +serde_with = {version="2.3.2", features =["json"],optional = true} anyhow = { version = "1.0.69", default-features = false } rust_decimal = { git = "https://github.com/Polkadex-Substrate/rust-decimal.git", branch = "master", features = ["scale-codec"], default-features = false } bls-primitives = { path = "../bls-primitives", default-features = false } libp2p = { version = "0.50.0", optional = true} + [dev-dependencies] serde_json = "1.0.94" @@ -36,6 +38,7 @@ std = [ "rand", "bls-primitives/std", "serde", + "serde_with", "anyhow/std", "rust_decimal/std", "polkadex-primitives/std", diff --git a/primitives/orderbook/src/lib.rs b/primitives/orderbook/src/lib.rs index 5235ba620..d573352cc 100644 --- a/primitives/orderbook/src/lib.rs +++ b/primitives/orderbook/src/lib.rs @@ -22,6 +22,9 @@ use sp_std::vec::Vec; pub mod constants; pub mod types; +#[cfg(feature = "std")] +pub mod recovery; + /// Key type for Orderbook module. pub const KEY_TYPE: sp_application_crypto::KeyTypeId = sp_application_crypto::KeyTypeId(*b"orbk"); diff --git a/primitives/orderbook/src/recovery.rs b/primitives/orderbook/src/recovery.rs new file mode 100644 index 000000000..62e16acd9 --- /dev/null +++ b/primitives/orderbook/src/recovery.rs @@ -0,0 +1,26 @@ +use crate::types::AccountAsset; +use parity_scale_codec::{Decode, Encode}; +use polkadex_primitives::{AccountId, BlockNumber}; +use rust_decimal::Decimal; +use serde_with::{json::JsonString, serde_as}; +use std::collections::BTreeMap; + +/// A struct representing the recovery state of an Order Book. +#[serde_as] +#[derive(Clone, Debug, Encode, Decode, Default, serde::Serialize, serde::Deserialize)] +pub struct ObRecoveryState { + /// The snapshot ID of the order book recovery state. + pub snapshot_id: u64, + /// A `BTreeMap` that maps main account to a vector of proxy account. + #[serde_as(as = "JsonString>")] + pub account_ids: BTreeMap>, + /// A `BTreeMap` that maps `AccountAsset`s to `Decimal` balances. + #[serde_as(as = "JsonString>")] + pub balances: BTreeMap, + /// The last block number that was processed by validator. + pub last_processed_block_number: BlockNumber, + /// State change id + pub state_change_id: u64, + /// worker nonce + pub worker_nonce: u64, +} diff --git a/primitives/orderbook/src/types.rs b/primitives/orderbook/src/types.rs index c8610782a..5bd3b5a73 100644 --- a/primitives/orderbook/src/types.rs +++ b/primitives/orderbook/src/types.rs @@ -1,12 +1,12 @@ use crate::constants::*; use parity_scale_codec::{Decode, Encode}; use polkadex_primitives::{ - ocex::TradingPairConfig, withdrawal::Withdrawal, AccountId, AssetId, BlockNumber, Signature, + ocex::TradingPairConfig, withdrawal::Withdrawal, AccountId, AssetId, Signature, }; use rust_decimal::{prelude::Zero, Decimal, RoundingStrategy}; use sp_core::H256; use sp_runtime::traits::Verify; -use sp_std::{cmp::Ordering, collections::btree_map::BTreeMap}; +use sp_std::cmp::Ordering; #[cfg(not(feature = "std"))] use sp_std::vec::Vec; @@ -20,24 +20,6 @@ use std::{ pub type OrderId = H256; -/// A struct representing the recovery state of an Order Book. -#[derive(Clone, Debug, Encode, Decode, Default)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -pub struct ObRecoveryState { - /// The snapshot ID of the order book recovery state. - pub snapshot_id: u64, - /// A `BTreeMap` that maps main account to a vector of proxy account. - pub account_ids: BTreeMap>, - /// A `BTreeMap` that maps `AccountAsset`s to `Decimal` balances. - pub balances: BTreeMap, - /// The last block number that was processed by validator. - pub last_processed_block_number: BlockNumber, - /// State change id - pub state_change_id: u64, - /// worker nonce - pub worker_nonce: u64, -} - #[derive(Clone, Debug, Encode, Decode)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub struct AccountInfo {