mirror of
https://github.com/hinto-janai/cuprate.git
synced 2024-12-22 11:39:30 +00:00
/get_transactions
This commit is contained in:
parent
b402c82557
commit
c3bc9b26ec
12 changed files with 401 additions and 182 deletions
|
@ -1,18 +1,19 @@
|
|||
//! RPC request handler functions (other JSON endpoints).
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||
|
||||
use anyhow::{anyhow, Error};
|
||||
|
||||
use cuprate_constants::rpc::{
|
||||
MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT, RESTRICTED_SPENT_KEY_IMAGES_COUNT,
|
||||
RESTRICTED_TRANSACTIONS_COUNT,
|
||||
};
|
||||
use cuprate_helper::cast::usize_to_u64;
|
||||
use cuprate_hex::Hex;
|
||||
use cuprate_rpc_interface::RpcHandler;
|
||||
use cuprate_rpc_types::{
|
||||
base::{AccessResponseBase, ResponseBase},
|
||||
misc::{KeyImageSpentStatus, Status},
|
||||
misc::{KeyImageSpentStatus, Status, TxEntry, TxEntryType},
|
||||
other::{
|
||||
GetAltBlocksHashesRequest, GetAltBlocksHashesResponse, GetHeightRequest, GetHeightResponse,
|
||||
GetLimitRequest, GetLimitResponse, GetNetStatsRequest, GetNetStatsResponse, GetOutsRequest,
|
||||
|
@ -31,15 +32,20 @@ use cuprate_rpc_types::{
|
|||
UpdateRequest, UpdateResponse,
|
||||
},
|
||||
};
|
||||
use cuprate_types::rpc::OutKey;
|
||||
use cuprate_types::{
|
||||
rpc::{OutKey, PoolInfo, PoolTxInfo},
|
||||
TxInPool,
|
||||
};
|
||||
use monero_serai::transaction::Transaction;
|
||||
|
||||
use crate::{
|
||||
rpc::CupratedRpcHandler,
|
||||
rpc::{helper, request::blockchain},
|
||||
rpc::{
|
||||
helper,
|
||||
request::{blockchain, blockchain_context, blockchain_manager, txpool},
|
||||
},
|
||||
};
|
||||
|
||||
use super::request::blockchain_manager;
|
||||
|
||||
/// Map a [`OtherRequest`] to the function that will lead to a [`OtherResponse`].
|
||||
pub(super) async fn map_request(
|
||||
state: CupratedRpcHandler,
|
||||
|
@ -112,12 +118,131 @@ async fn get_height(
|
|||
|
||||
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L979-L1227>
|
||||
async fn get_transactions(
|
||||
state: CupratedRpcHandler,
|
||||
mut state: CupratedRpcHandler,
|
||||
request: GetTransactionsRequest,
|
||||
) -> Result<GetTransactionsResponse, Error> {
|
||||
if state.is_restricted() && request.txs_hashes.len() > RESTRICTED_TRANSACTIONS_COUNT {
|
||||
return Err(anyhow!(
|
||||
"Too many transactions requested in restricted mode"
|
||||
));
|
||||
}
|
||||
|
||||
let requested_txs = request.txs_hashes.into_iter().map(|tx| tx.0).collect();
|
||||
|
||||
let (txs_in_blockchain, missed_txs) =
|
||||
blockchain::transactions(&mut state.blockchain_read, requested_txs).await?;
|
||||
|
||||
let missed_tx = missed_txs.clone().into_iter().map(Hex).collect();
|
||||
|
||||
// Check the txpool for missed transactions.
|
||||
let txs_in_pool = if missed_txs.is_empty() {
|
||||
vec![]
|
||||
} else {
|
||||
let include_sensitive_txs = !state.is_restricted();
|
||||
txpool::txs_by_hash(&mut state.txpool_read, missed_txs, include_sensitive_txs).await?
|
||||
};
|
||||
|
||||
let (txs, txs_as_json) = {
|
||||
// Prepare the final JSON output.
|
||||
let len = txs_in_blockchain.len() + txs_in_pool.len();
|
||||
let mut txs = Vec::with_capacity(len);
|
||||
let mut txs_as_json = Vec::with_capacity(if request.decode_as_json { len } else { 0 });
|
||||
|
||||
// Map all blockchain transactions.
|
||||
for tx in txs_in_blockchain {
|
||||
let tx_hash = Hex(tx.tx_hash);
|
||||
let pruned_as_hex = hex::encode(tx.pruned_blob);
|
||||
let prunable_as_hex = hex::encode(tx.prunable_blob);
|
||||
let prunable_hash = Hex(tx.prunable_hash);
|
||||
|
||||
let as_json = if request.decode_as_json {
|
||||
let tx = Transaction::read(&mut tx.tx_blob.as_slice())?;
|
||||
let json_type = cuprate_types::json::tx::Transaction::from(tx);
|
||||
let json = serde_json::to_string(&json_type).unwrap();
|
||||
txs_as_json.push(json.clone());
|
||||
json
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
let tx_entry_type = TxEntryType::Blockchain {
|
||||
block_height: tx.block_height,
|
||||
block_timestamp: tx.block_timestamp,
|
||||
confirmations: tx.confirmations,
|
||||
output_indices: tx.output_indices,
|
||||
in_pool: false,
|
||||
};
|
||||
|
||||
let tx = TxEntry {
|
||||
as_hex: String::new(),
|
||||
as_json,
|
||||
double_spend_seen: false,
|
||||
tx_hash,
|
||||
prunable_as_hex,
|
||||
prunable_hash,
|
||||
pruned_as_hex,
|
||||
tx_entry_type,
|
||||
};
|
||||
|
||||
txs.push(tx);
|
||||
}
|
||||
|
||||
// Map all txpool transactions.
|
||||
for tx_in_pool in txs_in_pool {
|
||||
let TxInPool {
|
||||
tx_blob,
|
||||
tx_hash,
|
||||
double_spend_seen,
|
||||
received_timestamp,
|
||||
relayed,
|
||||
} = tx_in_pool;
|
||||
|
||||
let tx_hash = Hex(tx_hash);
|
||||
let tx = Transaction::read(&mut tx_blob.as_slice())?;
|
||||
|
||||
// TODO: pruned data.
|
||||
let pruned_as_hex = String::new();
|
||||
let prunable_as_hex = String::new();
|
||||
let prunable_hash = Hex([0; 32]);
|
||||
|
||||
let as_json = if request.decode_as_json {
|
||||
let json_type = cuprate_types::json::tx::Transaction::from(tx);
|
||||
let json = serde_json::to_string(&json_type).unwrap();
|
||||
txs_as_json.push(json.clone());
|
||||
json
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
let tx_entry_type = TxEntryType::Pool {
|
||||
relayed,
|
||||
received_timestamp,
|
||||
in_pool: true,
|
||||
};
|
||||
|
||||
let tx = TxEntry {
|
||||
as_hex: String::new(),
|
||||
as_json,
|
||||
double_spend_seen,
|
||||
tx_hash,
|
||||
prunable_as_hex,
|
||||
prunable_hash,
|
||||
pruned_as_hex,
|
||||
tx_entry_type,
|
||||
};
|
||||
|
||||
txs.push(tx);
|
||||
}
|
||||
|
||||
(txs, txs_as_json)
|
||||
};
|
||||
|
||||
Ok(GetTransactionsResponse {
|
||||
base: AccessResponseBase::OK,
|
||||
..todo!()
|
||||
txs_as_hex: vec![],
|
||||
txs_as_json,
|
||||
missed_tx,
|
||||
txs,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! Functions to send [`BlockchainReadRequest`]s.
|
||||
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
collections::{BTreeSet, HashMap, HashSet},
|
||||
ops::Range,
|
||||
};
|
||||
|
||||
|
@ -14,7 +14,7 @@ use cuprate_helper::cast::{u64_to_usize, usize_to_u64};
|
|||
use cuprate_types::{
|
||||
blockchain::{BlockchainReadRequest, BlockchainResponse},
|
||||
rpc::{ChainInfo, CoinbaseTxSum, OutputHistogramEntry, OutputHistogramInput},
|
||||
Chain, ExtendedBlockHeader, OutputOnChain,
|
||||
Chain, ExtendedBlockHeader, OutputOnChain, TxInBlockchain,
|
||||
};
|
||||
|
||||
/// [`BlockchainReadRequest::Block`].
|
||||
|
@ -375,3 +375,20 @@ pub(crate) async fn alt_chain_count(
|
|||
|
||||
Ok(usize_to_u64(count))
|
||||
}
|
||||
|
||||
/// [`BlockchainReadRequest::Transactions`].
|
||||
pub(crate) async fn transactions(
|
||||
blockchain_read: &mut BlockchainReadHandle,
|
||||
tx_hashes: BTreeSet<[u8; 32]>,
|
||||
) -> Result<(Vec<TxInBlockchain>, Vec<[u8; 32]>), Error> {
|
||||
let BlockchainResponse::Transactions { txs, missed_txs } = blockchain_read
|
||||
.ready()
|
||||
.await?
|
||||
.call(BlockchainReadRequest::Transactions { tx_hashes })
|
||||
.await?
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
Ok((txs, missed_txs))
|
||||
}
|
||||
|
|
|
@ -13,7 +13,10 @@ use cuprate_txpool::{
|
|||
},
|
||||
TxEntry,
|
||||
};
|
||||
use cuprate_types::rpc::{PoolInfo, PoolInfoFull, PoolInfoIncremental, PoolTxInfo};
|
||||
use cuprate_types::{
|
||||
rpc::{PoolInfo, PoolInfoFull, PoolInfoIncremental, PoolTxInfo},
|
||||
TxInPool,
|
||||
};
|
||||
|
||||
// FIXME: use `anyhow::Error` over `tower::BoxError` in txpool.
|
||||
|
||||
|
@ -60,8 +63,8 @@ pub(crate) async fn pool_info(
|
|||
include_sensitive_txs: bool,
|
||||
max_tx_count: usize,
|
||||
start_time: Option<NonZero<usize>>,
|
||||
) -> Result<Vec<PoolInfo>, Error> {
|
||||
let TxpoolReadResponse::PoolInfo(vec) = txpool_read
|
||||
) -> Result<PoolInfo, Error> {
|
||||
let TxpoolReadResponse::PoolInfo(pool_info) = txpool_read
|
||||
.ready()
|
||||
.await
|
||||
.map_err(|e| anyhow!(e))?
|
||||
|
@ -76,7 +79,30 @@ pub(crate) async fn pool_info(
|
|||
unreachable!();
|
||||
};
|
||||
|
||||
Ok(vec)
|
||||
Ok(pool_info)
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub(crate) async fn txs_by_hash(
|
||||
txpool_read: &mut TxpoolReadHandle,
|
||||
tx_hashes: Vec<[u8; 32]>,
|
||||
include_sensitive_txs: bool,
|
||||
) -> Result<Vec<TxInPool>, Error> {
|
||||
let TxpoolReadResponse::TxsByHash(txs_in_pool) = txpool_read
|
||||
.ready()
|
||||
.await
|
||||
.map_err(|e| anyhow!(e))?
|
||||
.call(TxpoolReadRequest::TxsByHash {
|
||||
tx_hashes,
|
||||
include_sensitive_txs,
|
||||
})
|
||||
.await
|
||||
.map_err(|e| anyhow!(e))?
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
Ok(txs_in_pool)
|
||||
}
|
||||
|
||||
/// TODO
|
||||
|
|
|
@ -25,7 +25,7 @@ pub use distribution::{Distribution, DistributionCompressedBinary, DistributionU
|
|||
pub use key_image_spent_status::KeyImageSpentStatus;
|
||||
pub use requested_info::RequestedInfo;
|
||||
pub use status::Status;
|
||||
pub use tx_entry::TxEntry;
|
||||
pub use tx_entry::{TxEntry, TxEntryType};
|
||||
pub use types::{
|
||||
BlockHeader, ChainInfo, ConnectionInfo, GetBan, GetOutputsOut, HistogramEntry, OutKeyBin,
|
||||
SetBan, Span, SpentKeyImageInfo, SyncInfoPeer, TxInfo,
|
||||
|
|
|
@ -11,6 +11,8 @@ use cuprate_epee_encoding::{
|
|||
EpeeObject, EpeeObjectBuilder,
|
||||
};
|
||||
|
||||
use cuprate_hex::Hex;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use crate::serde::{serde_false, serde_true};
|
||||
|
||||
|
@ -28,100 +30,63 @@ use crate::serde::{serde_false, serde_true};
|
|||
///
|
||||
/// It is only implemented to satisfy the RPC type generator
|
||||
/// macro, which requires all objects to be serde + epee.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// use cuprate_rpc_types::misc::*;
|
||||
/// use serde_json::{json, from_value};
|
||||
///
|
||||
/// let json = json!({
|
||||
/// "as_hex": String::default(),
|
||||
/// "as_json": String::default(),
|
||||
/// "block_height": u64::default(),
|
||||
/// "block_timestamp": u64::default(),
|
||||
/// "confirmations": u64::default(),
|
||||
/// "double_spend_seen": bool::default(),
|
||||
/// "output_indices": Vec::<u64>::default(),
|
||||
/// "prunable_as_hex": String::default(),
|
||||
/// "prunable_hash": String::default(),
|
||||
/// "pruned_as_hex": String::default(),
|
||||
/// "tx_hash": String::default(),
|
||||
/// "in_pool": bool::default(),
|
||||
/// });
|
||||
/// let tx_entry = from_value::<TxEntry>(json).unwrap();
|
||||
/// assert!(matches!(tx_entry, TxEntry::InPool { .. }));
|
||||
///
|
||||
/// let json = json!({
|
||||
/// "as_hex": String::default(),
|
||||
/// "as_json": String::default(),
|
||||
/// "double_spend_seen": bool::default(),
|
||||
/// "prunable_as_hex": String::default(),
|
||||
/// "prunable_hash": String::default(),
|
||||
/// "pruned_as_hex": String::default(),
|
||||
/// "received_timestamp": u64::default(),
|
||||
/// "relayed": bool::default(),
|
||||
/// "tx_hash": String::default(),
|
||||
/// "in_pool": bool::default(),
|
||||
/// });
|
||||
/// let tx_entry = from_value::<TxEntry>(json).unwrap();
|
||||
/// assert!(matches!(tx_entry, TxEntry::NotInPool { .. }));
|
||||
/// ```
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct TxEntry {
|
||||
/// `cuprate_types::json::tx::Transaction` should be used
|
||||
/// to create this JSON string in a type-safe manner.
|
||||
pub as_json: String,
|
||||
|
||||
pub as_hex: String,
|
||||
pub double_spend_seen: bool,
|
||||
pub tx_hash: Hex<32>,
|
||||
pub prunable_as_hex: String,
|
||||
pub prunable_hash: Hex<32>,
|
||||
pub pruned_as_hex: String,
|
||||
|
||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||
pub tx_entry_type: TxEntryType,
|
||||
}
|
||||
|
||||
/// Different fields in [`TxEntry`] variants.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(untagged))]
|
||||
pub enum TxEntry {
|
||||
/// This entry exists in the transaction pool.
|
||||
InPool {
|
||||
/// This field is [flattened](https://serde.rs/field-attrs.html#flatten).
|
||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||
prefix: TxEntryPrefix,
|
||||
pub enum TxEntryType {
|
||||
/// This transaction exists in the blockchain.
|
||||
Blockchain {
|
||||
block_height: u64,
|
||||
block_timestamp: u64,
|
||||
confirmations: u64,
|
||||
output_indices: Vec<u64>,
|
||||
#[cfg_attr(feature = "serde", serde(serialize_with = "serde_true"))]
|
||||
/// Will always be serialized as `true`.
|
||||
|
||||
/// Will always be serialized as `false`.
|
||||
#[cfg_attr(feature = "serde", serde(serialize_with = "serde_false"))]
|
||||
in_pool: bool,
|
||||
},
|
||||
/// This entry _does not_ exist in the transaction pool.
|
||||
NotInPool {
|
||||
/// This field is [flattened](https://serde.rs/field-attrs.html#flatten).
|
||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||
prefix: TxEntryPrefix,
|
||||
|
||||
/// This transaction exists in the transaction pool.
|
||||
Pool {
|
||||
received_timestamp: u64,
|
||||
relayed: bool,
|
||||
#[cfg_attr(feature = "serde", serde(serialize_with = "serde_false"))]
|
||||
/// Will always be serialized as `false`.
|
||||
|
||||
/// Will always be serialized as `true`.
|
||||
#[cfg_attr(feature = "serde", serde(serialize_with = "serde_true"))]
|
||||
in_pool: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl Default for TxEntry {
|
||||
impl Default for TxEntryType {
|
||||
fn default() -> Self {
|
||||
Self::NotInPool {
|
||||
prefix: Default::default(),
|
||||
received_timestamp: u64::default(),
|
||||
relayed: bool::default(),
|
||||
in_pool: false,
|
||||
Self::Blockchain {
|
||||
block_height: Default::default(),
|
||||
block_timestamp: Default::default(),
|
||||
confirmations: Default::default(),
|
||||
output_indices: Default::default(),
|
||||
in_pool: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Common fields in all [`TxEntry`] variants.
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct TxEntryPrefix {
|
||||
as_hex: String,
|
||||
/// `cuprate_rpc_types::json::tx::Transaction` should be used
|
||||
/// to create this JSON string in a type-safe manner.
|
||||
as_json: String,
|
||||
double_spend_seen: bool,
|
||||
tx_hash: String,
|
||||
prunable_as_hex: String,
|
||||
prunable_hash: String,
|
||||
pruned_as_hex: String,
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Epee
|
||||
#[cfg(feature = "epee")]
|
||||
impl EpeeObjectBuilder<TxEntry> for () {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -11,7 +11,7 @@
|
|||
//---------------------------------------------------------------------------------------------------- Import
|
||||
use std::{
|
||||
cmp::min,
|
||||
collections::{HashMap, HashSet},
|
||||
collections::{BTreeSet, HashMap, HashSet},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
|
@ -134,6 +134,7 @@ fn map_request(
|
|||
R::CoinbaseTxSum { height, count } => coinbase_tx_sum(env, height, count),
|
||||
R::AltChains => alt_chains(env),
|
||||
R::AltChainCount => alt_chain_count(env),
|
||||
R::Transactions { tx_hashes } => transactions(env, tx_hashes),
|
||||
}
|
||||
|
||||
/* SOMEDAY: post-request handling, run some code for each request? */
|
||||
|
@ -783,3 +784,11 @@ fn alt_chains(env: &ConcreteEnv) -> ResponseResult {
|
|||
fn alt_chain_count(env: &ConcreteEnv) -> ResponseResult {
|
||||
Ok(BlockchainResponse::AltChainCount(todo!()))
|
||||
}
|
||||
|
||||
/// [`BlockchainReadRequest::Transactions`]
|
||||
fn transactions(env: &ConcreteEnv, tx_hashes: BTreeSet<[u8; 32]>) -> ResponseResult {
|
||||
Ok(BlockchainResponse::Transactions {
|
||||
txs: todo!(),
|
||||
missed_txs: todo!(),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -5,9 +5,10 @@ use std::{
|
|||
collections::{HashMap, HashSet},
|
||||
num::NonZero,
|
||||
sync::Arc,
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use cuprate_types::{rpc::PoolInfo, TransactionVerificationData};
|
||||
use cuprate_types::{rpc::PoolInfo, TransactionVerificationData, TxInPool};
|
||||
|
||||
use crate::{
|
||||
tx::TxEntry,
|
||||
|
@ -52,6 +53,11 @@ pub enum TxpoolReadRequest {
|
|||
/// TODO
|
||||
start_time: Option<NonZero<usize>>,
|
||||
},
|
||||
|
||||
TxsByHash {
|
||||
tx_hashes: Vec<[u8; 32]>,
|
||||
include_sensitive_txs: bool,
|
||||
},
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- TxpoolReadResponse
|
||||
|
@ -93,7 +99,10 @@ pub enum TxpoolReadResponse {
|
|||
Size(usize),
|
||||
|
||||
/// Response to [`TxpoolReadRequest::PoolInfo`].
|
||||
PoolInfo(Vec<PoolInfo>),
|
||||
PoolInfo(PoolInfo),
|
||||
|
||||
/// Response to [`TxpoolReadRequest::TxsByHash`].
|
||||
TxsByHash(Vec<TxInPool>),
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- TxpoolWriteRequest
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
unreachable_code,
|
||||
unused_variables,
|
||||
clippy::unnecessary_wraps,
|
||||
clippy::needless_pass_by_value,
|
||||
reason = "TODO: finish implementing the signatures from <https://github.com/Cuprate/cuprate/pull/297>"
|
||||
)]
|
||||
use std::{
|
||||
|
@ -79,7 +80,11 @@ fn map_request(
|
|||
include_sensitive_txs,
|
||||
max_tx_count,
|
||||
start_time,
|
||||
} => pool_info(include_sensitive_txs, max_tx_count, start_time),
|
||||
} => pool_info(env, include_sensitive_txs, max_tx_count, start_time),
|
||||
TxpoolReadRequest::TxsByHash {
|
||||
tx_hashes,
|
||||
include_sensitive_txs,
|
||||
} => txs_by_hash(env, tx_hashes, include_sensitive_txs),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,9 +220,19 @@ fn size(env: &ConcreteEnv, include_sensitive_txs: bool) -> ReadResponseResult {
|
|||
|
||||
/// [`TxpoolReadRequest::PoolInfo`].
|
||||
fn pool_info(
|
||||
env: &ConcreteEnv,
|
||||
include_sensitive_txs: bool,
|
||||
max_tx_count: usize,
|
||||
start_time: Option<NonZero<usize>>,
|
||||
) -> ReadResponseResult {
|
||||
Ok(TxpoolReadResponse::PoolInfo(todo!()))
|
||||
}
|
||||
|
||||
/// [`TxpoolReadRequest::TxsByHash`].
|
||||
fn txs_by_hash(
|
||||
env: &ConcreteEnv,
|
||||
tx_hashes: Vec<[u8; 32]>,
|
||||
include_sensitive_txs: bool,
|
||||
) -> ReadResponseResult {
|
||||
Ok(TxpoolReadResponse::TxsByHash(todo!()))
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//! responses are also tested in Cuprate's blockchain database crate.
|
||||
//---------------------------------------------------------------------------------------------------- Import
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
collections::{BTreeSet, HashMap, HashSet},
|
||||
ops::Range,
|
||||
};
|
||||
|
||||
|
@ -12,7 +12,7 @@ use monero_serai::block::Block;
|
|||
|
||||
use crate::{
|
||||
types::{Chain, ExtendedBlockHeader, OutputOnChain, TxsInBlock, VerifiedBlockInformation},
|
||||
AltBlockInformation, BlockCompleteEntry, ChainId,
|
||||
AltBlockInformation, BlockCompleteEntry, ChainId, TxInBlockchain,
|
||||
};
|
||||
|
||||
use crate::rpc::{ChainInfo, CoinbaseTxSum, OutputHistogramEntry, OutputHistogramInput};
|
||||
|
@ -161,6 +161,9 @@ pub enum BlockchainReadRequest {
|
|||
|
||||
/// Get the amount of alternative chains that exist.
|
||||
AltChainCount,
|
||||
|
||||
/// TODO
|
||||
Transactions { tx_hashes: BTreeSet<[u8; 32]> },
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- WriteRequest
|
||||
|
@ -348,6 +351,14 @@ pub enum BlockchainResponse {
|
|||
/// Response to [`BlockchainReadRequest::AltChainCount`].
|
||||
AltChainCount(usize),
|
||||
|
||||
/// Response to [`BlockchainReadRequest::Transactions`].
|
||||
Transactions {
|
||||
/// The transaction blobs found.
|
||||
txs: Vec<TxInBlockchain>,
|
||||
/// The hashes of any transactions that could not be found.
|
||||
missed_txs: Vec<[u8; 32]>,
|
||||
},
|
||||
|
||||
//------------------------------------------------------ Writes
|
||||
/// A generic Ok response to indicate a request was successfully handled.
|
||||
///
|
||||
|
|
|
@ -25,7 +25,7 @@ pub use transaction_verification_data::{
|
|||
};
|
||||
pub use types::{
|
||||
AltBlockInformation, BlockTemplate, Chain, ChainId, ExtendedBlockHeader, OutputOnChain,
|
||||
TxsInBlock, VerifiedBlockInformation, VerifiedTransactionInformation,
|
||||
TxInBlockchain, TxInPool, TxsInBlock, VerifiedBlockInformation, VerifiedTransactionInformation,
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Feature-gated
|
||||
|
|
|
@ -167,6 +167,30 @@ pub struct BlockTemplate {
|
|||
pub next_seed_hash: [u8; 32],
|
||||
}
|
||||
|
||||
/// TODO
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct TxInBlockchain {
|
||||
pub block_height: u64,
|
||||
pub block_timestamp: u64,
|
||||
pub confirmations: u64,
|
||||
pub output_indices: Vec<u64>,
|
||||
pub tx_hash: [u8; 32],
|
||||
pub tx_blob: Vec<u8>,
|
||||
pub pruned_blob: Vec<u8>,
|
||||
pub prunable_blob: Vec<u8>,
|
||||
pub prunable_hash: [u8; 32],
|
||||
}
|
||||
|
||||
/// TODO
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct TxInPool {
|
||||
pub tx_blob: Vec<u8>,
|
||||
pub tx_hash: [u8; 32],
|
||||
pub double_spend_seen: bool,
|
||||
pub received_timestamp: u64,
|
||||
pub relayed: bool,
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Tests
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
|
Loading…
Reference in a new issue