Skip to content

Commit

Permalink
clear_nft_db RPC
Browse files Browse the repository at this point in the history
  • Loading branch information
laruh committed Dec 13, 2023
1 parent c19e007 commit 1586b71
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 7 deletions.
2 changes: 1 addition & 1 deletion mm2src/coins/lp_coins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2335,7 +2335,7 @@ pub enum WithdrawError {
},
#[display(fmt = "DB error {}", _0)]
DbError(String),
#[display(fmt = "My address:= {}, while current Nft owner:= {}", my_address, token_owner)]
#[display(fmt = "My address is {}, while current Nft owner is {}", my_address, token_owner)]
MyAddressNotNftOwner {
my_address: String,
token_owner: String,
Expand Down
34 changes: 30 additions & 4 deletions mm2src/coins/nft.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ use nft_structs::{Chain, ContractType, ConvertChain, Nft, NftFromMoralis, NftLis

use crate::eth::{eth_addr_to_hex, get_eth_address, withdraw_erc1155, withdraw_erc721, EthCoin, EthCoinType,
EthTxFeeDetails};
use crate::nft::nft_errors::{MetaFromUrlError, ProtectFromSpamError, TransferConfirmationsError,
use crate::nft::nft_errors::{ClearNftDbError, MetaFromUrlError, ProtectFromSpamError, TransferConfirmationsError,
UpdateSpamPhishingError};
use crate::nft::nft_structs::{build_nft_with_empty_meta, BuildNftFields, NftCommon, NftCtx, NftTransferCommon,
PhishingDomainReq, PhishingDomainRes, RefreshMetadataReq, SpamContractReq,
SpamContractRes, TransferMeta, TransferStatus, UriMeta};
use crate::nft::nft_structs::{build_nft_with_empty_meta, BuildNftFields, ClearNftDbReq, NftCommon, NftCtx,
NftTransferCommon, PhishingDomainReq, PhishingDomainRes, RefreshMetadataReq,
SpamContractReq, SpamContractRes, TransferMeta, TransferStatus, UriMeta};
use crate::nft::storage::{NftListStorageOps, NftTransferHistoryStorageOps};
use common::parse_rfc3339_to_timestamp;
use crypto::StandardHDCoinAddress;
Expand Down Expand Up @@ -1372,3 +1372,29 @@ pub(crate) fn get_domain_from_url(url: Option<&str>) -> Option<String> {
url.and_then(|uri| Url::parse(uri).ok())
.and_then(|url| url.domain().map(String::from))
}

/// todo add doc com
pub async fn clear_nft_db(ctx: MmArc, req: ClearNftDbReq) -> MmResult<(), ClearNftDbError> {
let chains = if req.clear_all {
vec![Chain::Avalanche, Chain::Bsc, Chain::Eth, Chain::Fantom, Chain::Polygon]
} else {
req.chains
};
clear_nft_data_for_chains(&ctx, chains).await
}

async fn clear_nft_data_for_chains(ctx: &MmArc, chains: Vec<Chain>) -> MmResult<(), ClearNftDbError> {
let nft_ctx = NftCtx::from_ctx(ctx).map_to_mm(ClearNftDbError::Internal)?;

let storage = nft_ctx.lock_db().await?;
for chain in &chains {
let is_nft_list_init = NftListStorageOps::is_initialized(&storage, chain).await?;
let is_history_init = NftTransferHistoryStorageOps::is_initialized(&storage, chain).await?;
if !is_nft_list_init && !is_history_init {
continue;
}
storage.clear_nft_data(chain).await?;
storage.clear_history_data(chain).await?;
}
Ok(())
}
25 changes: 25 additions & 0 deletions mm2src/coins/nft/nft_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -380,3 +380,28 @@ impl From<CoinFindError> for TransferConfirmationsError {
}
}
}

#[derive(Clone, Debug, Deserialize, Display, PartialEq, Serialize, SerializeErrorType)]
#[serde(tag = "error_type", content = "error_data")]
pub enum ClearNftDbError {
#[display(fmt = "DB error {}", _0)]
DbError(String),
#[display(fmt = "Internal: {}", _0)]
Internal(String),
}

impl<T: NftStorageError> From<T> for ClearNftDbError {
fn from(err: T) -> Self { ClearNftDbError::DbError(format!("{:?}", err)) }
}

impl From<LockDBError> for ClearNftDbError {
fn from(e: LockDBError) -> Self { ClearNftDbError::DbError(e.to_string()) }
}

impl HttpStatusCode for ClearNftDbError {
fn status_code(&self) -> StatusCode {
match self {
ClearNftDbError::DbError(_) | ClearNftDbError::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR,
}
}
}
7 changes: 7 additions & 0 deletions mm2src/coins/nft/nft_structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -732,3 +732,10 @@ where
let s = String::deserialize(deserializer)?;
BigUint::from_str(&s).map_err(serde::de::Error::custom)
}

