Skip to content

Commit 97e5395

Browse files
hinto-janaiBoog900
andauthored
rpc: submit_block + /send_raw_transaction (#515)
* enable `submit_block` and `/send_raw_transaction` * endpoint * map * not_relayed * book * log * Update binaries/cuprated/src/rpc/service/tx_handler.rs Co-authored-by: Boog900 <boog900@tutanota.com> * review * fix --------- Co-authored-by: Boog900 <boog900@tutanota.com>
1 parent d43e095 commit 97e5395

12 files changed

Lines changed: 198 additions & 43 deletions

File tree

binaries/cuprated/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ fn main() {
162162
blockchain_read_handle,
163163
context_svc.clone(),
164164
txpool_read_handle,
165+
tx_handler,
165166
);
166167

167168
// Start the command listener.

binaries/cuprated/src/p2p/request_handler.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,12 @@ where
401401
.ready()
402402
.await
403403
.expect(PANIC_CRITICAL_SERVICE_ERROR)
404-
.call(IncomingTxs { txs, state })
404+
.call(IncomingTxs {
405+
txs,
406+
state,
407+
drop_relay_rule_errors: true,
408+
do_not_relay: false,
409+
})
405410
.await;
406411

407412
match res {

binaries/cuprated/src/rpc/handlers/json_rpc.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
//! <https://github.com/Cuprate/cuprate/pull/355>
66
77
use std::{
8+
collections::HashMap,
89
net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4},
910
num::NonZero,
1011
time::{Duration, Instant},
@@ -58,6 +59,7 @@ use cuprate_types::{
5859
};
5960

6061
use crate::{
62+
blockchain::interface as blockchain_interface,
6163
constants::VERSION_BUILD,
6264
rpc::{
6365
constants::{FIELD_NOT_SUPPORTED, UNSUPPORTED_RPC_CALL},
@@ -80,7 +82,7 @@ pub async fn map_request(
8082
Req::GetBlockTemplate(r) => Resp::GetBlockTemplate(not_available()?),
8183
Req::GetBlockCount(r) => Resp::GetBlockCount(get_block_count(state, r).await?),
8284
Req::OnGetBlockHash(r) => Resp::OnGetBlockHash(on_get_block_hash(state, r).await?),
83-
Req::SubmitBlock(r) => Resp::SubmitBlock(not_available()?),
85+
Req::SubmitBlock(r) => Resp::SubmitBlock(submit_block(state, r).await?),
8486
Req::GenerateBlocks(r) => Resp::GenerateBlocks(not_available()?),
8587
Req::GetLastBlockHeader(r) => {
8688
Resp::GetLastBlockHeader(get_last_block_header(state, r).await?)
@@ -234,7 +236,13 @@ async fn submit_block(
234236
let block_id = Hex(block.hash());
235237

236238
// Attempt to relay the block.
237-
blockchain_manager::relay_block(todo!(), Box::new(block)).await?;
239+
blockchain_interface::handle_incoming_block(
240+
block,
241+
HashMap::new(), // this function reads the txpool
242+
&mut state.blockchain_read,
243+
&mut state.txpool_read,
244+
)
245+
.await?;
238246

239247
Ok(SubmitBlockResponse {
240248
base: helper::response_base(false),

binaries/cuprated/src/rpc/handlers/other_json.rs

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use cuprate_constants::rpc::{
1616
MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT, RESTRICTED_SPENT_KEY_IMAGES_COUNT,
1717
RESTRICTED_TRANSACTIONS_COUNT,
1818
};
19+
use cuprate_dandelion_tower::TxState;
1920
use cuprate_helper::cast::usize_to_u64;
2021
use cuprate_hex::{Hex, HexVec};
2122
use cuprate_p2p_core::{client::handshaker::builder::DummyAddressBook, ClearNet};
@@ -49,11 +50,17 @@ use cuprate_types::{
4950
use crate::{
5051
rpc::{
5152
constants::UNSUPPORTED_RPC_CALL,
52-
handlers::{helper, shared, shared::not_available},
53-
service::{address_book, blockchain, blockchain_context, blockchain_manager, txpool},
53+
handlers::{
54+
helper,
55+
shared::{self, not_available},
56+
},
57+
service::{
58+
address_book, blockchain, blockchain_context, blockchain_manager, tx_handler, txpool,
59+
},
5460
CupratedRpcHandler,
5561
},
5662
statics::START_INSTANT_UNIX,
63+
txpool::IncomingTxs,
5764
};
5865

5966
/// Map a [`OtherRequest`] to the function that will lead to a [`OtherResponse`].
@@ -69,7 +76,9 @@ pub async fn map_request(
6976
Req::GetTransactions(r) => Resp::GetTransactions(not_available()?),
7077
Req::GetAltBlocksHashes(r) => Resp::GetAltBlocksHashes(not_available()?),
7178
Req::IsKeyImageSpent(r) => Resp::IsKeyImageSpent(not_available()?),
72-
Req::SendRawTransaction(r) => Resp::SendRawTransaction(not_available()?),
79+
Req::SendRawTransaction(r) => {
80+
Resp::SendRawTransaction(send_raw_transaction(state, r).await?)
81+
}
7382
Req::SaveBc(r) => Resp::SaveBc(not_available()?),
7483
Req::GetPeerList(r) => Resp::GetPeerList(not_available()?),
7584
Req::SetLogLevel(r) => Resp::SetLogLevel(not_available()?),
@@ -442,14 +451,32 @@ async fn send_raw_transaction(
442451
}
443452
}
444453

445-
// TODO: handle to txpool service.
446-
let tx_relay_checks =
447-
txpool::check_maybe_relay_local(todo!(), tx, !request.do_not_relay).await?;
454+
if state.is_restricted() && request.do_not_relay {
455+
// FIXME: implement something like `/check_tx` in `cuprated/monerod`.
456+
// boog900:
457+
// > making nodes hold txs in their pool that don't get passed
458+
// > around the network can cause issues, like targeted tx pool double spends
459+
// > there is also no reason to have this for public RPC
460+
return Err(anyhow!("do_not_relay is not supported on restricted RPC"));
461+
}
462+
463+
let txs = vec![tx.serialize().into()];
464+
465+
let mut txs = IncomingTxs {
466+
txs,
467+
state: TxState::Local,
468+
drop_relay_rule_errors: false,
469+
do_not_relay: request.do_not_relay,
470+
};
471+
472+
let tx_relay_checks = tx_handler::handle_incoming_txs(&mut state.tx_handler, txs).await?;
448473

449474
if tx_relay_checks.is_empty() {
450475
return Ok(resp);
451476
}
452477

478+
resp.not_relayed = true;
479+
453480
// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L124>
454481
fn add_reason(reasons: &mut String, reason: &'static str) {
455482
if !reasons.is_empty() {

binaries/cuprated/src/rpc/rpc_handler.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use cuprate_rpc_types::{
1919
use cuprate_txpool::service::TxpoolReadHandle;
2020
use cuprate_types::BlockTemplate;
2121

22-
use crate::rpc::handlers;
22+
use crate::{rpc::handlers, txpool::IncomingTxHandler};
2323

2424
/// TODO: use real type when public.
2525
#[derive(Clone)]
@@ -169,7 +169,8 @@ pub struct CupratedRpcHandler {
169169

170170
/// Read handle to the transaction pool database.
171171
pub txpool_read: TxpoolReadHandle,
172-
// TODO: handle to txpool service.
172+
173+
pub tx_handler: IncomingTxHandler,
173174
}
174175

175176
impl CupratedRpcHandler {
@@ -179,12 +180,14 @@ impl CupratedRpcHandler {
179180
blockchain_read: BlockchainReadHandle,
180181
blockchain_context: BlockchainContextService,
181182
txpool_read: TxpoolReadHandle,
183+
tx_handler: IncomingTxHandler,
182184
) -> Self {
183185
Self {
184186
restricted,
185187
blockchain_read,
186188
blockchain_context,
187189
txpool_read,
190+
tx_handler,
188191
}
189192
}
190193
}

binaries/cuprated/src/rpc/server.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use cuprate_txpool::service::TxpoolReadHandle;
1919
use crate::{
2020
config::RpcConfig,
2121
rpc::{rpc_handler::BlockchainManagerHandle, CupratedRpcHandler},
22+
txpool::IncomingTxHandler,
2223
};
2324

2425
/// Initialize the RPC server(s).
@@ -33,6 +34,7 @@ pub fn init_rpc_servers(
3334
blockchain_read: BlockchainReadHandle,
3435
blockchain_context: BlockchainContextService,
3536
txpool_read: TxpoolReadHandle,
37+
tx_handler: IncomingTxHandler,
3638
) {
3739
for ((enable, addr, request_byte_limit), restricted) in [
3840
(
@@ -76,6 +78,7 @@ pub fn init_rpc_servers(
7678
blockchain_read.clone(),
7779
blockchain_context.clone(),
7880
txpool_read.clone(),
81+
tx_handler.clone(),
7982
);
8083

8184
tokio::task::spawn(async move {
@@ -107,6 +110,8 @@ async fn run_rpc_server(
107110
let router = RouterBuilder::new()
108111
.json_rpc()
109112
.other_get_height()
113+
.other_send_raw_transaction()
114+
.other_sendrawtransaction()
110115
.fallback()
111116
.build()
112117
.with_state(rpc_handler);

binaries/cuprated/src/rpc/service.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ pub(super) mod address_book;
1616
pub(super) mod blockchain;
1717
pub(super) mod blockchain_context;
1818
pub(super) mod blockchain_manager;
19+
pub(super) mod tx_handler;
1920
pub(super) mod txpool;
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
use anyhow::{anyhow, Error};
2+
use cuprate_consensus::ExtendedConsensusError;
3+
use cuprate_consensus_rules::{transactions::TransactionError, ConsensusError};
4+
use tower::{Service, ServiceExt};
5+
6+
use cuprate_types::TxRelayChecks;
7+
8+
use crate::txpool::{IncomingTxError, IncomingTxHandler, IncomingTxs, RelayRuleError};
9+
10+
pub async fn handle_incoming_txs(
11+
tx_handler: &mut IncomingTxHandler,
12+
incoming_txs: IncomingTxs,
13+
) -> Result<TxRelayChecks, Error> {
14+
let resp = tx_handler
15+
.ready()
16+
.await
17+
.map_err(|e| anyhow!(e))?
18+
.call(incoming_txs)
19+
.await;
20+
21+
Ok(match resp {
22+
Ok(()) => TxRelayChecks::empty(),
23+
Err(e) => match e {
24+
IncomingTxError::Consensus(ExtendedConsensusError::ConErr(
25+
ConsensusError::Transaction(e),
26+
)) => match e {
27+
TransactionError::TooBig => TxRelayChecks::TOO_BIG,
28+
TransactionError::KeyImageSpent => TxRelayChecks::DOUBLE_SPEND,
29+
30+
TransactionError::OutputNotValidPoint
31+
| TransactionError::OutputTypeInvalid
32+
| TransactionError::ZeroOutputForV1
33+
| TransactionError::NonZeroOutputForV2
34+
| TransactionError::OutputsOverflow
35+
| TransactionError::OutputsTooHigh => TxRelayChecks::INVALID_OUTPUT,
36+
37+
TransactionError::MoreThanOneMixableInputWithUnmixable
38+
| TransactionError::InvalidNumberOfOutputs
39+
| TransactionError::InputDoesNotHaveExpectedNumbDecoys
40+
| TransactionError::IncorrectInputType
41+
| TransactionError::InputsAreNotOrdered
42+
| TransactionError::InputsOverflow
43+
| TransactionError::NoInputs => TxRelayChecks::INVALID_INPUT,
44+
45+
TransactionError::KeyImageIsNotInPrimeSubGroup
46+
| TransactionError::AmountNotDecomposed
47+
| TransactionError::DuplicateRingMember
48+
| TransactionError::OneOrMoreRingMembersLocked
49+
| TransactionError::RingMemberNotFoundOrInvalid
50+
| TransactionError::RingSignatureIncorrect
51+
| TransactionError::TransactionVersionInvalid
52+
| TransactionError::RingCTError(_) => return Err(anyhow!("unreachable")),
53+
},
54+
IncomingTxError::Parse(_) | IncomingTxError::Consensus(_) => {
55+
return Err(anyhow!("unreachable"))
56+
}
57+
IncomingTxError::RelayRule(RelayRuleError::NonZeroTimelock) => {
58+
TxRelayChecks::NONZERO_UNLOCK_TIME
59+
}
60+
IncomingTxError::RelayRule(RelayRuleError::ExtraFieldTooLarge) => {
61+
TxRelayChecks::TX_EXTRA_TOO_BIG
62+
}
63+
IncomingTxError::RelayRule(RelayRuleError::FeeBelowMinimum) => {
64+
TxRelayChecks::FEE_TOO_LOW
65+
}
66+
IncomingTxError::DuplicateTransaction => TxRelayChecks::DOUBLE_SPEND,
67+
},
68+
})
69+
}

binaries/cuprated/src/rpc/service/txpool.rs

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
//! Functions to send [`TxpoolReadRequest`]s.
22
3-
use std::{collections::HashSet, convert::Infallible, num::NonZero};
3+
use std::{
4+
collections::{HashMap, HashSet},
5+
convert::Infallible,
6+
num::NonZero,
7+
};
48

59
use anyhow::{anyhow, Error};
610
use monero_serai::transaction::Transaction;
@@ -17,7 +21,7 @@ use cuprate_txpool::{
1721
};
1822
use cuprate_types::{
1923
rpc::{PoolInfo, PoolInfoFull, PoolInfoIncremental, PoolTxInfo, TxpoolStats},
20-
TxInPool, TxRelayChecks,
24+
TransactionVerificationData, TxInPool, TxRelayChecks,
2125
};
2226

2327
// FIXME: use `anyhow::Error` over `tower::BoxError` in txpool.
@@ -222,6 +226,25 @@ pub async fn all_hashes(
222226
Ok(hashes)
223227
}
224228

229+
/// [`TxpoolReadRequest::TxsForBlock`]
230+
pub async fn txs_for_block(
231+
txpool_read: &mut TxpoolReadHandle,
232+
tx_hashes: Vec<[u8; 32]>,
233+
) -> Result<(HashMap<[u8; 32], TransactionVerificationData>, Vec<usize>), Error> {
234+
let TxpoolReadResponse::TxsForBlock { txs, missing } = txpool_read
235+
.ready()
236+
.await
237+
.map_err(|e| anyhow!(e))?
238+
.call(TxpoolReadRequest::TxsForBlock(tx_hashes))
239+
.await
240+
.map_err(|e| anyhow!(e))?
241+
else {
242+
unreachable!();
243+
};
244+
245+
Ok((txs, missing))
246+
}
247+
225248
/// TODO: impl txpool manager.
226249
pub async fn flush(txpool_manager: &mut Infallible, tx_hashes: Vec<[u8; 32]>) -> Result<(), Error> {
227250
todo!();
@@ -233,12 +256,3 @@ pub async fn relay(txpool_manager: &mut Infallible, tx_hashes: Vec<[u8; 32]>) ->
233256
todo!();
234257
Ok(())
235258
}
236-
237-
/// TODO: impl txpool manager.
238-
pub async fn check_maybe_relay_local(
239-
txpool_manager: &mut Infallible,
240-
tx: Transaction,
241-
relay: bool,
242-
) -> Result<TxRelayChecks, Error> {
243-
Ok(todo!())
244-
}

binaries/cuprated/src/txpool.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ mod relay_rules;
1212
mod txs_being_handled;
1313

1414
pub use incoming_tx::{IncomingTxError, IncomingTxHandler, IncomingTxs};
15+
pub use relay_rules::RelayRuleError;

0 commit comments

Comments
 (0)