added RPC explorer commands

This commit is contained in:
viraladmin 2026-06-12 10:27:28 -06:00
parent 38dabfa27f
commit a4c4518adf
57 changed files with 790 additions and 210 deletions

View File

@ -182,7 +182,7 @@ impl BurnTransaction {
let signature = &self.signature;
let client_handle = db_client().await?;
let client = client_handle.as_ref();
let client = client_handle.as_ref();
client
.execute(

View File

@ -177,7 +177,7 @@ impl CollateralClaimTransaction {
// Collateral-claim transactions remain in the mempool table until mined or removed.
let client_handle = db_client().await?;
let client = client_handle.as_ref();
let client = client_handle.as_ref();
client
.execute(

View File

@ -183,7 +183,7 @@ impl IssueTokenTransaction {
// Issue-token transactions remain in the mempool table until mined or removed.
let client_handle = db_client().await?;
let client = client_handle.as_ref();
let client = client_handle.as_ref();
client
.execute(

View File

@ -209,7 +209,7 @@ impl ContractPaymentTransaction {
// Loan-payment transactions remain in the mempool table until mined or removed.
let client_handle = db_client().await?;
let client = client_handle.as_ref();
let client = client_handle.as_ref();
client
.execute(

View File

@ -327,7 +327,7 @@ impl LoanContractTransaction {
// Loan contracts remain in the mempool table until mined or removed.
let client_handle = db_client().await?;
let client = client_handle.as_ref();
let client = client_handle.as_ref();
client
.execute(

View File

@ -254,7 +254,7 @@ impl MarketingTransaction {
// Marketing transactions remain in the mempool table until mined or removed.
let client_handle = db_client().await?;
let client = client_handle.as_ref();
let client = client_handle.as_ref();
client
.execute(

View File

@ -231,7 +231,7 @@ impl CreateNftTransaction {
// NFT-creation transactions remain in the mempool table until mined or removed.
let client_handle = db_client().await?;
let client = client_handle.as_ref();
let client = client_handle.as_ref();
client
.execute(

View File

@ -328,7 +328,7 @@ impl SwapTransaction {
// Swap transactions remain in the mempool table until mined or removed.
let client_handle = db_client().await?;
let client = client_handle.as_ref();
let client = client_handle.as_ref();
client
.execute(

View File

@ -205,7 +205,7 @@ impl CreateTokenTransaction {
// Token-creation transactions remain in the mempool table until mined or removed.
let client_handle = db_client().await?;
let client = client_handle.as_ref();
let client = client_handle.as_ref();
client
.execute(

View File

@ -227,7 +227,7 @@ impl TransferTransaction {
// Transfer transactions remain in the mempool table until mined or removed.
let client_handle = db_client().await?;
let client = client_handle.as_ref();
let client = client_handle.as_ref();
client
.execute(

View File

@ -183,7 +183,7 @@ impl VanityAddressTransaction {
// Vanity transactions are written to the vanity mempool table
// until the transaction is mined or removed.
let client_handle = db_client().await?;
let client = client_handle.as_ref();
let client = client_handle.as_ref();
client
.execute(

View File

@ -3,10 +3,10 @@ use crate::orphans::structs::UndoTransactions;
use crate::orphans::torrent_candidates::hydrate_torrent_candidates;
use crate::records::block_height::get_block_height::get_height;
use crate::records::memory::response_channels::reserve_entry_with_context;
use crate::rpc::command_maps::RPC_TORRENT_BY_HEIGHT;
use crate::records::memory::torrent_status::{
get_torrent_status, set_torrent_status, TorrentStatus,
};
use crate::rpc::command_maps::RPC_TORRENT_BY_HEIGHT;
use crate::torrent::structs::Torrent;
use crate::torrent::torrenting_system::save_torrent::{
list_staged_torrents_for_height, read_staged_torrent,

View File

@ -5,6 +5,7 @@ use crate::decode;
use crate::records::balance_sheet::operations::balance_sheet_operation_with_db;
use crate::records::record_chain::add_payments_db::remove_payment;
use crate::records::record_chain::nft_provenance::remove_nft_history_entry;
use crate::records::record_chain::wallet_tx_index::remove_wallet_transaction_index;
use crate::rpc::commands::transaction_by_txid::request_transaction_by_txid;
use crate::rpc::responses::RpcResponse;
use crate::sled::Db;
@ -84,8 +85,11 @@ pub async fn undo_borrower_transaction(
.open_tree("txid")
.map_err(|e| format!("Failed to open txid tree: {e}"))?;
let tx_hash = transaction.unsigned_contract_payment.hash().await;
let tx_hash_bytes = decode(&tx_hash).map_err(|e| format!("Error decoding txid: {e}"))?;
let _ =
remove_wallet_transaction_index(db, &[borrower, &lender, mining_receiver], &tx_hash_bytes);
txid_tree
.remove(decode(&tx_hash).map_err(|e| format!("Error decoding txid: {e}"))?)
.remove(tx_hash_bytes.clone())
.map_err(|e| format!("Failed to remove borrower txid: {e}"))?;
// Loan payments involving NFTs also add a provenance entry for the loan
@ -93,7 +97,6 @@ pub async fn undo_borrower_transaction(
let nft_tree = db
.open_tree("nfts")
.map_err(|e| format!("Failed to open nfts tree: {e}"))?;
let tx_hash_bytes = decode(&tx_hash).map_err(|e| format!("Error decoding txid: {e}"))?;
if nft_tree.contains_key(loan_coin.as_bytes()).unwrap_or(false) {
let _ = remove_nft_history_entry(db, &loan_coin, &tx_hash_bytes);
}

View File

@ -5,6 +5,7 @@ use crate::decode;
use crate::records::balance_sheet::operations::balance_sheet_operation_with_db;
use crate::records::record_chain::nft_provenance::remove_nft_history_entry;
use crate::records::record_chain::token_provenance::remove_token_history_entry;
use crate::records::record_chain::wallet_tx_index::remove_wallet_transaction_index;
use crate::sled::Db;
pub async fn undo_burn_transaction(transaction: BurnTransaction, mining_receiver: &str, db: &Db) {
@ -53,6 +54,11 @@ pub async fn undo_burn_transaction(transaction: BurnTransaction, mining_receiver
);
let hash_binary = decode(&transaction.unsigned_burn.hash().await).unwrap();
let _ = remove_wallet_transaction_index(
db,
&[&transaction.unsigned_burn.address, mining_receiver],
&hash_binary,
);
// Delete the txid lookup inserted when the burn was saved.
let txid_tree = db.open_tree("txid").unwrap();

View File

@ -4,6 +4,7 @@ use crate::common::network_paths_and_settings::block_extension_and_paths;
use crate::decode;
use crate::records::balance_sheet::operations::balance_sheet_operation_with_db;
use crate::records::record_chain::nft_provenance::remove_nft_history_entry;
use crate::records::record_chain::wallet_tx_index::remove_wallet_transaction_index;
use crate::rpc::commands::transaction_by_txid::request_transaction_by_txid;
use crate::rpc::responses::RpcResponse;
use crate::sled::Db;
@ -85,13 +86,12 @@ pub async fn undo_collateral_transaction(
// Remove the collateral-claim transaction lookup from the txid tree.
let txid_tree = db.open_tree("txid").unwrap();
let tx_hash = transaction.unsigned_collateral_claim.hash().await;
txid_tree
.remove(decode(&tx_hash).map_err(|e| format!("Error decoding txid: {e}"))?)
.unwrap();
let tx_hash_bytes = decode(&tx_hash).map_err(|e| format!("Error decoding txid: {e}"))?;
let _ = remove_wallet_transaction_index(db, &[claimer, mining_receiver], &tx_hash_bytes);
txid_tree.remove(tx_hash_bytes.clone()).unwrap();
// NFT collateral claims write provenance for the collateral asset.
let nft_tree = db.open_tree("nfts").unwrap();
let tx_hash_bytes = decode(&tx_hash).map_err(|e| format!("Error decoding txid: {e}"))?;
if nft_tree
.contains_key(collateral.as_bytes())
.unwrap_or(false)

View File

@ -4,6 +4,7 @@ use crate::common::nft_assets::nft_asset_name;
use crate::decode;
use crate::records::balance_sheet::operations::balance_sheet_operation_with_db;
use crate::records::record_chain::nft_provenance::{remove_nft_history_entry, remove_nft_origin};
use crate::records::record_chain::wallet_tx_index::remove_wallet_transaction_index;
use crate::sled::Db;
const NFT_UNIT: u64 = 100_000_000;
@ -43,6 +44,7 @@ pub async fn undo_create_nft_transaction(
);
let _ = balance_sheet_operation_with_db(db, creator, *txfee, &type_str, operand_addition);
let hash_binary = decode(&transaction.unsigned_create_nft.hash().await).unwrap();
let _ = remove_wallet_transaction_index(db, &[creator, mining_receiver], &hash_binary);
// Remove the create-NFT transaction lookup from the txid tree.
let tree = db.open_tree("txid").unwrap();

View File

@ -3,6 +3,7 @@ use crate::common::network_paths_and_settings::block_extension_and_paths;
use crate::decode;
use crate::records::balance_sheet::operations::balance_sheet_operation_with_db;
use crate::records::record_chain::token_provenance::clear_token_history;
use crate::records::record_chain::wallet_tx_index::remove_wallet_transaction_index;
use crate::sled::Db;
pub async fn undo_create_token_transaction(
@ -46,6 +47,7 @@ pub async fn undo_create_token_transaction(
let ticker_binary = &transaction.unsigned_create_token.ticker.as_bytes();
let hash_binary = decode(&transaction.unsigned_create_token.hash().await).unwrap();
let _ = remove_wallet_transaction_index(db, &[creator, mining_receiver], &hash_binary);
// Remove the create-token transaction lookup from the txid tree.
let tree = db.open_tree("txid").unwrap();

View File

@ -3,6 +3,7 @@ use crate::common::network_paths_and_settings::block_extension_and_paths;
use crate::decode;
use crate::records::balance_sheet::operations::balance_sheet_operation_with_db;
use crate::records::record_chain::token_provenance::remove_token_history_entry;
use crate::records::record_chain::wallet_tx_index::remove_wallet_transaction_index;
use crate::sled::Db;
pub async fn undo_issue_token_transaction(
@ -43,6 +44,7 @@ pub async fn undo_issue_token_transaction(
let _ = balance_sheet_operation_with_db(db, creator, *number, ticker, operand_subtraction);
let hash_binary = decode(&transaction.unsigned_issue_token.hash().await).unwrap();
let _ = remove_wallet_transaction_index(db, &[creator, mining_receiver], &hash_binary);
// Delete the issued-token transaction lookup and provenance record.
let txid_tree = db.open_tree("txid").unwrap();

View File

@ -3,6 +3,7 @@ use crate::common::network_paths_and_settings::block_extension_and_paths;
use crate::decode;
use crate::records::balance_sheet::operations::balance_sheet_operation_with_db;
use crate::records::record_chain::nft_provenance::remove_nft_history_entry;
use crate::records::record_chain::wallet_tx_index::remove_wallet_transaction_index;
use crate::sled::Db;
pub async fn undo_loan_creation_transaction(
@ -66,6 +67,7 @@ pub async fn undo_loan_creation_transaction(
);
let hash_binary = decode(hash).unwrap();
let _ = remove_wallet_transaction_index(db, &[lender, borrower, mining_receiver], &hash_binary);
// delete the txid and remove the active loan record
// so the contract no longer exists on-chain

View File

@ -2,6 +2,7 @@ use crate::blocks::marketing::MarketingTransaction;
use crate::common::network_paths_and_settings::block_extension_and_paths;
use crate::decode;
use crate::records::balance_sheet::operations::balance_sheet_operation_with_db;
use crate::records::record_chain::wallet_tx_index::remove_wallet_transaction_index;
use crate::sled::Db;
pub async fn undo_marketing_transaction(
@ -40,6 +41,7 @@ pub async fn undo_marketing_transaction(
let _ = balance_sheet_operation_with_db(db, advertiser, *txfee, &type_str, operand_addition);
let hash = decode(&transaction.unsigned_marketing.hash().await).unwrap();
let _ = remove_wallet_transaction_index(db, &[advertiser, mining_receiver], &hash);
// Remove the marketing transaction lookup from the txid tree.
let tree = db.open_tree("txid").unwrap();

View File

@ -5,6 +5,7 @@ use crate::records::balance_sheet::operations::balance_sheet_operation_with_db;
use crate::records::record_chain::rewards_tx::{
remove_reward_credit_marker, reward_credit_applied,
};
use crate::records::record_chain::wallet_tx_index::remove_wallet_transaction_index;
use crate::sled::Db;
pub async fn undo_rewards_transaction(
@ -38,6 +39,7 @@ pub async fn undo_rewards_transaction(
}
let hash = decode(transaction.unsigned.hash().await).unwrap();
let _ = remove_wallet_transaction_index(db, &[mining_receiver], &hash);
// Remove the reward transaction lookup from the txid tree.
let tree = db.open_tree("txid").unwrap();

View File

@ -4,6 +4,7 @@ use crate::common::nft_assets::nft_asset_name;
use crate::decode;
use crate::records::balance_sheet::operations::balance_sheet_operation_with_db;
use crate::records::record_chain::nft_provenance::remove_nft_history_entry;
use crate::records::record_chain::wallet_tx_index::remove_wallet_transaction_index;
use crate::sled::Db;
pub async fn undo_swap_transaction(transaction: SwapTransaction, mining_receiver: &str, db: &Db) {
@ -84,6 +85,7 @@ pub async fn undo_swap_transaction(transaction: SwapTransaction, mining_receiver
// Convert the txid hash back to bytes for tree lookup/removal.
let hash = decode(&transaction.unsigned_swap.hash().await).unwrap();
let _ = remove_wallet_transaction_index(db, &[sender1, sender2, mining_receiver], &hash);
// Remove the txid lookup for the rolled-back swap.
let tree = db.open_tree("txid").unwrap();

View File

@ -4,6 +4,7 @@ use crate::common::nft_assets::nft_asset_name;
use crate::decode;
use crate::records::balance_sheet::operations::balance_sheet_operation_with_db;
use crate::records::record_chain::nft_provenance::remove_nft_history_entry;
use crate::records::record_chain::wallet_tx_index::remove_wallet_transaction_index;
use crate::sled::Db;
pub async fn undo_transfer_transaction(
@ -51,6 +52,7 @@ pub async fn undo_transfer_transaction(
let _ = balance_sheet_operation_with_db(db, sender, *txfee, &type_str, operand_addition);
let hash = decode(&transaction.unsigned_transfer.hash().await).unwrap();
let _ = remove_wallet_transaction_index(db, &[sender, receiver, mining_receiver], &hash);
// Remove the txid lookup so the rolled-back transfer no longer resolves as
// an on-chain transaction.

View File

@ -2,6 +2,7 @@ use crate::blocks::vanity::VanityAddressTransaction;
use crate::decode;
use crate::records::balance_sheet::operations::balance_sheet_operation_with_db;
use crate::records::memory::mempool::BASECOIN;
use crate::records::record_chain::wallet_tx_index::remove_wallet_transaction_index;
use crate::records::wallet_registry::{
register_or_update_vanity_address, remove_registered_vanity_for_owner,
take_previous_vanity_for_txid, VanityRegistrationResult,
@ -63,6 +64,7 @@ pub async fn undo_vanity_transaction(
.map_err(|err| format!("Could not open txid tree during vanity undo: {err}"))?;
let txkey = decode(&txhash)
.map_err(|err| format!("Could not decode vanity txhash during undo: {err}"))?;
let _ = remove_wallet_transaction_index(db, &[&owner_address, mining_receiver], &txkey);
tree.remove(txkey)
.map_err(|err| format!("Could not remove vanity txid mapping during undo: {err}"))?;

View File

@ -351,13 +351,12 @@ impl Connection {
}
let message_type = RPC_BLOCK_HEIGHT; // Block-height request used as a lightweight checkup ping.
let (checkup_key, _checkup_tx, checkup_rx_mutex) =
reserve_entry_with_context(
command_map.clone(),
Some(RPC_BLOCK_HEIGHT),
Some(format!("{ip}:{port}")),
)
.await;
let (checkup_key, _checkup_tx, checkup_rx_mutex) = reserve_entry_with_context(
command_map.clone(),
Some(RPC_BLOCK_HEIGHT),
Some(format!("{ip}:{port}")),
)
.await;
// Send a lightweight ping message and wait for the reply
// routed back through the shared response hashmap.

View File

@ -27,9 +27,7 @@ async fn connect_client() -> Result<Client> {
}
pub async fn db_client() -> Result<Arc<Client>> {
let slot = DB
.get()
.ok_or_else(|| anyhow!("DB not initialized"))?;
let slot = DB.get().ok_or_else(|| anyhow!("DB not initialized"))?;
Ok(slot.read().await.clone())
}

View File

@ -1,5 +1,19 @@
use super::*;
use crate::records::record_chain::pending_effects::{BalanceOperand, PendingEffects};
use crate::records::record_chain::wallet_tx_index::index_wallet_transaction;
fn index_selected_wallet_transaction(
pending_effects: &mut PendingEffects,
addresses: &[&str],
block_height: u32,
entry_index: usize,
txid: &[u8],
) -> Result<()> {
let entry_index =
u32::try_from(entry_index).map_err(|_| anyhow!("Wallet transaction index overflowed"))?;
index_wallet_transaction(pending_effects, addresses, block_height, entry_index, txid)
.map_err(|err| anyhow!(err))
}
pub async fn select_transactions_for_block(limit: i64) -> Result<SelectedMempoolBatch> {
// Pull the highest-priority unprocessed rows across all mempool
@ -383,6 +397,13 @@ pub async fn apply_selected_transaction_math(
decode(hash)?,
format!("{block_number}:{tx_index}").into_bytes(),
);
index_selected_wallet_transaction(
pending_effects,
&[sender, receiver, &miner],
block_number,
tx_index,
&decode(hash)?,
)?;
}
SelectedMempoolTransaction::Token {
fee,
@ -413,7 +434,7 @@ pub async fn apply_selected_transaction_math(
// Local mined blocks need to persist the token hard-limit
// metadata just like the downloaded-block save path does.
let client_handle = db_client().await?;
let client = client_handle.as_ref();
let client = client_handle.as_ref();
let token_row = client
.query_opt(
"SELECT hard_limit FROM token WHERE hash = $1 LIMIT 1",
@ -443,6 +464,13 @@ pub async fn apply_selected_transaction_math(
decode(hash)?,
format!("{block_number}:{tx_index}").into_bytes(),
);
index_selected_wallet_transaction(
pending_effects,
&[creator, &miner],
block_number,
tx_index,
&decode(hash)?,
)?;
}
SelectedMempoolTransaction::IssueToken {
fee,
@ -474,6 +502,13 @@ pub async fn apply_selected_transaction_math(
decode(hash)?,
format!("{block_number}:{tx_index}").into_bytes(),
);
index_selected_wallet_transaction(
pending_effects,
&[creator, &miner],
block_number,
tx_index,
&decode(hash)?,
)?;
}
SelectedMempoolTransaction::Burn {
fee,
@ -502,6 +537,13 @@ pub async fn apply_selected_transaction_math(
decode(hash)?,
format!("{block_number}:{tx_index}").into_bytes(),
);
index_selected_wallet_transaction(
pending_effects,
&[address, &miner],
block_number,
tx_index,
&decode(hash)?,
)?;
}
SelectedMempoolTransaction::Nft {
fee,
@ -568,6 +610,13 @@ pub async fn apply_selected_transaction_math(
decode(hash)?,
format!("{block_number}:{tx_index}").into_bytes(),
);
index_selected_wallet_transaction(
pending_effects,
&[creator, &miner],
block_number,
tx_index,
&decode(hash)?,
)?;
}
SelectedMempoolTransaction::Marketing {
fee,
@ -587,6 +636,13 @@ pub async fn apply_selected_transaction_math(
decode(hash)?,
format!("{block_number}:{tx_index}").into_bytes(),
);
index_selected_wallet_transaction(
pending_effects,
&[advertiser, &miner],
block_number,
tx_index,
&decode(hash)?,
)?;
}
SelectedMempoolTransaction::Vanity {
fee,
@ -610,6 +666,13 @@ pub async fn apply_selected_transaction_math(
decode(hash)?,
format!("{block_number}:{tx_index}").into_bytes(),
);
index_selected_wallet_transaction(
pending_effects,
&[address, &miner],
block_number,
tx_index,
&decode(hash)?,
)?;
}
SelectedMempoolTransaction::Swap {
fee1,
@ -683,6 +746,13 @@ pub async fn apply_selected_transaction_math(
decode(hash)?,
format!("{block_number}:{tx_index}").into_bytes(),
);
index_selected_wallet_transaction(
pending_effects,
&[sender1, sender2, &miner],
block_number,
tx_index,
&decode(hash)?,
)?;
}
SelectedMempoolTransaction::Lender {
fee,
@ -745,6 +815,13 @@ pub async fn apply_selected_transaction_math(
decode(hash)?,
format!("{block_number}:{tx_index}").into_bytes(),
);
index_selected_wallet_transaction(
pending_effects,
&[lender, borrower, &miner],
block_number,
tx_index,
&decode(hash)?,
)?;
}
SelectedMempoolTransaction::Borrower {
fee,
@ -806,6 +883,14 @@ pub async fn apply_selected_transaction_math(
decode(hash)?,
format!("{block_number}:{tx_index}").into_bytes(),
);
let lender_address = binary_to_string(lender.clone());
index_selected_wallet_transaction(
pending_effects,
&[address, &lender_address, &miner],
block_number,
tx_index,
&decode(hash)?,
)?;
}
SelectedMempoolTransaction::Collateral {
fee,
@ -854,6 +939,13 @@ pub async fn apply_selected_transaction_math(
decode(hash)?,
format!("{block_number}:{tx_index}").into_bytes(),
);
index_selected_wallet_transaction(
pending_effects,
&[address, &miner],
block_number,
tx_index,
&decode(hash)?,
)?;
}
}
}

View File

@ -335,7 +335,9 @@ impl NodeInfo {
}
if !address_map.contains_key(&edit.address) {
if let Some(existing_node) = address_map.values_mut().find(|node| node.ip == edit.ip) {
if let Some(existing_node) =
address_map.values_mut().find(|node| node.ip == edit.ip)
{
if existing_node.deleted_timestamp == 0 && edit.ip != GENESIS_IP {
penalize_duplicate_ip = true;
}
@ -344,20 +346,17 @@ impl NodeInfo {
if !penalize_duplicate_ip {
// Persist the new node locally. Network-map entries are bare
// IP membership records, separate from live socket keys.
address_map.insert(
edit.address.clone(),
{
let mut node = NodeInfo::new(
edit.ip.clone(),
blocks_mined,
edit.modified_by.clone(),
edit.modified_timestamp,
edit.modified_signature.clone(),
);
node.monitoring = monitors.clone();
node
},
);
address_map.insert(edit.address.clone(), {
let mut node = NodeInfo::new(
edit.ip.clone(),
blocks_mined,
edit.modified_by.clone(),
edit.modified_timestamp,
edit.modified_signature.clone(),
);
node.monitoring = monitors.clone();
node
});
state_changed = true;
}
}

View File

@ -113,13 +113,8 @@ impl NodeInfo {
.unwrap(),
);
let mut node = NodeInfo::new(
ip,
blocks_mined,
added_by,
added_timestamp,
added_signature,
);
let mut node =
NodeInfo::new(ip, blocks_mined, added_by, added_timestamp, added_signature);
node.deleted_timestamp = deleted_timestamp;
node.deleted_block = deleted_block;
node.monitoring = Vec::new();

View File

@ -112,12 +112,13 @@ pub async fn reserve_transient_entry_with_context(
tokio::spawn(async move {
let received = {
let mut rx = rx.lock().await;
matches!(crate::timeout(Duration::from_secs(30), rx.recv()).await, Ok(Some(_)))
matches!(
crate::timeout(Duration::from_secs(30), rx.recv()).await,
Ok(Some(_))
)
};
if !received {
warn!(
"[rpc_trace] transient uid expired without reply: uid={key:?}"
);
warn!("[rpc_trace] transient uid expired without reply: uid={key:?}");
}
delete_entry(map, key).await;
});

View File

@ -3,6 +3,7 @@ use crate::blocks::loans::LoanContractTransaction;
use crate::decode;
use crate::records::memory::mempool::BASECOIN;
use crate::records::record_chain::pending_effects::{BalanceOperand, PendingEffects};
use crate::records::record_chain::wallet_tx_index::index_wallet_transaction;
use crate::rpc::commands::transaction_by_txid::request_transaction_by_txid;
use crate::rpc::responses::RpcResponse;
use crate::sled::Db;
@ -106,6 +107,17 @@ pub async fn process_borrower(
let txkey = decode(txhash).map_err(|e| format!("Error decoding borrower txid key: {e}"))?;
let txvalue = format!("{block_header_number}:{}", **index);
pending_effects.set_tree("txid", txkey, txvalue.into_bytes());
index_wallet_transaction(
pending_effects,
&[
&transaction.unsigned_contract_payment.address,
&lender,
&miner,
],
block_header_number,
**index as u32,
&txhash_bytes,
)?;
pending_effects.append_tree_if_key_exists(
"nfts",
"nft_history",

View File

@ -3,6 +3,7 @@ use crate::common::nft_assets::nft_asset_name;
use crate::decode;
use crate::records::memory::mempool::BASECOIN;
use crate::records::record_chain::pending_effects::{BalanceOperand, PendingEffects};
use crate::records::record_chain::wallet_tx_index::index_wallet_transaction;
use crate::sled::Db;
use crate::Arc;
use crate::Mutex;
@ -70,6 +71,13 @@ pub async fn process_burn(
let txkey = decode(txhash).map_err(|e| format!("Error decoding burn txid key: {e}"))?;
let txvalue = format!("{block_header_number}:{}", **index);
pending_effects.set_tree("txid", txkey, txvalue.into_bytes());
index_wallet_transaction(
pending_effects,
&[&transaction.unsigned_burn.address, &miner],
block_header_number,
**index as u32,
&txhash_bytes,
)?;
Ok(binary_data)
}

View File

@ -3,6 +3,7 @@ use crate::blocks::loans::LoanContractTransaction;
use crate::decode;
use crate::records::memory::mempool::BASECOIN;
use crate::records::record_chain::pending_effects::{BalanceOperand, PendingEffects};
use crate::records::record_chain::wallet_tx_index::index_wallet_transaction;
use crate::rpc::commands::transaction_by_txid::request_transaction_by_txid;
use crate::rpc::responses::RpcResponse;
use crate::sled::Db;
@ -96,6 +97,13 @@ pub async fn process_collateral(
let txkey = decode(txhash).map_err(|e| format!("Error decoding hex: {e}"))?;
let txvalue = format!("{block_header_number}:{}", **index);
pending_effects.set_tree("txid", txkey, txvalue.into_bytes());
index_wallet_transaction(
pending_effects,
&[&transaction.unsigned_collateral_claim.address, &miner],
block_header_number,
**index as u32,
&txhash_bytes,
)?;
pending_effects.append_tree_if_key_exists(
"nfts",
"nft_history",

View File

@ -2,6 +2,7 @@ use crate::blocks::issue_token::IssueTokenTransaction;
use crate::decode;
use crate::records::memory::mempool::BASECOIN;
use crate::records::record_chain::pending_effects::{BalanceOperand, PendingEffects};
use crate::records::record_chain::wallet_tx_index::index_wallet_transaction;
use crate::sled::Db;
use crate::Arc;
use crate::Mutex;
@ -66,7 +67,14 @@ pub async fn process_issue_token(
// transaction back to its block and index position.
let txkey = txhash_bytes;
let txvalue = format!("{block_header_number}:{}", **index);
pending_effects.set_tree("txid", txkey, txvalue.into_bytes());
pending_effects.set_tree("txid", txkey.clone(), txvalue.into_bytes());
index_wallet_transaction(
pending_effects,
&[&transaction.unsigned_issue_token.creator, &miner],
block_header_number,
**index as u32,
&txkey,
)?;
Ok(binary_data)
}

View File

@ -2,6 +2,7 @@ use crate::blocks::loans::LoanContractTransaction;
use crate::decode;
use crate::records::memory::mempool::BASECOIN;
use crate::records::record_chain::pending_effects::{BalanceOperand, PendingEffects};
use crate::records::record_chain::wallet_tx_index::index_wallet_transaction;
use crate::sled::Db;
use crate::Arc;
use crate::Mutex;
@ -75,6 +76,17 @@ pub async fn process_lender(
let txkey = decode(&txhash).map_err(|e| format!("Error decoding hex: {e}"))?;
let txvalue = format!("{block_header_number}:{}", **index);
pending_effects.set_tree("txid", txkey, txvalue.into_bytes());
index_wallet_transaction(
pending_effects,
&[
&transaction.unsigned_loan_contract.lender,
&transaction.unsigned_loan_contract.borrower,
&miner,
],
block_header_number,
**index as u32,
&txhash_bytes,
)?;
let loankey = decode(&txhash).map_err(|e| format!("Error decoding hex: {e}"))?;
pending_effects.set_tree("loan", loankey, b"true".to_vec());
pending_effects.append_tree_if_key_exists(

View File

@ -2,6 +2,7 @@ use crate::blocks::marketing::MarketingTransaction;
use crate::decode;
use crate::records::memory::mempool::BASECOIN;
use crate::records::record_chain::pending_effects::{BalanceOperand, PendingEffects};
use crate::records::record_chain::wallet_tx_index::index_wallet_transaction;
use crate::sled::Db;
use crate::Arc;
use crate::Mutex;
@ -23,6 +24,8 @@ pub async fn process_marketing(
// Serialize the marketing transaction and compute its txid before
// applying the fee transfer side effects.
let txhash = transaction.unsigned_marketing.hash().await;
let txhash_bytes =
decode(&txhash).map_err(|e| format!("Error decoding marketing txhash: {e}"))?;
let transaction_bytes = match transaction.to_bytes().await {
Ok(bytes) => bytes,
Err(e) => return Err(e.to_string()),
@ -46,8 +49,15 @@ pub async fn process_marketing(
// Record the txid location so RPC lookups can resolve the saved
// transaction back to its block and index position.
let txkey = decode(txhash).map_err(|e| format!("Error decoding marketing txid key: {e}"))?;
let txkey = txhash_bytes.clone();
let txvalue = format!("{block_header_number}:{}", **index);
pending_effects.set_tree("txid", txkey, txvalue.into_bytes());
index_wallet_transaction(
pending_effects,
&[&transaction.unsigned_marketing.advertiser, &miner],
block_header_number,
**index as u32,
&txhash_bytes,
)?;
Ok(binary_data)
}

View File

@ -22,3 +22,4 @@ pub mod token_provenance;
pub mod token_tx;
pub mod transfer_tx;
pub mod vanity_tx;
pub mod wallet_tx_index;

View File

@ -3,6 +3,7 @@ use crate::common::nft_assets::nft_asset_name;
use crate::decode;
use crate::records::memory::mempool::BASECOIN;
use crate::records::record_chain::pending_effects::{BalanceOperand, PendingEffects};
use crate::records::record_chain::wallet_tx_index::index_wallet_transaction;
use crate::sled::Db;
use crate::Arc;
use crate::Mutex;
@ -97,6 +98,13 @@ pub async fn process_nft(
let txkey = decode(txhash).map_err(|e| format!("Error decoding nft txid key: {e}"))?;
let txvalue = format!("{block_header_number}:{}", **index);
pending_effects.set_tree("txid", txkey, txvalue.into_bytes());
index_wallet_transaction(
pending_effects,
&[&transaction.unsigned_create_nft.creator, &miner],
block_header_number,
**index as u32,
&txhash_bytes,
)?;
Ok(binary_data)
}

View File

@ -4,6 +4,7 @@ use crate::decode;
use crate::records::balance_sheet::operations::balance_sheet_operation_with_db;
use crate::records::memory::mempool::BASECOIN;
use crate::records::record_chain::pending_effects::PendingEffects;
use crate::records::record_chain::wallet_tx_index::index_wallet_transaction;
use crate::records::unpack_block::load_by_block_number::load_block;
use crate::sled::Db;
use crate::Arc;
@ -72,7 +73,7 @@ pub async fn process_rewards(
mut binary_data: Vec<u8>,
_db: &Db,
index_counter: Arc<Mutex<&mut usize>>,
_miner: String,
miner: String,
block_header_number: u32,
pending_effects: &mut PendingEffects,
) -> Result<Vec<u8>, String> {
@ -94,6 +95,13 @@ pub async fn process_rewards(
// block/index, but does not make the reward spendable yet.
let txkey = decode(txhash).map_err(|e| format!("Error decoding rewards txid key: {e}"))?;
let txvalue = format!("{block_header_number}:{}", **index);
pending_effects.set_tree("txid", txkey, txvalue.into_bytes());
pending_effects.set_tree("txid", txkey.clone(), txvalue.into_bytes());
index_wallet_transaction(
pending_effects,
&[&miner],
block_header_number,
**index as u32,
&txkey,
)?;
Ok(binary_data)
}

View File

@ -3,6 +3,7 @@ use crate::common::nft_assets::nft_asset_name;
use crate::decode;
use crate::records::memory::mempool::BASECOIN;
use crate::records::record_chain::pending_effects::{BalanceOperand, PendingEffects};
use crate::records::record_chain::wallet_tx_index::index_wallet_transaction;
use crate::sled::Db;
use crate::Arc;
use crate::Mutex;
@ -120,6 +121,17 @@ pub async fn process_swap(
let txkey = decode(txhash).map_err(|e| format!("Error decoding swap txid key: {e}"))?;
let txvalue = format!("{block_header_number}:{}", **index);
pending_effects.set_tree("txid", txkey, txvalue.into_bytes());
index_wallet_transaction(
pending_effects,
&[
&transaction.unsigned_swap.sender1,
&transaction.unsigned_swap.sender2,
&miner,
],
block_header_number,
**index as u32,
&txhash_bytes,
)?;
pending_effects.append_tree_if_key_exists(
"nfts",
"nft_history",

View File

@ -2,6 +2,7 @@ use crate::blocks::token::CreateTokenTransaction;
use crate::decode;
use crate::records::memory::mempool::BASECOIN;
use crate::records::record_chain::pending_effects::{BalanceOperand, PendingEffects};
use crate::records::record_chain::wallet_tx_index::index_wallet_transaction;
use crate::sled::Db;
use crate::Arc;
use crate::Mutex;
@ -77,6 +78,13 @@ pub async fn process_token(
// transaction back to its block and index position.
let txkey = txhash_bytes;
let txvalue = format!("{block_header_number}:{}", **index);
pending_effects.set_tree("txid", txkey, txvalue.into_bytes());
pending_effects.set_tree("txid", txkey.clone(), txvalue.into_bytes());
index_wallet_transaction(
pending_effects,
&[&transaction.unsigned_create_token.creator, &miner],
block_header_number,
**index as u32,
&txkey,
)?;
Ok(binary_data)
}

View File

@ -3,6 +3,7 @@ use crate::common::nft_assets::nft_asset_name;
use crate::decode;
use crate::records::memory::mempool::BASECOIN;
use crate::records::record_chain::pending_effects::{BalanceOperand, PendingEffects};
use crate::records::record_chain::wallet_tx_index::index_wallet_transaction;
use crate::sled::Db;
use crate::Arc;
use crate::Mutex;
@ -69,6 +70,17 @@ pub async fn process_transfer(
let txkey = decode(txhash).map_err(|e| format!("Error decoding transfer txid key: {e}"))?;
let txvalue = format!("{block_header_number}:{}", **index);
pending_effects.set_tree("txid", txkey, txvalue.into_bytes());
index_wallet_transaction(
pending_effects,
&[
&transaction.unsigned_transfer.sender,
&transaction.unsigned_transfer.receiver,
&miner,
],
block_header_number,
**index as u32,
&txhash_bytes,
)?;
pending_effects.append_tree_if_key_exists(
"nfts",
"nft_history",

View File

@ -2,6 +2,7 @@ use crate::blocks::vanity::VanityAddressTransaction;
use crate::decode;
use crate::records::memory::mempool::BASECOIN;
use crate::records::record_chain::pending_effects::{BalanceOperand, PendingEffects};
use crate::records::record_chain::wallet_tx_index::index_wallet_transaction;
use crate::sled::Db;
use crate::Arc;
use crate::Mutex;
@ -55,7 +56,14 @@ pub async fn process_vanity(
let txkey = decode(&txhash)
.map_err(|err| format!("Could not decode vanity transaction hash: {err}"))?;
let txvalue = format!("{block_header_number}:{}", **index);
pending_effects.set_tree("txid", txkey, txvalue.into_bytes());
pending_effects.set_tree("txid", txkey.clone(), txvalue.into_bytes());
index_wallet_transaction(
pending_effects,
&[owner_address, &miner],
block_header_number,
**index as u32,
&txkey,
)?;
Ok(binary_data)
}

View File

@ -0,0 +1,111 @@
use crate::records::record_chain::pending_effects::PendingEffects;
use crate::sled::Db;
use crate::wallets::structures::Wallet;
pub const WALLET_TX_INDEX_TREE: &str = "wallet_tx_index";
fn wallet_tx_index_key(
address: &str,
block_height: u32,
entry_index: u32,
) -> Result<Vec<u8>, String> {
let address_bytes = Wallet::short_address_to_bytes(address)
.ok_or_else(|| format!("Invalid wallet history address: {address}"))?;
let mut key = Vec::with_capacity(Wallet::SHORT_ADDRESS_BYTES_LENGTH + 8);
key.extend_from_slice(&address_bytes);
key.extend_from_slice(&block_height.to_be_bytes());
key.extend_from_slice(&entry_index.to_be_bytes());
Ok(key)
}
pub fn index_wallet_transaction(
pending_effects: &mut PendingEffects,
addresses: &[&str],
block_height: u32,
entry_index: u32,
txid: &[u8],
) -> Result<(), String> {
let mut indexed_addresses: Vec<Vec<u8>> = Vec::new();
for address in addresses {
let address_bytes = Wallet::short_address_to_bytes(address)
.ok_or_else(|| format!("Invalid wallet history address: {address}"))?;
if indexed_addresses
.iter()
.any(|stored| stored == &address_bytes)
{
continue;
}
indexed_addresses.push(address_bytes);
let key = wallet_tx_index_key(address, block_height, entry_index)?;
pending_effects.set_tree(WALLET_TX_INDEX_TREE, key, txid.to_vec());
}
Ok(())
}
fn txid_block_height(db: &Db, txid: &[u8]) -> Result<Option<u32>, String> {
let tree = db
.open_tree("txid")
.map_err(|err| format!("Failed to open txid tree: {err}"))?;
let Some(value) = tree
.get(txid)
.map_err(|err| format!("Failed to read txid tree: {err}"))?
else {
return Ok(None);
};
let value = String::from_utf8_lossy(&value);
let Some((block_height, _entry_index)) = value.split_once(':') else {
return Err("Invalid txid location value.".to_string());
};
block_height
.parse::<u32>()
.map(Some)
.map_err(|err| format!("Invalid txid block height: {err}"))
}
pub fn remove_wallet_transaction_index(
db: &Db,
addresses: &[&str],
txid: &[u8],
) -> Result<(), String> {
let Some(block_height) = txid_block_height(db, txid)? else {
return Ok(());
};
let tree = db
.open_tree(WALLET_TX_INDEX_TREE)
.map_err(|err| format!("Failed to open wallet transaction index: {err}"))?;
let mut indexed_addresses: Vec<Vec<u8>> = Vec::new();
for address in addresses {
let address_bytes = Wallet::short_address_to_bytes(address)
.ok_or_else(|| format!("Invalid wallet history address: {address}"))?;
if indexed_addresses
.iter()
.any(|stored| stored == &address_bytes)
{
continue;
}
indexed_addresses.push(address_bytes.clone());
let mut prefix = Vec::with_capacity(Wallet::SHORT_ADDRESS_BYTES_LENGTH + 4);
prefix.extend_from_slice(&address_bytes);
prefix.extend_from_slice(&block_height.to_be_bytes());
let keys = tree
.scan_prefix(prefix)
.filter_map(|entry| match entry {
Ok((key, value)) if value.as_ref() == txid => Some(key.to_vec()),
_ => None,
})
.collect::<Vec<_>>();
for key in keys {
tree.remove(key)
.map_err(|err| format!("Failed to remove wallet transaction index: {err}"))?;
}
}
Ok(())
}

View File

@ -36,9 +36,9 @@ use crate::rpc::responses::RpcResponse;
use crate::rpc::server::connection_memory_manager::remove_key_from_memory;
use crate::rpc::server::rpc_command_loop::start_loop;
use crate::sled::Db;
use crate::sleep;
use crate::startup::network_broadcast::announce_self_to_network;
use crate::startup::remote_height::request_remote_height;
use crate::sleep;
use crate::timeout;
use crate::wallets::structures::Wallet;
use crate::Arc;

View File

@ -65,9 +65,9 @@ pub async fn register_connected_wallet(
let response_text = String::from_utf8_lossy(&response);
match response_text.trim() {
"1" => match register_short_address(db, &short_address_bytes, &public_key_bytes) {
Ok(WalletRegistrationResult::Inserted | WalletRegistrationResult::AlreadyRegistered) => {
Ok(())
}
Ok(
WalletRegistrationResult::Inserted | WalletRegistrationResult::AlreadyRegistered,
) => Ok(()),
Ok(WalletRegistrationResult::Conflict) => {
Err("Local wallet registry conflicts with startup wallet".to_string())
}

View File

@ -54,7 +54,10 @@ pub const RPC_WALLET_REGISTRY_SYNC: u8 = 39;
pub const RPC_VANITY_LOOKUP: u8 = 40;
pub const RPC_TORRENT_CANDIDATES: u8 = 41;
pub const RPC_BLOCK_HASH_AT_HEIGHT: u8 = 42;
pub const RPC_WALLET_REGISTRATION_STATUS: u8 = 43;
pub const RPC_ADDRESS_HISTORY: u8 = 44;
pub const RPC_VANITY_OWNER_LOOKUP: u8 = 45;
pub const RPC_LATEST_ADDRESS_HISTORY: u8 = 46;
pub const RPC_REPLY: u8 = 255;
pub const MAX_RPC_REPLY_BYTES: usize = 64 * 1024 * 1024;

View File

@ -48,8 +48,8 @@ pub async fn add_network_node(
read_bytes_from_stream::read_signature_from_stream(connections_key, stream_locked.clone())
.await?;
let monitor_count =
read_bytes_from_stream::read_u16_from_stream(connections_key, stream_locked.clone())
.await? as usize;
read_bytes_from_stream::read_u16_from_stream(connections_key, stream_locked.clone()).await?
as usize;
let mut monitors = Vec::with_capacity(monitor_count);
for _ in 0..monitor_count {
let monitor_bytes = read_bytes_from_stream::read_short_address_from_stream(

View File

@ -0,0 +1,81 @@
use crate::records::record_chain::wallet_tx_index::WALLET_TX_INDEX_TREE;
use crate::rpc::responses::RpcResponse;
use crate::sled::Db;
use crate::wallets::structures::Wallet;
use std::ops::Bound;
const TXID_LENGTH: usize = 32;
const MAX_ADDRESS_HISTORY_TXIDS: usize = 10_000;
fn prefix_successor(prefix: &[u8]) -> Option<Vec<u8>> {
let mut next = prefix.to_vec();
for index in (0..next.len()).rev() {
if next[index] != u8::MAX {
next[index] += 1;
next.truncate(index + 1);
return Some(next);
}
}
None
}
pub async fn lookup(address_bytes: Vec<u8>, skip: u32, limit: u32, db: &Db) -> RpcResponse {
if address_bytes.len() != Wallet::SHORT_ADDRESS_BYTES_LENGTH {
return RpcResponse::Binary(b"error: Invalid wallet address bytes".to_vec());
}
let limit = (limit as usize).min(MAX_ADDRESS_HISTORY_TXIDS);
if limit == 0 {
return RpcResponse::Binary(Vec::new());
}
let tree = match db.open_tree(WALLET_TX_INDEX_TREE) {
Ok(tree) => tree,
Err(err) => {
return RpcResponse::Binary(
format!("error: Failed to open wallet transaction index: {err}").into_bytes(),
);
}
};
let start = Bound::Included(address_bytes.clone());
let end = prefix_successor(&address_bytes)
.map(Bound::Excluded)
.unwrap_or(Bound::Unbounded);
let mut skipped = 0usize;
let mut found = 0usize;
let mut txids = Vec::with_capacity(limit * TXID_LENGTH);
for entry in tree.range((start, end)).rev() {
let (_key, value) = match entry {
Ok(entry) => entry,
Err(err) => {
return RpcResponse::Binary(
format!("error: Failed to read wallet transaction index: {err}").into_bytes(),
);
}
};
if value.len() != TXID_LENGTH {
continue;
}
if skipped < skip as usize {
skipped += 1;
continue;
}
txids.extend_from_slice(&value);
found += 1;
if found >= limit {
break;
}
}
RpcResponse::Binary(txids)
}
pub async fn latest(address_bytes: Vec<u8>, limit: u32, db: &Db) -> RpcResponse {
lookup(address_bytes, 0, limit, db).await
}

View File

@ -2,6 +2,7 @@
pub mod add_network_node;
pub mod address_coin_lookup;
pub mod address_complete_balance_sheet;
pub mod address_history;
pub mod bad_rpc_call;
pub mod block_by_hash;
pub mod block_by_height;
@ -41,6 +42,7 @@ pub mod validate_address;
pub mod validate_message;
pub mod validate_torrent;
pub mod wallet_register;
pub mod wallet_registration_status;
pub mod wallet_registry_sync;
pub mod wallet_vanity_lookup;
pub mod wallet_vanity_owner_lookup;

View File

@ -1,6 +1,6 @@
use crate::records::block_height::get_block_height::get_height;
use crate::records::memory::connections::CONNECTIONS;
use crate::records::memory::network_mapping::NodeInfo;
use crate::records::block_height::get_block_height::get_height;
use crate::rpc::responses::RpcResponse;
use crate::sled::Db;

View File

@ -15,9 +15,7 @@ use crate::common::types::{
};
use crate::records::memory::connections::get_client_type_from_memory;
use crate::records::memory::enums::ClientType;
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::responses::RpcResponse;
use crate::sled::Db;

View File

@ -0,0 +1,18 @@
use crate::records::wallet_registry::short_address_exists;
use crate::rpc::responses::RpcResponse;
use crate::sled::Db;
use crate::wallets::structures::Wallet;
pub async fn lookup(short_address_bytes: Vec<u8>, db: &Db) -> RpcResponse {
if short_address_bytes.len() != Wallet::SHORT_ADDRESS_BYTES_LENGTH {
return RpcResponse::Binary(b"0".to_vec());
}
match short_address_exists(db, &short_address_bytes) {
Ok(true) => RpcResponse::Binary(b"1".to_vec()),
Ok(false) => RpcResponse::Binary(b"0".to_vec()),
Err(err) => RpcResponse::Binary(
format!("error: Failed to lookup wallet registration status: {err}").into_bytes(),
),
}
}

View File

@ -817,6 +817,53 @@ pub async fn start_loop(
.send(&stream_locked, Some(&connections_key), uid)
.await;
}
43 => {
// request whether a canonical short wallet address is registered
let (uid, _) = read_bytes_from_stream::read_uid_from_stream(
&connections_key,
stream_locked.clone(),
)
.await?;
let short_address = read_bytes_from_stream::read_short_address_from_stream(
&connections_key,
stream_locked.clone(),
)
.await?;
let result = commands::wallet_registration_status::lookup(short_address, &db).await;
result
.send(&stream_locked, Some(&connections_key), uid)
.await;
}
44 => {
// request confirmed transaction ids indexed to a wallet address
let (uid, _) = read_bytes_from_stream::read_uid_from_stream(
&connections_key,
stream_locked.clone(),
)
.await?;
let short_address = read_bytes_from_stream::read_short_address_from_stream(
&connections_key,
stream_locked.clone(),
)
.await?;
let skip = read_bytes_from_stream::read_u32_from_stream(
&connections_key,
stream_locked.clone(),
)
.await?;
let limit = read_bytes_from_stream::read_u32_from_stream(
&connections_key,
stream_locked.clone(),
)
.await?;
let result =
commands::address_history::lookup(short_address, skip, limit, &db).await;
result
.send(&stream_locked, Some(&connections_key), uid)
.await;
}
45 => {
// request the canonical short address that owns a registered vanity address
let (uid, _) = read_bytes_from_stream::read_uid_from_stream(
@ -850,6 +897,29 @@ pub async fn start_loop(
.send(&stream_locked, Some(&connections_key), uid)
.await;
}
46 => {
// request the latest confirmed transaction ids for a wallet address
let (uid, _) = read_bytes_from_stream::read_uid_from_stream(
&connections_key,
stream_locked.clone(),
)
.await?;
let short_address = read_bytes_from_stream::read_short_address_from_stream(
&connections_key,
stream_locked.clone(),
)
.await?;
let limit = read_bytes_from_stream::read_u32_from_stream(
&connections_key,
stream_locked.clone(),
)
.await?;
let result = commands::address_history::latest(short_address, limit, &db).await;
result
.send(&stream_locked, Some(&connections_key), uid)
.await;
}
255 => {
commands::route_reply::route_reply(
&connections_key,

View File

@ -3,12 +3,13 @@ use crate::decode;
use crate::io;
use crate::records::memory::response_channels::Byte3;
use crate::rpc::command_maps::{
MAX_RPC_REPLY_BYTES, RPC_ADDRESS_TOTAL_BALANCE, RPC_BLOCK_BY_HASH, RPC_BLOCK_BY_HEIGHT,
RPC_BLOCK_HEIGHT, RPC_BLOCK_IP, RPC_CONTRACT_BY_ADDRESS, RPC_DIFFICULTY, RPC_LARGEST_TX_FEE,
RPC_LOAN_CONTRACT, RPC_MEMPOOL_TX_BY_ADDRESS, RPC_MEMPOOL_TX_BY_SIGNATURE,
RPC_MEMPOOL_TX_COUNT, RPC_NETWORK_INFO, RPC_NFT_DETAILS, RPC_NFT_LIST, RPC_REGISTER_WALLET,
RPC_TIME, RPC_TOKEN_DETAILS, RPC_TOKEN_LIST, RPC_TORRENT_BY_HEIGHT, RPC_TOTAL_CONFIRMED_TX,
RPC_TRANSACTION_BY_TXID, RPC_UNBLOCK_IP, RPC_VANITY_LOOKUP, RPC_VANITY_OWNER_LOOKUP,
MAX_RPC_REPLY_BYTES, RPC_ADDRESS_HISTORY, RPC_ADDRESS_TOTAL_BALANCE, RPC_BLOCK_BY_HASH,
RPC_BLOCK_BY_HEIGHT, RPC_BLOCK_HEIGHT, RPC_BLOCK_IP, RPC_CONTRACT_BY_ADDRESS, RPC_DIFFICULTY,
RPC_LARGEST_TX_FEE, RPC_LATEST_ADDRESS_HISTORY, RPC_LOAN_CONTRACT, RPC_MEMPOOL_TX_BY_ADDRESS,
RPC_MEMPOOL_TX_BY_SIGNATURE, RPC_MEMPOOL_TX_COUNT, RPC_NETWORK_INFO, RPC_NFT_DETAILS,
RPC_NFT_LIST, RPC_REGISTER_WALLET, RPC_TIME, RPC_TOKEN_DETAILS, RPC_TOKEN_LIST,
RPC_TORRENT_BY_HEIGHT, RPC_TOTAL_CONFIRMED_TX, RPC_TRANSACTION_BY_TXID, RPC_UNBLOCK_IP,
RPC_VANITY_LOOKUP, RPC_VANITY_OWNER_LOOKUP, RPC_WALLET_REGISTRATION_STATUS,
};
use crate::standalone_tools::transaction_creator::create_transaction_request;
use crate::timeout;
@ -461,6 +462,51 @@ async fn build_request_bytes(
bin_msg.extend_from_slice(&address_bytes);
}
// Lookup canonical short owner address by registered vanity address.
43 => {
let command_number: u8 = RPC_WALLET_REGISTRATION_STATUS;
let address_bytes = Wallet::normalize_to_short_address(&command_input)
.and_then(|short| Wallet::short_address_to_bytes(&short))
.ok_or_else(|| {
io::Error::new(io::ErrorKind::InvalidInput, "Invalid wallet address")
})?;
bin_msg.extend_from_slice(&command_number.to_le_bytes());
bin_msg.extend_from_slice(&hashmap_key);
bin_msg.extend_from_slice(&address_bytes);
}
// Lookup canonical short owner address by registered vanity address.
44 => {
let command_number: u8 = RPC_ADDRESS_HISTORY;
let (address, rest) = command_input.split_once('|').ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"Address history input must be address|skip|limit",
)
})?;
let (skip, limit) = rest.split_once('|').ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"Address history input must be address|skip|limit",
)
})?;
let address_bytes = Wallet::normalize_to_short_address(address)
.and_then(|short| Wallet::short_address_to_bytes(&short))
.ok_or_else(|| {
io::Error::new(io::ErrorKind::InvalidInput, "Invalid wallet address")
})?;
let skip = skip
.parse::<u32>()
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "Invalid history skip"))?;
let limit = limit.parse::<u32>().map_err(|_| {
io::Error::new(io::ErrorKind::InvalidInput, "Invalid history limit")
})?;
bin_msg.extend_from_slice(&command_number.to_le_bytes());
bin_msg.extend_from_slice(&hashmap_key);
bin_msg.extend_from_slice(&address_bytes);
bin_msg.extend_from_slice(&skip.to_le_bytes());
bin_msg.extend_from_slice(&limit.to_le_bytes());
}
// Lookup canonical short owner address by registered vanity address.
45 => {
let command_number: u8 = RPC_VANITY_OWNER_LOOKUP;
let address_bytes = Wallet::normalize_to_short_address(&command_input)
@ -472,6 +518,29 @@ async fn build_request_bytes(
bin_msg.extend_from_slice(&hashmap_key);
bin_msg.extend_from_slice(&address_bytes);
}
// Lookup newest confirmed transaction ids tied to an address.
46 => {
let command_number: u8 = RPC_LATEST_ADDRESS_HISTORY;
let (address, limit) = command_input.split_once('|').ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"Latest address history input must be address|limit",
)
})?;
let address_bytes = Wallet::normalize_to_short_address(address)
.and_then(|short| Wallet::short_address_to_bytes(&short))
.ok_or_else(|| {
io::Error::new(io::ErrorKind::InvalidInput, "Invalid wallet address")
})?;
let limit = limit.parse::<u32>().map_err(|_| {
io::Error::new(io::ErrorKind::InvalidInput, "Invalid history limit")
})?;
bin_msg.extend_from_slice(&command_number.to_le_bytes());
bin_msg.extend_from_slice(&hashmap_key);
bin_msg.extend_from_slice(&address_bytes);
bin_msg.extend_from_slice(&limit.to_le_bytes());
}
_ => {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,

View File

@ -1,11 +1,10 @@
use crate::common::binary_conversions::{binary_to_ip, binary_to_string, ip_to_binary};
use crate::log::warn;
use crate::common::network_startup::get_ip_and_port;
use crate::log::warn;
use crate::records::memory::network_mapping::structs::{
SignedNodeEdit, NODE_ADDED_BY_OFFSET, NODE_ADDED_SIGNATURE_OFFSET,
NODE_ADDED_TIMESTAMP_OFFSET, NODE_BLOCKS_MINED_OFFSET, NODE_DELETED_BLOCK_OFFSET,
NODE_DELETED_TIMESTAMP_OFFSET, NODE_IP_OFFSET, NODE_MONITOR_COUNT_OFFSET,
NODE_RECORD_FIXED_BYTES,
SignedNodeEdit, NODE_ADDED_BY_OFFSET, NODE_ADDED_SIGNATURE_OFFSET, NODE_ADDED_TIMESTAMP_OFFSET,
NODE_BLOCKS_MINED_OFFSET, NODE_DELETED_BLOCK_OFFSET, NODE_DELETED_TIMESTAMP_OFFSET,
NODE_IP_OFFSET, NODE_MONITOR_COUNT_OFFSET, NODE_RECORD_FIXED_BYTES,
};
use crate::records::memory::network_mapping::NodeInfo;
use crate::records::memory::response_channels::{reserve_entry, Command};

View File

@ -13,9 +13,12 @@ pub async fn request_remote_height(
) -> Result<u32, String> {
// request the remote node's current chain height using
// the standard reply-channel request/response flow
let (hashmap_key, _tx, rx) =
reserve_entry_with_context(map.clone(), Some(RPC_BLOCK_HEIGHT), Some(connections_key.clone()))
.await;
let (hashmap_key, _tx, rx) = reserve_entry_with_context(
map.clone(),
Some(RPC_BLOCK_HEIGHT),
Some(connections_key.clone()),
)
.await;
// message format is the height command plus the unique
// reply key used to route the response back here