Skip to content

Commit 3f28a29

Browse files
authored
Merge branch 'main' into hack
2 parents 372d5cc + b57ee2f commit 3f28a29

34 files changed

+1146
-90
lines changed

Cargo.lock

Lines changed: 32 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ cuprate-rpc-interface = { path = "rpc/interface" ,default-feature
8282
anyhow = { version = "1.0.89", default-features = false }
8383
async-trait = { version = "0.1.82", default-features = false }
8484
bitflags = { version = "2.6.0", default-features = false }
85+
blake3 = { version = "1", default-features = false }
8586
borsh = { version = "1.5.1", default-features = false }
8687
bytemuck = { version = "1.18.0", default-features = false }
8788
bytes = { version = "1.7.2", default-features = false }

binaries/cuprated/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ cuprate-levin = { workspace = true }
2121
cuprate-wire = { workspace = true }
2222
cuprate-p2p = { workspace = true }
2323
cuprate-p2p-core = { workspace = true }
24-
cuprate-dandelion-tower = { workspace = true }
24+
cuprate-dandelion-tower = { workspace = true, features = ["txpool"] }
2525
cuprate-async-buffer = { workspace = true }
2626
cuprate-address-book = { workspace = true }
2727
cuprate-blockchain = { workspace = true, features = ["service"] }

binaries/cuprated/src/blockchain.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ mod manager;
2525
mod syncer;
2626
mod types;
2727

28-
use types::{
28+
pub use types::{
2929
ConcreteBlockVerifierService, ConcreteTxVerifierService, ConsensusBlockchainReadHandle,
3030
};
3131

binaries/cuprated/src/blockchain/interface.rs

Lines changed: 60 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,16 @@ use std::{
88
};
99

1010
use monero_serai::{block::Block, transaction::Transaction};
11-
use rayon::prelude::*;
1211
use tokio::sync::{mpsc, oneshot};
1312
use tower::{Service, ServiceExt};
1413

1514
use cuprate_blockchain::service::BlockchainReadHandle;
1615
use cuprate_consensus::transactions::new_tx_verification_data;
17-
use cuprate_helper::cast::usize_to_u64;
18-
use cuprate_types::{
19-
blockchain::{BlockchainReadRequest, BlockchainResponse},
20-
Chain,
16+
use cuprate_txpool::service::{
17+
interface::{TxpoolReadRequest, TxpoolReadResponse},
18+
TxpoolReadHandle,
2119
};
20+
use cuprate_types::blockchain::{BlockchainReadRequest, BlockchainResponse};
2221

2322
use crate::{
2423
blockchain::manager::{BlockchainManagerCommand, IncomingBlockOk},
@@ -38,7 +37,7 @@ pub enum IncomingBlockError {
3837
///
3938
/// The inner values are the block hash and the indexes of the missing txs in the block.
4039
#[error("Unknown transactions in block.")]
41-
UnknownTransactions([u8; 32], Vec<u64>),
40+
UnknownTransactions([u8; 32], Vec<usize>),
4241
/// We are missing the block's parent.
4342
#[error("The block has an unknown parent.")]
4443
Orphan,
@@ -59,8 +58,9 @@ pub enum IncomingBlockError {
5958
/// - the block's parent is unknown
6059
pub async fn handle_incoming_block(
6160
block: Block,
62-
given_txs: Vec<Transaction>,
61+
mut given_txs: HashMap<[u8; 32], Transaction>,
6362
blockchain_read_handle: &mut BlockchainReadHandle,
63+
txpool_read_handle: &mut TxpoolReadHandle,
6464
) -> Result<IncomingBlockOk, IncomingBlockError> {
6565
/// A [`HashSet`] of block hashes that the blockchain manager is currently handling.
6666
///
@@ -72,7 +72,12 @@ pub async fn handle_incoming_block(
7272
/// which are also more expensive than `Mutex`s.
7373
static BLOCKS_BEING_HANDLED: LazyLock<Mutex<HashSet<[u8; 32]>>> =
7474
LazyLock::new(|| Mutex::new(HashSet::new()));
75-
// FIXME: we should look in the tx-pool for txs when that is ready.
75+
76+
if given_txs.len() > block.transactions.len() {
77+
return Err(IncomingBlockError::InvalidBlock(anyhow::anyhow!(
78+
"Too many transactions given for block"
79+
)));
80+
}
7681

7782
if !block_exists(block.header.previous, blockchain_read_handle)
7883
.await
@@ -90,23 +95,36 @@ pub async fn handle_incoming_block(
9095
return Ok(IncomingBlockOk::AlreadyHave);
9196
}
9297

93-
// TODO: remove this when we have a working tx-pool.
94-
if given_txs.len() != block.transactions.len() {
95-
return Err(IncomingBlockError::UnknownTransactions(
96-
block_hash,
97-
(0..usize_to_u64(block.transactions.len())).collect(),
98-
));
99-
}
98+
let TxpoolReadResponse::TxsForBlock { mut txs, missing } = txpool_read_handle
99+
.ready()
100+
.await
101+
.expect(PANIC_CRITICAL_SERVICE_ERROR)
102+
.call(TxpoolReadRequest::TxsForBlock(block.transactions.clone()))
103+
.await
104+
.expect(PANIC_CRITICAL_SERVICE_ERROR)
105+
else {
106+
unreachable!()
107+
};
100108

101-
// TODO: check we actually got given the right txs.
102-
let prepped_txs = given_txs
103-
.into_par_iter()
104-
.map(|tx| {
105-
let tx = new_tx_verification_data(tx)?;
106-
Ok((tx.tx_hash, tx))
107-
})
108-
.collect::<Result<_, anyhow::Error>>()
109-
.map_err(IncomingBlockError::InvalidBlock)?;
109+
if !missing.is_empty() {
110+
let needed_hashes = missing.iter().map(|index| block.transactions[*index]);
111+
112+
for needed_hash in needed_hashes {
113+
let Some(tx) = given_txs.remove(&needed_hash) else {
114+
// We return back the indexes of all txs missing from our pool, not taking into account the txs
115+
// that were given with the block, as these txs will be dropped. It is not worth it to try to add
116+
// these txs to the pool as this will only happen with a misbehaving peer or if the txpool reaches
117+
// the size limit.
118+
return Err(IncomingBlockError::UnknownTransactions(block_hash, missing));
119+
};
120+
121+
txs.insert(
122+
needed_hash,
123+
new_tx_verification_data(tx)
124+
.map_err(|e| IncomingBlockError::InvalidBlock(e.into()))?,
125+
);
126+
}
127+
}
110128

111129
let Some(incoming_block_tx) = COMMAND_TX.get() else {
112130
// We could still be starting up the blockchain manager.
@@ -119,28 +137,37 @@ pub async fn handle_incoming_block(
119137
return Ok(IncomingBlockOk::AlreadyHave);
120138
}
121139

122-
// From this point on we MUST not early return without removing the block hash from `BLOCKS_BEING_HANDLED`.
140+
// We must remove the block hash from `BLOCKS_BEING_HANDLED`.
141+
let _guard = {
142+
struct RemoveFromBlocksBeingHandled {
143+
block_hash: [u8; 32],
144+
}
145+
impl Drop for RemoveFromBlocksBeingHandled {
146+
fn drop(&mut self) {
147+
BLOCKS_BEING_HANDLED
148+
.lock()
149+
.unwrap()
150+
.remove(&self.block_hash);
151+
}
152+
}
153+
RemoveFromBlocksBeingHandled { block_hash }
154+
};
123155

124156
let (response_tx, response_rx) = oneshot::channel();
125157

126158
incoming_block_tx
127159
.send(BlockchainManagerCommand::AddBlock {
128160
block,
129-
prepped_txs,
161+
prepped_txs: txs,
130162
response_tx,
131163
})
132164
.await
133165
.expect("TODO: don't actually panic here, an err means we are shutting down");
134166

135-
let res = response_rx
167+
response_rx
136168
.await
137169
.expect("The blockchain manager will always respond")
138-
.map_err(IncomingBlockError::InvalidBlock);
139-
140-
// Remove the block hash from the blocks being handled.
141-
BLOCKS_BEING_HANDLED.lock().unwrap().remove(&block_hash);
142-
143-
res
170+
.map_err(IncomingBlockError::InvalidBlock)
144171
}
145172

146173
/// Check if we have a block with the given hash.

binaries/cuprated/src/blockchain/manager.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use cuprate_p2p::{
1818
BroadcastSvc, NetworkInterface,
1919
};
2020
use cuprate_p2p_core::ClearNet;
21+
use cuprate_txpool::service::TxpoolWriteHandle;
2122
use cuprate_types::{
2223
blockchain::{BlockchainReadRequest, BlockchainResponse},
2324
Chain, TransactionVerificationData,
@@ -46,6 +47,7 @@ pub async fn init_blockchain_manager(
4647
clearnet_interface: NetworkInterface<ClearNet>,
4748
blockchain_write_handle: BlockchainWriteHandle,
4849
blockchain_read_handle: BlockchainReadHandle,
50+
txpool_write_handle: TxpoolWriteHandle,
4951
mut blockchain_context_service: BlockChainContextService,
5052
block_verifier_service: ConcreteBlockVerifierService,
5153
block_downloader_config: BlockDownloaderConfig,
@@ -80,6 +82,7 @@ pub async fn init_blockchain_manager(
8082
let manager = BlockchainManager {
8183
blockchain_write_handle,
8284
blockchain_read_handle,
85+
txpool_write_handle,
8386
blockchain_context_service,
8487
cached_blockchain_context: blockchain_context.unchecked_blockchain_context().clone(),
8588
block_verifier_service,
@@ -102,6 +105,8 @@ pub struct BlockchainManager {
102105
blockchain_write_handle: BlockchainWriteHandle,
103106
/// A [`BlockchainReadHandle`].
104107
blockchain_read_handle: BlockchainReadHandle,
108+
/// A [`TxpoolWriteHandle`].
109+
txpool_write_handle: TxpoolWriteHandle,
105110
// TODO: Improve the API of the cache service.
106111
// TODO: rename the cache service -> `BlockchainContextService`.
107112
/// The blockchain context cache, this caches the current state of the blockchain to quickly calculate/retrieve

binaries/cuprated/src/blockchain/manager/handler.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
//! The blockchain manager handler functions.
22
use bytes::Bytes;
33
use futures::{TryFutureExt, TryStreamExt};
4-
use monero_serai::{block::Block, transaction::Transaction};
4+
use monero_serai::{
5+
block::Block,
6+
transaction::{Input, Transaction},
7+
};
58
use rayon::prelude::*;
69
use std::ops::ControlFlow;
710
use std::{collections::HashMap, sync::Arc};
@@ -17,16 +20,14 @@ use cuprate_consensus::{
1720
use cuprate_consensus_context::NewBlockData;
1821
use cuprate_helper::cast::usize_to_u64;
1922
use cuprate_p2p::{block_downloader::BlockBatch, constants::LONG_BAN, BroadcastRequest};
23+
use cuprate_txpool::service::interface::TxpoolWriteRequest;
2024
use cuprate_types::{
2125
blockchain::{BlockchainReadRequest, BlockchainResponse, BlockchainWriteRequest},
2226
AltBlockInformation, HardFork, TransactionVerificationData, VerifiedBlockInformation,
2327
};
2428

25-
use crate::blockchain::manager::commands::IncomingBlockOk;
2629
use crate::{
27-
blockchain::{
28-
manager::commands::BlockchainManagerCommand, types::ConsensusBlockchainReadHandle,
29-
},
30+
blockchain::manager::commands::{BlockchainManagerCommand, IncomingBlockOk},
3031
constants::PANIC_CRITICAL_SERVICE_ERROR,
3132
signals::REORG_LOCK,
3233
};
@@ -434,6 +435,18 @@ impl super::BlockchainManager {
434435
&mut self,
435436
verified_block: VerifiedBlockInformation,
436437
) {
438+
// FIXME: this is pretty inefficient, we should probably return the KI map created in the consensus crate.
439+
let spent_key_images = verified_block
440+
.txs
441+
.iter()
442+
.flat_map(|tx| {
443+
tx.tx.prefix().inputs.iter().map(|input| match input {
444+
Input::ToKey { key_image, .. } => key_image.compress().0,
445+
Input::Gen(_) => unreachable!(),
446+
})
447+
})
448+
.collect::<Vec<[u8; 32]>>();
449+
437450
self.blockchain_context_service
438451
.ready()
439452
.await
@@ -472,6 +485,14 @@ impl super::BlockchainManager {
472485
};
473486

474487
self.cached_blockchain_context = blockchain_context.unchecked_blockchain_context().clone();
488+
489+
self.txpool_write_handle
490+
.ready()
491+
.await
492+
.expect(PANIC_CRITICAL_SERVICE_ERROR)
493+
.call(TxpoolWriteRequest::NewBlock { spent_key_images })
494+
.await
495+
.expect(PANIC_CRITICAL_SERVICE_ERROR);
475496
}
476497
}
477498

binaries/cuprated/src/blockchain/syncer.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
// FIXME: This whole module is not great and should be rewritten when the PeerSet is made.
2-
use std::{pin::pin, sync::Arc, time::Duration};
2+
use std::{sync::Arc, time::Duration};
33

44
use futures::StreamExt;
5-
use tokio::time::interval;
65
use tokio::{
76
sync::{mpsc, Notify},
8-
time::sleep,
7+
time::interval,
98
};
109
use tower::{Service, ServiceExt};
1110
use tracing::instrument;

binaries/cuprated/src/blockchain/types.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
1-
use std::task::{Context, Poll};
2-
3-
use futures::future::BoxFuture;
4-
use futures::{FutureExt, TryFutureExt};
5-
use tower::{util::MapErr, Service};
1+
use tower::util::MapErr;
62

73
use cuprate_blockchain::{cuprate_database::RuntimeError, service::BlockchainReadHandle};
84
use cuprate_consensus::{BlockChainContextService, BlockVerifierService, TxVerifierService};
9-
use cuprate_p2p::block_downloader::{ChainSvcRequest, ChainSvcResponse};
10-
use cuprate_types::blockchain::{BlockchainReadRequest, BlockchainResponse};
115

126
/// The [`BlockVerifierService`] with all generic types defined.
137
pub type ConcreteBlockVerifierService = BlockVerifierService<

binaries/cuprated/src/p2p.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@
22
//!
33
//! Will handle initiating the P2P and contains a protocol request handler.
44
5+
mod network_address;
56
pub mod request_handler;
7+
8+
pub use network_address::CrossNetworkInternalPeerId;

0 commit comments

Comments
 (0)