mirror of
https://github.com/hinto-janai/cuprate.git
synced 2024-12-23 03:59:37 +00:00
Compare commits
No commits in common. "f7f9063890f356c5b1cd43d78e4d68cb4ccda06e" and "0b3ee2d1d14a26bcacf449c7378595ac06beb373" have entirely different histories.
f7f9063890
...
0b3ee2d1d1
16 changed files with 151 additions and 320 deletions
|
@ -9,6 +9,5 @@ mod helper;
|
||||||
mod json;
|
mod json;
|
||||||
mod other;
|
mod other;
|
||||||
mod request;
|
mod request;
|
||||||
mod shared;
|
|
||||||
|
|
||||||
pub use handler::CupratedRpcHandler;
|
pub use handler::CupratedRpcHandler;
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
//! RPC request handler functions (binary endpoints).
|
//! RPC request handler functions (binary endpoints).
|
||||||
|
|
||||||
use anyhow::{anyhow, Error};
|
use anyhow::{anyhow, Error};
|
||||||
use bytes::Bytes;
|
|
||||||
|
|
||||||
use cuprate_constants::rpc::{RESTRICTED_BLOCK_COUNT, RESTRICTED_TRANSACTIONS_COUNT};
|
use cuprate_constants::rpc::{RESTRICTED_BLOCK_COUNT, RESTRICTED_TRANSACTIONS_COUNT};
|
||||||
use cuprate_fixed_bytes::ByteArrayVec;
|
|
||||||
use cuprate_rpc_interface::RpcHandler;
|
use cuprate_rpc_interface::RpcHandler;
|
||||||
use cuprate_rpc_types::{
|
use cuprate_rpc_types::{
|
||||||
base::{AccessResponseBase, ResponseBase},
|
base::{AccessResponseBase, ResponseBase},
|
||||||
|
@ -19,11 +17,7 @@ use cuprate_rpc_types::{
|
||||||
};
|
};
|
||||||
use cuprate_types::{rpc::PoolInfoExtent, BlockCompleteEntry};
|
use cuprate_types::{rpc::PoolInfoExtent, BlockCompleteEntry};
|
||||||
|
|
||||||
use crate::rpc::{
|
use crate::rpc::{helper, request::blockchain, CupratedRpcHandler};
|
||||||
helper,
|
|
||||||
request::{blockchain, txpool},
|
|
||||||
shared, CupratedRpcHandler,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Map a [`BinRequest`] to the function that will lead to a [`BinResponse`].
|
/// Map a [`BinRequest`] to the function that will lead to a [`BinResponse`].
|
||||||
pub(super) async fn map_request(
|
pub(super) async fn map_request(
|
||||||
|
@ -128,16 +122,18 @@ async fn get_blocks(
|
||||||
|
|
||||||
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L817-L857>
|
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L817-L857>
|
||||||
async fn get_blocks_by_height(
|
async fn get_blocks_by_height(
|
||||||
mut state: CupratedRpcHandler,
|
state: CupratedRpcHandler,
|
||||||
request: GetBlocksByHeightRequest,
|
request: GetBlocksByHeightRequest,
|
||||||
) -> Result<GetBlocksByHeightResponse, Error> {
|
) -> Result<GetBlocksByHeightResponse, Error> {
|
||||||
if state.is_restricted() && request.heights.len() > RESTRICTED_BLOCK_COUNT {
|
if state.is_restricted() && request.heights.len() > RESTRICTED_BLOCK_COUNT {
|
||||||
return Err(anyhow!("Too many blocks requested in restricted mode"));
|
return Err(anyhow!("Too many blocks requested in restricted mode"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let blocks =
|
let blocks = request
|
||||||
blockchain::block_complete_entries_by_height(&mut state.blockchain_read, request.heights)
|
.heights
|
||||||
.await?;
|
.into_iter()
|
||||||
|
.map(|height| Ok(todo!()))
|
||||||
|
.collect::<Result<Vec<BlockCompleteEntry>, Error>>()?;
|
||||||
|
|
||||||
Ok(GetBlocksByHeightResponse {
|
Ok(GetBlocksByHeightResponse {
|
||||||
base: helper::access_response_base(false),
|
base: helper::access_response_base(false),
|
||||||
|
@ -161,6 +157,13 @@ async fn get_hashes(
|
||||||
request.block_ids[len - 1]
|
request.block_ids[len - 1]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const GENESIS_BLOCK_HASH: [u8; 32] = [0; 32]; // TODO
|
||||||
|
if last != GENESIS_BLOCK_HASH {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"genesis block mismatch, found: {last:?}, expected: {GENESIS_BLOCK_HASH:?}"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let mut bytes = request.block_ids;
|
let mut bytes = request.block_ids;
|
||||||
let hashes: Vec<[u8; 32]> = (&bytes).into();
|
let hashes: Vec<[u8; 32]> = (&bytes).into();
|
||||||
|
|
||||||
|
@ -184,12 +187,12 @@ async fn get_hashes(
|
||||||
|
|
||||||
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L959-L977>
|
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L959-L977>
|
||||||
async fn get_output_indexes(
|
async fn get_output_indexes(
|
||||||
mut state: CupratedRpcHandler,
|
state: CupratedRpcHandler,
|
||||||
request: GetOutputIndexesRequest,
|
request: GetOutputIndexesRequest,
|
||||||
) -> Result<GetOutputIndexesResponse, Error> {
|
) -> Result<GetOutputIndexesResponse, Error> {
|
||||||
Ok(GetOutputIndexesResponse {
|
Ok(GetOutputIndexesResponse {
|
||||||
base: helper::access_response_base(false),
|
base: helper::access_response_base(false),
|
||||||
o_indexes: blockchain::tx_output_indexes(&mut state.blockchain_read, request.txid).await?,
|
..todo!()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,19 +201,20 @@ async fn get_outs(
|
||||||
state: CupratedRpcHandler,
|
state: CupratedRpcHandler,
|
||||||
request: GetOutsRequest,
|
request: GetOutsRequest,
|
||||||
) -> Result<GetOutsResponse, Error> {
|
) -> Result<GetOutsResponse, Error> {
|
||||||
shared::get_outs(state, request).await
|
Ok(GetOutsResponse {
|
||||||
|
base: helper::access_response_base(false),
|
||||||
|
..todo!()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L1689-L1711>
|
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L1689-L1711>
|
||||||
async fn get_transaction_pool_hashes(
|
async fn get_transaction_pool_hashes(
|
||||||
mut state: CupratedRpcHandler,
|
state: CupratedRpcHandler,
|
||||||
_: GetTransactionPoolHashesRequest,
|
request: GetTransactionPoolHashesRequest,
|
||||||
) -> Result<GetTransactionPoolHashesResponse, Error> {
|
) -> Result<GetTransactionPoolHashesResponse, Error> {
|
||||||
Ok(GetTransactionPoolHashesResponse {
|
Ok(GetTransactionPoolHashesResponse {
|
||||||
base: helper::access_response_base(false),
|
base: helper::access_response_base(false),
|
||||||
tx_hashes: shared::get_transaction_pool_hashes(state)
|
..todo!()
|
||||||
.await
|
|
||||||
.map(ByteArrayVec::from)?,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,5 +223,8 @@ async fn get_output_distribution(
|
||||||
state: CupratedRpcHandler,
|
state: CupratedRpcHandler,
|
||||||
request: GetOutputDistributionRequest,
|
request: GetOutputDistributionRequest,
|
||||||
) -> Result<GetOutputDistributionResponse, Error> {
|
) -> Result<GetOutputDistributionResponse, Error> {
|
||||||
shared::get_output_distribution(state, request).await
|
Ok(GetOutputDistributionResponse {
|
||||||
|
base: helper::access_response_base(false),
|
||||||
|
..todo!()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ use crate::{
|
||||||
rpc::{
|
rpc::{
|
||||||
helper,
|
helper,
|
||||||
request::{address_book, blockchain, blockchain_context, blockchain_manager, txpool},
|
request::{address_book, blockchain, blockchain_context, blockchain_manager, txpool},
|
||||||
shared, CupratedRpcHandler,
|
CupratedRpcHandler,
|
||||||
},
|
},
|
||||||
statics::START_INSTANT_UNIX,
|
statics::START_INSTANT_UNIX,
|
||||||
};
|
};
|
||||||
|
@ -958,10 +958,35 @@ async fn get_transaction_pool_backlog(
|
||||||
|
|
||||||
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L3352-L3398>
|
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L3352-L3398>
|
||||||
async fn get_output_distribution(
|
async fn get_output_distribution(
|
||||||
state: CupratedRpcHandler,
|
mut state: CupratedRpcHandler,
|
||||||
request: GetOutputDistributionRequest,
|
request: GetOutputDistributionRequest,
|
||||||
) -> Result<GetOutputDistributionResponse, Error> {
|
) -> Result<GetOutputDistributionResponse, Error> {
|
||||||
shared::get_output_distribution(state, request).await
|
if state.is_restricted() && request.amounts != [1, 0] {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"Restricted RPC can only get output distribution for RCT outputs. Use your own node."
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0 is placeholder for the whole chain
|
||||||
|
let req_to_height = if request.to_height == 0 {
|
||||||
|
helper::top_height(&mut state).await?.0.saturating_sub(1)
|
||||||
|
} else {
|
||||||
|
request.to_height
|
||||||
|
};
|
||||||
|
|
||||||
|
let distributions = request.amounts.into_iter().map(|amount| {
|
||||||
|
fn get_output_distribution() -> Result<Distribution, Error> {
|
||||||
|
todo!("https://github.com/monero-project/monero/blob/893916ad091a92e765ce3241b94e706ad012b62a/src/rpc/rpc_handler.cpp#L29");
|
||||||
|
Err(anyhow!("Failed to get output distribution"))
|
||||||
|
}
|
||||||
|
|
||||||
|
get_output_distribution()
|
||||||
|
}).collect::<Result<Vec<Distribution>, _>>()?;
|
||||||
|
|
||||||
|
Ok(GetOutputDistributionResponse {
|
||||||
|
base: helper::access_response_base(false),
|
||||||
|
distributions,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L1998-L2033>
|
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L1998-L2033>
|
||||||
|
|
|
@ -37,7 +37,7 @@ use cuprate_rpc_types::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use cuprate_types::{
|
use cuprate_types::{
|
||||||
rpc::{KeyImageSpentStatus, PoolInfo, PoolTxInfo, PublicNode},
|
rpc::{KeyImageSpentStatus, OutKey, PoolInfo, PoolTxInfo, PublicNode},
|
||||||
TxInPool, TxRelayChecks,
|
TxInPool, TxRelayChecks,
|
||||||
};
|
};
|
||||||
use monero_serai::transaction::{Input, Timelock, Transaction};
|
use monero_serai::transaction::{Input, Timelock, Transaction};
|
||||||
|
@ -47,7 +47,7 @@ use crate::{
|
||||||
rpc::{
|
rpc::{
|
||||||
helper,
|
helper,
|
||||||
request::{blockchain, blockchain_context, blockchain_manager, txpool},
|
request::{blockchain, blockchain_context, blockchain_manager, txpool},
|
||||||
shared, CupratedRpcHandler,
|
CupratedRpcHandler,
|
||||||
},
|
},
|
||||||
statics::START_INSTANT_UNIX,
|
statics::START_INSTANT_UNIX,
|
||||||
};
|
};
|
||||||
|
@ -610,21 +610,45 @@ async fn get_net_stats(
|
||||||
|
|
||||||
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L912-L957>
|
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L912-L957>
|
||||||
async fn get_outs(
|
async fn get_outs(
|
||||||
state: CupratedRpcHandler,
|
mut state: CupratedRpcHandler,
|
||||||
request: GetOutsRequest,
|
request: GetOutsRequest,
|
||||||
) -> Result<GetOutsResponse, Error> {
|
) -> Result<GetOutsResponse, Error> {
|
||||||
let outs = shared::get_outs(
|
if state.is_restricted() && request.outputs.len() > MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT {
|
||||||
state,
|
return Err(anyhow!("Too many outs requested"));
|
||||||
cuprate_rpc_types::bin::GetOutsRequest {
|
}
|
||||||
outputs: request.outputs,
|
|
||||||
get_txid: request.get_txid,
|
let outputs = {
|
||||||
},
|
let mut outputs = HashMap::<u64, HashSet<u64>>::with_capacity(request.outputs.len());
|
||||||
)
|
|
||||||
|
for out in request.outputs {
|
||||||
|
outputs
|
||||||
|
.entry(out.amount)
|
||||||
|
.and_modify(|set| {
|
||||||
|
set.insert(out.index);
|
||||||
|
})
|
||||||
|
.or_insert_with(|| HashSet::from([out.index]));
|
||||||
|
}
|
||||||
|
|
||||||
|
outputs
|
||||||
|
};
|
||||||
|
|
||||||
|
let outs = blockchain::outputs(&mut state.blockchain_read, outputs)
|
||||||
.await?
|
.await?
|
||||||
.outs
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(Into::into)
|
.flat_map(|(amount, index_map)| {
|
||||||
.collect();
|
index_map.into_iter().map(|(index, out)| OutKey {
|
||||||
|
key: out.key.map_or(Hex([0; 32]), |e| Hex(e.compress().0)),
|
||||||
|
mask: Hex(out.commitment.compress().0),
|
||||||
|
unlocked: matches!(out.time_lock, Timelock::None),
|
||||||
|
height: usize_to_u64(out.height),
|
||||||
|
txid: if request.get_txid {
|
||||||
|
hex::encode(out.txid)
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<Vec<OutKey>>();
|
||||||
|
|
||||||
Ok(GetOutsResponse {
|
Ok(GetOutsResponse {
|
||||||
base: helper::response_base(false),
|
base: helper::response_base(false),
|
||||||
|
@ -651,13 +675,20 @@ async fn get_transaction_pool_hashes(
|
||||||
mut state: CupratedRpcHandler,
|
mut state: CupratedRpcHandler,
|
||||||
_: GetTransactionPoolHashesRequest,
|
_: GetTransactionPoolHashesRequest,
|
||||||
) -> Result<GetTransactionPoolHashesResponse, Error> {
|
) -> Result<GetTransactionPoolHashesResponse, Error> {
|
||||||
|
let include_sensitive_txs = !state.is_restricted();
|
||||||
|
|
||||||
|
// FIXME: this request is a bit overkill, we only need the hashes.
|
||||||
|
// We could create a separate request for this.
|
||||||
|
let tx_hashes = txpool::pool(&mut state.txpool_read, include_sensitive_txs)
|
||||||
|
.await?
|
||||||
|
.0
|
||||||
|
.into_iter()
|
||||||
|
.map(|tx| tx.id_hash)
|
||||||
|
.collect();
|
||||||
|
|
||||||
Ok(GetTransactionPoolHashesResponse {
|
Ok(GetTransactionPoolHashesResponse {
|
||||||
base: helper::response_base(false),
|
base: helper::response_base(false),
|
||||||
tx_hashes: shared::get_transaction_pool_hashes(state)
|
tx_hashes,
|
||||||
.await?
|
|
||||||
.into_iter()
|
|
||||||
.map(Hex)
|
|
||||||
.collect(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ use cuprate_types::{
|
||||||
rpc::{
|
rpc::{
|
||||||
ChainInfo, CoinbaseTxSum, KeyImageSpentStatus, OutputHistogramEntry, OutputHistogramInput,
|
ChainInfo, CoinbaseTxSum, KeyImageSpentStatus, OutputHistogramEntry, OutputHistogramInput,
|
||||||
},
|
},
|
||||||
BlockCompleteEntry, Chain, ExtendedBlockHeader, OutputOnChain, TxInBlockchain,
|
Chain, ExtendedBlockHeader, OutputOnChain, TxInBlockchain,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// [`BlockchainReadRequest::Block`].
|
/// [`BlockchainReadRequest::Block`].
|
||||||
|
@ -399,7 +399,7 @@ pub(crate) async fn transactions(
|
||||||
pub(crate) async fn total_rct_outputs(
|
pub(crate) async fn total_rct_outputs(
|
||||||
blockchain_read: &mut BlockchainReadHandle,
|
blockchain_read: &mut BlockchainReadHandle,
|
||||||
) -> Result<u64, Error> {
|
) -> Result<u64, Error> {
|
||||||
let BlockchainResponse::TotalRctOutputs(n) = blockchain_read
|
let BlockchainResponse::TotalRctOutputs(total_rct_outputs) = blockchain_read
|
||||||
.ready()
|
.ready()
|
||||||
.await?
|
.await?
|
||||||
.call(BlockchainReadRequest::TotalRctOutputs)
|
.call(BlockchainReadRequest::TotalRctOutputs)
|
||||||
|
@ -408,41 +408,5 @@ pub(crate) async fn total_rct_outputs(
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(n)
|
Ok(total_rct_outputs)
|
||||||
}
|
|
||||||
|
|
||||||
/// [`BlockchainReadRequest::BlockCompleteEntriesByHeight`].
|
|
||||||
pub(crate) async fn block_complete_entries_by_height(
|
|
||||||
blockchain_read: &mut BlockchainReadHandle,
|
|
||||||
block_heights: Vec<u64>,
|
|
||||||
) -> Result<Vec<BlockCompleteEntry>, Error> {
|
|
||||||
let BlockchainResponse::BlockCompleteEntriesByHeight(blocks) = blockchain_read
|
|
||||||
.ready()
|
|
||||||
.await?
|
|
||||||
.call(BlockchainReadRequest::BlockCompleteEntriesByHeight(
|
|
||||||
block_heights.into_iter().map(u64_to_usize).collect(),
|
|
||||||
))
|
|
||||||
.await?
|
|
||||||
else {
|
|
||||||
unreachable!();
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(blocks)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// [`BlockchainReadRequest::TxOutputIndexes`].
|
|
||||||
pub(crate) async fn tx_output_indexes(
|
|
||||||
blockchain_read: &mut BlockchainReadHandle,
|
|
||||||
tx_hash: [u8; 32],
|
|
||||||
) -> Result<Vec<u64>, Error> {
|
|
||||||
let BlockchainResponse::TxOutputIndexes(o_indexes) = blockchain_read
|
|
||||||
.ready()
|
|
||||||
.await?
|
|
||||||
.call(BlockchainReadRequest::TxOutputIndexes { tx_hash })
|
|
||||||
.await?
|
|
||||||
else {
|
|
||||||
unreachable!();
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(o_indexes)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,132 +0,0 @@
|
||||||
//! RPC handler functions that are shared between different endpoint/methods.
|
|
||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
|
|
||||||
use anyhow::{anyhow, Error};
|
|
||||||
use monero_serai::transaction::Timelock;
|
|
||||||
|
|
||||||
use cuprate_constants::rpc::MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT;
|
|
||||||
use cuprate_helper::cast::usize_to_u64;
|
|
||||||
use cuprate_hex::Hex;
|
|
||||||
use cuprate_rpc_interface::RpcHandler;
|
|
||||||
use cuprate_rpc_types::{
|
|
||||||
bin::{
|
|
||||||
GetOutsRequest, GetOutsResponse, GetTransactionPoolHashesRequest,
|
|
||||||
GetTransactionPoolHashesResponse,
|
|
||||||
},
|
|
||||||
json::{GetOutputDistributionRequest, GetOutputDistributionResponse},
|
|
||||||
misc::{Distribution, OutKeyBin},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::rpc::{
|
|
||||||
helper,
|
|
||||||
request::{blockchain, txpool},
|
|
||||||
CupratedRpcHandler,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L912-L957>
|
|
||||||
///
|
|
||||||
/// Shared between:
|
|
||||||
/// - Other JSON's `/get_outs`
|
|
||||||
/// - Binary's `/get_outs.bin`
|
|
||||||
pub(super) async fn get_outs(
|
|
||||||
mut state: CupratedRpcHandler,
|
|
||||||
request: GetOutsRequest,
|
|
||||||
) -> Result<GetOutsResponse, Error> {
|
|
||||||
if state.is_restricted() && request.outputs.len() > MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT {
|
|
||||||
return Err(anyhow!("Too many outs requested"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let outputs = {
|
|
||||||
let mut outputs = HashMap::<u64, HashSet<u64>>::with_capacity(request.outputs.len());
|
|
||||||
|
|
||||||
for out in request.outputs {
|
|
||||||
outputs
|
|
||||||
.entry(out.amount)
|
|
||||||
.and_modify(|set| {
|
|
||||||
set.insert(out.index);
|
|
||||||
})
|
|
||||||
.or_insert_with(|| HashSet::from([out.index]));
|
|
||||||
}
|
|
||||||
|
|
||||||
outputs
|
|
||||||
};
|
|
||||||
|
|
||||||
let outs = blockchain::outputs(&mut state.blockchain_read, outputs)
|
|
||||||
.await?
|
|
||||||
.into_iter()
|
|
||||||
.flat_map(|(amount, index_map)| {
|
|
||||||
index_map.into_values().map(|out| OutKeyBin {
|
|
||||||
key: out.key.map_or([0; 32], |e| e.compress().0),
|
|
||||||
mask: out.commitment.compress().0,
|
|
||||||
unlocked: matches!(out.time_lock, Timelock::None),
|
|
||||||
height: usize_to_u64(out.height),
|
|
||||||
txid: if request.get_txid { out.txid } else { [0; 32] },
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect::<Vec<OutKeyBin>>();
|
|
||||||
|
|
||||||
Ok(GetOutsResponse {
|
|
||||||
base: helper::access_response_base(false),
|
|
||||||
outs,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L1713-L1739>
|
|
||||||
///
|
|
||||||
/// Shared between:
|
|
||||||
/// - Other JSON's `/get_transaction_pool_hashes`
|
|
||||||
/// - Binary's `/get_transaction_pool_hashes.bin`
|
|
||||||
///
|
|
||||||
/// Returns transaction hashes.
|
|
||||||
pub(super) async fn get_transaction_pool_hashes(
|
|
||||||
mut state: CupratedRpcHandler,
|
|
||||||
) -> Result<Vec<[u8; 32]>, Error> {
|
|
||||||
let include_sensitive_txs = !state.is_restricted();
|
|
||||||
|
|
||||||
// FIXME: this request is a bit overkill, we only need the hashes.
|
|
||||||
// We could create a separate request for this.
|
|
||||||
Ok(txpool::pool(&mut state.txpool_read, include_sensitive_txs)
|
|
||||||
.await?
|
|
||||||
.0
|
|
||||||
.into_iter()
|
|
||||||
.map(|tx| tx.id_hash.0)
|
|
||||||
.collect())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L3352-L3398>
|
|
||||||
///
|
|
||||||
/// Shared between:
|
|
||||||
/// - JSON-RPC's `get_output_distribution`
|
|
||||||
/// - Binary's `/get_output_distribution.bin`
|
|
||||||
pub(super) async fn get_output_distribution(
|
|
||||||
mut state: CupratedRpcHandler,
|
|
||||||
request: GetOutputDistributionRequest,
|
|
||||||
) -> Result<GetOutputDistributionResponse, Error> {
|
|
||||||
if state.is_restricted() && request.amounts != [1, 0] {
|
|
||||||
return Err(anyhow!(
|
|
||||||
"Restricted RPC can only get output distribution for RCT outputs. Use your own node."
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0 is placeholder for the whole chain
|
|
||||||
let req_to_height = if request.to_height == 0 {
|
|
||||||
helper::top_height(&mut state).await?.0.saturating_sub(1)
|
|
||||||
} else {
|
|
||||||
request.to_height
|
|
||||||
};
|
|
||||||
|
|
||||||
let distributions = request.amounts.into_iter().map(|amount| {
|
|
||||||
fn get_output_distribution() -> Result<Distribution, Error> {
|
|
||||||
todo!("https://github.com/monero-project/monero/blob/893916ad091a92e765ce3241b94e706ad012b62a/src/rpc/rpc_handler.cpp#L29");
|
|
||||||
Err(anyhow!("Failed to get output distribution"))
|
|
||||||
}
|
|
||||||
|
|
||||||
get_output_distribution()
|
|
||||||
}).collect::<Result<Vec<Distribution>, _>>()?;
|
|
||||||
|
|
||||||
Ok(GetOutputDistributionResponse {
|
|
||||||
base: helper::access_response_base(false),
|
|
||||||
distributions,
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -120,6 +120,7 @@ define_request_and_response! {
|
||||||
|
|
||||||
Request {
|
Request {
|
||||||
requested_info: u8 = default::<u8>(), "default",
|
requested_info: u8 = default::<u8>(), "default",
|
||||||
|
// FIXME: This is a `std::list` in `monerod` because...?
|
||||||
block_ids: ByteArrayVec<32> = default::<ByteArrayVec<32>>(), "default",
|
block_ids: ByteArrayVec<32> = default::<ByteArrayVec<32>>(), "default",
|
||||||
start_height: u64,
|
start_height: u64,
|
||||||
prune: bool,
|
prune: bool,
|
||||||
|
|
|
@ -193,15 +193,3 @@ impl From<SpentKeyImageInfo> for crate::misc::SpentKeyImageInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<crate::misc::OutKeyBin> for crate::misc::OutKey {
|
|
||||||
fn from(x: crate::misc::OutKeyBin) -> Self {
|
|
||||||
Self {
|
|
||||||
key: Hex(x.key),
|
|
||||||
mask: Hex(x.mask),
|
|
||||||
unlocked: x.unlocked,
|
|
||||||
height: x.height,
|
|
||||||
txid: hex::encode(x.txid),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -25,6 +25,6 @@ pub use requested_info::RequestedInfo;
|
||||||
pub use status::Status;
|
pub use status::Status;
|
||||||
pub use tx_entry::{TxEntry, TxEntryType};
|
pub use tx_entry::{TxEntry, TxEntryType};
|
||||||
pub use types::{
|
pub use types::{
|
||||||
BlockHeader, ChainInfo, ConnectionInfo, GetBan, GetOutputsOut, HistogramEntry, OutKey,
|
BlockHeader, ChainInfo, ConnectionInfo, GetBan, GetOutputsOut, HistogramEntry, OutKeyBin,
|
||||||
OutKeyBin, SetBan, Span, SpentKeyImageInfo, SyncInfoPeer, TxInfo,
|
SetBan, Span, SpentKeyImageInfo, SyncInfoPeer, TxInfo,
|
||||||
};
|
};
|
||||||
|
|
|
@ -252,23 +252,6 @@ define_struct_and_impl_epee! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
define_struct_and_impl_epee! {
|
|
||||||
#[doc = monero_definition_link!(
|
|
||||||
"cc73fe71162d564ffda8e549b79a350bca53c454",
|
|
||||||
"rpc/core_rpc_server_commands_defs.h",
|
|
||||||
582..=597
|
|
||||||
)]
|
|
||||||
/// Used in [`crate::other::GetOutsRequest`].
|
|
||||||
OutKey {
|
|
||||||
key: Hex<32>,
|
|
||||||
mask: Hex<32>,
|
|
||||||
unlocked: bool,
|
|
||||||
height: u64,
|
|
||||||
/// Optionally empty with `/get_outs`'s `"get_txid": false`.
|
|
||||||
txid: String,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
define_struct_and_impl_epee! {
|
define_struct_and_impl_epee! {
|
||||||
#[doc = monero_definition_link!(
|
#[doc = monero_definition_link!(
|
||||||
"cc73fe71162d564ffda8e549b79a350bca53c454",
|
"cc73fe71162d564ffda8e549b79a350bca53c454",
|
||||||
|
|
|
@ -7,12 +7,12 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use cuprate_hex::Hex;
|
use cuprate_hex::Hex;
|
||||||
use cuprate_types::rpc::{Peer, PublicNode, TxpoolStats};
|
use cuprate_types::rpc::{OutKey, Peer, PublicNode, TxpoolStats};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
base::{AccessResponseBase, ResponseBase},
|
base::{AccessResponseBase, ResponseBase},
|
||||||
macros::define_request_and_response,
|
macros::define_request_and_response,
|
||||||
misc::{GetOutputsOut, OutKey, SpentKeyImageInfo, Status, TxEntry, TxInfo},
|
misc::{GetOutputsOut, SpentKeyImageInfo, Status, TxEntry, TxInfo},
|
||||||
RpcCallValue,
|
RpcCallValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1206,8 +1206,9 @@ mod test {
|
||||||
mask: Hex(hex!(
|
mask: Hex(hex!(
|
||||||
"1738eb7a677c6149228a2beaa21bea9e3370802d72a3eec790119580e02bd522"
|
"1738eb7a677c6149228a2beaa21bea9e3370802d72a3eec790119580e02bd522"
|
||||||
)),
|
)),
|
||||||
txid: "9d651903b80fb70b9935b72081cd967f543662149aed3839222511acd9100601"
|
txid: Hex(hex!(
|
||||||
.into(),
|
"9d651903b80fb70b9935b72081cd967f543662149aed3839222511acd9100601"
|
||||||
|
)),
|
||||||
unlocked: true,
|
unlocked: true,
|
||||||
},
|
},
|
||||||
OutKey {
|
OutKey {
|
||||||
|
@ -1218,8 +1219,9 @@ mod test {
|
||||||
mask: Hex(hex!(
|
mask: Hex(hex!(
|
||||||
"1738eb7a677c6149228a2beaa21bea9e3370802d72a3eec790119580e02bd522"
|
"1738eb7a677c6149228a2beaa21bea9e3370802d72a3eec790119580e02bd522"
|
||||||
)),
|
)),
|
||||||
txid: "230bff732dc5f225df14fff82aadd1bf11b3fb7ad3a03413c396a617e843f7d0"
|
txid: Hex(hex!(
|
||||||
.into(),
|
"230bff732dc5f225df14fff82aadd1bf11b3fb7ad3a03413c396a617e843f7d0"
|
||||||
|
)),
|
||||||
unlocked: true,
|
unlocked: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -254,7 +254,7 @@ pub fn get_block_blob_with_tx_indexes(
|
||||||
Ok((block, miner_tx_idx, numb_txs))
|
Ok((block, miner_tx_idx, numb_txs))
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- `get_block_complete_entry_*`
|
//---------------------------------------------------------------------------------------------------- `get_block_extended_header_*`
|
||||||
/// Retrieve a [`BlockCompleteEntry`] from the database.
|
/// Retrieve a [`BlockCompleteEntry`] from the database.
|
||||||
///
|
///
|
||||||
#[doc = doc_error!()]
|
#[doc = doc_error!()]
|
||||||
|
@ -263,18 +263,8 @@ pub fn get_block_complete_entry(
|
||||||
tables: &impl TablesIter,
|
tables: &impl TablesIter,
|
||||||
) -> Result<BlockCompleteEntry, RuntimeError> {
|
) -> Result<BlockCompleteEntry, RuntimeError> {
|
||||||
let block_height = tables.block_heights().get(block_hash)?;
|
let block_height = tables.block_heights().get(block_hash)?;
|
||||||
get_block_complete_entry_from_height(&block_height, tables)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieve a [`BlockCompleteEntry`] from the database.
|
|
||||||
///
|
|
||||||
#[doc = doc_error!()]
|
|
||||||
pub fn get_block_complete_entry_from_height(
|
|
||||||
block_height: &BlockHeight,
|
|
||||||
tables: &impl TablesIter,
|
|
||||||
) -> Result<BlockCompleteEntry, RuntimeError> {
|
|
||||||
let (block_blob, miner_tx_idx, numb_non_miner_txs) =
|
let (block_blob, miner_tx_idx, numb_non_miner_txs) =
|
||||||
get_block_blob_with_tx_indexes(block_height, tables)?;
|
get_block_blob_with_tx_indexes(&block_height, tables)?;
|
||||||
|
|
||||||
let first_tx_idx = miner_tx_idx + 1;
|
let first_tx_idx = miner_tx_idx + 1;
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
block::{
|
block::{
|
||||||
block_exists, get_block_blob_with_tx_indexes, get_block_complete_entry,
|
block_exists, get_block_blob_with_tx_indexes, get_block_complete_entry,
|
||||||
get_block_complete_entry_from_height, get_block_extended_header_from_height,
|
get_block_extended_header_from_height, get_block_height, get_block_info,
|
||||||
get_block_height, get_block_info,
|
|
||||||
},
|
},
|
||||||
blockchain::{cumulative_generated_coins, find_split_point, top_block_height},
|
blockchain::{cumulative_generated_coins, find_split_point, top_block_height},
|
||||||
key_image::key_image_exists,
|
key_image::key_image_exists,
|
||||||
|
@ -54,7 +53,6 @@ use crate::{
|
||||||
},
|
},
|
||||||
tables::{
|
tables::{
|
||||||
AltBlockHeights, BlockHeights, BlockInfos, OpenTables, RctOutputs, Tables, TablesIter,
|
AltBlockHeights, BlockHeights, BlockInfos, OpenTables, RctOutputs, Tables, TablesIter,
|
||||||
TxIds, TxOutputs,
|
|
||||||
},
|
},
|
||||||
types::{
|
types::{
|
||||||
AltBlockHeight, Amount, AmountIndex, BlockHash, BlockHeight, KeyImage, PreRctOutputId,
|
AltBlockHeight, Amount, AmountIndex, BlockHash, BlockHeight, KeyImage, PreRctOutputId,
|
||||||
|
@ -110,7 +108,6 @@ fn map_request(
|
||||||
|
|
||||||
match request {
|
match request {
|
||||||
R::BlockCompleteEntries(block_hashes) => block_complete_entries(env, block_hashes),
|
R::BlockCompleteEntries(block_hashes) => block_complete_entries(env, block_hashes),
|
||||||
R::BlockCompleteEntriesByHeight(heights) => block_complete_entries_by_height(env, heights),
|
|
||||||
R::BlockExtendedHeader(block) => block_extended_header(env, block),
|
R::BlockExtendedHeader(block) => block_extended_header(env, block),
|
||||||
R::BlockHash(block, chain) => block_hash(env, block, chain),
|
R::BlockHash(block, chain) => block_hash(env, block, chain),
|
||||||
R::FindBlock(block_hash) => find_block(env, block_hash),
|
R::FindBlock(block_hash) => find_block(env, block_hash),
|
||||||
|
@ -141,7 +138,6 @@ fn map_request(
|
||||||
R::AltChainCount => alt_chain_count(env),
|
R::AltChainCount => alt_chain_count(env),
|
||||||
R::Transactions { tx_hashes } => transactions(env, tx_hashes),
|
R::Transactions { tx_hashes } => transactions(env, tx_hashes),
|
||||||
R::TotalRctOutputs => total_rct_outputs(env),
|
R::TotalRctOutputs => total_rct_outputs(env),
|
||||||
R::TxOutputIndexes { tx_hash } => tx_output_indexes(env, &tx_hash),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SOMEDAY: post-request handling, run some code for each request? */
|
/* SOMEDAY: post-request handling, run some code for each request? */
|
||||||
|
@ -249,31 +245,6 @@ fn block_complete_entries(env: &ConcreteEnv, block_hashes: Vec<BlockHash>) -> Re
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [`BlockchainReadRequest::BlockCompleteEntriesByHeight`].
|
|
||||||
fn block_complete_entries_by_height(
|
|
||||||
env: &ConcreteEnv,
|
|
||||||
block_heights: Vec<BlockHeight>,
|
|
||||||
) -> ResponseResult {
|
|
||||||
// Prepare tx/tables in `ThreadLocal`.
|
|
||||||
let env_inner = env.env_inner();
|
|
||||||
let tx_ro = thread_local(env);
|
|
||||||
let tables = thread_local(env);
|
|
||||||
|
|
||||||
let blocks = block_heights
|
|
||||||
.into_par_iter()
|
|
||||||
.map(|height| {
|
|
||||||
let tx_ro = tx_ro.get_or_try(|| env_inner.tx_ro())?;
|
|
||||||
let tables = get_tables!(env_inner, tx_ro, tables)?.as_ref();
|
|
||||||
get_block_complete_entry_from_height(&height, tables)
|
|
||||||
})
|
|
||||||
.collect::<DbResult<_>>()?;
|
|
||||||
|
|
||||||
let tx_ro = tx_ro.get_or_try(|| env_inner.tx_ro())?;
|
|
||||||
let tables = get_tables!(env_inner, tx_ro, tables)?.as_ref();
|
|
||||||
|
|
||||||
Ok(BlockchainResponse::BlockCompleteEntriesByHeight(blocks))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// [`BlockchainReadRequest::BlockExtendedHeader`].
|
/// [`BlockchainReadRequest::BlockExtendedHeader`].
|
||||||
#[inline]
|
#[inline]
|
||||||
fn block_extended_header(env: &ConcreteEnv, block_height: BlockHeight) -> ResponseResult {
|
fn block_extended_header(env: &ConcreteEnv, block_height: BlockHeight) -> ResponseResult {
|
||||||
|
@ -821,14 +792,3 @@ fn total_rct_outputs(env: &ConcreteEnv) -> ResponseResult {
|
||||||
|
|
||||||
Ok(BlockchainResponse::TotalRctOutputs(len))
|
Ok(BlockchainResponse::TotalRctOutputs(len))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [`BlockchainReadRequest::TxOutputIndexes`]
|
|
||||||
fn tx_output_indexes(env: &ConcreteEnv, tx_hash: &[u8; 32]) -> ResponseResult {
|
|
||||||
// Single-threaded, no `ThreadLocal` required.
|
|
||||||
let env_inner = env.env_inner();
|
|
||||||
let tx_ro = env_inner.tx_ro()?;
|
|
||||||
let tx_id = env_inner.open_db_ro::<TxIds>(&tx_ro)?.get(tx_hash)?;
|
|
||||||
let o_indexes = env_inner.open_db_ro::<TxOutputs>(&tx_ro)?.get(&tx_id)?;
|
|
||||||
|
|
||||||
Ok(BlockchainResponse::TxOutputIndexes(o_indexes.0))
|
|
||||||
}
|
|
||||||
|
|
|
@ -32,11 +32,6 @@ pub enum BlockchainReadRequest {
|
||||||
/// The input is the block hashes.
|
/// The input is the block hashes.
|
||||||
BlockCompleteEntries(Vec<[u8; 32]>),
|
BlockCompleteEntries(Vec<[u8; 32]>),
|
||||||
|
|
||||||
/// Request [`BlockCompleteEntry`]s.
|
|
||||||
///
|
|
||||||
/// The input is the block heights.
|
|
||||||
BlockCompleteEntriesByHeight(Vec<usize>),
|
|
||||||
|
|
||||||
/// Request a block's extended header.
|
/// Request a block's extended header.
|
||||||
///
|
///
|
||||||
/// The input is the block's height.
|
/// The input is the block's height.
|
||||||
|
@ -171,9 +166,6 @@ pub enum BlockchainReadRequest {
|
||||||
|
|
||||||
/// TODO
|
/// TODO
|
||||||
TotalRctOutputs,
|
TotalRctOutputs,
|
||||||
|
|
||||||
/// TODO
|
|
||||||
TxOutputIndexes { tx_hash: [u8; 32] },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- WriteRequest
|
//---------------------------------------------------------------------------------------------------- WriteRequest
|
||||||
|
@ -231,9 +223,6 @@ pub enum BlockchainResponse {
|
||||||
blockchain_height: usize,
|
blockchain_height: usize,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Response to [`BlockchainReadRequest::BlockCompleteEntriesByHeight`].
|
|
||||||
BlockCompleteEntriesByHeight(Vec<BlockCompleteEntry>),
|
|
||||||
|
|
||||||
/// Response to [`BlockchainReadRequest::BlockExtendedHeader`].
|
/// Response to [`BlockchainReadRequest::BlockExtendedHeader`].
|
||||||
///
|
///
|
||||||
/// Inner value is the extended headed of the requested block.
|
/// Inner value is the extended headed of the requested block.
|
||||||
|
@ -375,9 +364,6 @@ pub enum BlockchainResponse {
|
||||||
/// Response to [`BlockchainReadRequest::TotalRctOutputs`].
|
/// Response to [`BlockchainReadRequest::TotalRctOutputs`].
|
||||||
TotalRctOutputs(u64),
|
TotalRctOutputs(u64),
|
||||||
|
|
||||||
/// Response to [`BlockchainReadRequest::TxOutputIndexes`].
|
|
||||||
TxOutputIndexes(Vec<u64>),
|
|
||||||
|
|
||||||
//------------------------------------------------------ Writes
|
//------------------------------------------------------ Writes
|
||||||
/// A generic Ok response to indicate a request was successfully handled.
|
/// A generic Ok response to indicate a request was successfully handled.
|
||||||
///
|
///
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub use pool_info_extent::PoolInfoExtent;
|
||||||
pub use types::{
|
pub use types::{
|
||||||
AddAuxPow, AuxPow, BlockHeader, BlockOutputIndices, ChainInfo, CoinbaseTxSum, ConnectionInfo,
|
AddAuxPow, AuxPow, BlockHeader, BlockOutputIndices, ChainInfo, CoinbaseTxSum, ConnectionInfo,
|
||||||
FeeEstimate, GetBan, GetMinerDataTxBacklogEntry, GetOutputsOut, HardForkEntry, HardForkInfo,
|
FeeEstimate, GetBan, GetMinerDataTxBacklogEntry, GetOutputsOut, HardForkEntry, HardForkInfo,
|
||||||
HistogramEntry, MinerData, MinerDataTxBacklogEntry, OutputDistributionData,
|
HistogramEntry, MinerData, MinerDataTxBacklogEntry, OutKey, OutKeyBin, OutputDistributionData,
|
||||||
OutputHistogramEntry, OutputHistogramInput, Peer, PoolInfoFull, PoolInfoIncremental,
|
OutputHistogramEntry, OutputHistogramInput, Peer, PoolInfoFull, PoolInfoIncremental,
|
||||||
PoolTxInfo, PublicNode, SetBan, Span, SpentKeyImageInfo, SyncInfoPeer, TxBacklogEntry, TxInfo,
|
PoolTxInfo, PublicNode, SetBan, Span, SpentKeyImageInfo, SyncInfoPeer, TxBacklogEntry, TxInfo,
|
||||||
TxOutputIndices, TxpoolHisto, TxpoolStats,
|
TxOutputIndices, TxpoolHisto, TxpoolStats,
|
||||||
|
|
|
@ -308,6 +308,19 @@ define_struct_and_impl_epee! {
|
||||||
index: u64,
|
index: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc = monero_definition_link!(
|
||||||
|
"cc73fe71162d564ffda8e549b79a350bca53c454",
|
||||||
|
"rpc/core_rpc_server_commands_defs.h",
|
||||||
|
538..=553
|
||||||
|
)]
|
||||||
|
OutKeyBin {
|
||||||
|
key: [u8; 32],
|
||||||
|
mask: [u8; 32],
|
||||||
|
unlocked: bool,
|
||||||
|
height: u64,
|
||||||
|
txid: [u8; 32],
|
||||||
|
}
|
||||||
|
|
||||||
#[doc = monero_definition_link!(
|
#[doc = monero_definition_link!(
|
||||||
"cc73fe71162d564ffda8e549b79a350bca53c454",
|
"cc73fe71162d564ffda8e549b79a350bca53c454",
|
||||||
"rpc/core_rpc_server_commands_defs.h",
|
"rpc/core_rpc_server_commands_defs.h",
|
||||||
|
@ -406,6 +419,20 @@ define_struct_and_impl_epee! {
|
||||||
txs_total: u32,
|
txs_total: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc = monero_definition_link!(
|
||||||
|
"cc73fe71162d564ffda8e549b79a350bca53c454",
|
||||||
|
"rpc/core_rpc_server_commands_defs.h",
|
||||||
|
582..=597
|
||||||
|
)]
|
||||||
|
OutKey {
|
||||||
|
key: Hex<32>,
|
||||||
|
mask: Hex<32>,
|
||||||
|
unlocked: bool,
|
||||||
|
height: u64,
|
||||||
|
// Optionally empty with `/get_outs`'s `"get_txid": false`.
|
||||||
|
txid: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[doc = monero_definition_link!(
|
#[doc = monero_definition_link!(
|
||||||
"893916ad091a92e765ce3241b94e706ad012b62a",
|
"893916ad091a92e765ce3241b94e706ad012b62a",
|
||||||
"blockchain_db/lmdb/db_lmdb.cpp",
|
"blockchain_db/lmdb/db_lmdb.cpp",
|
||||||
|
|
Loading…
Reference in a new issue