use crate::blocks::burn::BurnTransaction; use crate::blocks::collateral::CollateralClaimTransaction; use crate::blocks::issue_token::IssueTokenTransaction; use crate::blocks::loan_payment::ContractPaymentTransaction; use crate::blocks::loans::LoanContractTransaction; use crate::blocks::marketing::MarketingTransaction; use crate::blocks::nft::CreateNftTransaction; use crate::blocks::swap::SwapTransaction; use crate::blocks::token::CreateTokenTransaction; use crate::blocks::transfer::TransferTransaction; use crate::blocks::vanity::VanityAddressTransaction; use crate::common::nft_assets::nft_asset_name; use crate::common::types::Transaction; use crate::decode; use crate::records::memory::mempool::{restore_processed_by_signatures, BASECOIN}; use crate::rpc::commands::transaction_by_txid::request_transaction_by_txid; use crate::rpc::responses::RpcResponse; use crate::sled::Db; use crate::verifications::async_funcs::checks::balance_check::balance_checkup; async fn restore_if_spendable(signatures: &[String], spendable: bool, insert: F) where F: FnOnce() -> Fut, Fut: std::future::Future, { if !spendable { return; } match restore_processed_by_signatures(signatures).await { Ok(false) | Err(_) => insert().await, Ok(true) => {} } } async fn loan_coin_for_contract(db: &Db, contract_hash: &str) -> Option { let contract_key = decode(contract_hash).ok()?; let RpcResponse::Binary(bytes) = request_transaction_by_txid(db, contract_key).await; if bytes.is_empty() || bytes[0] != 7 { return None; } LoanContractTransaction::from_bytes(7, &bytes[1..]) .await .ok() .map(|contract| contract.unsigned_loan_contract.loan_coin) } pub async fn restore_transfer(transaction: &TransferTransaction, db: &Db) { let transfer = &transaction.unsigned_transfer; let asset = nft_asset_name(&transfer.coin, transfer.nft_series); let spendable = balance_checkup(db, transfer.value, transfer.txfee, asset, &transfer.sender).await; let signature = transaction.signature.clone(); restore_if_spendable(&[signature], spendable, || async { let _ = transaction.add_to_memory().await; }) .await; } pub async fn restore_burn(transaction: &BurnTransaction, db: &Db) { let burn = &transaction.unsigned_burn; let asset = nft_asset_name(&burn.coin, burn.nft_series); let spendable = balance_checkup(db, burn.value, burn.txfee, asset, &burn.address).await; let signature = transaction.signature.clone(); restore_if_spendable(&[signature], spendable, || async { let _ = transaction.add_to_memory().await; }) .await; } pub async fn restore_create_token(transaction: &CreateTokenTransaction, db: &Db) { let token = &transaction.unsigned_create_token; let spendable = balance_checkup(db, 0, token.txfee, BASECOIN.clone(), &token.creator).await; let signature = transaction.signature.clone(); restore_if_spendable(&[signature], spendable, || async { let _ = transaction.add_to_memory().await; }) .await; } pub async fn restore_issue_token(transaction: &IssueTokenTransaction, db: &Db) { let token = &transaction.unsigned_issue_token; let spendable = balance_checkup(db, 0, token.txfee, BASECOIN.clone(), &token.creator).await; let signature = transaction.signature.clone(); restore_if_spendable(&[signature], spendable, || async { let _ = transaction.add_to_memory().await; }) .await; } pub async fn restore_create_nft(transaction: &CreateNftTransaction, db: &Db) { let nft = &transaction.unsigned_create_nft; let spendable = balance_checkup(db, 0, nft.txfee, BASECOIN.clone(), &nft.creator).await; let signature = transaction.signature.clone(); restore_if_spendable(&[signature], spendable, || async { let _ = transaction.add_to_memory().await; }) .await; } pub async fn restore_marketing(transaction: &MarketingTransaction, db: &Db) { let marketing = &transaction.unsigned_marketing; let spendable = balance_checkup( db, 0, marketing.txfee, BASECOIN.clone(), &marketing.advertiser, ) .await; let signature = transaction.signature.clone(); restore_if_spendable(&[signature], spendable, || async { let _ = transaction.add_to_memory().await; }) .await; } pub async fn restore_swap(transaction: &SwapTransaction, db: &Db) { let swap = &transaction.unsigned_swap; let asset1 = nft_asset_name(&swap.ticker1, swap.nft_series1); let asset2 = nft_asset_name(&swap.ticker2, swap.nft_series2); let value1 = swap.value1.saturating_add(swap.tip1); let value2 = swap.value2.saturating_add(swap.tip2); let sender1_spendable = balance_checkup(db, value1, swap.txfee1, asset1, &swap.sender1).await; let sender2_spendable = balance_checkup(db, value2, swap.txfee2, asset2, &swap.sender2).await; let signatures = vec![ transaction.signature1.clone(), transaction.signature2.clone(), ]; restore_if_spendable( &signatures, sender1_spendable && sender2_spendable, || async { let _ = transaction.add_to_memory().await; }, ) .await; } pub async fn restore_loan_creation(transaction: &LoanContractTransaction, db: &Db) { let loan = &transaction.unsigned_loan_contract; let lender_spendable = balance_checkup( db, loan.loan_amount, loan.txfee, loan.loan_coin.clone(), &loan.lender, ) .await; let borrower_spendable = balance_checkup( db, loan.collateral_amount, 0, loan.collateral.clone(), &loan.borrower, ) .await; let signatures = vec![ transaction.signature1.clone(), transaction.signature2.clone(), ]; restore_if_spendable( &signatures, lender_spendable && borrower_spendable, || async { let _ = transaction.add_to_memory().await; }, ) .await; } pub async fn restore_borrower(transaction: &ContractPaymentTransaction, db: &Db) { let payment = &transaction.unsigned_contract_payment; let Some(loan_coin) = loan_coin_for_contract(db, &payment.contract_hash).await else { return; }; let value = payment.payback_amount.saturating_add(payment.tip); let spendable = balance_checkup(db, value, payment.txfee, loan_coin, &payment.address).await; let signature = transaction.signature.clone(); restore_if_spendable(&[signature], spendable, || async { let _ = transaction.add_to_memory().await; }) .await; } pub async fn restore_collateral(transaction: &CollateralClaimTransaction, db: &Db) { let collateral = &transaction.unsigned_collateral_claim; let spendable = balance_checkup( db, 0, collateral.txfee, BASECOIN.clone(), &collateral.address, ) .await; let signature = transaction.signature.clone(); restore_if_spendable(&[signature], spendable, || async { let _ = transaction.add_to_memory().await; }) .await; } pub async fn restore_vanity(transaction: &VanityAddressTransaction, db: &Db) { let vanity = &transaction.unsigned_vanity_address; let spendable = balance_checkup(db, 0, vanity.txfee, BASECOIN.clone(), &vanity.address).await; let signature = transaction.signature.clone(); restore_if_spendable(&[signature], spendable, || async { let _ = transaction.add_to_memory().await; }) .await; } pub async fn restore_rolled_back_transaction(transaction: &Transaction, db: &Db) { match transaction { Transaction::Transfer(tx) => restore_transfer(tx, db).await, Transaction::Burn(tx) => restore_burn(tx, db).await, Transaction::Token(tx) => restore_create_token(tx, db).await, Transaction::IssueToken(tx) => restore_issue_token(tx, db).await, Transaction::Nft(tx) => restore_create_nft(tx, db).await, Transaction::Marketing(tx) => restore_marketing(tx, db).await, Transaction::Swap(tx) => restore_swap(tx, db).await, Transaction::Lender(tx) => restore_loan_creation(tx, db).await, Transaction::Borrower(tx) => restore_borrower(tx, db).await, Transaction::Collateral(tx) => restore_collateral(tx, db).await, Transaction::Vanity(tx) => restore_vanity(tx, db).await, Transaction::Genesis(_) | Transaction::Rewards(_) => {} } }