#[derive(Debug, Deserialize)]
pub struct ClearNftDbReq {
pub(crate) chains: Vec<Chain>,
#[serde(default)]
pub(crate) clear_all: bool,
}
61 changes: 60 additions & 1 deletion mm2src/coins/nft/nft_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,36 @@ cross_test!(test_exclude_nft_phishing_spam, {
assert_eq!(nfts.len(), 2);
});

cross_test!(test_clear_nft, {
let chain = Chain::Bsc;
let nft_ctx = get_nft_ctx(&chain).await;
let storage = nft_ctx.lock_db().await.unwrap();
NftListStorageOps::init(&storage, &chain).await.unwrap();
let nft = nft();
storage.add_nfts_to_list(chain, vec![nft], 28056726).await.unwrap();

storage.clear_nft_data(&chain).await.unwrap();
test_clear_nft_target(&storage, &chain).await;
});

#[cfg(not(target_arch = "wasm32"))]
async fn test_clear_nft_target<S: NftListStorageOps>(storage: &S, chain: &Chain) {
let is_initialized = NftListStorageOps::is_initialized(storage, chain).await.unwrap();
assert!(!is_initialized);

let is_err = storage.get_nft_list(vec![*chain], false, 10, None, None).await.is_err();
assert!(is_err);

let is_err = storage.get_last_scanned_block(chain).await.is_err();
assert!(is_err);
}

#[cfg(target_arch = "wasm32")]
async fn test_clear_nft_target<S: NftListStorageOps>(storage: &S, chain: &Chain) {
let nft_list = storage.get_nft_list(vec![*chain], true, 1, None, None).await.unwrap();
assert!(nft_list.nfts.is_empty());
}

cross_test!(test_add_get_transfers, {
let chain = Chain::Bsc;
let nft_ctx = get_nft_ctx(&chain).await;
Expand Down Expand Up @@ -527,7 +557,7 @@ cross_test!(test_get_update_transfer_meta, {
storage.add_transfers_to_history(chain, transfers).await.unwrap();

let vec_token_add_id = storage.get_transfers_with_empty_meta(chain).await.unwrap();
assert_eq!(vec_token_add_id.len(), 3);
assert_eq!(vec_token_add_id.len(), 2);

let token_add = "0x5c7d6712dfaf0cb079d48981781c8705e8417ca0".to_string();
let transfer_meta = TransferMeta {
Expand Down Expand Up @@ -693,3 +723,32 @@ cross_test!(test_exclude_transfer_phishing_spam, {
.transfer_history;
assert_eq!(transfers.len(), 1);
});

cross_test!(test_clear_history, {
let chain = Chain::Bsc;
let nft_ctx = get_nft_ctx(&chain).await;
let storage = nft_ctx.lock_db().await.unwrap();
NftTransferHistoryStorageOps::init(&storage, &chain).await.unwrap();
let transfers = nft_transfer_history();
storage.add_transfers_to_history(chain, transfers).await.unwrap();

storage.clear_history_data(&chain).await.unwrap();
test_clear_history_target(&storage, &chain).await;
});

#[cfg(not(target_arch = "wasm32"))]
async fn test_clear_history_target<S: NftTransferHistoryStorageOps>(storage: &S, chain: &Chain) {
let is_init = NftTransferHistoryStorageOps::is_initialized(storage, chain)
.await
.unwrap();
assert!(!is_init);
}

#[cfg(target_arch = "wasm32")]
async fn test_clear_history_target<S: NftTransferHistoryStorageOps>(storage: &S, chain: &Chain) {
let transfer_list = storage
.get_transfer_history(vec![*chain], true, 1, None, None)
.await
.unwrap();
assert!(transfer_list.transfer_history.is_empty());
}
4 changes: 4 additions & 0 deletions mm2src/coins/nft/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ pub trait NftListStorageOps {
domain: String,
possible_phishing: bool,
) -> MmResult<(), Self::Error>;

async fn clear_nft_data(&self, chain: &Chain) -> MmResult<(), Self::Error>;
}

/// Provides asynchronous operations related to the history of NFT transfers.
Expand Down Expand Up @@ -196,6 +198,8 @@ pub trait NftTransferHistoryStorageOps {
domain: String,
possible_phishing: bool,
) -> MmResult<(), Self::Error>;

async fn clear_history_data(&self, chain: &Chain) -> MmResult<(), Self::Error>;
}

/// `get_offset_limit` function calculates offset and limit for final result if we use pagination.
Expand Down
39 changes: 39 additions & 0 deletions mm2src/coins/nft/storage/sql_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,33 @@ impl NftListStorageOps for AsyncMutexGuard<'_, AsyncConnection> {
.await
.map_to_mm(AsyncConnError::from)
}

async fn clear_nft_data(&self, chain: &Chain) -> MmResult<(), Self::Error> {
let table_nft_name = chain.nft_list_table_name()?;
let sql_nft = format!("DROP TABLE {};", table_nft_name);
let table_scanned_blocks_name = scanned_nft_blocks_table_name()?;
let sql_scanned_block = format!("DELETE from {} where chain=?1", table_scanned_blocks_name);
let scanned_block_param = [chain.to_ticker()];
self.call(move |conn| {
let sql_transaction = conn.transaction()?;
sql_transaction.execute(&sql_nft, [])?;
sql_transaction.execute(&sql_scanned_block, scanned_block_param)?;
sql_transaction.commit()?;
if is_table_empty(conn, table_scanned_blocks_name.as_str())? {
conn.execute(&format!("DROP TABLE {};", table_scanned_blocks_name), [])
.map(|_| ())?;
}
Ok(())
})
.await
.map_to_mm(AsyncConnError::from)
}
}

fn is_table_empty(conn: &Connection, table_name: &str) -> Result<bool, SqlError> {
let mut stmt = conn.prepare(&format!("SELECT COUNT(*) FROM {}", table_name))?;
let count: i64 = stmt.query_row([], |row| row.get(0))?;
Ok(count == 0)
}

#[async_trait]
Expand Down Expand Up @@ -1215,4 +1242,16 @@ impl NftTransferHistoryStorageOps for AsyncMutexGuard<'_, AsyncConnection> {
.await
.map_to_mm(AsyncConnError::from)
}

