2024-05-31 00:52:12 +00:00
|
|
|
//! Cuprate Consensus
|
|
|
|
//!
|
|
|
|
//! This crate contains 3 [`tower::Service`]s that implement Monero's consensus rules:
|
|
|
|
//!
|
|
|
|
//! - [`BlockChainContextService`] Which handles keeping the current state of the blockchain.
|
|
|
|
//! - [`BlockVerifierService`] Which handles block verification.
|
|
|
|
//! - [`TxVerifierService`] Which handles transaction verification.
|
|
|
|
//!
|
|
|
|
//! This crate is generic over the database which is implemented as a [`tower::Service`]. To
|
|
|
|
//! implement a database you need to have a service which accepts [`DatabaseRequest`] and responds
|
|
|
|
//! with [`DatabaseResponse`].
|
|
|
|
//!
|
2023-11-05 18:44:41 +00:00
|
|
|
use std::{
|
|
|
|
collections::{HashMap, HashSet},
|
|
|
|
future::Future,
|
|
|
|
};
|
2023-10-20 00:04:26 +00:00
|
|
|
|
2024-05-31 00:52:12 +00:00
|
|
|
use cuprate_consensus_rules::{transactions::OutputOnChain, ConsensusError, HardFork};
|
2023-12-16 23:03:02 +00:00
|
|
|
|
2023-12-27 23:50:18 +00:00
|
|
|
mod batch_verifier;
|
2023-09-28 11:21:06 +00:00
|
|
|
pub mod block;
|
2023-10-22 16:27:37 +00:00
|
|
|
pub mod context;
|
2023-10-28 23:39:22 +00:00
|
|
|
#[cfg(test)]
|
2024-01-19 00:34:30 +00:00
|
|
|
mod tests;
|
2023-10-20 00:04:26 +00:00
|
|
|
pub mod transactions;
|
2023-10-22 16:27:37 +00:00
|
|
|
|
2023-11-11 01:55:15 +00:00
|
|
|
pub use block::{
|
2024-05-31 00:52:12 +00:00
|
|
|
BlockVerifierService, PrePreparedBlock, VerifiedBlockInformation, VerifyBlockRequest,
|
|
|
|
VerifyBlockResponse,
|
2023-11-11 01:55:15 +00:00
|
|
|
};
|
2023-11-05 18:44:41 +00:00
|
|
|
pub use context::{
|
2023-12-02 22:57:34 +00:00
|
|
|
initialize_blockchain_context, BlockChainContext, BlockChainContextRequest,
|
2024-05-31 00:52:12 +00:00
|
|
|
BlockChainContextResponse, BlockChainContextService, ContextConfig,
|
2023-11-05 18:44:41 +00:00
|
|
|
};
|
2024-05-31 00:52:12 +00:00
|
|
|
pub use transactions::{TxVerifierService, VerifyTxRequest, VerifyTxResponse};
|
2023-10-22 16:27:37 +00:00
|
|
|
|
2024-05-31 00:52:12 +00:00
|
|
|
/// An Error returned from one of the consensus services.
|
2023-12-16 23:03:02 +00:00
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
pub enum ExtendedConsensusError {
|
2024-05-31 00:52:12 +00:00
|
|
|
/// A consensus error.
|
2023-12-16 23:03:02 +00:00
|
|
|
#[error("{0}")]
|
2024-05-31 00:52:12 +00:00
|
|
|
ConErr(#[from] ConsensusError),
|
|
|
|
/// A database error.
|
2023-12-16 23:03:02 +00:00
|
|
|
#[error("Database error: {0}")]
|
|
|
|
DBErr(#[from] tower::BoxError),
|
2024-05-31 00:52:12 +00:00
|
|
|
/// The transactions passed in with this block were not the ones needed.
|
2024-02-13 00:51:11 +00:00
|
|
|
#[error("The transactions passed in with the block are incorrect.")]
|
|
|
|
TxsIncludedWithBlockIncorrect,
|
2024-05-31 00:52:12 +00:00
|
|
|
/// One or more statements in the batch verifier was invalid.
|
|
|
|
#[error("One or more statements in the batch verifier was invalid.")]
|
|
|
|
OneOrMoreBatchVerificationStatementsInvalid,
|
2023-12-16 23:03:02 +00:00
|
|
|
}
|
|
|
|
|
2024-05-31 00:52:12 +00:00
|
|
|
/// Initialize the 2 verifier [`tower::Service`]s (block and transaction).
|
2024-02-13 00:51:11 +00:00
|
|
|
pub async fn initialize_verifier<D, Ctx>(
|
2023-10-22 16:27:37 +00:00
|
|
|
database: D,
|
2023-11-05 18:44:41 +00:00
|
|
|
ctx_svc: Ctx,
|
2023-10-22 16:27:37 +00:00
|
|
|
) -> Result<
|
|
|
|
(
|
2024-05-31 00:52:12 +00:00
|
|
|
BlockVerifierService<Ctx, TxVerifierService<D>, D>,
|
|
|
|
TxVerifierService<D>,
|
2023-10-22 16:27:37 +00:00
|
|
|
),
|
|
|
|
ConsensusError,
|
|
|
|
>
|
|
|
|
where
|
|
|
|
D: Database + Clone + Send + Sync + 'static,
|
|
|
|
D::Future: Send + 'static,
|
2023-11-05 18:44:41 +00:00
|
|
|
Ctx: tower::Service<
|
|
|
|
BlockChainContextRequest,
|
2023-12-02 22:57:34 +00:00
|
|
|
Response = BlockChainContextResponse,
|
2023-11-05 18:44:41 +00:00
|
|
|
Error = tower::BoxError,
|
|
|
|
> + Clone
|
|
|
|
+ Send
|
|
|
|
+ Sync
|
|
|
|
+ 'static,
|
|
|
|
Ctx::Future: Send + 'static,
|
2023-10-22 16:27:37 +00:00
|
|
|
{
|
2024-05-31 00:52:12 +00:00
|
|
|
let tx_svc = TxVerifierService::new(database.clone());
|
|
|
|
let block_svc = BlockVerifierService::new(ctx_svc, tx_svc.clone(), database);
|
2023-11-05 18:44:41 +00:00
|
|
|
Ok((block_svc, tx_svc))
|
2023-10-22 16:27:37 +00:00
|
|
|
}
|
2023-09-03 22:50:38 +00:00
|
|
|
|
2024-05-31 00:52:12 +00:00
|
|
|
/// An internal trait used to represent a database so we don't have to write [`tower::Service`] bounds
|
|
|
|
/// everywhere.
|
2023-09-03 22:50:38 +00:00
|
|
|
pub trait Database:
|
2024-05-31 00:52:12 +00:00
|
|
|
tower::Service<
|
|
|
|
DatabaseRequest,
|
|
|
|
Response = DatabaseResponse,
|
|
|
|
Error = tower::BoxError,
|
|
|
|
Future = Self::Future2,
|
|
|
|
>
|
2023-09-03 22:50:38 +00:00
|
|
|
{
|
2024-05-31 00:52:12 +00:00
|
|
|
type Future2: Future<Output = Result<Self::Response, Self::Error>> + Send + 'static;
|
2023-09-03 22:50:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: tower::Service<DatabaseRequest, Response = DatabaseResponse, Error = tower::BoxError>>
|
|
|
|
Database for T
|
2024-05-31 00:52:12 +00:00
|
|
|
where
|
|
|
|
T::Future: Future<Output = Result<Self::Response, Self::Error>> + Send + 'static,
|
2023-09-03 22:50:38 +00:00
|
|
|
{
|
2024-05-31 00:52:12 +00:00
|
|
|
type Future2 = T::Future;
|
2023-09-03 22:50:38 +00:00
|
|
|
}
|
|
|
|
|
2024-05-31 00:52:12 +00:00
|
|
|
/// An extended block header.
|
2023-10-22 16:27:37 +00:00
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
|
|
pub struct ExtendedBlockHeader {
|
2024-05-31 00:52:12 +00:00
|
|
|
/// The blocks major version.
|
2023-10-22 16:27:37 +00:00
|
|
|
pub version: HardFork,
|
2024-05-31 00:52:12 +00:00
|
|
|
/// The blocks vote.
|
2023-10-22 16:27:37 +00:00
|
|
|
pub vote: HardFork,
|
|
|
|
|
2024-05-31 00:52:12 +00:00
|
|
|
/// The blocks timestamp.
|
2023-10-22 16:27:37 +00:00
|
|
|
pub timestamp: u64,
|
2024-05-31 00:52:12 +00:00
|
|
|
/// The blocks cumulative difficulty.
|
2023-10-22 16:27:37 +00:00
|
|
|
pub cumulative_difficulty: u128,
|
|
|
|
|
2024-05-31 00:52:12 +00:00
|
|
|
/// The blocks weight.
|
2023-10-22 16:27:37 +00:00
|
|
|
pub block_weight: usize,
|
2024-05-31 00:52:12 +00:00
|
|
|
/// The blocks long term weight.
|
2023-10-22 16:27:37 +00:00
|
|
|
pub long_term_weight: usize,
|
|
|
|
}
|
|
|
|
|
2024-05-31 00:52:12 +00:00
|
|
|
/// A database request to the database [`tower::Service`]
|
2023-09-05 18:13:46 +00:00
|
|
|
#[derive(Debug, Clone)]
|
2023-09-03 22:50:38 +00:00
|
|
|
pub enum DatabaseRequest {
|
2024-05-31 00:52:12 +00:00
|
|
|
/// A block extended header request.
|
|
|
|
/// Must return: [`DatabaseResponse::BlockExtendedHeader`]
|
2024-01-22 01:56:34 +00:00
|
|
|
BlockExtendedHeader(u64),
|
2024-05-31 00:52:12 +00:00
|
|
|
/// A block hash request.
|
|
|
|
/// Must return: [`DatabaseResponse::BlockHash`]
|
2023-10-05 16:54:19 +00:00
|
|
|
BlockHash(u64),
|
2023-09-28 11:21:06 +00:00
|
|
|
|
2024-05-31 00:52:12 +00:00
|
|
|
/// Removes the block hashes that are not in the _main_ chain.
|
|
|
|
///
|
|
|
|
/// This should filter (remove) hashes in alt-blocks as well.
|
|
|
|
FilterUnknownHashes(HashSet<[u8; 32]>),
|
|
|
|
|
|
|
|
/// A request for multiple block extended headers.
|
|
|
|
/// Must return: [`DatabaseResponse::BlockExtendedHeaderInRange`]
|
2023-10-22 16:27:37 +00:00
|
|
|
BlockExtendedHeaderInRange(std::ops::Range<u64>),
|
2023-09-28 11:21:06 +00:00
|
|
|
|
2024-05-31 00:52:12 +00:00
|
|
|
/// A request for the chains height.
|
|
|
|
/// Must return: [`DatabaseResponse::ChainHeight`]
|
2023-09-03 22:50:38 +00:00
|
|
|
ChainHeight,
|
2024-05-31 00:52:12 +00:00
|
|
|
/// A request for the total amount of generated coins.
|
|
|
|
/// Must return: [`DatabaseResponse::GeneratedCoins`]
|
2023-10-23 18:14:40 +00:00
|
|
|
GeneratedCoins,
|
2023-10-03 21:10:31 +00:00
|
|
|
|
2024-05-31 00:52:12 +00:00
|
|
|
/// A request for transaction outputs, this contains a map of amounts to amount indexes.
|
|
|
|
/// Must return: [`DatabaseResponse::Outputs`]
|
2023-10-20 00:04:26 +00:00
|
|
|
Outputs(HashMap<u64, HashSet<u64>>),
|
2024-05-31 00:52:12 +00:00
|
|
|
/// A request for the number of outputs with these amounts.
|
|
|
|
/// Must return: [`DatabaseResponse::NumberOutputsWithAmount`]
|
2023-12-16 23:03:02 +00:00
|
|
|
NumberOutputsWithAmount(Vec<u64>),
|
2023-10-28 23:39:22 +00:00
|
|
|
|
2024-05-31 00:52:12 +00:00
|
|
|
/// A request to check if these key images are in the database.
|
|
|
|
/// Must return: [`DatabaseResponse::KeyImagesSpent`]
|
|
|
|
KeyImagesSpent(HashSet<[u8; 32]>),
|
2023-09-03 22:50:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum DatabaseResponse {
|
2024-05-31 00:52:12 +00:00
|
|
|
/// A block extended header response.
|
2023-10-22 16:27:37 +00:00
|
|
|
BlockExtendedHeader(ExtendedBlockHeader),
|
2024-05-31 00:52:12 +00:00
|
|
|
/// A block hash response.
|
2023-10-05 16:54:19 +00:00
|
|
|
BlockHash([u8; 32]),
|
2023-09-28 11:21:06 +00:00
|
|
|
|
2024-05-31 00:52:12 +00:00
|
|
|
FilteredHashes(HashSet<[u8; 32]>),
|
|
|
|
|
|
|
|
/// A batch block extended header response.
|
2023-10-22 16:27:37 +00:00
|
|
|
BlockExtendedHeaderInRange(Vec<ExtendedBlockHeader>),
|
2023-09-28 11:21:06 +00:00
|
|
|
|
2024-05-31 00:52:12 +00:00
|
|
|
/// A chain height response.
|
|
|
|
/// Should contains the chains height and top block hash.
|
2023-10-22 16:27:37 +00:00
|
|
|
ChainHeight(u64, [u8; 32]),
|
2024-05-31 00:52:12 +00:00
|
|
|
/// Generated coins response.
|
|
|
|
/// Should contain the total amount of coins emitted in all block rewards.
|
2023-10-23 18:14:40 +00:00
|
|
|
GeneratedCoins(u64),
|
2023-10-03 21:10:31 +00:00
|
|
|
|
2024-05-31 00:52:12 +00:00
|
|
|
/// Outputs response.
|
|
|
|
/// Should contain a map of (amounts, amount_idx) -> Output.
|
|
|
|
/// If an outputs requested does not exist this should *not* be an error, the output
|
|
|
|
/// should just be omitted from the map.
|
2023-10-22 16:27:37 +00:00
|
|
|
Outputs(HashMap<u64, HashMap<u64, OutputOnChain>>),
|
2024-05-31 00:52:12 +00:00
|
|
|
/// Number of outputs response.
|
|
|
|
/// Should contain a map of amounts -> numb outs.
|
|
|
|
/// If there are no outputs with that amount then the numb outs should be zero, *no* amounts
|
|
|
|
/// requested should be omitted.
|
2023-12-16 23:03:02 +00:00
|
|
|
NumberOutputsWithAmount(HashMap<u64, usize>),
|
2023-10-20 00:04:26 +00:00
|
|
|
|
2024-05-31 00:52:12 +00:00
|
|
|
/// Key images spent response.
|
2023-11-05 18:44:41 +00:00
|
|
|
/// returns true if key images are spent
|
2024-05-31 00:52:12 +00:00
|
|
|
KeyImagesSpent(bool),
|
2023-09-03 22:50:38 +00:00
|
|
|
}
|