Contractless/src/orphans/undo_transactions/restore_mempool.rs

208 lines
8.1 KiB
Rust
Raw Normal View History

2026-05-24 17:56:57 +00:00
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::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;
use crate::decode;
async fn restore_if_spendable<F, Fut>(signatures: &[String], spendable: bool, insert: F)
where
F: FnOnce() -> Fut,
Fut: std::future::Future<Output = ()>,
{
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<String> {
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(_) => {}
}
}