sp_consensus/block_validation.rs
1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Block announcement validation.
19
20use crate::BlockStatus;
21use futures::FutureExt as _;
22use sp_runtime::traits::Block;
23use std::{error::Error, future::Future, pin::Pin, sync::Arc};
24
25/// A type which provides access to chain information.
26pub trait Chain<B: Block> {
27 /// Retrieve the status of the block denoted by the given [`Block::Hash`].
28 fn block_status(&self, hash: B::Hash) -> Result<BlockStatus, Box<dyn Error + Send>>;
29}
30
31impl<T: Chain<B>, B: Block> Chain<B> for Arc<T> {
32 fn block_status(&self, hash: B::Hash) -> Result<BlockStatus, Box<dyn Error + Send>> {
33 (&**self).block_status(hash)
34 }
35}
36
37/// Result of `BlockAnnounceValidator::validate`.
38#[derive(Debug, PartialEq, Eq)]
39pub enum Validation {
40 /// Valid block announcement.
41 Success {
42 /// Is this the new best block of the node?
43 is_new_best: bool,
44 },
45 /// Invalid block announcement.
46 Failure {
47 /// Should we disconnect from this peer?
48 ///
49 /// This should be used if the peer for example send junk to spam us.
50 disconnect: bool,
51 },
52}
53
54/// Type which checks incoming block announcements.
55pub trait BlockAnnounceValidator<B: Block> {
56 /// Validate the announced header and its associated data.
57 ///
58 /// # Note
59 ///
60 /// Returning [`Validation::Failure`] will lead to a decrease of the
61 /// peers reputation as it sent us invalid data.
62 ///
63 /// The returned future should only resolve to an error if there was an internal error
64 /// validating the block announcement. If the block announcement itself is invalid, this should
65 /// *always* return [`Validation::Failure`].
66 fn validate(
67 &mut self,
68 header: &B::Header,
69 data: &[u8],
70 ) -> Pin<Box<dyn Future<Output = Result<Validation, Box<dyn Error + Send>>> + Send>>;
71}
72
73/// Default implementation of `BlockAnnounceValidator`.
74#[derive(Debug)]
75pub struct DefaultBlockAnnounceValidator;
76
77impl<B: Block> BlockAnnounceValidator<B> for DefaultBlockAnnounceValidator {
78 fn validate(
79 &mut self,
80 _: &B::Header,
81 data: &[u8],
82 ) -> Pin<Box<dyn Future<Output = Result<Validation, Box<dyn Error + Send>>> + Send>> {
83 let is_empty = data.is_empty();
84
85 async move {
86 if !is_empty {
87 log::debug!(
88 target: "sync",
89 "Received unknown data alongside the block announcement.",
90 );
91 Ok(Validation::Failure { disconnect: true })
92 } else {
93 Ok(Validation::Success { is_new_best: false })
94 }
95 }
96 .boxed()
97 }
98}