// Copyright 2016 The Grin Developers // // 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. //! Base types that the block chain pipeline requires. use std::io; use util::secp::pedersen::Commitment; use grin_store as store; use core::core::{block, Block, BlockHeader, Output}; use core::core::hash::{Hash, Hashed}; use core::core::target::Difficulty; use core::ser; use grin_store; bitflags! { /// Options for block validation pub flags Options: u32 { /// None flag const NONE = 0b00000001, /// Runs without checking the Proof of Work, mostly to make testing easier. const SKIP_POW = 0b00000010, /// Adds block while in syncing mode. const SYNC = 0b00001000, } } /// Errors #[derive(Debug)] pub enum Error { /// The block doesn't fit anywhere in our chain Unfit(String), /// Special case of orphan blocks Orphan, /// Difficulty is too low either compared to ours or the block PoW hash DifficultyTooLow, /// Addition of difficulties on all previous block is wrong WrongTotalDifficulty, /// The proof of work is invalid InvalidPow, /// The block doesn't sum correctly or a tx signature is invalid InvalidBlockProof(block::Error), /// Block time is too old InvalidBlockTime, /// Block height is invalid (not previous + 1) InvalidBlockHeight, /// One of the root hashes in the block is invalid InvalidRoot, /// One of the inputs in the block has already been spent AlreadySpent(Commitment), /// An output with that commitment already exists (should be unique) DuplicateCommitment(Commitment), /// A kernel with that excess commitment already exists (should be unique) DuplicateKernel(Commitment), /// coinbase can only be spent after it has matured (n blocks) ImmatureCoinbase, /// output not found OutputNotFound, /// output spent OutputSpent, /// Invalid block version, either a mistake or outdated software InvalidBlockVersion(u16), /// Internal issue when trying to save or load data from store StoreErr(grin_store::Error, String), /// Error serializing or deserializing a type SerErr(ser::Error), /// Error while updating the sum trees SumTreeErr(String), /// No chain exists and genesis block is required GenesisBlockRequired, /// Anything else Other(String), } impl From for Error { fn from(e: grin_store::Error) -> Error { Error::StoreErr(e, "wrapped".to_owned()) } } impl From for Error { fn from(e: ser::Error) -> Error { Error::SerErr(e) } } impl From for Error { fn from(e: io::Error) -> Error { Error::SumTreeErr(e.to_string()) } } impl Error { /// Whether the error is due to a block that was intrinsically wrong pub fn is_bad_block(&self) -> bool { // shorter to match on all the "not the block's fault" errors match *self { Error::Unfit(_) | Error::Orphan | Error::StoreErr(_, _) | Error::SerErr(_) | Error::SumTreeErr(_)| Error::GenesisBlockRequired | Error::Other(_) => false, _ => true, } } } /// The tip of a fork. A handle to the fork ancestry from its leaf in the /// blockchain tree. References the max height and the latest and previous /// blocks /// for convenience and the total difficulty. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Tip { /// Height of the tip (max height of the fork) pub height: u64, /// Last block pushed to the fork pub last_block_h: Hash, /// Block previous to last pub prev_block_h: Hash, /// Total difficulty accumulated on that fork pub total_difficulty: Difficulty, } impl Tip { /// Creates a new tip at height zero and the provided genesis hash. pub fn new(gbh: Hash) -> Tip { Tip { height: 0, last_block_h: gbh, prev_block_h: gbh, total_difficulty: Difficulty::one(), } } /// Append a new block to this tip, returning a new updated tip. pub fn from_block(bh: &BlockHeader) -> Tip { Tip { height: bh.height, last_block_h: bh.hash(), prev_block_h: bh.previous, total_difficulty: bh.total_difficulty.clone(), } } } /// Serialization of a tip, required to save to datastore. impl ser::Writeable for Tip { fn write(&self, writer: &mut W) -> Result<(), ser::Error> { try!(writer.write_u64(self.height)); try!(writer.write_fixed_bytes(&self.last_block_h)); try!(writer.write_fixed_bytes(&self.prev_block_h)); self.total_difficulty.write(writer) } } impl ser::Readable for Tip { fn read(reader: &mut ser::Reader) -> Result { let height = try!(reader.read_u64()); let last = try!(Hash::read(reader)); let prev = try!(Hash::read(reader)); let diff = try!(Difficulty::read(reader)); Ok(Tip { height: height, last_block_h: last, prev_block_h: prev, total_difficulty: diff, }) } } /// Trait the chain pipeline requires an implementor for in order to process /// blocks. pub trait ChainStore: Send + Sync { /// Get the tip that's also the head of the chain fn head(&self) -> Result; /// Block header for the chain head fn head_header(&self) -> Result; /// Save the provided tip as the current head of our chain fn save_head(&self, t: &Tip) -> Result<(), store::Error>; /// Save the provided tip as the current head of the body chain, leaving the /// header chain alone. fn save_body_head(&self, t: &Tip) -> Result<(), store::Error>; /// Gets a block header by hash fn get_block(&self, h: &Hash) -> Result; /// Gets a block header by hash fn get_block_header(&self, h: &Hash) -> Result; /// Checks whether a block has been been processed and saved fn check_block_exists(&self, h: &Hash) -> Result; /// Save the provided block in store fn save_block(&self, b: &Block) -> Result<(), store::Error>; /// Save the provided block header in store fn save_block_header(&self, bh: &BlockHeader) -> Result<(), store::Error>; /// Get the tip of the header chain fn get_header_head(&self) -> Result; /// Save the provided tip as the current head of the block header chain fn save_header_head(&self, t: &Tip) -> Result<(), store::Error>; /// Get the tip of the current sync header chain fn get_sync_head(&self) -> Result; /// Save the provided tip as the current head of the sync header chain fn save_sync_head(&self, t: &Tip) -> Result<(), store::Error>; /// Reset header_head and sync_head to head of current body chain fn reset_head(&self) -> Result<(), store::Error>; /// Gets the block header at the provided height fn get_header_by_height(&self, height: u64) -> Result; /// Delete the block header at the height fn delete_header_by_height(&self, height: u64) -> Result<(), store::Error>; /// Is the block header on the current chain? /// Use the header_by_height index to verify the block header is where we think it is. fn is_on_current_chain(&self, header: &BlockHeader) -> Result<(), store::Error>; /// Gets an output by its commitment fn get_output_by_commit(&self, commit: &Commitment) -> Result; /// Gets a block_header for the given input commit fn get_block_header_by_output_commit( &self, commit: &Commitment, ) -> Result; /// Saves the position of an output, represented by its commitment, in the /// UTXO MMR. Used as an index for spending and pruning. fn save_output_pos(&self, commit: &Commitment, pos: u64) -> Result<(), store::Error>; /// Gets the position of an output, represented by its commitment, in the /// UTXO MMR. Used as an index for spending and pruning. fn get_output_pos(&self, commit: &Commitment) -> Result; /// Saves the position of a kernel, represented by its excess, in the /// UTXO MMR. Used as an index for spending and pruning. fn save_kernel_pos(&self, commit: &Commitment, pos: u64) -> Result<(), store::Error>; /// Gets the position of a kernel, represented by its excess, in the /// UTXO MMR. Used as an index for spending and pruning. fn get_kernel_pos(&self, commit: &Commitment) -> Result; /// Saves the provided block header at the corresponding height. Also check /// the consistency of the height chain in store by assuring previous /// headers are also at their respective heights. fn setup_height(&self, bh: &BlockHeader, old_tip: &Tip) -> Result<(), store::Error>; } /// Bridge between the chain pipeline and the rest of the system. Handles /// downstream processing of valid blocks by the rest of the system, most /// importantly the broadcasting of blocks to our peers. pub trait ChainAdapter { /// The blockchain pipeline has accepted this block as valid and added /// it to our chain. fn block_accepted(&self, b: &Block); } /// Dummy adapter used as a placeholder for real implementations pub struct NoopAdapter {} impl ChainAdapter for NoopAdapter { fn block_accepted(&self, _: &Block) {} }