fixed bug in prevalidation mempool lookup
This commit is contained in:
parent
ac7c0f0558
commit
8d0007eb1a
|
|
@ -19,7 +19,7 @@ GPT-5.6 SOL assisted with:
|
||||||
- Hardening network-map monitoring and connection-state handling.
|
- Hardening network-map monitoring and connection-state handling.
|
||||||
- Implementing and reviewing on-chain data-storage transaction support.
|
- Implementing and reviewing on-chain data-storage transaction support.
|
||||||
- Integrating data storage, address data, NFTs, loans, assets, and transaction history into the GUI wallet.
|
- Integrating data storage, address data, NFTs, loans, assets, and transaction history into the GUI wallet.
|
||||||
- Improving GUI wallet cache synchronization, cache deletion safety, and Windows file-access coordination.
|
- Improving [GUI wallet](https://contractless.dev/contractless/Contractless-GUI-Wallet) cache synchronization, cache deletion safety, and Windows file-access coordination.
|
||||||
- Reviewing Rust transaction validation, mempool handling, block saving, and chain-reorganization paths.
|
- Reviewing Rust transaction validation, mempool handling, block saving, and chain-reorganization paths.
|
||||||
- Identifying behavioral inconsistencies between local wallet caches and RPC responses.
|
- Identifying behavioral inconsistencies between local wallet caches and RPC responses.
|
||||||
- Expanding and reorganizing user documentation for installation, wallets, transactions, validation tools, loans, swaps, NFTs, fees, and data storage.
|
- Expanding and reorganizing user documentation for installation, wallets, transactions, validation tools, loans, swaps, NFTs, fees, and data storage.
|
||||||
|
|
@ -90,5 +90,3 @@ Use the release package that matches your operating system and follow the matchi
|
||||||
## Current Status
|
## Current Status
|
||||||
|
|
||||||
Contractless is still under active testnet development. Interfaces, transaction tools, docs, and node behavior may continue to change while the chain is tested.
|
Contractless is still under active testnet development. Interfaces, transaction tools, docs, and node behavior may continue to change while the chain is tested.
|
||||||
|
|
||||||
If you are interested in running a testnet node, start with the installation guide for your operating system, then review the configuration and wallet tools documentation.
|
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,10 @@ pub struct VrfBlock {
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
pub vrf_block: VrfBlock,
|
pub vrf_block: VrfBlock,
|
||||||
pub transactions: Vec<Transaction>,
|
pub transactions: Vec<Transaction>,
|
||||||
|
// Exact transaction slices are retained for downloaded/stored blocks so
|
||||||
|
// mempool reuse can compare bytes without serializing or hashing again.
|
||||||
|
#[serde(skip)]
|
||||||
|
pub original_transactions: Vec<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UnminedBlock {
|
impl UnminedBlock {
|
||||||
|
|
|
||||||
|
|
@ -131,3 +131,39 @@ pub enum Transaction {
|
||||||
StorageI128(StorageI128),
|
StorageI128(StorageI128),
|
||||||
DeleteKey(DeleteKey),
|
DeleteKey(DeleteKey),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Transaction {
|
||||||
|
// Return the signature used by the indexed mempool lookup. Two-party
|
||||||
|
// transactions use the final signer because valid submitted swaps and
|
||||||
|
// loan contracts must already contain both signatures.
|
||||||
|
pub fn mempool_signature(&self) -> Option<&str> {
|
||||||
|
match self {
|
||||||
|
Transaction::Genesis(_) | Transaction::Rewards(_) => None,
|
||||||
|
Transaction::Transfer(tx) => Some(&tx.signature),
|
||||||
|
Transaction::Burn(tx) => Some(&tx.signature),
|
||||||
|
Transaction::Token(tx) => Some(&tx.signature),
|
||||||
|
Transaction::IssueToken(tx) => Some(&tx.signature),
|
||||||
|
Transaction::Nft(tx) => Some(&tx.signature),
|
||||||
|
Transaction::Marketing(tx) => Some(&tx.signature),
|
||||||
|
Transaction::Swap(tx) => Some(&tx.signature2),
|
||||||
|
Transaction::Lender(tx) => Some(&tx.signature2),
|
||||||
|
Transaction::Borrower(tx) => Some(&tx.signature),
|
||||||
|
Transaction::Collateral(tx) => Some(&tx.signature),
|
||||||
|
Transaction::Vanity(tx) => Some(&tx.signature),
|
||||||
|
Transaction::StorageKey(tx) => Some(&tx.signature),
|
||||||
|
Transaction::StorageBool(tx) => Some(&tx.signature),
|
||||||
|
Transaction::StorageU8(tx) => Some(&tx.signature),
|
||||||
|
Transaction::StorageU16(tx) => Some(&tx.signature),
|
||||||
|
Transaction::StorageU32(tx) => Some(&tx.signature),
|
||||||
|
Transaction::StorageU64(tx) => Some(&tx.signature),
|
||||||
|
Transaction::StorageU128(tx) => Some(&tx.signature),
|
||||||
|
Transaction::StorageString(tx) => Some(&tx.signature),
|
||||||
|
Transaction::StorageI8(tx) => Some(&tx.signature),
|
||||||
|
Transaction::StorageI16(tx) => Some(&tx.signature),
|
||||||
|
Transaction::StorageI32(tx) => Some(&tx.signature),
|
||||||
|
Transaction::StorageI64(tx) => Some(&tx.signature),
|
||||||
|
Transaction::StorageI128(tx) => Some(&tx.signature),
|
||||||
|
Transaction::DeleteKey(tx) => Some(&tx.signature),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,7 @@ async fn create_genesis_block(
|
||||||
let block = Block {
|
let block = Block {
|
||||||
vrf_block,
|
vrf_block,
|
||||||
transactions: vec![Transaction::Genesis(signed_genesis_transaction.clone())],
|
transactions: vec![Transaction::Genesis(signed_genesis_transaction.clone())],
|
||||||
|
original_transactions: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Reuse normal block verification before saving so genesis
|
// Reuse normal block verification before saving so genesis
|
||||||
|
|
|
||||||
|
|
@ -285,6 +285,7 @@ pub async fn mine_block_internal(
|
||||||
let new_block = Block {
|
let new_block = Block {
|
||||||
vrf_block,
|
vrf_block,
|
||||||
transactions: vec![Transaction::Rewards(rewards_transaction)],
|
transactions: vec![Transaction::Rewards(rewards_transaction)],
|
||||||
|
original_transactions: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return only candidates that pass local verification.
|
// Return only candidates that pass local verification.
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,37 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub async fn signature_exists(signature: &str, hash: &str) -> Result<bool> {
|
pub async fn exact_transaction_exists(signature: &str, original: &[u8]) -> Result<bool> {
|
||||||
let client_handle = db_client().await?;
|
let client_handle = db_client().await?;
|
||||||
let client = client_handle.as_ref();
|
let client = client_handle.as_ref();
|
||||||
|
|
||||||
// Check every mempool table because the signature column names differ by
|
// Use the indexed signature to locate a candidate row, then compare the
|
||||||
// transaction type, especially for two-party swaps and loans.
|
// complete serialized transaction so every byte must match what was
|
||||||
|
// previously validated and admitted to the mempool.
|
||||||
let row = client
|
let row = client
|
||||||
.query_one(
|
.query_one(
|
||||||
r#"
|
r#"
|
||||||
SELECT
|
SELECT
|
||||||
CASE
|
CASE
|
||||||
WHEN EXISTS (SELECT 1 FROM transfer a WHERE a.signature = $1 AND a.hash = $2 AND a.processed = false)
|
WHEN EXISTS (SELECT 1 FROM transfer a WHERE a.signature = $1 AND a.original = $2 AND a.processed = false)
|
||||||
OR EXISTS (SELECT 1 FROM token b WHERE b.signature = $1 AND b.hash = $2 AND b.processed = false)
|
OR EXISTS (SELECT 1 FROM token b WHERE b.signature = $1 AND b.original = $2 AND b.processed = false)
|
||||||
OR EXISTS (SELECT 1 FROM issue_token c WHERE c.signature = $1 AND c.hash = $2 AND c.processed = false)
|
OR EXISTS (SELECT 1 FROM issue_token c WHERE c.signature = $1 AND c.original = $2 AND c.processed = false)
|
||||||
OR EXISTS (SELECT 1 FROM burn d WHERE d.signature = $1 AND d.hash = $2 AND d.processed = false)
|
OR EXISTS (SELECT 1 FROM burn d WHERE d.signature = $1 AND d.original = $2 AND d.processed = false)
|
||||||
OR EXISTS (SELECT 1 FROM nft e WHERE e.signature = $1 AND e.hash = $2 AND e.processed = false)
|
OR EXISTS (SELECT 1 FROM nft e WHERE e.signature = $1 AND e.original = $2 AND e.processed = false)
|
||||||
OR EXISTS (SELECT 1 FROM marketing f WHERE f.signature = $1 AND f.hash = $2 AND f.processed = false)
|
OR EXISTS (SELECT 1 FROM marketing f WHERE f.signature = $1 AND f.original = $2 AND f.processed = false)
|
||||||
OR EXISTS (SELECT 1 FROM vanity_address va WHERE va.signature = $1 AND va.hash = $2 AND va.processed = false)
|
OR EXISTS (SELECT 1 FROM vanity_address va WHERE va.signature = $1 AND va.original = $2 AND va.processed = false)
|
||||||
OR EXISTS (SELECT 1 FROM swap g WHERE g.signature1 = $1 AND g.hash = $2 AND g.processed = false)
|
OR EXISTS (SELECT 1 FROM swap g WHERE g.signature1 = $1 AND g.original = $2 AND g.processed = false)
|
||||||
OR EXISTS (SELECT 1 FROM swap h WHERE h.signature2 = $1 AND h.hash = $2 AND h.processed = false)
|
OR EXISTS (SELECT 1 FROM swap h WHERE h.signature2 = $1 AND h.original = $2 AND h.processed = false)
|
||||||
OR EXISTS (SELECT 1 FROM loan_contract i WHERE i.signature1 = $1 AND i.hash = $2 AND i.processed = false)
|
OR EXISTS (SELECT 1 FROM loan_contract i WHERE i.signature1 = $1 AND i.original = $2 AND i.processed = false)
|
||||||
OR EXISTS (SELECT 1 FROM loan_contract j WHERE j.signature2 = $1 AND j.hash = $2 AND j.processed = false)
|
OR EXISTS (SELECT 1 FROM loan_contract j WHERE j.signature2 = $1 AND j.original = $2 AND j.processed = false)
|
||||||
OR EXISTS (SELECT 1 FROM loan_payment k WHERE k.signature = $1 AND k.hash = $2 AND k.processed = false)
|
OR EXISTS (SELECT 1 FROM loan_payment k WHERE k.signature = $1 AND k.original = $2 AND k.processed = false)
|
||||||
OR EXISTS (SELECT 1 FROM collateral_claim l WHERE l.signature = $1 AND l.hash = $2 AND l.processed = false)
|
OR EXISTS (SELECT 1 FROM collateral_claim l WHERE l.signature = $1 AND l.original = $2 AND l.processed = false)
|
||||||
OR EXISTS (SELECT 1 FROM storage_key sk WHERE sk.signature = $1 AND sk.hash = $2 AND sk.processed = false)
|
OR EXISTS (SELECT 1 FROM storage_key sk WHERE sk.signature = $1 AND sk.original = $2 AND sk.processed = false)
|
||||||
OR EXISTS (SELECT 1 FROM storage_value sv WHERE sv.signature = $1 AND sv.hash = $2 AND sv.processed = false)
|
OR EXISTS (SELECT 1 FROM storage_value sv WHERE sv.signature = $1 AND sv.original = $2 AND sv.processed = false)
|
||||||
THEN 1
|
THEN 1
|
||||||
ELSE 0
|
ELSE 0
|
||||||
END AS signature_found;
|
END AS signature_found;
|
||||||
"#,
|
"#,
|
||||||
&[&signature, &hash],
|
&[&signature, &original],
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -225,9 +225,10 @@ mod schema;
|
||||||
mod selection;
|
mod selection;
|
||||||
|
|
||||||
pub use lookups::{
|
pub use lookups::{
|
||||||
get_basecoin_balance, get_coin_balance, get_pending_payments_for_contract, largest_fee,
|
exact_transaction_exists, get_basecoin_balance, get_coin_balance,
|
||||||
latest_pending_txids_by_address, pending_transaction_by_txid, signature_exists,
|
get_pending_payments_for_contract, largest_fee, latest_pending_txids_by_address,
|
||||||
total_transactions, transaction_by_signature, transactions_by_address,
|
pending_transaction_by_txid, total_transactions, transaction_by_signature,
|
||||||
|
transactions_by_address,
|
||||||
};
|
};
|
||||||
pub use processing::{
|
pub use processing::{
|
||||||
delete_by_signatures, delete_unprocessed_by_address, mark_processed_by_signatures,
|
delete_by_signatures, delete_unprocessed_by_address, mark_processed_by_signatures,
|
||||||
|
|
|
||||||
|
|
@ -64,10 +64,12 @@ pub async fn load_block_from_binary(binary_data: &[u8]) -> Result<Block, String>
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
let mut i = VRF_BLOCK_BYTES;
|
let mut i = VRF_BLOCK_BYTES;
|
||||||
let mut transactions: Vec<Transaction> = Vec::new();
|
let mut transactions: Vec<Transaction> = Vec::new();
|
||||||
|
let mut original_transactions = Vec::new();
|
||||||
|
|
||||||
while i < binary_data.len() {
|
while i < binary_data.len() {
|
||||||
// Each transaction starts with its type byte, followed by the fixed-length body
|
// Each transaction starts with its type byte, followed by the fixed-length body
|
||||||
// defined for that transaction family.
|
// defined for that transaction family.
|
||||||
|
let transaction_start = i;
|
||||||
let txtype = binary_data[i];
|
let txtype = binary_data[i];
|
||||||
i += 1;
|
i += 1;
|
||||||
let body_len = transaction_body_len(txtype)?;
|
let body_len = transaction_body_len(txtype)?;
|
||||||
|
|
@ -332,11 +334,13 @@ pub async fn load_block_from_binary(binary_data: &[u8]) -> Result<Block, String>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
transactions.push(transaction);
|
transactions.push(transaction);
|
||||||
|
original_transactions.push(binary_data[transaction_start..i].to_vec());
|
||||||
}
|
}
|
||||||
|
|
||||||
let block = Block {
|
let block = Block {
|
||||||
vrf_block,
|
vrf_block,
|
||||||
transactions,
|
transactions,
|
||||||
|
original_transactions,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(block)
|
Ok(block)
|
||||||
|
|
|
||||||
|
|
@ -92,10 +92,12 @@ pub async fn load_block(block_number: u32) -> Result<Block, String> {
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
let mut i = VRF_BLOCK_BYTES;
|
let mut i = VRF_BLOCK_BYTES;
|
||||||
let mut transactions: Vec<Transaction> = Vec::new();
|
let mut transactions: Vec<Transaction> = Vec::new();
|
||||||
|
let mut original_transactions = Vec::new();
|
||||||
|
|
||||||
while i < binary_data.len() {
|
while i < binary_data.len() {
|
||||||
// Each stored transaction begins with its type byte, followed by the fixed-size
|
// Each stored transaction begins with its type byte, followed by the fixed-size
|
||||||
// body for that transaction family.
|
// body for that transaction family.
|
||||||
|
let transaction_start = i;
|
||||||
let txtype = binary_data[i];
|
let txtype = binary_data[i];
|
||||||
i += 1;
|
i += 1;
|
||||||
let body_len = transaction_body_len(txtype)?;
|
let body_len = transaction_body_len(txtype)?;
|
||||||
|
|
@ -349,11 +351,13 @@ pub async fn load_block(block_number: u32) -> Result<Block, String> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
transactions.push(transaction);
|
transactions.push(transaction);
|
||||||
|
original_transactions.push(binary_data[transaction_start..i].to_vec());
|
||||||
}
|
}
|
||||||
|
|
||||||
let block = Block {
|
let block = Block {
|
||||||
vrf_block,
|
vrf_block,
|
||||||
transactions,
|
transactions,
|
||||||
|
original_transactions,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(block)
|
Ok(block)
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,16 @@ use crate::common::types::{
|
||||||
STORAGE_STRING_TYPE, STORAGE_U128_TYPE, STORAGE_U16_TYPE, STORAGE_U32_TYPE, STORAGE_U64_TYPE,
|
STORAGE_STRING_TYPE, STORAGE_U128_TYPE, STORAGE_U16_TYPE, STORAGE_U32_TYPE, STORAGE_U64_TYPE,
|
||||||
STORAGE_U8_TYPE, SWAP_TYPE, TRANSFER_TYPE, VANITY_ADDRESS_TYPE,
|
STORAGE_U8_TYPE, SWAP_TYPE, TRANSFER_TYPE, VANITY_ADDRESS_TYPE,
|
||||||
};
|
};
|
||||||
|
use crate::encode;
|
||||||
use crate::records::memory::connections::get_client_type_from_memory;
|
use crate::records::memory::connections::get_client_type_from_memory;
|
||||||
use crate::records::memory::enums::ClientType;
|
use crate::records::memory::enums::ClientType;
|
||||||
|
use crate::records::memory::mempool::exact_transaction_exists;
|
||||||
use crate::records::memory::response_channels::{reserve_transient_entry_with_context, Command};
|
use crate::records::memory::response_channels::{reserve_transient_entry_with_context, Command};
|
||||||
use crate::rpc::command_maps::RPC_SUBMIT_TRANSACTION;
|
use crate::rpc::command_maps::RPC_SUBMIT_TRANSACTION;
|
||||||
use crate::rpc::responses::RpcResponse;
|
use crate::rpc::responses::RpcResponse;
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
use crate::torrent::torrenting_system::get_nodes::get_live_node_broadcast_peers;
|
use crate::torrent::torrenting_system::get_nodes::get_live_node_broadcast_peers;
|
||||||
|
use crate::wallets::structures::Wallet;
|
||||||
use crate::Arc;
|
use crate::Arc;
|
||||||
use crate::Mutex;
|
use crate::Mutex;
|
||||||
use crate::OnceLock;
|
use crate::OnceLock;
|
||||||
|
|
@ -124,6 +127,27 @@ pub async fn save_and_submit(
|
||||||
// the declared transaction type.
|
// the declared transaction type.
|
||||||
// In each branch, a non-empty verifier response means the transaction
|
// In each branch, a non-empty verifier response means the transaction
|
||||||
// already exists in the mempool and should not be rebroadcast.
|
// already exists in the mempool and should not be rebroadcast.
|
||||||
|
// All submitted transaction families end with their final signature.
|
||||||
|
// Use that indexed signature to locate a candidate mempool row, then
|
||||||
|
// require the complete original bytes to match before reporting a duplicate.
|
||||||
|
if tx.len() >= Wallet::SIGNATURE_LENGTH {
|
||||||
|
let signature = encode(&tx[tx.len() - Wallet::SIGNATURE_LENGTH..]);
|
||||||
|
let mut original = Vec::with_capacity(1 + tx.len());
|
||||||
|
original.push(txtype);
|
||||||
|
original.extend_from_slice(&tx);
|
||||||
|
match exact_transaction_exists(&signature, &original).await {
|
||||||
|
Ok(true) => {
|
||||||
|
return RpcResponse::Binary(
|
||||||
|
b"successful_broadcast: false already_in_mempool".to_vec(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(false) => {}
|
||||||
|
Err(err) => {
|
||||||
|
return RpcResponse::Binary(format!("error: {err}").into_bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match txtype {
|
match txtype {
|
||||||
TRANSFER_TYPE => match TransferTransaction::from_bytes(txtype, &tx).await {
|
TRANSFER_TYPE => match TransferTransaction::from_bytes(txtype, &tx).await {
|
||||||
Ok(transfer) => match transfer.verify(db).await {
|
Ok(transfer) => match transfer.verify(db).await {
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,7 @@ use crate::common::nft_assets::nft_asset_name;
|
||||||
use crate::common::types::Transaction;
|
use crate::common::types::Transaction;
|
||||||
use crate::decode;
|
use crate::decode;
|
||||||
use crate::records::balance_sheet::get_wallet_balance::get_balance_with_db;
|
use crate::records::balance_sheet::get_wallet_balance::get_balance_with_db;
|
||||||
use crate::records::memory::mempool::{
|
use crate::records::memory::mempool::{get_basecoin_balance, get_coin_balance, BASECOIN};
|
||||||
get_basecoin_balance, get_coin_balance, signature_exists, BASECOIN,
|
|
||||||
};
|
|
||||||
use crate::rpc::commands::transaction_by_txid::request_transaction_by_txid;
|
use crate::rpc::commands::transaction_by_txid::request_transaction_by_txid;
|
||||||
use crate::rpc::responses::RpcResponse;
|
use crate::rpc::responses::RpcResponse;
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
|
|
@ -172,23 +170,6 @@ fn add_amount_to_total(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn transaction_is_pending(view: &TransactionBalanceView) -> Result<bool, String> {
|
|
||||||
for signature in &view.signatures {
|
|
||||||
if signature.is_empty() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if signature_exists(signature, &view.hash)
|
|
||||||
.await
|
|
||||||
.map_err(|err| err.to_string())?
|
|
||||||
{
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn loan_contract_for_hash(
|
async fn loan_contract_for_hash(
|
||||||
db: &Db,
|
db: &Db,
|
||||||
contract_hash: &str,
|
contract_hash: &str,
|
||||||
|
|
@ -678,13 +659,13 @@ async fn pending_reserved_amount(db: &Db, address: &str, coin: &str) -> Result<u
|
||||||
pub(crate) async fn prepare_transaction_balance_reservation(
|
pub(crate) async fn prepare_transaction_balance_reservation(
|
||||||
db: &Db,
|
db: &Db,
|
||||||
transaction: &Transaction,
|
transaction: &Transaction,
|
||||||
|
already_reserved_in_mempool: bool,
|
||||||
) -> Result<TransactionBalanceReservation, String> {
|
) -> Result<TransactionBalanceReservation, String> {
|
||||||
let view = transaction_balance_view(db, transaction).await?;
|
let view = transaction_balance_view(db, transaction).await?;
|
||||||
if view.check_saved_txid && saved_txid_exists(db, &view.hash)? {
|
if view.check_saved_txid && saved_txid_exists(db, &view.hash)? {
|
||||||
return Err("This transaction already exists.".to_string());
|
return Err("This transaction already exists.".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
let already_reserved_in_mempool = transaction_is_pending(&view).await?;
|
|
||||||
let loan_payment = if let Transaction::Borrower(tx) = transaction {
|
let loan_payment = if let Transaction::Borrower(tx) = transaction {
|
||||||
let payment = &tx.unsigned_contract_payment;
|
let payment = &tx.unsigned_contract_payment;
|
||||||
let contract = loan_contract_for_hash(db, &payment.contract_hash).await?;
|
let contract = loan_contract_for_hash(db, &payment.contract_hash).await?;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
// These lower-level checks are reused by the higher-level async verification routines.
|
// These lower-level checks are reused by the higher-level async verification routines.
|
||||||
pub mod balance_check;
|
pub mod balance_check;
|
||||||
pub mod block_balance;
|
pub mod block_balance;
|
||||||
pub mod mempool_check;
|
|
||||||
pub mod time_checks;
|
pub mod time_checks;
|
||||||
pub mod verify_db;
|
pub mod verify_db;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
use crate::common::types::Transaction;
|
use crate::common::types::Transaction;
|
||||||
|
use crate::records::memory::mempool::exact_transaction_exists;
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
use crate::verifications::async_funcs::checks::block_balance::{
|
use crate::verifications::async_funcs::checks::block_balance::{
|
||||||
prepare_transaction_balance_reservation, BlockBalanceTracker,
|
prepare_transaction_balance_reservation, BlockBalanceTracker,
|
||||||
};
|
};
|
||||||
use crate::verifications::sync_funcs::transaction_verify_loop::COUNTER;
|
use crate::verifications::sync_funcs::transaction_verify_loop::COUNTER;
|
||||||
|
use crate::verifications::verification_types::VerifiableTransaction;
|
||||||
use crate::Arc;
|
use crate::Arc;
|
||||||
use crate::AtomicBool;
|
use crate::AtomicBool;
|
||||||
use crate::AtomicOrdering;
|
use crate::AtomicOrdering;
|
||||||
|
|
@ -11,7 +13,7 @@ use crate::Mutex;
|
||||||
|
|
||||||
pub async fn verify_transactions(
|
pub async fn verify_transactions(
|
||||||
miner: String,
|
miner: String,
|
||||||
transactions: Vec<Transaction>,
|
transactions: Vec<VerifiableTransaction>,
|
||||||
db: &Db,
|
db: &Db,
|
||||||
stop_flag: Arc<AtomicBool>,
|
stop_flag: Arc<AtomicBool>,
|
||||||
balance_tracker: Arc<Mutex<BlockBalanceTracker>>,
|
balance_tracker: Arc<Mutex<BlockBalanceTracker>>,
|
||||||
|
|
@ -78,15 +80,41 @@ pub async fn verify_transactions(
|
||||||
// normalize failures into a consistent error string.
|
// normalize failures into a consistent error string.
|
||||||
async fn verify_transaction(
|
async fn verify_transaction(
|
||||||
miner: String,
|
miner: String,
|
||||||
transaction: Transaction,
|
verifiable: VerifiableTransaction,
|
||||||
db: &Db,
|
db: &Db,
|
||||||
balance_tracker: Arc<Mutex<BlockBalanceTracker>>,
|
balance_tracker: Arc<Mutex<BlockBalanceTracker>>,
|
||||||
block_timestamp: u32,
|
block_timestamp: u32,
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
|
let transaction = verifiable.transaction;
|
||||||
|
let already_in_mempool = match (
|
||||||
|
transaction.mempool_signature(),
|
||||||
|
verifiable.original.as_deref(),
|
||||||
|
) {
|
||||||
|
(Some(signature), Some(original)) if !signature.is_empty() => {
|
||||||
|
exact_transaction_exists(signature, original)
|
||||||
|
.await
|
||||||
|
.map_err(|err| err.to_string())?
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Exact mempool bytes prove ordinary transactions already passed their
|
||||||
|
// complete type-specific validation. Collateral claims remain time-aware
|
||||||
|
// and must recheck their schedule against the containing block timestamp.
|
||||||
|
if already_in_mempool && !matches!(&transaction, Transaction::Collateral(_)) {
|
||||||
|
let signature = transaction
|
||||||
|
.mempool_signature()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string();
|
||||||
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool).await?;
|
||||||
|
return Ok(signature);
|
||||||
|
}
|
||||||
|
|
||||||
if let Transaction::Genesis(genesis_tx) = &transaction {
|
if let Transaction::Genesis(genesis_tx) = &transaction {
|
||||||
match genesis_tx.verify().await {
|
match genesis_tx.verify().await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -105,7 +133,13 @@ async fn verify_transaction(
|
||||||
"You cannot include more than 1 reward in a mined block.".to_string()
|
"You cannot include more than 1 reward in a mined block.".to_string()
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(
|
||||||
|
db,
|
||||||
|
&transaction,
|
||||||
|
balance_tracker,
|
||||||
|
already_in_mempool,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -117,7 +151,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::Transfer(transfer_tx) = &transaction {
|
if let Transaction::Transfer(transfer_tx) = &transaction {
|
||||||
match transfer_tx.verify(db).await {
|
match transfer_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -128,7 +163,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::Burn(burn_tx) = &transaction {
|
if let Transaction::Burn(burn_tx) = &transaction {
|
||||||
match burn_tx.verify(db).await {
|
match burn_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -139,7 +175,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::Token(create_token_tx) = &transaction {
|
if let Transaction::Token(create_token_tx) = &transaction {
|
||||||
match create_token_tx.verify(db).await {
|
match create_token_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -152,7 +189,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::IssueToken(issue_token_tx) = &transaction {
|
if let Transaction::IssueToken(issue_token_tx) = &transaction {
|
||||||
match issue_token_tx.verify(db).await {
|
match issue_token_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -165,7 +203,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::Nft(create_nft_tx) = &transaction {
|
if let Transaction::Nft(create_nft_tx) = &transaction {
|
||||||
match create_nft_tx.verify(db).await {
|
match create_nft_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -178,7 +217,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::Marketing(marketing_tx) = &transaction {
|
if let Transaction::Marketing(marketing_tx) = &transaction {
|
||||||
match marketing_tx.verify(db).await {
|
match marketing_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -191,7 +231,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::Swap(swap_tx) = &transaction {
|
if let Transaction::Swap(swap_tx) = &transaction {
|
||||||
match swap_tx.verify(db).await {
|
match swap_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -202,7 +243,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::Lender(loan_creation_tx) = &transaction {
|
if let Transaction::Lender(loan_creation_tx) = &transaction {
|
||||||
match loan_creation_tx.verify(db).await {
|
match loan_creation_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -215,7 +257,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::Borrower(loan_payment_tx) = &transaction {
|
if let Transaction::Borrower(loan_payment_tx) = &transaction {
|
||||||
match loan_payment_tx.verify_for_block(db).await {
|
match loan_payment_tx.verify_for_block(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -226,9 +269,13 @@ async fn verify_transaction(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Transaction::Collateral(collateral_claim_tx) = &transaction {
|
if let Transaction::Collateral(collateral_claim_tx) = &transaction {
|
||||||
match collateral_claim_tx.verify_at(db, block_timestamp).await {
|
match collateral_claim_tx
|
||||||
|
.verify_at(db, block_timestamp, already_in_mempool)
|
||||||
|
.await
|
||||||
|
{
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -241,7 +288,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::Vanity(vanity_tx) = &transaction {
|
if let Transaction::Vanity(vanity_tx) = &transaction {
|
||||||
match vanity_tx.verify(db).await {
|
match vanity_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -254,7 +302,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::StorageKey(storage_key_tx) = &transaction {
|
if let Transaction::StorageKey(storage_key_tx) = &transaction {
|
||||||
match storage_key_tx.verify(db).await {
|
match storage_key_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -267,7 +316,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::StorageBool(storage_tx) = &transaction {
|
if let Transaction::StorageBool(storage_tx) = &transaction {
|
||||||
match storage_tx.verify(db).await {
|
match storage_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -280,7 +330,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::StorageU8(storage_tx) = &transaction {
|
if let Transaction::StorageU8(storage_tx) = &transaction {
|
||||||
match storage_tx.verify(db).await {
|
match storage_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -293,7 +344,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::StorageU16(storage_tx) = &transaction {
|
if let Transaction::StorageU16(storage_tx) = &transaction {
|
||||||
match storage_tx.verify(db).await {
|
match storage_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -306,7 +358,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::StorageU32(storage_tx) = &transaction {
|
if let Transaction::StorageU32(storage_tx) = &transaction {
|
||||||
match storage_tx.verify(db).await {
|
match storage_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -319,7 +372,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::StorageU64(storage_tx) = &transaction {
|
if let Transaction::StorageU64(storage_tx) = &transaction {
|
||||||
match storage_tx.verify(db).await {
|
match storage_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -332,7 +386,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::StorageU128(storage_tx) = &transaction {
|
if let Transaction::StorageU128(storage_tx) = &transaction {
|
||||||
match storage_tx.verify(db).await {
|
match storage_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -345,7 +400,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::StorageString(storage_tx) = &transaction {
|
if let Transaction::StorageString(storage_tx) = &transaction {
|
||||||
match storage_tx.verify(db).await {
|
match storage_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -358,7 +414,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::StorageI8(storage_tx) = &transaction {
|
if let Transaction::StorageI8(storage_tx) = &transaction {
|
||||||
match storage_tx.verify(db).await {
|
match storage_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -371,7 +428,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::StorageI16(storage_tx) = &transaction {
|
if let Transaction::StorageI16(storage_tx) = &transaction {
|
||||||
match storage_tx.verify(db).await {
|
match storage_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -384,7 +442,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::StorageI32(storage_tx) = &transaction {
|
if let Transaction::StorageI32(storage_tx) = &transaction {
|
||||||
match storage_tx.verify(db).await {
|
match storage_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -397,7 +456,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::StorageI64(storage_tx) = &transaction {
|
if let Transaction::StorageI64(storage_tx) = &transaction {
|
||||||
match storage_tx.verify(db).await {
|
match storage_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -410,7 +470,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::StorageI128(storage_tx) = &transaction {
|
if let Transaction::StorageI128(storage_tx) = &transaction {
|
||||||
match storage_tx.verify(db).await {
|
match storage_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -423,7 +484,8 @@ async fn verify_transaction(
|
||||||
if let Transaction::DeleteKey(delete_key_tx) = &transaction {
|
if let Transaction::DeleteKey(delete_key_tx) = &transaction {
|
||||||
match delete_key_tx.verify(db).await {
|
match delete_key_tx.verify(db).await {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
reserve_verified_transaction(db, &transaction, balance_tracker).await?;
|
reserve_verified_transaction(db, &transaction, balance_tracker, already_in_mempool)
|
||||||
|
.await?;
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -443,10 +505,12 @@ async fn reserve_verified_transaction(
|
||||||
db: &Db,
|
db: &Db,
|
||||||
transaction: &Transaction,
|
transaction: &Transaction,
|
||||||
balance_tracker: Arc<Mutex<BlockBalanceTracker>>,
|
balance_tracker: Arc<Mutex<BlockBalanceTracker>>,
|
||||||
|
already_in_mempool: bool,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
// Build the balance reservation while this worker still has the
|
// Build the balance reservation while this worker still has the
|
||||||
// transaction in hand, then lock only the shared in-block totals.
|
// transaction in hand, then lock only the shared in-block totals.
|
||||||
let reservation = prepare_transaction_balance_reservation(db, transaction).await?;
|
let reservation =
|
||||||
|
prepare_transaction_balance_reservation(db, transaction, already_in_mempool).await?;
|
||||||
let mut tracker = balance_tracker.lock().await;
|
let mut tracker = balance_tracker.lock().await;
|
||||||
tracker.reserve(reservation)
|
tracker.reserve(reservation)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::blocks::block::{Block, UnminedBlock};
|
use crate::blocks::block::{Block, UnminedBlock};
|
||||||
use crate::common::binary_conversions::hex_to_u64;
|
use crate::common::binary_conversions::hex_to_u64;
|
||||||
use crate::common::check_genesis::genesis_checkup;
|
use crate::common::check_genesis::genesis_checkup;
|
||||||
use crate::common::types::Transaction;
|
|
||||||
use crate::encode;
|
use crate::encode;
|
||||||
use crate::miner::fairness::fairness_difficulty;
|
use crate::miner::fairness::fairness_difficulty;
|
||||||
use crate::records::block_height::get_block_height::get_height;
|
use crate::records::block_height::get_block_height::get_height;
|
||||||
|
|
@ -13,6 +12,7 @@ use crate::records::unpack_block::unpack_header::load_block_header;
|
||||||
use crate::records::wallet_registry::resolve_pubkey_from_short_address;
|
use crate::records::wallet_registry::resolve_pubkey_from_short_address;
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
use crate::verifications::verification_service::VerificationService;
|
use crate::verifications::verification_service::VerificationService;
|
||||||
|
use crate::verifications::verification_types::VerifiableTransaction;
|
||||||
use crate::wallets::structures::Wallet;
|
use crate::wallets::structures::Wallet;
|
||||||
use crate::Arc;
|
use crate::Arc;
|
||||||
use crate::Utc;
|
use crate::Utc;
|
||||||
|
|
@ -97,9 +97,20 @@ impl Block {
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let transactions = self
|
||||||
|
.transactions
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, transaction)| VerifiableTransaction {
|
||||||
|
transaction,
|
||||||
|
original: self.original_transactions.get(index).cloned(),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
let results = Self::send_transactions_to_validate(
|
let results = Self::send_transactions_to_validate(
|
||||||
miner.to_string(),
|
miner.to_string(),
|
||||||
self.transactions.clone(),
|
transactions,
|
||||||
db.clone(),
|
db.clone(),
|
||||||
verification_service,
|
verification_service,
|
||||||
timestamp,
|
timestamp,
|
||||||
|
|
@ -181,7 +192,7 @@ impl Block {
|
||||||
|
|
||||||
async fn send_transactions_to_validate(
|
async fn send_transactions_to_validate(
|
||||||
miner: String,
|
miner: String,
|
||||||
transactions: Vec<Transaction>,
|
transactions: Vec<VerifiableTransaction>,
|
||||||
db: crate::sled::Db,
|
db: crate::sled::Db,
|
||||||
verification_service: Arc<VerificationService>,
|
verification_service: Arc<VerificationService>,
|
||||||
block_timestamp: u32,
|
block_timestamp: u32,
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ use crate::rpc::commands::transaction_by_txid::request_transaction_by_txid;
|
||||||
use crate::rpc::responses::RpcResponse;
|
use crate::rpc::responses::RpcResponse;
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
||||||
use crate::verifications::async_funcs::checks::mempool_check::memcheck;
|
|
||||||
use crate::verifications::async_funcs::checks::verify_db::db_hex_verification;
|
use crate::verifications::async_funcs::checks::verify_db::db_hex_verification;
|
||||||
use crate::verifications::async_funcs::total_payments::get_total_payments;
|
use crate::verifications::async_funcs::total_payments::get_total_payments;
|
||||||
use crate::wallets::structures::Wallet;
|
use crate::wallets::structures::Wallet;
|
||||||
|
|
@ -32,12 +31,6 @@ impl ContractPaymentTransaction {
|
||||||
let hash = self.unsigned_contract_payment.hash().await;
|
let hash = self.unsigned_contract_payment.hash().await;
|
||||||
let signature = &self.signature;
|
let signature = &self.signature;
|
||||||
|
|
||||||
// Transactions already present in the mempool can short-circuit
|
|
||||||
// the deeper verification path and reuse their stored signature.
|
|
||||||
if memcheck(signature, &hash).await {
|
|
||||||
return Ok(signature.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loan payments must come from a valid wallet address and carry a
|
// Loan payments must come from a valid wallet address and carry a
|
||||||
// valid signature from the payer.
|
// valid signature from the payer.
|
||||||
let address = &self.unsigned_contract_payment.address;
|
let address = &self.unsigned_contract_payment.address;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ use crate::records::wallet_registry::{
|
||||||
};
|
};
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
||||||
use crate::verifications::async_funcs::checks::mempool_check::memcheck;
|
|
||||||
use crate::verifications::async_funcs::checks::verify_db::{
|
use crate::verifications::async_funcs::checks::verify_db::{
|
||||||
db_bytes_verification, db_hex_verification,
|
db_bytes_verification, db_hex_verification,
|
||||||
};
|
};
|
||||||
|
|
@ -21,12 +20,6 @@ impl BurnTransaction {
|
||||||
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
||||||
let hash = self.unsigned_burn.hash().await;
|
let hash = self.unsigned_burn.hash().await;
|
||||||
|
|
||||||
// Transactions already present in the mempool can short-circuit
|
|
||||||
// the deeper verification path and reuse their stored signature.
|
|
||||||
if memcheck(&self.signature, &hash).await {
|
|
||||||
return Ok(self.signature.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Burn transactions are anchored to the sender wallet and the
|
// Burn transactions are anchored to the sender wallet and the
|
||||||
// signed burn payload before any asset-specific rules apply.
|
// signed burn payload before any asset-specific rules apply.
|
||||||
if !Wallet::short_address_validation(&self.unsigned_burn.address) {
|
if !Wallet::short_address_validation(&self.unsigned_burn.address) {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ use crate::rpc::commands::transaction_by_txid::request_transaction_by_txid;
|
||||||
use crate::rpc::responses::RpcResponse;
|
use crate::rpc::responses::RpcResponse;
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
||||||
use crate::verifications::async_funcs::checks::mempool_check::memcheck;
|
|
||||||
use crate::verifications::async_funcs::checks::verify_db::db_hex_verification;
|
use crate::verifications::async_funcs::checks::verify_db::db_hex_verification;
|
||||||
use crate::verifications::async_funcs::total_payments::get_total_payments;
|
use crate::verifications::async_funcs::total_payments::get_total_payments;
|
||||||
use crate::wallets::structures::Wallet;
|
use crate::wallets::structures::Wallet;
|
||||||
|
|
@ -19,19 +18,25 @@ use crate::{decode, encode};
|
||||||
|
|
||||||
impl CollateralClaimTransaction {
|
impl CollateralClaimTransaction {
|
||||||
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
||||||
self.verify_internal(db, Utc::now().timestamp() as u32, true)
|
self.verify_internal(db, Utc::now().timestamp() as u32, false)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn verify_at(&self, db: &Db, as_of_timestamp: u32) -> Result<String, String> {
|
pub async fn verify_at(
|
||||||
self.verify_internal(db, as_of_timestamp, false).await
|
&self,
|
||||||
|
db: &Db,
|
||||||
|
as_of_timestamp: u32,
|
||||||
|
already_in_mempool: bool,
|
||||||
|
) -> Result<String, String> {
|
||||||
|
self.verify_internal(db, as_of_timestamp, already_in_mempool)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn verify_internal(
|
async fn verify_internal(
|
||||||
&self,
|
&self,
|
||||||
db: &Db,
|
db: &Db,
|
||||||
as_of_timestamp: u32,
|
as_of_timestamp: u32,
|
||||||
allow_mempool_short_circuit: bool,
|
already_in_mempool: bool,
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
let hash = self.unsigned_collateral_claim.hash().await;
|
let hash = self.unsigned_collateral_claim.hash().await;
|
||||||
let signature = &self.signature;
|
let signature = &self.signature;
|
||||||
|
|
@ -42,13 +47,6 @@ impl CollateralClaimTransaction {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let already_in_mempool = memcheck(signature, &hash).await;
|
|
||||||
// Submission can reuse an already verified mempool entry. Block
|
|
||||||
// validation still checks the schedule against the block timestamp.
|
|
||||||
if allow_mempool_short_circuit && already_in_mempool {
|
|
||||||
return Ok(signature.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collateral claims are valid only when the claimant signs the
|
// Collateral claims are valid only when the claimant signs the
|
||||||
// claim transaction with the same wallet in the payload.
|
// claim transaction with the same wallet in the payload.
|
||||||
if !Wallet::short_address_validation(&self.unsigned_collateral_claim.address) {
|
if !Wallet::short_address_validation(&self.unsigned_collateral_claim.address) {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ use crate::records::wallet_registry::{
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
use crate::verifications::async_funcs::asset_rules::is_reserved_base_coin_ticker;
|
use crate::verifications::async_funcs::asset_rules::is_reserved_base_coin_ticker;
|
||||||
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
||||||
use crate::verifications::async_funcs::checks::mempool_check::memcheck;
|
|
||||||
use crate::verifications::async_funcs::checks::verify_db::db_hex_verification;
|
use crate::verifications::async_funcs::checks::verify_db::db_hex_verification;
|
||||||
use crate::wallets::structures::Wallet;
|
use crate::wallets::structures::Wallet;
|
||||||
use crate::Cid;
|
use crate::Cid;
|
||||||
|
|
@ -38,12 +37,6 @@ impl CreateNftTransaction {
|
||||||
return Err("NFT name is reserved for the base coin.".to_string());
|
return Err("NFT name is reserved for the base coin.".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transactions already present in the mempool can short-circuit
|
|
||||||
// the deeper verification path and reuse their stored signature.
|
|
||||||
if memcheck(signature, hash).await {
|
|
||||||
return Ok(signature.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// NFT creation is anchored to a valid creator wallet and a valid
|
// NFT creation is anchored to a valid creator wallet and a valid
|
||||||
// signature over the unsigned NFT payload.
|
// signature over the unsigned NFT payload.
|
||||||
let creator = &self.unsigned_create_nft.creator;
|
let creator = &self.unsigned_create_nft.creator;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ use crate::records::wallet_registry::{
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
use crate::verifications::async_funcs::asset_rules::is_reserved_base_coin_ticker;
|
use crate::verifications::async_funcs::asset_rules::is_reserved_base_coin_ticker;
|
||||||
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
||||||
use crate::verifications::async_funcs::checks::mempool_check::memcheck;
|
|
||||||
use crate::verifications::async_funcs::checks::verify_db::{
|
use crate::verifications::async_funcs::checks::verify_db::{
|
||||||
db_bytes_verification, db_hex_verification,
|
db_bytes_verification, db_hex_verification,
|
||||||
};
|
};
|
||||||
|
|
@ -17,10 +16,7 @@ use crate::wallets::structures::Wallet;
|
||||||
|
|
||||||
impl CreateTokenTransaction {
|
impl CreateTokenTransaction {
|
||||||
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
||||||
// Transactions already present in the mempool can short-circuit
|
|
||||||
// the deeper verification path and reuse their stored signature.
|
|
||||||
let hash = self.unsigned_create_token.hash().await;
|
let hash = self.unsigned_create_token.hash().await;
|
||||||
let signature = &self.signature;
|
|
||||||
|
|
||||||
// Token tickers use the fixed padded coin-length format.
|
// Token tickers use the fixed padded coin-length format.
|
||||||
let ticker_length = self.unsigned_create_token.ticker.len();
|
let ticker_length = self.unsigned_create_token.ticker.len();
|
||||||
|
|
@ -38,10 +34,6 @@ impl CreateTokenTransaction {
|
||||||
return Err("Ticker is reserved for the base coin.".to_string());
|
return Err("Ticker is reserved for the base coin.".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
if memcheck(signature, &hash).await {
|
|
||||||
return Ok(self.signature.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Token creation is anchored to the creator's wallet signature.
|
// Token creation is anchored to the creator's wallet signature.
|
||||||
if !Wallet::short_address_validation(&self.unsigned_create_token.creator) {
|
if !Wallet::short_address_validation(&self.unsigned_create_token.creator) {
|
||||||
return Err("Sender Wallet Address is Invalid.".to_string());
|
return Err("Sender Wallet Address is Invalid.".to_string());
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ use crate::records::wallet_registry::{
|
||||||
require_canonical_registered_short_address, resolve_pubkey_from_short_address,
|
require_canonical_registered_short_address, resolve_pubkey_from_short_address,
|
||||||
};
|
};
|
||||||
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
||||||
use crate::verifications::async_funcs::checks::mempool_check::memcheck;
|
|
||||||
use crate::verifications::async_funcs::checks::verify_db::db_hex_verification;
|
use crate::verifications::async_funcs::checks::verify_db::db_hex_verification;
|
||||||
use crate::wallets::structures::Wallet;
|
use crate::wallets::structures::Wallet;
|
||||||
use crate::{decode, encode, sled::Db};
|
use crate::{decode, encode, sled::Db};
|
||||||
|
|
@ -16,10 +15,6 @@ impl DeleteKey {
|
||||||
let delete = &self.unsigned_deletekey;
|
let delete = &self.unsigned_deletekey;
|
||||||
let hash = delete.hash().await;
|
let hash = delete.hash().await;
|
||||||
|
|
||||||
// Existing mempool entries short-circuit before the storage-state checks.
|
|
||||||
if memcheck(&self.signature, &hash).await {
|
|
||||||
return Ok(self.signature.clone());
|
|
||||||
}
|
|
||||||
if delete.txtype != DELETE_KEY_TYPE {
|
if delete.txtype != DELETE_KEY_TYPE {
|
||||||
return Err("Delete-key transaction type is invalid.".to_string());
|
return Err("Delete-key transaction type is invalid.".to_string());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ use crate::rpc::responses::RpcResponse;
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
use crate::verifications::async_funcs::asset_rules::reserved_base_coins;
|
use crate::verifications::async_funcs::asset_rules::reserved_base_coins;
|
||||||
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
||||||
use crate::verifications::async_funcs::checks::mempool_check::memcheck;
|
|
||||||
use crate::verifications::async_funcs::checks::verify_db::{
|
use crate::verifications::async_funcs::checks::verify_db::{
|
||||||
db_bytes_verification, db_hex_verification,
|
db_bytes_verification, db_hex_verification,
|
||||||
};
|
};
|
||||||
|
|
@ -50,13 +49,6 @@ fn token_hard_limit(db: &Db, ticker: &str) -> Option<u8> {
|
||||||
impl IssueTokenTransaction {
|
impl IssueTokenTransaction {
|
||||||
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
||||||
let hash = self.unsigned_issue_token.hash().await;
|
let hash = self.unsigned_issue_token.hash().await;
|
||||||
let signature = &self.signature;
|
|
||||||
|
|
||||||
// Transactions already present in the mempool can short-circuit
|
|
||||||
// the deeper verification path and reuse their stored signature.
|
|
||||||
if memcheck(signature, &hash).await {
|
|
||||||
return Ok(self.signature.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Issuance is anchored to the creator's wallet signature.
|
// Issuance is anchored to the creator's wallet signature.
|
||||||
if !Wallet::short_address_validation(&self.unsigned_issue_token.creator) {
|
if !Wallet::short_address_validation(&self.unsigned_issue_token.creator) {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ use crate::records::wallet_registry::{
|
||||||
};
|
};
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
||||||
use crate::verifications::async_funcs::checks::mempool_check::memcheck;
|
|
||||||
use crate::verifications::async_funcs::checks::time_checks::is_within_30_days;
|
use crate::verifications::async_funcs::checks::time_checks::is_within_30_days;
|
||||||
use crate::verifications::async_funcs::checks::verify_db::{
|
use crate::verifications::async_funcs::checks::verify_db::{
|
||||||
db_bytes_verification, db_hex_verification,
|
db_bytes_verification, db_hex_verification,
|
||||||
|
|
@ -21,13 +20,6 @@ use crate::wallets::structures::Wallet;
|
||||||
impl LoanContractTransaction {
|
impl LoanContractTransaction {
|
||||||
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
||||||
let calculated_hash = &self.unsigned_loan_contract.hash().await;
|
let calculated_hash = &self.unsigned_loan_contract.hash().await;
|
||||||
let signature2 = &self.signature2;
|
|
||||||
|
|
||||||
// Transactions already present in the mempool can short-circuit
|
|
||||||
// the deeper verification path and reuse their stored signature.
|
|
||||||
if memcheck(signature2, calculated_hash).await {
|
|
||||||
return Ok(signature2.to_string());
|
|
||||||
};
|
|
||||||
|
|
||||||
// Loan contracts require valid lender and borrower wallet addresses.
|
// Loan contracts require valid lender and borrower wallet addresses.
|
||||||
let lender = &self.unsigned_loan_contract.lender;
|
let lender = &self.unsigned_loan_contract.lender;
|
||||||
|
|
|
||||||
|
|
@ -7,20 +7,13 @@ use crate::records::wallet_registry::{
|
||||||
};
|
};
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
||||||
use crate::verifications::async_funcs::checks::mempool_check::memcheck;
|
|
||||||
use crate::verifications::async_funcs::checks::verify_db::db_hex_verification;
|
use crate::verifications::async_funcs::checks::verify_db::db_hex_verification;
|
||||||
use crate::wallets::structures::Wallet;
|
use crate::wallets::structures::Wallet;
|
||||||
|
|
||||||
impl MarketingTransaction {
|
impl MarketingTransaction {
|
||||||
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
||||||
// Transactions already present in the mempool can short-circuit
|
|
||||||
// the deeper verification path and reuse their stored signature.
|
|
||||||
let hash = &self.unsigned_marketing.hash().await;
|
let hash = &self.unsigned_marketing.hash().await;
|
||||||
let signature = &self.signature;
|
let signature = &self.signature;
|
||||||
if memcheck(signature, hash).await {
|
|
||||||
return Ok(signature.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marketing transactions must come from a valid advertiser wallet
|
// Marketing transactions must come from a valid advertiser wallet
|
||||||
// and carry a valid signature from that same wallet.
|
// and carry a valid signature from that same wallet.
|
||||||
let advertiser = &self.unsigned_marketing.advertiser;
|
let advertiser = &self.unsigned_marketing.advertiser;
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ use crate::records::wallet_registry::{
|
||||||
};
|
};
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
||||||
use crate::verifications::async_funcs::checks::mempool_check::memcheck;
|
|
||||||
use crate::verifications::async_funcs::checks::verify_db::db_hex_verification;
|
use crate::verifications::async_funcs::checks::verify_db::db_hex_verification;
|
||||||
use crate::wallets::structures::Wallet;
|
use crate::wallets::structures::Wallet;
|
||||||
|
|
||||||
|
|
@ -21,13 +20,7 @@ impl StorageKey {
|
||||||
return Err("Storage key transaction type is invalid.".to_string());
|
return Err("Storage key transaction type is invalid.".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transactions already present in the mempool can short-circuit
|
|
||||||
// deeper verification and return their stored signature.
|
|
||||||
let hash = storage_key.hash().await;
|
let hash = storage_key.hash().await;
|
||||||
if memcheck(&self.signature, &hash).await {
|
|
||||||
return Ok(self.signature.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only canonical registered short addresses can create storage
|
// Only canonical registered short addresses can create storage
|
||||||
// keys. Vanity aliases are resolved by callers before they reach
|
// keys. Vanity aliases are resolved by callers before they reach
|
||||||
// this fixed transaction format.
|
// this fixed transaction format.
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ use crate::records::wallet_registry::{
|
||||||
};
|
};
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
||||||
use crate::verifications::async_funcs::checks::mempool_check::memcheck;
|
|
||||||
use crate::verifications::async_funcs::checks::verify_db::db_hex_verification;
|
use crate::verifications::async_funcs::checks::verify_db::db_hex_verification;
|
||||||
use crate::wallets::structures::Wallet;
|
use crate::wallets::structures::Wallet;
|
||||||
|
|
||||||
|
|
@ -32,13 +31,6 @@ async fn verify_storage_value<T: StorageValueTransaction>(
|
||||||
// fee, hash, and signature.
|
// fee, hash, and signature.
|
||||||
let parts = tx.storage_parts();
|
let parts = tx.storage_parts();
|
||||||
|
|
||||||
// Match the rest of transaction verification: if this exact signed
|
|
||||||
// transaction is already in the mempool, return before doing deeper
|
|
||||||
// database checks.
|
|
||||||
if memcheck(parts.signature, &parts.hash).await {
|
|
||||||
return Ok(parts.signature.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// The shared verifier is called by each concrete storage type, so
|
// The shared verifier is called by each concrete storage type, so
|
||||||
// confirm the embedded transaction type matches that caller.
|
// confirm the embedded transaction type matches that caller.
|
||||||
if parts.txtype != expected_type {
|
if parts.txtype != expected_type {
|
||||||
|
|
@ -187,14 +179,6 @@ impl StorageString {
|
||||||
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
||||||
// String storage has extra chain-linking rules before it can use
|
// String storage has extra chain-linking rules before it can use
|
||||||
// the common storage-value verifier.
|
// the common storage-value verifier.
|
||||||
let parts = self.storage_parts();
|
|
||||||
|
|
||||||
// Existing mempool entries can still short-circuit before walking
|
|
||||||
// the previous-hash string chain.
|
|
||||||
if memcheck(parts.signature, &parts.hash).await {
|
|
||||||
return Ok(parts.signature.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// The on-chain string chunk is fixed at 180 bytes. Shorter text is
|
// The on-chain string chunk is fixed at 180 bytes. Shorter text is
|
||||||
// padded by the creator and trimmed only when saved into sled.
|
// padded by the creator and trimmed only when saved into sled.
|
||||||
if self.unsigned_storage.value.as_bytes().len() != STORAGE_STRING_VALUE_BYTES {
|
if self.unsigned_storage.value.as_bytes().len() != STORAGE_STRING_VALUE_BYTES {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ use crate::records::wallet_registry::{
|
||||||
};
|
};
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
||||||
use crate::verifications::async_funcs::checks::mempool_check::memcheck;
|
|
||||||
use crate::verifications::async_funcs::checks::time_checks::is_within_30_days;
|
use crate::verifications::async_funcs::checks::time_checks::is_within_30_days;
|
||||||
use crate::verifications::async_funcs::checks::verify_db::{
|
use crate::verifications::async_funcs::checks::verify_db::{
|
||||||
db_bytes_verification, db_hex_verification,
|
db_bytes_verification, db_hex_verification,
|
||||||
|
|
@ -36,13 +35,7 @@ fn validate_swap_tip(value: u64, tip: u64, is_nft: bool, sender: &str) -> Result
|
||||||
|
|
||||||
impl SwapTransaction {
|
impl SwapTransaction {
|
||||||
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
||||||
// Transactions already present in the mempool can short-circuit
|
|
||||||
// the deeper verification path and reuse their stored signature.
|
|
||||||
let hash = self.unsigned_swap.hash().await;
|
let hash = self.unsigned_swap.hash().await;
|
||||||
if memcheck(&self.signature2, &hash).await {
|
|
||||||
return Ok(self.signature2.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Both swap participants must provide valid wallet addresses and
|
// Both swap participants must provide valid wallet addresses and
|
||||||
// matching signatures over the shared unsigned swap payload.
|
// matching signatures over the shared unsigned swap payload.
|
||||||
if !(Wallet::short_address_validation(&self.unsigned_swap.sender1)
|
if !(Wallet::short_address_validation(&self.unsigned_swap.sender1)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ use crate::records::wallet_registry::{
|
||||||
};
|
};
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
||||||
use crate::verifications::async_funcs::checks::mempool_check::memcheck;
|
|
||||||
use crate::verifications::async_funcs::checks::verify_db::{
|
use crate::verifications::async_funcs::checks::verify_db::{
|
||||||
db_bytes_verification, db_hex_verification,
|
db_bytes_verification, db_hex_verification,
|
||||||
};
|
};
|
||||||
|
|
@ -35,12 +34,6 @@ fn is_zero_burn_address(address: &str) -> bool {
|
||||||
impl TransferTransaction {
|
impl TransferTransaction {
|
||||||
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
pub async fn verify(&self, db: &Db) -> Result<String, String> {
|
||||||
let hash = self.unsigned_transfer.hash().await;
|
let hash = self.unsigned_transfer.hash().await;
|
||||||
// Transactions that are already sitting in the mempool can skip
|
|
||||||
// the deeper verification work and return their stored signature.
|
|
||||||
if memcheck(&self.signature, &hash).await {
|
|
||||||
return Ok(self.signature.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate both wallet addresses and the signed transfer payload
|
// Validate both wallet addresses and the signed transfer payload
|
||||||
// before checking balances and asset-specific rules.
|
// before checking balances and asset-specific rules.
|
||||||
if !(Wallet::short_address_validation(&self.unsigned_transfer.sender)
|
if !(Wallet::short_address_validation(&self.unsigned_transfer.sender)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ use crate::records::wallet_registry::{
|
||||||
};
|
};
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
use crate::verifications::async_funcs::checks::balance_check::balance_checkup;
|
||||||
use crate::verifications::async_funcs::checks::mempool_check::memcheck;
|
|
||||||
use crate::verifications::async_funcs::checks::verify_db::db_hex_verification;
|
use crate::verifications::async_funcs::checks::verify_db::db_hex_verification;
|
||||||
use crate::wallets::structures::Wallet;
|
use crate::wallets::structures::Wallet;
|
||||||
|
|
||||||
|
|
@ -17,12 +16,6 @@ impl VanityAddressTransaction {
|
||||||
// address-registration payload, so recompute that hash first.
|
// address-registration payload, so recompute that hash first.
|
||||||
let hash = self.unsigned_vanity_address.hash().await;
|
let hash = self.unsigned_vanity_address.hash().await;
|
||||||
|
|
||||||
// Transactions already present in the mempool can short-circuit
|
|
||||||
// the deeper verification path and reuse their stored signature.
|
|
||||||
if memcheck(&self.signature, &hash).await {
|
|
||||||
return Ok(self.signature.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// The paying wallet must already be a valid short address for the
|
// The paying wallet must already be a valid short address for the
|
||||||
// current network before registry ownership is checked.
|
// current network before registry ownership is checked.
|
||||||
let address = &self.unsigned_vanity_address.address;
|
let address = &self.unsigned_vanity_address.address;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
use crate::common::types::Transaction;
|
|
||||||
use crate::rayon::ThreadPool;
|
use crate::rayon::ThreadPool;
|
||||||
use crate::rayon::ThreadPoolBuilder;
|
use crate::rayon::ThreadPoolBuilder;
|
||||||
use crate::verifications::async_funcs::checks::block_balance::BlockBalanceTracker;
|
use crate::verifications::async_funcs::checks::block_balance::BlockBalanceTracker;
|
||||||
use crate::verifications::async_funcs::transactions::verify_transactions;
|
use crate::verifications::async_funcs::transactions::verify_transactions;
|
||||||
use crate::verifications::sync_funcs::transaction_verify_loop::COUNTER;
|
use crate::verifications::sync_funcs::transaction_verify_loop::COUNTER;
|
||||||
use crate::verifications::verification_types::{
|
use crate::verifications::verification_types::{
|
||||||
VerificationChunkJob, VerificationChunkResult, VerificationJob,
|
VerifiableTransaction, VerificationChunkJob, VerificationChunkResult, VerificationJob,
|
||||||
};
|
};
|
||||||
use crate::Arc;
|
use crate::Arc;
|
||||||
use crate::AtomicBool;
|
use crate::AtomicBool;
|
||||||
|
|
@ -75,7 +74,7 @@ impl VerificationService {
|
||||||
pub async fn verify_block_transactions(
|
pub async fn verify_block_transactions(
|
||||||
&self,
|
&self,
|
||||||
miner: String,
|
miner: String,
|
||||||
transactions: Vec<Transaction>,
|
transactions: Vec<VerifiableTransaction>,
|
||||||
db: crate::sled::Db,
|
db: crate::sled::Db,
|
||||||
block_timestamp: u32,
|
block_timestamp: u32,
|
||||||
) -> Result<Vec<String>, String> {
|
) -> Result<Vec<String>, String> {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,16 @@
|
||||||
use crate::common::types::Transaction;
|
use crate::common::types::Transaction;
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct VerifiableTransaction {
|
||||||
|
pub transaction: Transaction,
|
||||||
|
pub original: Option<Vec<u8>>,
|
||||||
|
}
|
||||||
|
|
||||||
// VerificationJob represents one full transaction batch submitted to the verification service.
|
// VerificationJob represents one full transaction batch submitted to the verification service.
|
||||||
pub struct VerificationJob {
|
pub struct VerificationJob {
|
||||||
pub miner: String,
|
pub miner: String,
|
||||||
pub transactions: Vec<Transaction>,
|
pub transactions: Vec<VerifiableTransaction>,
|
||||||
pub db: Db,
|
pub db: Db,
|
||||||
pub block_timestamp: u32,
|
pub block_timestamp: u32,
|
||||||
}
|
}
|
||||||
|
|
@ -12,7 +18,7 @@ pub struct VerificationJob {
|
||||||
// VerificationChunkJob is the per-worker slice created from a larger verification job.
|
// VerificationChunkJob is the per-worker slice created from a larger verification job.
|
||||||
pub struct VerificationChunkJob {
|
pub struct VerificationChunkJob {
|
||||||
pub miner: String,
|
pub miner: String,
|
||||||
pub transactions: Vec<Transaction>,
|
pub transactions: Vec<VerifiableTransaction>,
|
||||||
pub db: Db,
|
pub db: Db,
|
||||||
pub block_timestamp: u32,
|
pub block_timestamp: u32,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue