standalone tools fix for command 47
This commit is contained in:
parent
9cc17ac0b5
commit
7e99a98643
|
|
@ -57,6 +57,7 @@ pub const RPC_WALLET_REGISTRATION_STATUS: u8 = 43;
|
||||||
pub const RPC_ADDRESS_HISTORY: u8 = 44;
|
pub const RPC_ADDRESS_HISTORY: u8 = 44;
|
||||||
pub const RPC_VANITY_OWNER_LOOKUP: u8 = 45;
|
pub const RPC_VANITY_OWNER_LOOKUP: u8 = 45;
|
||||||
pub const RPC_LATEST_ADDRESS_HISTORY: u8 = 46;
|
pub const RPC_LATEST_ADDRESS_HISTORY: u8 = 46;
|
||||||
|
pub const RPC_LATEST_ADDRESS_TRANSACTIONS: u8 = 47;
|
||||||
pub const RPC_REPLY: u8 = 255;
|
pub const RPC_REPLY: u8 = 255;
|
||||||
pub const MAX_RPC_REPLY_BYTES: usize = 64 * 1024 * 1024;
|
pub const MAX_RPC_REPLY_BYTES: usize = 64 * 1024 * 1024;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::records::memory::mempool::latest_pending_txids_by_address;
|
use crate::records::memory::mempool::latest_pending_txids_by_address;
|
||||||
use crate::records::record_chain::wallet_tx_index::WALLET_TX_INDEX_TREE;
|
use crate::records::record_chain::wallet_tx_index::WALLET_TX_INDEX_TREE;
|
||||||
|
use crate::rpc::commands::transaction_by_txid::transaction_bytes_with_block;
|
||||||
use crate::rpc::responses::RpcResponse;
|
use crate::rpc::responses::RpcResponse;
|
||||||
use crate::sled::Db;
|
use crate::sled::Db;
|
||||||
use crate::wallets::structures::Wallet;
|
use crate::wallets::structures::Wallet;
|
||||||
|
|
@ -151,3 +152,36 @@ pub async fn latest(address_bytes: Vec<u8>, limit: u32, db: &Db) -> RpcResponse
|
||||||
|
|
||||||
RpcResponse::Binary(txids)
|
RpcResponse::Binary(txids)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn latest_transactions(address_bytes: Vec<u8>, limit: u32, db: &Db) -> RpcResponse {
|
||||||
|
let RpcResponse::Binary(txid_bytes) = latest(address_bytes, limit, db).await;
|
||||||
|
if txid_bytes.starts_with(b"error:") {
|
||||||
|
return RpcResponse::Binary(txid_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut entries = Vec::new();
|
||||||
|
for txid in txid_bytes.chunks_exact(TXID_LENGTH) {
|
||||||
|
match transaction_bytes_with_block(db, txid).await {
|
||||||
|
Ok((block_height, transaction_bytes)) => {
|
||||||
|
entries.push((txid.to_vec(), block_height, transaction_bytes));
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
return RpcResponse::Binary(err.into_bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut response = Vec::new();
|
||||||
|
response.extend_from_slice(&(entries.len() as u32).to_le_bytes());
|
||||||
|
for (txid, block_height, transaction_bytes) in entries {
|
||||||
|
let Ok(tx_len) = u32::try_from(transaction_bytes.len()) else {
|
||||||
|
return RpcResponse::Binary(b"error: Transaction payload too large".to_vec());
|
||||||
|
};
|
||||||
|
response.extend_from_slice(&txid);
|
||||||
|
response.extend_from_slice(&block_height.to_le_bytes());
|
||||||
|
response.extend_from_slice(&tx_len.to_le_bytes());
|
||||||
|
response.extend_from_slice(&transaction_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
RpcResponse::Binary(response)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ const HEADER_SIZE: u64 = VRF_BLOCK_BYTES as u64;
|
||||||
pub async fn request_transaction_by_txid(db: &Db, txid: Vec<u8>) -> RpcResponse {
|
pub async fn request_transaction_by_txid(db: &Db, txid: Vec<u8>) -> RpcResponse {
|
||||||
// Resolve the saved transaction bytes directly from the txid lookup
|
// Resolve the saved transaction bytes directly from the txid lookup
|
||||||
// tree and the referenced block file.
|
// tree and the referenced block file.
|
||||||
match lookup_transaction_location(db, txid).await {
|
match lookup_transaction_location(db, &txid).await {
|
||||||
Ok((_block, _position, block_filename)) => {
|
Ok((_block, _position, block_filename)) => {
|
||||||
let bytes = calculate_offset(&block_filename, _position).await;
|
let bytes = calculate_offset(&block_filename, _position).await;
|
||||||
match bytes {
|
match bytes {
|
||||||
|
|
@ -33,36 +33,37 @@ pub async fn request_transaction_by_txid(db: &Db, txid: Vec<u8>) -> RpcResponse
|
||||||
pub async fn request_transaction_by_txid_with_block(db: &Db, txid: Vec<u8>) -> RpcResponse {
|
pub async fn request_transaction_by_txid_with_block(db: &Db, txid: Vec<u8>) -> RpcResponse {
|
||||||
// Some callers need the block number alongside the raw transaction
|
// Some callers need the block number alongside the raw transaction
|
||||||
// bytes, so this variant prefixes the payload with the block height.
|
// bytes, so this variant prefixes the payload with the block height.
|
||||||
match lookup_transaction_location(db, txid.clone()).await {
|
match transaction_bytes_with_block(db, &txid).await {
|
||||||
|
Ok((block, vec)) => {
|
||||||
|
let mut response = Vec::with_capacity(4 + vec.len());
|
||||||
|
response.extend_from_slice(&block.to_le_bytes());
|
||||||
|
response.extend_from_slice(&vec);
|
||||||
|
RpcResponse::Binary(response)
|
||||||
|
}
|
||||||
|
Err(msg) => RpcResponse::Binary(msg.into_bytes()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn transaction_bytes_with_block(db: &Db, txid: &[u8]) -> Result<(u32, Vec<u8>), String> {
|
||||||
|
match lookup_transaction_location(db, txid).await {
|
||||||
Ok((block, position, block_filename)) => {
|
Ok((block, position, block_filename)) => {
|
||||||
let bytes = calculate_offset(&block_filename, position).await;
|
let bytes = calculate_offset(&block_filename, position).await;
|
||||||
match bytes {
|
match bytes {
|
||||||
Some(vec) => {
|
Some(vec) => Ok((block as u32, vec)),
|
||||||
let mut response = Vec::with_capacity(4 + vec.len());
|
None => Err("error: Error parsing block".to_string()),
|
||||||
response.extend_from_slice(&(block as u32).to_le_bytes());
|
|
||||||
response.extend_from_slice(&vec);
|
|
||||||
RpcResponse::Binary(response)
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let msg = "error: Error parsing block".to_string().as_bytes().to_vec();
|
|
||||||
RpcResponse::Binary(msg)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
if let Some(bytes) = pending_transaction_by_txid(&txid).await {
|
if let Some(bytes) = pending_transaction_by_txid(txid).await {
|
||||||
let mut response = Vec::with_capacity(4 + bytes.len());
|
Ok((0, bytes))
|
||||||
response.extend_from_slice(&0u32.to_le_bytes());
|
|
||||||
response.extend_from_slice(&bytes);
|
|
||||||
RpcResponse::Binary(response)
|
|
||||||
} else {
|
} else {
|
||||||
RpcResponse::Binary(msg.into_bytes())
|
Err(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn lookup_transaction_location(db: &Db, txid: Vec<u8>) -> Result<(u64, u32, String), String> {
|
async fn lookup_transaction_location(db: &Db, txid: &[u8]) -> Result<(u64, u32, String), String> {
|
||||||
// The txid tree stores `block:index`, which is enough to locate the
|
// The txid tree stores `block:index`, which is enough to locate the
|
||||||
// transaction inside the saved block file on disk.
|
// transaction inside the saved block file on disk.
|
||||||
let tree = db.open_tree("txid").unwrap();
|
let tree = db.open_tree("txid").unwrap();
|
||||||
|
|
|
||||||
|
|
@ -906,6 +906,30 @@ pub async fn start_loop(
|
||||||
.send(&stream_locked, Some(&connections_key), uid)
|
.send(&stream_locked, Some(&connections_key), uid)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
47 => {
|
||||||
|
// request latest transaction records for a wallet address in one response
|
||||||
|
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_transactions(short_address, limit, &db).await;
|
||||||
|
result
|
||||||
|
.send(&stream_locked, Some(&connections_key), uid)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
255 => {
|
255 => {
|
||||||
commands::route_reply::route_reply(
|
commands::route_reply::route_reply(
|
||||||
&connections_key,
|
&connections_key,
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ use crate::records::memory::response_channels::Byte3;
|
||||||
use crate::rpc::command_maps::{
|
use crate::rpc::command_maps::{
|
||||||
MAX_RPC_REPLY_BYTES, RPC_ADDRESS_HISTORY, RPC_ADDRESS_TOTAL_BALANCE, RPC_BLOCK_BY_HASH,
|
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_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_LARGEST_TX_FEE, RPC_LATEST_ADDRESS_HISTORY, RPC_LATEST_ADDRESS_TRANSACTIONS, RPC_LOAN_CONTRACT,
|
||||||
RPC_MEMPOOL_TX_BY_SIGNATURE, RPC_MEMPOOL_TX_COUNT, RPC_NETWORK_INFO, RPC_NFT_DETAILS,
|
RPC_MEMPOOL_TX_BY_ADDRESS, RPC_MEMPOOL_TX_BY_SIGNATURE, RPC_MEMPOOL_TX_COUNT, RPC_NETWORK_INFO,
|
||||||
RPC_NFT_LIST, RPC_REGISTER_WALLET, RPC_TIME, RPC_TOKEN_DETAILS, RPC_TOKEN_LIST,
|
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_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,
|
RPC_VANITY_LOOKUP, RPC_VANITY_OWNER_LOOKUP, RPC_WALLET_REGISTRATION_STATUS,
|
||||||
};
|
};
|
||||||
|
|
@ -541,6 +541,22 @@ async fn build_request_bytes(
|
||||||
bin_msg.extend_from_slice(&address_bytes);
|
bin_msg.extend_from_slice(&address_bytes);
|
||||||
bin_msg.extend_from_slice(&limit.to_le_bytes());
|
bin_msg.extend_from_slice(&limit.to_le_bytes());
|
||||||
}
|
}
|
||||||
|
47 => {
|
||||||
|
// NEW: latest address transaction bytes (RPC_LATEST_ADDRESS_TRANSACTIONS)
|
||||||
|
let command_number: u8 = RPC_LATEST_ADDRESS_TRANSACTIONS;
|
||||||
|
let (address, limit) = command_input.split_once('|')
|
||||||
|
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput,
|
||||||
|
"Latest address transactions input must be address|limit"))?;
|
||||||
|
let address_bytes = Wallet::normalize_to_short_address(address)
|
||||||
|
.and_then(|s| Wallet::short_address_to_bytes(&s))
|
||||||
|
.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(
|
return Err(io::Error::new(
|
||||||
io::ErrorKind::InvalidInput,
|
io::ErrorKind::InvalidInput,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue