finish other draft

This commit is contained in:
hinto.janai 2024-12-16 17:56:27 -05:00
parent 805f475083
commit 0b3ee2d1d1
No known key found for this signature in database
GPG key ID: D47CE05FA175A499
5 changed files with 122 additions and 30 deletions

View file

@ -37,10 +37,10 @@ use cuprate_rpc_types::{
}, },
}; };
use cuprate_types::{ use cuprate_types::{
rpc::{KeyImageSpentStatus, OutKey, PoolInfo, PoolTxInfo}, rpc::{KeyImageSpentStatus, OutKey, PoolInfo, PoolTxInfo, PublicNode},
TxInPool, TxRelayChecks, TxInPool, TxRelayChecks,
}; };
use monero_serai::transaction::{Input, Transaction}; use monero_serai::transaction::{Input, Timelock, Transaction};
use crate::{ use crate::{
constants::UNSUPPORTED_RPC_CALL, constants::UNSUPPORTED_RPC_CALL,
@ -49,6 +49,7 @@ use crate::{
request::{blockchain, blockchain_context, blockchain_manager, txpool}, request::{blockchain, blockchain_context, blockchain_manager, txpool},
CupratedRpcHandler, CupratedRpcHandler,
}, },
statics::START_INSTANT_UNIX,
}; };
use super::request::address_book; use super::request::address_book;
@ -541,9 +542,12 @@ async fn get_limit(
mut state: CupratedRpcHandler, mut state: CupratedRpcHandler,
_: GetLimitRequest, _: GetLimitRequest,
) -> Result<GetLimitResponse, Error> { ) -> Result<GetLimitResponse, Error> {
todo!("waiting on p2p service");
Ok(GetLimitResponse { Ok(GetLimitResponse {
base: helper::response_base(false), base: helper::response_base(false),
..todo!() limit_down: todo!(),
limit_up: todo!(),
}) })
} }
@ -552,9 +556,12 @@ async fn set_limit(
mut state: CupratedRpcHandler, mut state: CupratedRpcHandler,
request: SetLimitRequest, request: SetLimitRequest,
) -> Result<SetLimitResponse, Error> { ) -> Result<SetLimitResponse, Error> {
todo!("waiting on p2p service");
Ok(SetLimitResponse { Ok(SetLimitResponse {
base: helper::response_base(false), base: helper::response_base(false),
..todo!() limit_down: todo!(),
limit_up: todo!(),
}) })
} }
@ -563,9 +570,11 @@ async fn out_peers(
mut state: CupratedRpcHandler, mut state: CupratedRpcHandler,
request: OutPeersRequest, request: OutPeersRequest,
) -> Result<OutPeersResponse, Error> { ) -> Result<OutPeersResponse, Error> {
todo!("waiting on p2p service");
Ok(OutPeersResponse { Ok(OutPeersResponse {
base: helper::response_base(false), base: helper::response_base(false),
..todo!() out_peers: todo!(),
}) })
} }
@ -574,9 +583,11 @@ async fn in_peers(
mut state: CupratedRpcHandler, mut state: CupratedRpcHandler,
request: InPeersRequest, request: InPeersRequest,
) -> Result<InPeersResponse, Error> { ) -> Result<InPeersResponse, Error> {
todo!("waiting on p2p service");
Ok(InPeersResponse { Ok(InPeersResponse {
base: helper::response_base(false), base: helper::response_base(false),
..todo!() in_peers: todo!(),
}) })
} }
@ -585,9 +596,15 @@ async fn get_net_stats(
mut state: CupratedRpcHandler, mut state: CupratedRpcHandler,
_: GetNetStatsRequest, _: GetNetStatsRequest,
) -> Result<GetNetStatsResponse, Error> { ) -> Result<GetNetStatsResponse, Error> {
todo!("waiting on p2p service");
Ok(GetNetStatsResponse { Ok(GetNetStatsResponse {
base: helper::response_base(false), base: helper::response_base(false),
..todo!() start_time: *START_INSTANT_UNIX,
total_packets_in: todo!(),
total_bytes_in: todo!(),
total_packets_out: todo!(),
total_bytes_out: todo!(),
}) })
} }
@ -600,7 +617,9 @@ async fn get_outs(
return Err(anyhow!("Too many outs requested")); return Err(anyhow!("Too many outs requested"));
} }
let outputs = {
let mut outputs = HashMap::<u64, HashSet<u64>>::with_capacity(request.outputs.len()); let mut outputs = HashMap::<u64, HashSet<u64>>::with_capacity(request.outputs.len());
for out in request.outputs { for out in request.outputs {
outputs outputs
.entry(out.amount) .entry(out.amount)
@ -610,22 +629,27 @@ async fn get_outs(
.or_insert_with(|| HashSet::from([out.index])); .or_insert_with(|| HashSet::from([out.index]));
} }
outputs
};
let outs = blockchain::outputs(&mut state.blockchain_read, outputs) let outs = blockchain::outputs(&mut state.blockchain_read, outputs)
.await? .await?
.into_iter() .into_iter()
.flat_map(|(amount, index_map)| { .flat_map(|(amount, index_map)| {
index_map.into_iter().map(|(index, out)| OutKey { index_map.into_iter().map(|(index, out)| OutKey {
key: todo!(), key: out.key.map_or(Hex([0; 32]), |e| Hex(e.compress().0)),
mask: todo!(), mask: Hex(out.commitment.compress().0),
unlocked: todo!(), unlocked: matches!(out.time_lock, Timelock::None),
height: usize_to_u64(out.height), height: usize_to_u64(out.height),
txid: todo!(), txid: if request.get_txid {
hex::encode(out.txid)
} else {
String::new()
},
}) })
}) })
.collect::<Vec<OutKey>>(); .collect::<Vec<OutKey>>();
// TODO: check txpool
Ok(GetOutsResponse { Ok(GetOutsResponse {
base: helper::response_base(false), base: helper::response_base(false),
outs, outs,
@ -651,9 +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),
..todo!() tx_hashes,
}) })
} }
@ -662,9 +697,37 @@ async fn get_public_nodes(
mut state: CupratedRpcHandler, mut state: CupratedRpcHandler,
request: GetPublicNodesRequest, request: GetPublicNodesRequest,
) -> Result<GetPublicNodesResponse, Error> { ) -> Result<GetPublicNodesResponse, Error> {
let (white, gray) = address_book::peerlist::<ClearNet>(&mut DummyAddressBook).await?;
fn map(peers: Vec<cuprate_types::rpc::Peer>) -> Vec<PublicNode> {
peers
.into_iter()
.map(|peer| {
let cuprate_types::rpc::Peer {
host,
rpc_port,
rpc_credits_per_hash,
last_seen,
..
} = peer;
PublicNode {
host,
rpc_port,
rpc_credits_per_hash,
last_seen,
}
})
.collect()
}
let white = map(white);
let gray = map(gray);
Ok(GetPublicNodesResponse { Ok(GetPublicNodesResponse {
base: helper::response_base(false), base: helper::response_base(false),
..todo!() white,
gray,
}) })
} }

View file

@ -78,6 +78,7 @@ macro_rules! test_verify_valid_v2_tx {
key: CompressedEdwardsY::from_slice(&hex_literal::hex!($ring_member)) key: CompressedEdwardsY::from_slice(&hex_literal::hex!($ring_member))
.unwrap() .unwrap()
.decompress(), .decompress(),
txid: [0; 32],
}),)+)+ }),)+)+
]; ];
@ -107,6 +108,7 @@ macro_rules! test_verify_valid_v2_tx {
key: CompressedEdwardsY::from_slice(&hex_literal::hex!($ring_member)) key: CompressedEdwardsY::from_slice(&hex_literal::hex!($ring_member))
.unwrap() .unwrap()
.decompress(), .decompress(),
txid: [0; 32],
}),)+)+ }),)+)+
]; ];

View file

@ -7,13 +7,13 @@ use monero_serai::transaction::Timelock;
use cuprate_database::{ use cuprate_database::{
DbResult, RuntimeError, {DatabaseRo, DatabaseRw}, DbResult, RuntimeError, {DatabaseRo, DatabaseRw},
}; };
use cuprate_helper::crypto::compute_zero_commitment; use cuprate_helper::{cast::u32_to_usize, crypto::compute_zero_commitment};
use cuprate_helper::map::u64_to_timelock; use cuprate_helper::{cast::u64_to_usize, map::u64_to_timelock};
use cuprate_types::OutputOnChain; use cuprate_types::OutputOnChain;
use crate::{ use crate::{
ops::macros::{doc_add_block_inner_invariant, doc_error}, ops::macros::{doc_add_block_inner_invariant, doc_error},
tables::{Outputs, RctOutputs, Tables, TablesMut, TxUnlockTime}, tables::{BlockTxsHashes, Outputs, RctOutputs, Tables, TablesMut, TxUnlockTime},
types::{Amount, AmountIndex, Output, OutputFlags, PreRctOutputId, RctOutput}, types::{Amount, AmountIndex, Output, OutputFlags, PreRctOutputId, RctOutput},
}; };
@ -153,6 +153,7 @@ pub fn output_to_output_on_chain(
output: &Output, output: &Output,
amount: Amount, amount: Amount,
table_tx_unlock_time: &impl DatabaseRo<TxUnlockTime>, table_tx_unlock_time: &impl DatabaseRo<TxUnlockTime>,
table_block_txs_hashes: &impl DatabaseRo<BlockTxsHashes>,
) -> DbResult<OutputOnChain> { ) -> DbResult<OutputOnChain> {
let commitment = compute_zero_commitment(amount); let commitment = compute_zero_commitment(amount);
@ -169,11 +170,18 @@ pub fn output_to_output_on_chain(
.map(|y| y.decompress()) .map(|y| y.decompress())
.unwrap_or(None); .unwrap_or(None);
let txid = {
let height = u32_to_usize(output.height);
let tx_idx = u64_to_usize(output.tx_idx);
table_block_txs_hashes.get(&height)?[tx_idx]
};
Ok(OutputOnChain { Ok(OutputOnChain {
height: output.height as usize, height: output.height as usize,
time_lock, time_lock,
key, key,
commitment, commitment,
txid,
}) })
} }
@ -189,6 +197,7 @@ pub fn output_to_output_on_chain(
pub fn rct_output_to_output_on_chain( pub fn rct_output_to_output_on_chain(
rct_output: &RctOutput, rct_output: &RctOutput,
table_tx_unlock_time: &impl DatabaseRo<TxUnlockTime>, table_tx_unlock_time: &impl DatabaseRo<TxUnlockTime>,
table_block_txs_hashes: &impl DatabaseRo<BlockTxsHashes>,
) -> DbResult<OutputOnChain> { ) -> DbResult<OutputOnChain> {
// INVARIANT: Commitments stored are valid when stored by the database. // INVARIANT: Commitments stored are valid when stored by the database.
let commitment = CompressedEdwardsY::from_slice(&rct_output.commitment) let commitment = CompressedEdwardsY::from_slice(&rct_output.commitment)
@ -209,11 +218,18 @@ pub fn rct_output_to_output_on_chain(
.map(|y| y.decompress()) .map(|y| y.decompress())
.unwrap_or(None); .unwrap_or(None);
let txid = {
let height = u32_to_usize(rct_output.height);
let tx_idx = u64_to_usize(rct_output.tx_idx);
table_block_txs_hashes.get(&height)?[tx_idx]
};
Ok(OutputOnChain { Ok(OutputOnChain {
height: rct_output.height as usize, height: rct_output.height as usize,
time_lock, time_lock,
key, key,
commitment, commitment,
txid,
}) })
} }
@ -225,14 +241,22 @@ pub fn id_to_output_on_chain(id: &PreRctOutputId, tables: &impl Tables) -> DbRes
// v2 transactions. // v2 transactions.
if id.amount == 0 { if id.amount == 0 {
let rct_output = get_rct_output(&id.amount_index, tables.rct_outputs())?; let rct_output = get_rct_output(&id.amount_index, tables.rct_outputs())?;
let output_on_chain = rct_output_to_output_on_chain(&rct_output, tables.tx_unlock_time())?; let output_on_chain = rct_output_to_output_on_chain(
&rct_output,
tables.tx_unlock_time(),
tables.block_txs_hashes(),
)?;
Ok(output_on_chain) Ok(output_on_chain)
} else { } else {
// v1 transactions. // v1 transactions.
let output = get_output(id, tables.outputs())?; let output = get_output(id, tables.outputs())?;
let output_on_chain = let output_on_chain = output_to_output_on_chain(
output_to_output_on_chain(&output, id.amount, tables.tx_unlock_time())?; &output,
id.amount,
tables.tx_unlock_time(),
tables.block_txs_hashes(),
)?;
Ok(output_on_chain) Ok(output_on_chain)
} }

View file

@ -429,7 +429,8 @@ define_struct_and_impl_epee! {
mask: Hex<32>, mask: Hex<32>,
unlocked: bool, unlocked: bool,
height: u64, height: u64,
txid: Hex<32>, // Optionally empty with `/get_outs`'s `"get_txid": false`.
txid: String,
} }
#[doc = monero_definition_link!( #[doc = monero_definition_link!(

View file

@ -145,6 +145,8 @@ pub struct OutputOnChain {
pub key: Option<EdwardsPoint>, pub key: Option<EdwardsPoint>,
/// The output's commitment. /// The output's commitment.
pub commitment: EdwardsPoint, pub commitment: EdwardsPoint,
/// The transaction ID this output belongs to.
pub txid: [u8; 32],
} }
/// The inner response for a request for txs in a block. /// The inner response for a request for txs in a block.