mirror of
https://github.com/hinto-janai/cuprate.git
synced 2024-12-22 11:39:30 +00:00
/is_key_image_spent
This commit is contained in:
parent
c3bc9b26ec
commit
a359eed8be
15 changed files with 139 additions and 88 deletions
|
@ -11,7 +11,7 @@ use cuprate_helper::{
|
|||
cast::{u64_to_usize, usize_to_u64},
|
||||
map::split_u128_into_low_high_bits,
|
||||
};
|
||||
use cuprate_rpc_types::misc::{BlockHeader, KeyImageSpentStatus};
|
||||
use cuprate_rpc_types::misc::BlockHeader;
|
||||
use cuprate_types::HardFork;
|
||||
|
||||
use crate::{
|
||||
|
@ -166,18 +166,3 @@ pub(super) async fn top_height(state: &mut CupratedRpcHandler) -> Result<(u64, [
|
|||
let height = chain_height.saturating_sub(1);
|
||||
Ok((height, hash))
|
||||
}
|
||||
|
||||
/// Check if a key image is spent.
|
||||
pub(super) async fn key_image_spent(
|
||||
state: &mut CupratedRpcHandler,
|
||||
key_image: [u8; 32],
|
||||
) -> Result<KeyImageSpentStatus, Error> {
|
||||
todo!("impl key image vec check responding KeyImageSpentStatus")
|
||||
// if blockchain::key_image_spent(state, key_image).await? {
|
||||
// Ok(KeyImageSpentStatus::SpentInBlockchain)
|
||||
// } else if todo!("key image is spent in tx pool") {
|
||||
// Ok(KeyImageSpentStatus::SpentInPool)
|
||||
// } else {
|
||||
// Ok(KeyImageSpentStatus::Unspent)
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ use cuprate_hex::Hex;
|
|||
use cuprate_rpc_interface::RpcHandler;
|
||||
use cuprate_rpc_types::{
|
||||
base::{AccessResponseBase, ResponseBase},
|
||||
misc::{KeyImageSpentStatus, Status, TxEntry, TxEntryType},
|
||||
misc::{Status, TxEntry, TxEntryType},
|
||||
other::{
|
||||
GetAltBlocksHashesRequest, GetAltBlocksHashesResponse, GetHeightRequest, GetHeightResponse,
|
||||
GetLimitRequest, GetLimitResponse, GetNetStatsRequest, GetNetStatsResponse, GetOutsRequest,
|
||||
|
@ -33,7 +33,7 @@ use cuprate_rpc_types::{
|
|||
},
|
||||
};
|
||||
use cuprate_types::{
|
||||
rpc::{OutKey, PoolInfo, PoolTxInfo},
|
||||
rpc::{KeyImageSpentStatus, OutKey, PoolInfo, PoolTxInfo},
|
||||
TxInPool,
|
||||
};
|
||||
use monero_serai::transaction::Transaction;
|
||||
|
@ -127,10 +127,10 @@ async fn get_transactions(
|
|||
));
|
||||
}
|
||||
|
||||
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 (txs_in_blockchain, missed_txs) = {
|
||||
let requested_txs = request.txs_hashes.into_iter().map(|tx| tx.0).collect();
|
||||
blockchain::transactions(&mut state.blockchain_read, requested_txs).await?
|
||||
};
|
||||
|
||||
let missed_tx = missed_txs.clone().into_iter().map(Hex).collect();
|
||||
|
||||
|
@ -248,12 +248,18 @@ async fn get_transactions(
|
|||
|
||||
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L790-L815>
|
||||
async fn get_alt_blocks_hashes(
|
||||
state: CupratedRpcHandler,
|
||||
mut state: CupratedRpcHandler,
|
||||
request: GetAltBlocksHashesRequest,
|
||||
) -> Result<GetAltBlocksHashesResponse, Error> {
|
||||
let blks_hashes = blockchain::alt_chains(&mut state.blockchain_read)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|info| Hex(info.block_hash))
|
||||
.collect();
|
||||
|
||||
Ok(GetAltBlocksHashesResponse {
|
||||
base: AccessResponseBase::OK,
|
||||
..todo!()
|
||||
blks_hashes,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -262,16 +268,41 @@ async fn is_key_image_spent(
|
|||
mut state: CupratedRpcHandler,
|
||||
request: IsKeyImageSpentRequest,
|
||||
) -> Result<IsKeyImageSpentResponse, Error> {
|
||||
if state.is_restricted() && request.key_images.len() > RESTRICTED_SPENT_KEY_IMAGES_COUNT {
|
||||
let restricted = state.is_restricted();
|
||||
|
||||
if restricted && request.key_images.len() > RESTRICTED_SPENT_KEY_IMAGES_COUNT {
|
||||
return Err(anyhow!("Too many key images queried in restricted mode"));
|
||||
}
|
||||
|
||||
let mut spent_status = Vec::with_capacity(request.key_images.len());
|
||||
let key_images = request
|
||||
.key_images
|
||||
.into_iter()
|
||||
.map(|k| k.0)
|
||||
.collect::<Vec<[u8; 32]>>();
|
||||
|
||||
for key_image in request.key_images {
|
||||
let status = helper::key_image_spent(&mut state, key_image.0).await?;
|
||||
spent_status.push(status.to_u8());
|
||||
}
|
||||
let mut spent_status = Vec::with_capacity(key_images.len());
|
||||
|
||||
blockchain::key_images_spent(&mut state.blockchain_read, key_images.clone())
|
||||
.await?
|
||||
.into_iter()
|
||||
.for_each(|ki| {
|
||||
if ki {
|
||||
spent_status.push(KeyImageSpentStatus::SpentInBlockchain.to_u8());
|
||||
} else {
|
||||
spent_status.push(KeyImageSpentStatus::Unspent.to_u8());
|
||||
}
|
||||
});
|
||||
|
||||
txpool::key_images_spent(&mut state.txpool_read, key_images, !restricted)
|
||||
.await?
|
||||
.into_iter()
|
||||
.for_each(|ki| {
|
||||
if ki {
|
||||
spent_status.push(KeyImageSpentStatus::SpentInPool.to_u8());
|
||||
} else {
|
||||
spent_status.push(KeyImageSpentStatus::Unspent.to_u8());
|
||||
}
|
||||
});
|
||||
|
||||
Ok(IsKeyImageSpentResponse {
|
||||
base: AccessResponseBase::OK,
|
||||
|
|
|
@ -13,7 +13,9 @@ use cuprate_blockchain::service::BlockchainReadHandle;
|
|||
use cuprate_helper::cast::{u64_to_usize, usize_to_u64};
|
||||
use cuprate_types::{
|
||||
blockchain::{BlockchainReadRequest, BlockchainResponse},
|
||||
rpc::{ChainInfo, CoinbaseTxSum, OutputHistogramEntry, OutputHistogramInput},
|
||||
rpc::{
|
||||
ChainInfo, CoinbaseTxSum, KeyImageSpentStatus, OutputHistogramEntry, OutputHistogramInput,
|
||||
},
|
||||
Chain, ExtendedBlockHeader, OutputOnChain, TxInBlockchain,
|
||||
};
|
||||
|
||||
|
@ -221,9 +223,9 @@ pub(crate) async fn number_outputs_with_amount(
|
|||
/// [`BlockchainReadRequest::KeyImagesSpent`]
|
||||
pub(crate) async fn key_images_spent(
|
||||
blockchain_read: &mut BlockchainReadHandle,
|
||||
key_images: HashSet<[u8; 32]>,
|
||||
) -> Result<bool, Error> {
|
||||
let BlockchainResponse::KeyImagesSpent(is_spent) = blockchain_read
|
||||
key_images: Vec<[u8; 32]>,
|
||||
) -> Result<Vec<bool>, Error> {
|
||||
let BlockchainResponse::KeyImagesSpent(status) = blockchain_read
|
||||
.ready()
|
||||
.await?
|
||||
.call(BlockchainReadRequest::KeyImagesSpent(key_images))
|
||||
|
@ -232,7 +234,7 @@ pub(crate) async fn key_images_spent(
|
|||
unreachable!();
|
||||
};
|
||||
|
||||
Ok(is_spent)
|
||||
Ok(status)
|
||||
}
|
||||
|
||||
/// [`BlockchainReadRequest::CompactChainHistory`]
|
||||
|
@ -379,7 +381,7 @@ pub(crate) async fn alt_chain_count(
|
|||
/// [`BlockchainReadRequest::Transactions`].
|
||||
pub(crate) async fn transactions(
|
||||
blockchain_read: &mut BlockchainReadHandle,
|
||||
tx_hashes: BTreeSet<[u8; 32]>,
|
||||
tx_hashes: HashSet<[u8; 32]>,
|
||||
) -> Result<(Vec<TxInBlockchain>, Vec<[u8; 32]>), Error> {
|
||||
let BlockchainResponse::Transactions { txs, missed_txs } = blockchain_read
|
||||
.ready()
|
||||
|
|
|
@ -105,6 +105,29 @@ pub(crate) async fn txs_by_hash(
|
|||
Ok(txs_in_pool)
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub(crate) async fn key_images_spent(
|
||||
txpool_read: &mut TxpoolReadHandle,
|
||||
key_images: Vec<[u8; 32]>,
|
||||
include_sensitive_txs: bool,
|
||||
) -> Result<Vec<bool>, Error> {
|
||||
let TxpoolReadResponse::KeyImagesSpent(status) = txpool_read
|
||||
.ready()
|
||||
.await
|
||||
.map_err(|e| anyhow!(e))?
|
||||
.call(TxpoolReadRequest::KeyImagesSpent {
|
||||
key_images,
|
||||
include_sensitive_txs,
|
||||
})
|
||||
.await
|
||||
.map_err(|e| anyhow!(e))?
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
Ok(status)
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub(crate) async fn flush(
|
||||
txpool_manager: &mut Infallible,
|
||||
|
|
|
@ -232,16 +232,18 @@ where
|
|||
})
|
||||
})?;
|
||||
|
||||
let BlockchainResponse::KeyImagesSpent(kis_spent) = database
|
||||
let BlockchainResponse::KeyImagesSpent(kis_status) = database
|
||||
.ready()
|
||||
.await?
|
||||
.call(BlockchainReadRequest::KeyImagesSpent(spent_kis))
|
||||
.call(BlockchainReadRequest::KeyImagesSpent(
|
||||
spent_kis.into_iter().collect(),
|
||||
))
|
||||
.await?
|
||||
else {
|
||||
panic!("Database sent incorrect response!");
|
||||
};
|
||||
|
||||
if kis_spent {
|
||||
if kis_status.contains(&true) {
|
||||
tracing::debug!("One or more key images in batch already spent.");
|
||||
return Err(ConsensusError::Transaction(TransactionError::KeyImageSpent).into());
|
||||
}
|
||||
|
|
|
@ -45,7 +45,9 @@ fn dummy_database(outputs: BTreeMap<u64, OutputOnChain>) -> impl Database + Clon
|
|||
|
||||
BlockchainResponse::Outputs(ret)
|
||||
}
|
||||
BlockchainReadRequest::KeyImagesSpent(_) => BlockchainResponse::KeyImagesSpent(false),
|
||||
BlockchainReadRequest::KeyImagesSpent(_) => {
|
||||
BlockchainResponse::KeyImagesSpent(vec![false])
|
||||
}
|
||||
_ => panic!("Database request not needed for this test"),
|
||||
}))
|
||||
})
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
//---------------------------------------------------------------------------------------------------- Mod
|
||||
mod binary_string;
|
||||
mod distribution;
|
||||
mod key_image_spent_status;
|
||||
mod requested_info;
|
||||
mod status;
|
||||
mod tx_entry;
|
||||
|
@ -22,7 +21,6 @@ mod types;
|
|||
|
||||
pub use binary_string::BinaryString;
|
||||
pub use distribution::{Distribution, DistributionCompressedBinary, DistributionUncompressed};
|
||||
pub use key_image_spent_status::KeyImageSpentStatus;
|
||||
pub use requested_info::RequestedInfo;
|
||||
pub use status::Status;
|
||||
pub use tx_entry::{TxEntry, TxEntryType};
|
||||
|
|
|
@ -83,7 +83,7 @@ define_request_and_response! {
|
|||
},
|
||||
|
||||
AccessResponseBase {
|
||||
/// These [`u8`]s are [`crate::misc::KeyImageSpentStatus`].
|
||||
/// These [`u8`]s are [`cuprate_types::rpc::KeyImageSpentStatus`].
|
||||
spent_status: Vec<u8>,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
//---------------------------------------------------------------------------------------------------- Import
|
||||
use std::{
|
||||
cmp::min,
|
||||
collections::{BTreeSet, HashMap, HashSet},
|
||||
collections::{HashMap, HashSet},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
|
@ -507,7 +507,7 @@ fn number_outputs_with_amount(env: &ConcreteEnv, amounts: Vec<Amount>) -> Respon
|
|||
|
||||
/// [`BlockchainReadRequest::KeyImagesSpent`].
|
||||
#[inline]
|
||||
fn key_images_spent(env: &ConcreteEnv, key_images: HashSet<KeyImage>) -> ResponseResult {
|
||||
fn key_images_spent(env: &ConcreteEnv, key_images: Vec<KeyImage>) -> ResponseResult {
|
||||
// Prepare tx/tables in `ThreadLocal`.
|
||||
let env_inner = env.env_inner();
|
||||
let tx_ro = thread_local(env);
|
||||
|
@ -520,26 +520,13 @@ fn key_images_spent(env: &ConcreteEnv, key_images: HashSet<KeyImage>) -> Respons
|
|||
key_image_exists(&key_image, tables.key_images())
|
||||
};
|
||||
|
||||
// FIXME:
|
||||
// Create/use `enum cuprate_types::Exist { Does, DoesNot }`
|
||||
// or similar instead of `bool` for clarity.
|
||||
// <https://github.com/Cuprate/cuprate/pull/113#discussion_r1581536526>
|
||||
//
|
||||
// Collect results using `rayon`.
|
||||
match key_images
|
||||
.into_par_iter()
|
||||
.map(key_image_exists)
|
||||
// If the result is either:
|
||||
// `Ok(true)` => a key image was found, return early
|
||||
// `Err` => an error was found, return early
|
||||
//
|
||||
// Else, `Ok(false)` will continue the iterator.
|
||||
.find_any(|result| !matches!(result, Ok(false)))
|
||||
{
|
||||
None | Some(Ok(false)) => Ok(BlockchainResponse::KeyImagesSpent(false)), // Key image was NOT found.
|
||||
Some(Ok(true)) => Ok(BlockchainResponse::KeyImagesSpent(true)), // Key image was found.
|
||||
Some(Err(e)) => Err(e), // A database error occurred.
|
||||
}
|
||||
Ok(BlockchainResponse::KeyImagesSpent(
|
||||
key_images
|
||||
.into_par_iter()
|
||||
.map(key_image_exists)
|
||||
.collect::<DbResult<_>>()?,
|
||||
))
|
||||
}
|
||||
|
||||
/// [`BlockchainReadRequest::CompactChainHistory`]
|
||||
|
@ -786,7 +773,7 @@ fn alt_chain_count(env: &ConcreteEnv) -> ResponseResult {
|
|||
}
|
||||
|
||||
/// [`BlockchainReadRequest::Transactions`]
|
||||
fn transactions(env: &ConcreteEnv, tx_hashes: BTreeSet<[u8; 32]>) -> ResponseResult {
|
||||
fn transactions(env: &ConcreteEnv, tx_hashes: HashSet<[u8; 32]>) -> ResponseResult {
|
||||
Ok(BlockchainResponse::Transactions {
|
||||
txs: todo!(),
|
||||
missed_txs: todo!(),
|
||||
|
|
|
@ -179,8 +179,8 @@ async fn test_template(
|
|||
));
|
||||
|
||||
// Contains a fake non-spent key-image.
|
||||
let ki_req = HashSet::from([[0; 32]]);
|
||||
let ki_resp = Ok(BlockchainResponse::KeyImagesSpent(false));
|
||||
let ki_req = vec![[0; 32]];
|
||||
let ki_resp = Ok(BlockchainResponse::KeyImagesSpent(vec![false]));
|
||||
|
||||
//----------------------------------------------------------------------- Assert expected response
|
||||
// Assert read requests lead to the expected responses.
|
||||
|
@ -232,10 +232,13 @@ async fn test_template(
|
|||
// Assert each key image we inserted comes back as "spent".
|
||||
for key_image in tables.key_images_iter().keys().unwrap() {
|
||||
let key_image = key_image.unwrap();
|
||||
let request = BlockchainReadRequest::KeyImagesSpent(HashSet::from([key_image]));
|
||||
let request = BlockchainReadRequest::KeyImagesSpent(vec![key_image]);
|
||||
let response = reader.clone().oneshot(request).await;
|
||||
println!("response: {response:#?}, key_image: {key_image:#?}");
|
||||
assert_eq!(response.unwrap(), BlockchainResponse::KeyImagesSpent(true));
|
||||
assert_eq!(
|
||||
response.unwrap(),
|
||||
BlockchainResponse::KeyImagesSpent(vec![true])
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------- Output checks
|
||||
|
|
|
@ -5,7 +5,6 @@ use std::{
|
|||
collections::{HashMap, HashSet},
|
||||
num::NonZero,
|
||||
sync::Arc,
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use cuprate_types::{rpc::PoolInfo, TransactionVerificationData, TxInPool};
|
||||
|
@ -54,10 +53,17 @@ pub enum TxpoolReadRequest {
|
|||
start_time: Option<NonZero<usize>>,
|
||||
},
|
||||
|
||||
/// TODO
|
||||
TxsByHash {
|
||||
tx_hashes: Vec<[u8; 32]>,
|
||||
include_sensitive_txs: bool,
|
||||
},
|
||||
|
||||
/// TODO
|
||||
KeyImagesSpent {
|
||||
key_images: Vec<[u8; 32]>,
|
||||
include_sensitive_txs: bool,
|
||||
},
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- TxpoolReadResponse
|
||||
|
@ -103,6 +109,9 @@ pub enum TxpoolReadResponse {
|
|||
|
||||
/// Response to [`TxpoolReadRequest::TxsByHash`].
|
||||
TxsByHash(Vec<TxInPool>),
|
||||
|
||||
/// Response to [`TxpoolReadRequest::KeyImagesSpent`].
|
||||
KeyImagesSpent(Vec<bool>),
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- TxpoolWriteRequest
|
||||
|
|
|
@ -85,6 +85,10 @@ fn map_request(
|
|||
tx_hashes,
|
||||
include_sensitive_txs,
|
||||
} => txs_by_hash(env, tx_hashes, include_sensitive_txs),
|
||||
TxpoolReadRequest::KeyImagesSpent {
|
||||
key_images,
|
||||
include_sensitive_txs,
|
||||
} => key_images_spent(env, key_images, include_sensitive_txs),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,3 +240,12 @@ fn txs_by_hash(
|
|||
) -> ReadResponseResult {
|
||||
Ok(TxpoolReadResponse::TxsByHash(todo!()))
|
||||
}
|
||||
|
||||
/// [`TxpoolReadRequest::KeyImagesSpent`].
|
||||
fn key_images_spent(
|
||||
env: &ConcreteEnv,
|
||||
key_images: Vec<[u8; 32]>,
|
||||
include_sensitive_txs: bool,
|
||||
) -> ReadResponseResult {
|
||||
Ok(TxpoolReadResponse::KeyImagesSpent(todo!()))
|
||||
}
|
||||
|
|
|
@ -4,19 +4,18 @@
|
|||
//! responses are also tested in Cuprate's blockchain database crate.
|
||||
//---------------------------------------------------------------------------------------------------- Import
|
||||
use std::{
|
||||
collections::{BTreeSet, HashMap, HashSet},
|
||||
collections::{HashMap, HashSet},
|
||||
ops::Range,
|
||||
};
|
||||
|
||||
use monero_serai::block::Block;
|
||||
|
||||
use crate::{
|
||||
rpc::{ChainInfo, CoinbaseTxSum, OutputHistogramEntry, OutputHistogramInput},
|
||||
types::{Chain, ExtendedBlockHeader, OutputOnChain, TxsInBlock, VerifiedBlockInformation},
|
||||
AltBlockInformation, BlockCompleteEntry, ChainId, TxInBlockchain,
|
||||
};
|
||||
|
||||
use crate::rpc::{ChainInfo, CoinbaseTxSum, OutputHistogramEntry, OutputHistogramInput};
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- ReadRequest
|
||||
/// A read request to the blockchain database.
|
||||
///
|
||||
|
@ -94,10 +93,10 @@ pub enum BlockchainReadRequest {
|
|||
/// The input is a list of output amounts.
|
||||
NumberOutputsWithAmount(Vec<u64>),
|
||||
|
||||
/// Check that all key images within a set are not spent.
|
||||
/// Check the spend status of key images.
|
||||
///
|
||||
/// Input is a set of key images.
|
||||
KeyImagesSpent(HashSet<[u8; 32]>),
|
||||
KeyImagesSpent(Vec<[u8; 32]>),
|
||||
|
||||
/// A request for the compact chain history.
|
||||
CompactChainHistory,
|
||||
|
@ -163,7 +162,7 @@ pub enum BlockchainReadRequest {
|
|||
AltChainCount,
|
||||
|
||||
/// TODO
|
||||
Transactions { tx_hashes: BTreeSet<[u8; 32]> },
|
||||
Transactions { tx_hashes: HashSet<[u8; 32]> },
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- WriteRequest
|
||||
|
@ -271,11 +270,11 @@ pub enum BlockchainResponse {
|
|||
|
||||
/// Response to [`BlockchainReadRequest::KeyImagesSpent`].
|
||||
///
|
||||
/// The inner value is `true` if _any_ of the key images
|
||||
/// were spent (existed in the database already).
|
||||
/// Inner value is a `Vec` the same length as the input.
|
||||
///
|
||||
/// The inner value is `false` if _none_ of the key images were spent.
|
||||
KeyImagesSpent(bool),
|
||||
/// The index of each entry corresponds with the request.
|
||||
/// `true` means that the key image was spent.
|
||||
KeyImagesSpent(Vec<bool>),
|
||||
|
||||
/// Response to [`BlockchainReadRequest::CompactChainHistory`].
|
||||
CompactChainHistory {
|
||||
|
|
|
@ -12,12 +12,7 @@ use cuprate_epee_encoding::{
|
|||
};
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- KeyImageSpentStatus
|
||||
#[doc = crate::macros::monero_definition_link!(
|
||||
"cc73fe71162d564ffda8e549b79a350bca53c454",
|
||||
"rpc/core_rpc_server_commands_defs.h",
|
||||
456..=460
|
||||
)]
|
||||
/// Used in [`crate::other::IsKeyImageSpentResponse`].
|
||||
/// Used in RPC's `/is_key_image_spent`.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
|
||||
|
@ -32,7 +27,7 @@ impl KeyImageSpentStatus {
|
|||
/// Convert [`Self`] to a [`u8`].
|
||||
///
|
||||
/// ```rust
|
||||
/// use cuprate_rpc_types::misc::KeyImageSpentStatus as K;
|
||||
/// use cuprate_types::rpc::KeyImageSpentStatus as K;
|
||||
///
|
||||
/// assert_eq!(K::Unspent.to_u8(), 0);
|
||||
/// assert_eq!(K::SpentInBlockchain.to_u8(), 1);
|
||||
|
@ -52,7 +47,7 @@ impl KeyImageSpentStatus {
|
|||
/// This returns [`None`] if `u > 2`.
|
||||
///
|
||||
/// ```rust
|
||||
/// use cuprate_rpc_types::misc::KeyImageSpentStatus as K;
|
||||
/// use cuprate_types::rpc::KeyImageSpentStatus as K;
|
||||
///
|
||||
/// assert_eq!(K::from_u8(0), Some(K::Unspent));
|
||||
/// assert_eq!(K::from_u8(1), Some(K::SpentInBlockchain));
|
|
@ -5,10 +5,12 @@
|
|||
//! instead of `hash: String`, this module's types would use something like
|
||||
//! `hash: [u8; 32]`.
|
||||
|
||||
mod key_image_spent_status;
|
||||
mod pool_info;
|
||||
mod pool_info_extent;
|
||||
mod types;
|
||||
|
||||
pub use key_image_spent_status::KeyImageSpentStatus;
|
||||
pub use pool_info::PoolInfo;
|
||||
pub use pool_info_extent::PoolInfoExtent;
|
||||
pub use types::{
|
||||
|
|
Loading…
Reference in a new issue