// This file is part of Substrate. // Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Block evaluation and evaluation errors. use codec::Encode; use sp_runtime::traits::{Block as BlockT, CheckedConversion, Header as HeaderT, One}; // This is just a best effort to encode the number. None indicated that it's too big to encode // in a u128. type BlockNumber = Option; /// Result type alias. pub type Result = std::result::Result; /// Error type. #[derive(Debug, thiserror::Error)] pub enum Error { #[error("Failed to verify block encoding/decoding")] BadBlockCodec, /// Proposal provided not a block. #[error("Proposal provided not a block: decoding error: {0}")] BadProposalFormat(#[from] codec::Error), /// Proposal had wrong parent hash. #[error("Proposal had wrong parent hash. Expected {expected:?}, got {got:?}")] WrongParentHash { expected: String, got: String }, /// Proposal had wrong number. #[error("Proposal had wrong number. Expected {expected:?}, got {got:?}")] WrongNumber { expected: BlockNumber, got: BlockNumber }, } /// Attempt to evaluate a substrate block as a node block, returning error /// upon any initial validity checks failing. pub fn evaluate_initial( proposal: &Block, parent_hash: &::Hash, parent_number: <::Header as HeaderT>::Number, ) -> Result<()> { let encoded = Encode::encode(proposal); let block = Block::decode(&mut &encoded[..]).map_err(Error::BadProposalFormat)?; if &block != proposal { return Err(Error::BadBlockCodec) } if *parent_hash != *block.header().parent_hash() { return Err(Error::WrongParentHash { expected: format!("{:?}", *parent_hash), got: format!("{:?}", block.header().parent_hash()), }) } if parent_number + One::one() != *block.header().number() { return Err(Error::WrongNumber { expected: parent_number.checked_into::().map(|x| x + 1), got: (*block.header().number()).checked_into::(), }) } Ok(()) }