Skip to content

Commit d1e4a2a

Browse files
committed
classify validation errors by category, MEDIUM_BAN on hard-fork errors
1 parent 208eb28 commit d1e4a2a

3 files changed

Lines changed: 98 additions & 31 deletions

File tree

binaries/cuprated/src/blockchain/error.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use cuprate_blockchain::BlockchainError;
44
use cuprate_consensus::ExtendedConsensusError;
5-
use cuprate_consensus_rules::ConsensusError;
5+
use cuprate_consensus_rules::{blocks::BlockError, hard_forks::HardForkError, ConsensusError};
66
use cuprate_txpool::TxPoolError;
77
use cuprate_types::TxConversionError;
88

@@ -20,17 +20,21 @@ macro_rules! impl_internal_from {
2020
/// A validation failure - the peer should be banned.
2121
#[derive(Debug, thiserror::Error)]
2222
pub enum BlockValidationError {
23-
/// The block failed consensus validation.
23+
/// Invalid hard-fork rules.
2424
#[error(transparent)]
25-
Consensus(ExtendedConsensusError),
25+
HardFork(HardForkError),
26+
27+
/// Any other consensus rule violation.
28+
#[error(transparent)]
29+
Other(ExtendedConsensusError),
2630
}
2731

2832
/// An error from the blockchain manager's internal handlers.
2933
#[derive(Debug, thiserror::Error)]
3034
pub enum BlockManagerError {
3135
/// The peer sent us an invalid block; ban them.
3236
#[error(transparent)]
33-
Validation(#[from] BlockValidationError),
37+
Validation(BlockValidationError),
3438

3539
/// A node-side failure.
3640
#[error(transparent)]
@@ -39,16 +43,25 @@ pub enum BlockManagerError {
3943

4044
impl From<ExtendedConsensusError> for BlockManagerError {
4145
fn from(e: ExtendedConsensusError) -> Self {
42-
if let ExtendedConsensusError::DBErr(e) = e {
43-
return Self::Internal(e);
46+
match e {
47+
ExtendedConsensusError::DBErr(e) => Self::Internal(e),
48+
ExtendedConsensusError::ConErr(ConsensusError::Block(BlockError::HardForkError(e))) => {
49+
Self::Validation(BlockValidationError::HardFork(e))
50+
}
51+
52+
ExtendedConsensusError::ConErr(_)
53+
| ExtendedConsensusError::TxsIncludedWithBlockIncorrect
54+
| ExtendedConsensusError::OneOrMoreBatchVerificationStatementsInvalid
55+
| ExtendedConsensusError::NoBlocksToVerify => {
56+
Self::Validation(BlockValidationError::Other(e))
57+
}
4458
}
45-
BlockValidationError::Consensus(e).into()
4659
}
4760
}
4861

4962
impl From<ConsensusError> for BlockManagerError {
5063
fn from(e: ConsensusError) -> Self {
51-
BlockValidationError::Consensus(e.into()).into()
64+
ExtendedConsensusError::ConErr(e).into()
5265
}
5366
}
5467

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

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ use cuprate_consensus::{
2323
use cuprate_consensus_context::{BlockchainContext, NewBlockData};
2424
use cuprate_fast_sync::{block_to_verified_block_information, fast_sync_stop_height};
2525
use cuprate_helper::cast::usize_to_u64;
26-
use cuprate_p2p::{block_downloader::BlockBatch, constants::LONG_BAN, BroadcastRequest};
26+
use cuprate_p2p::{
27+
block_downloader::BlockBatch,
28+
constants::{LONG_BAN, MEDIUM_BAN},
29+
BroadcastRequest,
30+
};
2731
use cuprate_txpool::service::interface::TxpoolWriteRequest;
2832
use cuprate_types::{
2933
blockchain::{BlockchainReadRequest, BlockchainResponse, BlockchainWriteRequest},
@@ -246,15 +250,20 @@ impl super::BlockchainManager {
246250
{
247251
Ok(v) => v,
248252
Err(BlockManagerError::Internal(e)) => return Err(e),
249-
Err(BlockManagerError::Validation(_)) => {
250-
batch.peer_handle.ban_peer(LONG_BAN);
253+
Err(BlockManagerError::Validation(e)) => {
254+
let duration = match e {
255+
BlockValidationError::HardFork(_) => MEDIUM_BAN,
256+
BlockValidationError::Other(_) => LONG_BAN,
257+
};
258+
batch.peer_handle.ban_peer(duration);
251259
self.stop_current_block_downloader.notify_waiters();
252260
return Ok(());
253261
}
254262
};
255263

256264
for (block, txs) in prepped_blocks {
257265
let hash = block.block_hash;
266+
let block_version = block.hf_version.as_u8();
258267
let verified_block = match verify_prepped_main_chain_block(
259268
block,
260269
txs,
@@ -268,12 +277,27 @@ impl super::BlockchainManager {
268277
Ok(block) => block,
269278
Err(BlockManagerError::Internal(e)) => return Err(e),
270279
Err(BlockManagerError::Validation(e)) => {
271-
warn!(
272-
"Failed to verify block: {}, error {}, banning peer.",
273-
hex::encode(hash),
274-
e
275-
);
276-
batch.peer_handle.ban_peer(LONG_BAN);
280+
let duration = match e {
281+
BlockValidationError::HardFork(e) => {
282+
warn!(
283+
"Failed to verify block: {}, error {} (block v{}, current v{}), banning peer.",
284+
hex::encode(hash),
285+
e,
286+
block_version,
287+
self.blockchain_context_service.blockchain_context().current_hf.as_u8()
288+
);
289+
MEDIUM_BAN
290+
}
291+
BlockValidationError::Other(e) => {
292+
warn!(
293+
"Failed to verify block: {}, error {}, banning peer.",
294+
hex::encode(hash),
295+
e
296+
);
297+
LONG_BAN
298+
}
299+
};
300+
batch.peer_handle.ban_peer(duration);
277301
self.stop_current_block_downloader.notify_waiters();
278302
return Ok(());
279303
}
@@ -335,6 +359,7 @@ impl super::BlockchainManager {
335359

336360
while let Some((block, txs)) = blocks.next() {
337361
let hash = block.hash();
362+
let block_version = block.header.hardfork_version;
338363

339364
// async blocks work as try blocks.
340365
let res = async {
@@ -355,12 +380,27 @@ impl super::BlockchainManager {
355380
match res {
356381
Err(BlockManagerError::Internal(e)) => return Err(e),
357382
Err(BlockManagerError::Validation(e)) => {
358-
warn!(
359-
"Failed to verify block: {}, error {}, banning peer.",
360-
hex::encode(hash),
361-
e
362-
);
363-
batch.peer_handle.ban_peer(LONG_BAN);
383+
let duration = match e {
384+
BlockValidationError::HardFork(e) => {
385+
warn!(
386+
"Failed to verify block: {}, error {} (block v{}, current v{}), banning peer.",
387+
hex::encode(hash),
388+
e,
389+
block_version,
390+
self.blockchain_context_service.blockchain_context().current_hf.as_u8()
391+
);
392+
MEDIUM_BAN
393+
}
394+
BlockValidationError::Other(e) => {
395+
warn!(
396+
"Failed to verify block: {}, error {}, banning peer.",
397+
hex::encode(hash),
398+
e
399+
);
400+
LONG_BAN
401+
}
402+
};
403+
batch.peer_handle.ban_peer(duration);
364404
self.stop_current_block_downloader.notify_waiters();
365405
return Ok(());
366406
}

binaries/cuprated/src/p2p/request_handler.rs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use cuprate_helper::{
3030
};
3131
use cuprate_p2p::constants::{
3232
LONG_BAN, MAX_BLOCKS_IDS_IN_CHAIN_ENTRY, MAX_BLOCK_BATCH_LEN, MAX_TRANSACTION_BLOB_SIZE,
33+
MEDIUM_BAN,
3334
};
3435
use cuprate_p2p_core::{
3536
client::{InternalPeerID, PeerInformation},
@@ -46,7 +47,7 @@ use cuprate_wire::protocol::{
4647
};
4748

4849
use crate::{
49-
blockchain::{interface::BlockchainManagerHandle, IncomingBlockError},
50+
blockchain::{interface::BlockchainManagerHandle, BlockValidationError, IncomingBlockError},
5051
p2p::CrossNetworkInternalPeerId,
5152
txpool::{IncomingTxError, IncomingTxHandler, IncomingTxs},
5253
};
@@ -355,6 +356,7 @@ async fn new_fluffy_block<A: NetZoneAddress>(
355356
}
356357

357358
let block_hash = block.hash();
359+
let block_version = block.header.hardfork_version;
358360
let res = blockchain_manager
359361
.handle_incoming_block(
360362
block,
@@ -381,21 +383,33 @@ async fn new_fluffy_block<A: NetZoneAddress>(
381383
// Manager has exited (likely shutdown); drop silently.
382384
Ok(ProtocolResponse::NA)
383385
}
384-
Err(IncomingBlockError::Internal(e)) => {
385-
tracing::error!("Failed to handle incoming block: {e}");
386-
Ok(ProtocolResponse::NA)
387-
}
388-
Err(e) => {
389-
if matches!(e, IncomingBlockError::Validation(_)) {
386+
Err(IncomingBlockError::Validation(e)) => match e {
387+
BlockValidationError::HardFork(e) => {
388+
tracing::warn!(
389+
"Failed to verify block: {}, error {} (block v{}, current v{}), banning peer.",
390+
hex::encode(block_hash),
391+
e,
392+
block_version,
393+
context.current_hf.as_u8()
394+
);
395+
peer_information.handle.ban_peer(MEDIUM_BAN);
396+
Err(e.into())
397+
}
398+
BlockValidationError::Other(e) => {
390399
tracing::warn!(
391400
"Failed to verify block: {}, error {}, banning peer.",
392401
hex::encode(block_hash),
393402
e
394403
);
395404
peer_information.handle.ban_peer(LONG_BAN);
405+
Err(e.into())
396406
}
397-
Err(e.into())
407+
},
408+
Err(IncomingBlockError::Internal(e)) => {
409+
tracing::error!("Failed to handle incoming block: {e}");
410+
Ok(ProtocolResponse::NA)
398411
}
412+
Err(e) => Err(e.into()),
399413
}
400414
}
401415

0 commit comments

Comments
 (0)