2023-10-23 18:14:40 +00:00
|
|
|
use std::{
|
|
|
|
future::Future,
|
|
|
|
pin::Pin,
|
|
|
|
sync::Arc,
|
|
|
|
task::{Context, Poll},
|
|
|
|
};
|
2023-10-15 19:35:33 +00:00
|
|
|
|
2023-10-23 18:14:40 +00:00
|
|
|
use futures::FutureExt;
|
|
|
|
use monero_serai::{block::Block, transaction::Transaction};
|
|
|
|
use tower::{Service, ServiceExt};
|
2023-10-15 19:35:33 +00:00
|
|
|
|
2023-10-23 18:14:40 +00:00
|
|
|
use crate::{
|
|
|
|
context::{BlockChainContext, BlockChainContextRequest},
|
|
|
|
transactions::{TransactionVerificationData, VerifyTxRequest, VerifyTxResponse},
|
|
|
|
ConsensusError, HardFork,
|
|
|
|
};
|
2023-10-05 16:54:19 +00:00
|
|
|
|
2023-10-23 18:14:40 +00:00
|
|
|
mod hash_worker;
|
|
|
|
mod miner_tx;
|
2023-10-15 19:35:33 +00:00
|
|
|
|
2023-10-23 18:14:40 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct VerifiedBlockInformation {
|
|
|
|
pub block: Block,
|
|
|
|
pub hf_vote: HardFork,
|
|
|
|
pub txs: Vec<Arc<TransactionVerificationData>>,
|
|
|
|
pub block_hash: [u8; 32],
|
|
|
|
pub pow_hash: [u8; 32],
|
|
|
|
pub height: u64,
|
|
|
|
pub generated_coins: u64,
|
|
|
|
pub weight: usize,
|
|
|
|
pub long_term_weight: usize,
|
|
|
|
}
|
2023-10-15 19:35:33 +00:00
|
|
|
|
2023-10-23 18:14:40 +00:00
|
|
|
pub enum VerifyBlockRequest {
|
|
|
|
MainChainBatchSetupVerify(Block, Vec<Transaction>),
|
|
|
|
MainChain(Block, Vec<Arc<TransactionVerificationData>>),
|
2023-10-20 00:04:26 +00:00
|
|
|
}
|
|
|
|
|
2023-10-23 18:14:40 +00:00
|
|
|
pub enum VerifyBlockResponse {
|
|
|
|
MainChainBatchSetupVerify(),
|
2023-10-15 19:35:33 +00:00
|
|
|
}
|
|
|
|
|
2023-10-23 18:14:40 +00:00
|
|
|
// TODO: it is probably a bad idea for this to derive clone, if 2 places (RPC, P2P) receive valid but different blocks
|
|
|
|
// then they will both get approved but only one should go to main chain.
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct BlockVerifierService<C: Clone, Tx: Clone> {
|
|
|
|
context_svc: C,
|
|
|
|
tx_verifier_svc: Tx,
|
2023-10-15 19:35:33 +00:00
|
|
|
}
|
|
|
|
|
2023-10-23 18:14:40 +00:00
|
|
|
impl<C, Tx> BlockVerifierService<C, Tx>
|
|
|
|
where
|
|
|
|
C: Service<BlockChainContextRequest, Response = BlockChainContext> + Clone + Send + 'static,
|
|
|
|
Tx: Service<VerifyTxRequest, Response = VerifyTxResponse, Error = ConsensusError>
|
|
|
|
+ Clone
|
|
|
|
+ Send
|
|
|
|
+ 'static,
|
|
|
|
{
|
|
|
|
pub fn new(context_svc: C, tx_verifier_svc: Tx) -> BlockVerifierService<C, Tx> {
|
|
|
|
BlockVerifierService {
|
|
|
|
context_svc,
|
|
|
|
tx_verifier_svc,
|
|
|
|
}
|
2023-10-15 19:35:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-23 18:14:40 +00:00
|
|
|
impl<C, Tx> Service<VerifyBlockRequest> for BlockVerifierService<C, Tx>
|
|
|
|
where
|
|
|
|
C: Service<BlockChainContextRequest, Response = BlockChainContext, Error = tower::BoxError>
|
|
|
|
+ Clone
|
|
|
|
+ Send
|
|
|
|
+ 'static,
|
|
|
|
C::Future: Send + 'static,
|
|
|
|
Tx: Service<VerifyTxRequest, Response = VerifyTxResponse, Error = ConsensusError>
|
|
|
|
+ Clone
|
|
|
|
+ Send
|
|
|
|
+ 'static,
|
|
|
|
Tx::Future: Send + 'static,
|
|
|
|
{
|
|
|
|
type Response = VerifiedBlockInformation;
|
|
|
|
type Error = ConsensusError;
|
|
|
|
type Future =
|
|
|
|
Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + 'static>>;
|
|
|
|
|
|
|
|
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
|
|
futures::ready!(self.context_svc.poll_ready(cx)).map(Into::into)?;
|
|
|
|
self.tx_verifier_svc.poll_ready(cx)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn call(&mut self, req: VerifyBlockRequest) -> Self::Future {
|
|
|
|
let context_svc = self.context_svc.clone();
|
|
|
|
let tx_verifier_svc = self.tx_verifier_svc.clone();
|
|
|
|
|
|
|
|
async move {
|
|
|
|
match req {
|
|
|
|
VerifyBlockRequest::MainChainBatchSetupVerify(block, txs) => {
|
|
|
|
batch_setup_verify_main_chain_block(block, txs, context_svc, tx_verifier_svc)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
_ => todo!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.boxed()
|
2023-10-15 19:35:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-23 18:14:40 +00:00
|
|
|
async fn batch_setup_verify_main_chain_block<C, Tx>(
|
|
|
|
block: Block,
|
|
|
|
txs: Vec<Transaction>,
|
|
|
|
context_svc: C,
|
|
|
|
tx_verifier_svc: Tx,
|
|
|
|
) -> Result<VerifiedBlockInformation, ConsensusError>
|
|
|
|
where
|
|
|
|
C: Service<BlockChainContextRequest, Response = BlockChainContext, Error = tower::BoxError>
|
|
|
|
+ Send
|
|
|
|
+ 'static,
|
|
|
|
C::Future: Send + 'static,
|
|
|
|
Tx: Service<VerifyTxRequest, Response = VerifyTxResponse, Error = ConsensusError>,
|
|
|
|
{
|
|
|
|
tracing::info!("getting blockchain context");
|
|
|
|
let context = context_svc
|
|
|
|
.oneshot(BlockChainContextRequest)
|
|
|
|
.await
|
|
|
|
.map_err(Into::<ConsensusError>::into)?;
|
|
|
|
|
|
|
|
tracing::info!("got blockchain context: {:?}", context);
|
|
|
|
|
|
|
|
let txs = if !txs.is_empty() {
|
|
|
|
let VerifyTxResponse::BatchSetupOk(txs) = tx_verifier_svc
|
|
|
|
.oneshot(VerifyTxRequest::BatchSetupVerifyBlock {
|
|
|
|
txs,
|
|
|
|
current_chain_height: context.chain_height,
|
|
|
|
hf: context.current_hard_fork,
|
|
|
|
})
|
|
|
|
.await?
|
|
|
|
else {
|
|
|
|
panic!("tx verifier sent incorrect response!");
|
|
|
|
};
|
|
|
|
txs
|
2023-10-15 19:35:33 +00:00
|
|
|
} else {
|
2023-10-23 18:14:40 +00:00
|
|
|
vec![]
|
|
|
|
};
|
|
|
|
|
|
|
|
let block_weight = block.miner_tx.weight() + txs.iter().map(|tx| tx.tx_weight).sum::<usize>();
|
|
|
|
let total_fees = txs.iter().map(|tx| tx.fee).sum::<u64>();
|
|
|
|
|
|
|
|
let generated_coins = miner_tx::check_miner_tx(
|
|
|
|
&block.miner_tx,
|
|
|
|
total_fees,
|
|
|
|
context.chain_height,
|
|
|
|
block_weight,
|
|
|
|
context.median_weight_for_block_reward,
|
|
|
|
context.already_generated_coins,
|
|
|
|
&context.current_hard_fork,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
let hashing_blob = block.serialize_hashable();
|
|
|
|
|
|
|
|
let pow_hash = tokio::task::spawn_blocking(move || {
|
|
|
|
hash_worker::calculate_pow_hash(
|
|
|
|
&hashing_blob,
|
|
|
|
context.chain_height,
|
|
|
|
&context.current_hard_fork,
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.await
|
|
|
|
.unwrap()?;
|
|
|
|
|
|
|
|
Ok(VerifiedBlockInformation {
|
|
|
|
block_hash: block.hash(),
|
|
|
|
block,
|
|
|
|
txs,
|
|
|
|
pow_hash,
|
|
|
|
generated_coins,
|
|
|
|
weight: block_weight,
|
|
|
|
height: context.chain_height,
|
|
|
|
long_term_weight: 0,
|
|
|
|
hf_vote: HardFork::V1,
|
|
|
|
})
|
2023-10-15 19:35:33 +00:00
|
|
|
}
|