async fn clear_history_data(&self, chain: &Chain) -> MmResult<(), Self::Error> {
let table_name = chain.transfer_history_table_name()?;
self.call(move |conn| {
let sql_transaction = conn.transaction()?;
sql_transaction.execute(&format!("DROP TABLE {};", table_name), [])?;
sql_transaction.commit()?;
Ok(())
})
.await
.map_to_mm(AsyncConnError::from)
}
}
19 changes: 19 additions & 0 deletions mm2src/coins/nft/storage/wasm/wasm_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,18 @@ impl NftListStorageOps for NftCacheIDBLocked<'_> {
update_nft_phishing_for_index(&table, &chain_str, external_index, &domain, possible_phishing).await?;
Ok(())
}

async fn clear_nft_data(&self, chain: &Chain) -> MmResult<(), Self::Error> {
let db_transaction = self.get_inner().transaction().await?;
let nft_table = db_transaction.table::<NftListTable>().await?;
let last_scanned_block_table = db_transaction.table::<LastScannedBlockTable>().await?;

nft_table.delete_items_by_index("chain", chain.to_string()).await?;
last_scanned_block_table
.delete_item_by_unique_index("chain", chain.to_string())
.await?;
Ok(())
}
}

#[async_trait]
Expand Down Expand Up @@ -722,6 +734,13 @@ impl NftTransferHistoryStorageOps for NftCacheIDBLocked<'_> {
.await?;
Ok(())
}

async fn clear_history_data(&self, chain: &Chain) -> MmResult<(), Self::Error> {
let db_transaction = self.get_inner().transaction().await?;
let table = db_transaction.table::<NftTransferHistoryTable>().await?;
table.delete_items_by_index("chain", chain.to_string()).await?;
Ok(())
}
}

async fn update_transfer_phishing_for_index(
Expand Down
4 changes: 3 additions & 1 deletion mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ use http::Response;
use mm2_core::mm_ctx::MmArc;
use mm2_err_handle::prelude::*;
use mm2_rpc::mm_protocol::{MmRpcBuilder, MmRpcRequest, MmRpcVersion};
use nft::{get_nft_list, get_nft_metadata, get_nft_transfers, refresh_nft_metadata, update_nft, withdraw_nft};
use nft::{clear_nft_db, get_nft_list, get_nft_metadata, get_nft_transfers, refresh_nft_metadata, update_nft,
withdraw_nft};
use serde::de::DeserializeOwned;
use serde_json::{self as json, Value as Json};
use std::net::SocketAddr;
Expand Down Expand Up @@ -156,6 +157,7 @@ async fn dispatcher_v2(request: MmRpcRequest, ctx: MmArc) -> DispatcherResult<Re
"add_delegation" => handle_mmrpc(ctx, request, add_delegation).await,
"add_node_to_version_stat" => handle_mmrpc(ctx, request, add_node_to_version_stat).await,
"best_orders" => handle_mmrpc(ctx, request, best_orders_rpc_v2).await,
"clear_nft_db" => handle_mmrpc(ctx, request, clear_nft_db).await,
"enable_bch_with_tokens" => handle_mmrpc(ctx, request, enable_platform_coin_with_tokens::<BchCoin>).await,
"enable_slp" => handle_mmrpc(ctx, request, enable_token::<SlpToken>).await,
"enable_eth_with_tokens" => handle_mmrpc(ctx, request, enable_platform_coin_with_tokens::<EthCoin>).await,
Expand Down

0 comments on commit 1586b71

Please sign in to comment.