diff --git a/examples/counter/src/main.rs b/examples/counter/src/main.rs index 2db0fc1..b7b4e1d 100644 --- a/examples/counter/src/main.rs +++ b/examples/counter/src/main.rs @@ -3,302 +3,373 @@ extern crate parity_codec_derive as codec_derive; mod runtime; +use crate::runtime::{Block, Executor, Extrinsic}; use blockchain::backend::MemoryBackend; -use blockchain::chain::{SharedBackend, BlockBuilder}; +use blockchain::chain::{BlockBuilder, SharedBackend}; use blockchain::traits::{Block as BlockT, ChainQuery}; -use libp2p::{secio, NetworkBehaviour}; +use codec::{Decode, Encode}; +use codec_derive::{Decode, Encode}; +use futures::{ + sink::Sink, + stream::Stream, + sync::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}, + Async, +}; +use libp2p::core::swarm::NetworkBehaviourEventProcess; use libp2p::floodsub::{Floodsub, Topic, TopicBuilder}; use libp2p::kad::Kademlia; -use libp2p::core::swarm::NetworkBehaviourEventProcess; -use futures::{Async, sink::Sink, stream::Stream, sync::mpsc::{UnboundedSender, UnboundedReceiver, unbounded}}; -use codec::{Encode, Decode}; -use codec_derive::{Encode, Decode}; -use std::thread; -use std::time::Duration; +use libp2p::{secio, NetworkBehaviour}; +use primitive_types::H256; use std::collections::HashMap; use std::sync::{Arc, Mutex}; +use std::thread; +use std::time::Duration; use tokio_io::{AsyncRead, AsyncWrite}; -use primitive_types::H256; -use crate::runtime::{Block, Executor, Extrinsic}; #[derive(NetworkBehaviour)] struct CounterBehaviour<TSubstream: AsyncRead + AsyncWrite> { - floodsub: Floodsub<TSubstream>, - kademlia: Kademlia<TSubstream>, - - #[behaviour(ignore)] - sender: Option<UnboundedSender<Block>>, - #[behaviour(ignore)] - backend: SharedBackend<Block, (), MemoryBackend<Block, ()>>, - #[behaviour(ignore)] - topic: Topic, - #[behaviour(ignore)] - pending_transactions: Option<Arc<Mutex<Vec<Extrinsic>>>> + floodsub: Floodsub<TSubstream>, + kademlia: Kademlia<TSubstream>, + + #[behaviour(ignore)] + sender: Option<UnboundedSender<Block>>, + #[behaviour(ignore)] + backend: SharedBackend<Block, (), MemoryBackend<Block, ()>>, + #[behaviour(ignore)] + topic: Topic, + #[behaviour(ignore)] + pending_transactions: Option<Arc<Mutex<Vec<Extrinsic>>>>, } #[derive(Debug, Encode, Decode)] enum Message { - Request(H256), - Block(Block), - Extrinsic(Extrinsic), + Request(H256), + Block(Block), + Extrinsic(Extrinsic), } -impl<TSubstream: AsyncRead + AsyncWrite> NetworkBehaviourEventProcess<libp2p::floodsub::FloodsubEvent> for CounterBehaviour<TSubstream> { - fn inject_event(&mut self, floodsub_message: libp2p::floodsub::FloodsubEvent) { - if let libp2p::floodsub::FloodsubEvent::Message(floodsub_message) = floodsub_message { - let message = Message::decode(&mut &floodsub_message.data[..]).unwrap(); - println!("Received: {:?} from {:?}", message, floodsub_message.source); - - match message { - Message::Request(hash) => { - let block = self.backend.read().block_at(&hash).unwrap(); - self.floodsub.publish(&self.topic, Message::Block(block).encode()); - }, - Message::Block(block) => { - if let Some(sender) = &mut self.sender { - sender.start_send(block).unwrap(); - } - }, - Message::Extrinsic(extrinsic) => { - if let Some(pending_transactions) = &self.pending_transactions { - pending_transactions.lock().unwrap().push(extrinsic); - } - }, - } - } - } +impl<TSubstream: AsyncRead + AsyncWrite> + NetworkBehaviourEventProcess<libp2p::floodsub::FloodsubEvent> for CounterBehaviour<TSubstream> +{ + fn inject_event(&mut self, floodsub_message: libp2p::floodsub::FloodsubEvent) { + if let libp2p::floodsub::FloodsubEvent::Message(floodsub_message) = floodsub_message { + let message = Message::decode(&mut &floodsub_message.data[..]).unwrap(); + println!("Received: {:?} from {:?}", message, floodsub_message.source); + + match message { + Message::Request(hash) => { + let block = self.backend.read().block_at(&hash).unwrap(); + self.floodsub + .publish(&self.topic, Message::Block(block).encode()); + } + Message::Block(block) => { + if let Some(sender) = &mut self.sender { + sender.start_send(block).unwrap(); + } + } + Message::Extrinsic(extrinsic) => { + if let Some(pending_transactions) = &self.pending_transactions { + pending_transactions.lock().unwrap().push(extrinsic); + } + } + } + } + } } -impl<TSubstream: AsyncRead + AsyncWrite> NetworkBehaviourEventProcess<libp2p::kad::KademliaOut> for CounterBehaviour<TSubstream> { - fn inject_event(&mut self, message: libp2p::kad::KademliaOut) { - if let libp2p::kad::KademliaOut::Discovered { peer_id, .. } = message { - println!("Discovered via Kademlia {:?}", peer_id); - self.floodsub.add_node_to_partial_view(peer_id); - } - } +impl<TSubstream: AsyncRead + AsyncWrite> NetworkBehaviourEventProcess<libp2p::kad::KademliaOut> + for CounterBehaviour<TSubstream> +{ + fn inject_event(&mut self, message: libp2p::kad::KademliaOut) { + if let libp2p::kad::KademliaOut::Discovered { peer_id, .. } = message { + println!("Discovered via Kademlia {:?}", peer_id); + self.floodsub.add_node_to_partial_view(peer_id); + } + } } fn main() { - let (sender, receiver) = unbounded(); - - let genesis_block = Block::genesis(); - let backend = SharedBackend::new( - MemoryBackend::with_genesis(genesis_block.clone(), Default::default()) - ); - - if let Some(to_dial) = std::env::args().nth(1) { - let (request_sender, request_receiver) = unbounded(); - - { - let backend = backend.clone(); - thread::spawn(move || { - importer_thread(backend, receiver, request_sender); - }); - } - - start_network(backend, Some(sender), None, Some(request_receiver), None, Some(to_dial)); - } else { - let pending_transactions = Arc::new(Mutex::new(Default::default())); - - { - let backend = backend.clone(); - let pending_transactions = pending_transactions.clone(); - thread::spawn(|| { - builder_thread(backend, sender, pending_transactions); - }); - } - - start_network(backend, None, Some(receiver), None, Some(pending_transactions), None); - } + let (sender, receiver) = unbounded(); + + let genesis_block = Block::genesis(); + let backend = SharedBackend::new(MemoryBackend::with_genesis( + genesis_block.clone(), + Default::default(), + )); + + if let Some(to_dial) = std::env::args().nth(1) { + let (request_sender, request_receiver) = unbounded(); + + { + let backend = backend.clone(); + thread::spawn(move || { + importer_thread(backend, receiver, request_sender); + }); + } + + start_network( + backend, + Some(sender), + None, + Some(request_receiver), + None, + Some(to_dial), + ); + } else { + let pending_transactions = Arc::new(Mutex::new(Default::default())); + + { + let backend = backend.clone(); + let pending_transactions = pending_transactions.clone(); + thread::spawn(|| { + builder_thread(backend, sender, pending_transactions); + }); + } + + start_network( + backend, + None, + Some(receiver), + None, + Some(pending_transactions), + None, + ); + } } -fn start_network(backend: SharedBackend<Block, (), MemoryBackend<Block, ()>>, sender: Option<UnboundedSender<Block>>, mut receiver: Option<UnboundedReceiver<Block>>, mut request_receiver: Option<UnboundedReceiver<Message>>, pending_transactions: Option<Arc<Mutex<Vec<Extrinsic>>>>, to_dial: Option<String>) { - // Create a random PeerId - let local_key = if to_dial.is_some() { - secio::SecioKeyPair::ed25519_raw_key( - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] - ).unwrap() - } else { - secio::SecioKeyPair::ed25519_raw_key( - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2] - ).unwrap() - }; - let local_peer_id = local_key.to_peer_id(); - println!("Local peer id: {:?}", local_peer_id); - - let transport = libp2p::build_tcp_ws_secio_mplex_yamux(local_key); - let topic = TopicBuilder::new("blocks").build(); - - let mut swarm = { - let mut behaviour = CounterBehaviour { - floodsub: Floodsub::new(local_peer_id.clone()), - kademlia: Kademlia::new(local_peer_id.clone()), - - topic: topic.clone(), - backend, - sender, - pending_transactions, - }; - - assert!(behaviour.floodsub.subscribe(topic.clone())); - libp2p::Swarm::new(transport, behaviour, local_peer_id) - }; - - // Listen on all interfaces and whatever port the OS assigns - let addr = libp2p::Swarm::listen_on(&mut swarm, if to_dial.is_none() { "/ip4/0.0.0.0/tcp/37365".parse().unwrap() } else { "/ip4/0.0.0.0/tcp/0".parse().unwrap() }).unwrap(); - println!("Listening on {:?}", addr); - - // Reach out to another node if specified - if let Some(to_dial) = to_dial { - let dialing = to_dial.clone(); - match to_dial.parse() { - Ok(to_dial) => { - match libp2p::Swarm::dial_addr(&mut swarm, to_dial) { - Ok(_) => { - println!("Dialed {:?}", dialing); - swarm.floodsub.add_node_to_partial_view( - "QmSVnNf9HwVMT1Y4cK1P6aoJcEZjmoTXpjKBmAABLMnZEk".parse().unwrap() - ); - swarm.kademlia.add_connected_address( - &"QmSVnNf9HwVMT1Y4cK1P6aoJcEZjmoTXpjKBmAABLMnZEk".parse().unwrap(), - dialing.parse().unwrap(), - ); - }, - Err(e) => println!("Dial {:?} failed: {:?}", dialing, e) - } - }, - Err(err) => println!("Failed to parse address to dial: {:?}", err), - } - } else { - swarm.floodsub.add_node_to_partial_view( - "QmRpheLN4JWdAnY7HGJfWFNbfkQCb6tFf4vvA6hgjMZKrR".parse().unwrap() - ); - } - - // Kick it off - tokio::run(futures::future::poll_fn(move || -> Result<_, ()> { - if let Some(receiver) = &mut receiver { - loop { - match receiver.poll().expect("Error while polling channel") { - Async::Ready(Some(block)) => { - println!("Broadcasting block {:?} via floodsub", block); - swarm.floodsub.publish(&topic, Message::Block(block).encode()) - }, - Async::Ready(None) => panic!("Channel closed"), - Async::NotReady => break, - }; - } - } - - if let Some(request_receiver) = &mut request_receiver { - loop { - match request_receiver.poll().expect("Error while polling channel") { - Async::Ready(Some(message)) => { - println!("Requesting {:?} via floodsub", message); - swarm.floodsub.publish(&topic, message.encode()) - }, - Async::Ready(None) => panic!("Channel closed"), - Async::NotReady => break, - }; - } - } - - loop { - match swarm.poll().expect("Error while polling swarm") { - Async::Ready(Some(_)) => {}, - Async::Ready(None) | Async::NotReady => break, - } - } - - Ok(Async::NotReady) - })); +fn start_network( + backend: SharedBackend<Block, (), MemoryBackend<Block, ()>>, + sender: Option<UnboundedSender<Block>>, + mut receiver: Option<UnboundedReceiver<Block>>, + mut request_receiver: Option<UnboundedReceiver<Message>>, + pending_transactions: Option<Arc<Mutex<Vec<Extrinsic>>>>, + to_dial: Option<String>, +) { + // Create a random PeerId + let local_key = if to_dial.is_some() { + secio::SecioKeyPair::ed25519_raw_key([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, + ]) + .unwrap() + } else { + secio::SecioKeyPair::ed25519_raw_key([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, + ]) + .unwrap() + }; + let local_peer_id = local_key.to_peer_id(); + println!("Local peer id: {:?}", local_peer_id); + + let transport = libp2p::build_tcp_ws_secio_mplex_yamux(local_key); + let topic = TopicBuilder::new("blocks").build(); + + let mut swarm = { + let mut behaviour = CounterBehaviour { + floodsub: Floodsub::new(local_peer_id.clone()), + kademlia: Kademlia::new(local_peer_id.clone()), + + topic: topic.clone(), + backend, + sender, + pending_transactions, + }; + + assert!(behaviour.floodsub.subscribe(topic.clone())); + libp2p::Swarm::new(transport, behaviour, local_peer_id) + }; + + // Listen on all interfaces and whatever port the OS assigns + let addr = libp2p::Swarm::listen_on( + &mut swarm, + if to_dial.is_none() { + "/ip4/0.0.0.0/tcp/37365".parse().unwrap() + } else { + "/ip4/0.0.0.0/tcp/0".parse().unwrap() + }, + ) + .unwrap(); + println!("Listening on {:?}", addr); + + // Reach out to another node if specified + if let Some(to_dial) = to_dial { + let dialing = to_dial.clone(); + match to_dial.parse() { + Ok(to_dial) => match libp2p::Swarm::dial_addr(&mut swarm, to_dial) { + Ok(_) => { + println!("Dialed {:?}", dialing); + swarm.floodsub.add_node_to_partial_view( + "QmSVnNf9HwVMT1Y4cK1P6aoJcEZjmoTXpjKBmAABLMnZEk" + .parse() + .unwrap(), + ); + swarm.kademlia.add_connected_address( + &"QmSVnNf9HwVMT1Y4cK1P6aoJcEZjmoTXpjKBmAABLMnZEk" + .parse() + .unwrap(), + dialing.parse().unwrap(), + ); + } + Err(e) => println!("Dial {:?} failed: {:?}", dialing, e), + }, + Err(err) => println!("Failed to parse address to dial: {:?}", err), + } + } else { + swarm.floodsub.add_node_to_partial_view( + "QmRpheLN4JWdAnY7HGJfWFNbfkQCb6tFf4vvA6hgjMZKrR" + .parse() + .unwrap(), + ); + } + + // Kick it off + tokio::run(futures::future::poll_fn(move || -> Result<_, ()> { + if let Some(receiver) = &mut receiver { + loop { + match receiver.poll().expect("Error while polling channel") { + Async::Ready(Some(block)) => { + println!("Broadcasting block {:?} via floodsub", block); + swarm + .floodsub + .publish(&topic, Message::Block(block).encode()) + } + Async::Ready(None) => panic!("Channel closed"), + Async::NotReady => break, + }; + } + } + + if let Some(request_receiver) = &mut request_receiver { + loop { + match request_receiver + .poll() + .expect("Error while polling channel") + { + Async::Ready(Some(message)) => { + println!("Requesting {:?} via floodsub", message); + swarm.floodsub.publish(&topic, message.encode()) + } + Async::Ready(None) => panic!("Channel closed"), + Async::NotReady => break, + }; + } + } + + loop { + match swarm.poll().expect("Error while polling swarm") { + Async::Ready(Some(_)) => {} + Async::Ready(None) | Async::NotReady => break, + } + } + + Ok(Async::NotReady) + })); } -fn builder_thread(backend_build: SharedBackend<Block, (), MemoryBackend<Block, ()>>, sender: UnboundedSender<Block>, pending_transactions: Arc<Mutex<Vec<Extrinsic>>>) { - loop { - thread::sleep(Duration::from_secs(5)); - - let head = backend_build.read().head(); - let executor = Executor; - println!("Building on top of {}", head); - - // Build a block. - let mut builder = BlockBuilder::new(&backend_build, &executor, &head, ()).unwrap(); - let pending_transactions = { - let mut locked = pending_transactions.lock().unwrap(); - let ret = locked.clone(); - locked.clear(); - ret - }; - - for extrinsic in pending_transactions { - println!("Applying extrinsic {:?}", extrinsic); - builder.apply_extrinsic(extrinsic).unwrap(); - } - let op = builder.finalize().unwrap(); - let block = op.block.clone(); - - // Import the built block. - let mut build_importer = backend_build.begin_import(&executor); - build_importer.import_raw(op); - build_importer.set_head(block.id()); - build_importer.commit().unwrap(); - - sender.unbounded_send(block).unwrap(); - } +fn builder_thread( + backend_build: SharedBackend<Block, (), MemoryBackend<Block, ()>>, + sender: UnboundedSender<Block>, + pending_transactions: Arc<Mutex<Vec<Extrinsic>>>, +) { + loop { + thread::sleep(Duration::from_secs(5)); + + let head = backend_build.read().head(); + let executor = Executor; + println!("Building on top of {}", head); + + // Build a block. + let mut builder = BlockBuilder::new(&backend_build, &executor, &head, ()).unwrap(); + let pending_transactions = { + let mut locked = pending_transactions.lock().unwrap(); + let ret = locked.clone(); + locked.clear(); + ret + }; + + for extrinsic in pending_transactions { + println!("Applying extrinsic {:?}", extrinsic); + builder.apply_extrinsic(extrinsic).unwrap(); + } + let op = builder.finalize().unwrap(); + let block = op.block.clone(); + + // Import the built block. + let mut build_importer = backend_build.begin_import(&executor); + build_importer.import_raw(op); + build_importer.set_head(block.id()); + build_importer.commit().unwrap(); + + sender.unbounded_send(block).unwrap(); + } } -fn importer_thread(backend_import: SharedBackend<Block, (), MemoryBackend<Block, ()>>, receiver: UnboundedReceiver<Block>, request_sender: UnboundedSender<Message>) { - let mut receiver = receiver.wait(); - let mut waiting: HashMap<H256, Block> = HashMap::new(); - let mut count = 0; - - loop { - request_sender.unbounded_send(Message::Extrinsic(Extrinsic::Add(count))).unwrap(); - count += 1; - - let head = backend_import.read().head(); - let executor = Executor; - println!("Importing on top of {}", head); - - { - loop { - let mut imported = Vec::new(); - - for (_, block) in &waiting { - if backend_import.read().contains(&block.parent_id().unwrap()).unwrap() { - let mut importer = backend_import.begin_import(&executor); - importer.import_block(block.clone()).unwrap(); - importer.set_head(block.id()); - importer.commit().unwrap(); - imported.push(block.id()); - } - } - - for hash in &imported { - waiting.remove(hash); - } - - if imported.len() == 0 { - break - } - } - } - - let block = receiver.next().unwrap().unwrap(); - - // Import the block again to importer. - let mut importer = backend_import.begin_import(&executor); - if !backend_import.read().contains(&block.parent_id().unwrap()).unwrap() { - request_sender.unbounded_send(Message::Request(block.parent_id().unwrap())).unwrap(); - waiting.insert(block.id(), block); - - continue - } - importer.import_block(block.clone()).unwrap(); - importer.set_head(block.id()); - importer.commit().unwrap(); - } +fn importer_thread( + backend_import: SharedBackend<Block, (), MemoryBackend<Block, ()>>, + receiver: UnboundedReceiver<Block>, + request_sender: UnboundedSender<Message>, +) { + let mut receiver = receiver.wait(); + let mut waiting: HashMap<H256, Block> = HashMap::new(); + let mut count = 0; + + loop { + request_sender + .unbounded_send(Message::Extrinsic(Extrinsic::Add(count))) + .unwrap(); + count += 1; + + let head = backend_import.read().head(); + let executor = Executor; + println!("Importing on top of {}", head); + + { + loop { + let mut imported = Vec::new(); + + for (_, block) in &waiting { + if backend_import + .read() + .contains(&block.parent_id().unwrap()) + .unwrap() + { + let mut importer = backend_import.begin_import(&executor); + importer.import_block(block.clone()).unwrap(); + importer.set_head(block.id()); + importer.commit().unwrap(); + imported.push(block.id()); + } + } + + for hash in &imported { + waiting.remove(hash); + } + + if imported.len() == 0 { + break; + } + } + } + + let block = receiver.next().unwrap().unwrap(); + + // Import the block again to importer. + let mut importer = backend_import.begin_import(&executor); + if !backend_import + .read() + .contains(&block.parent_id().unwrap()) + .unwrap() + { + request_sender + .unbounded_send(Message::Request(block.parent_id().unwrap())) + .unwrap(); + waiting.insert(block.id(), block); + + continue; + } + importer.import_block(block.clone()).unwrap(); + importer.set_head(block.id()); + importer.commit().unwrap(); + } } diff --git a/examples/counter/src/runtime.rs b/examples/counter/src/runtime.rs index c421a36..cd4bd57 100644 --- a/examples/counter/src/runtime.rs +++ b/examples/counter/src/runtime.rs @@ -1,178 +1,181 @@ -use primitive_types::H256; -use blockchain::traits::{ - Block as BlockT, BlockExecutor, - BuilderExecutor, StorageExternalities, -}; -use codec::{Encode, Decode}; +use blockchain::traits::{Block as BlockT, BlockExecutor, BuilderExecutor, StorageExternalities}; +use codec::{Decode, Encode}; use codec_derive::{Decode, Encode}; +use primitive_types::H256; use sha3::{Digest, Sha3_256}; #[derive(Clone, Debug, Encode, Decode)] pub struct Block { - hash: H256, - parent_hash: Option<H256>, - extrinsics: Vec<Extrinsic>, + hash: H256, + parent_hash: Option<H256>, + extrinsics: Vec<Extrinsic>, } impl Block { - pub fn calculate_hash(&self) -> H256 { - let data = (self.parent_hash.clone(), self.extrinsics.clone()).encode(); - H256::from_slice(Sha3_256::digest(&data).as_slice()) - } - - pub fn verify_hash(&self) -> bool { - self.hash == self.calculate_hash() - } - - pub fn fix_hash(&mut self) { - self.hash = self.calculate_hash(); - } - - pub fn genesis() -> Self { - let mut block = Block { - hash: H256::default(), - parent_hash: None, - extrinsics: Vec::new(), - }; - block.fix_hash(); - block - } + pub fn calculate_hash(&self) -> H256 { + let data = (self.parent_hash.clone(), self.extrinsics.clone()).encode(); + H256::from_slice(Sha3_256::digest(&data).as_slice()) + } + + pub fn verify_hash(&self) -> bool { + self.hash == self.calculate_hash() + } + + pub fn fix_hash(&mut self) { + self.hash = self.calculate_hash(); + } + + pub fn genesis() -> Self { + let mut block = Block { + hash: H256::default(), + parent_hash: None, + extrinsics: Vec::new(), + }; + block.fix_hash(); + block + } } impl BlockT for Block { - type Identifier = H256; + type Identifier = H256; - fn parent_id(&self) -> Option<H256> { - self.parent_hash - } + fn parent_id(&self) -> Option<H256> { + self.parent_hash + } - fn id(&self) -> H256 { - self.hash - } + fn id(&self) -> H256 { + self.hash + } } #[derive(Clone, Debug, Encode, Decode)] pub enum Extrinsic { - Add(u128), + Add(u128), } #[derive(Debug)] pub enum Error { - Backend(Box<std::error::Error>), - HashMismatch, - StateCorruption, + Backend(Box<std::error::Error>), + HashMismatch, + StateCorruption, } impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - Error::HashMismatch => "Hash mismatch".fmt(f)?, - Error::StateCorruption => "State is corrupted".fmt(f)?, - Error::Backend(_) => "Backend error".fmt(f)?, - } - - Ok(()) - } + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Error::HashMismatch => "Hash mismatch".fmt(f)?, + Error::StateCorruption => "State is corrupted".fmt(f)?, + Error::Backend(_) => "Backend error".fmt(f)?, + } + + Ok(()) + } } -impl std::error::Error for Error { } +impl std::error::Error for Error {} #[derive(Clone)] pub struct Executor; impl Executor { - fn read_counter(&self, state: &mut <Self as BlockExecutor>::Externalities) -> Result<u128, Error> { - Ok( - match state.read_storage(b"counter").map_err(|e| Error::Backend(e))? { - Some(counter) => { - u128::decode(&mut counter.as_slice()).ok_or(Error::StateCorruption)? - }, - None => 0, - } - ) - } - - fn write_counter(&self, counter: u128, state: &mut <Self as BlockExecutor>::Externalities) { - state.write_storage(b"counter".to_vec(), counter.encode()); - } + fn read_counter( + &self, + state: &mut <Self as BlockExecutor>::Externalities, + ) -> Result<u128, Error> { + Ok( + match state + .read_storage(b"counter") + .map_err(|e| Error::Backend(e))? + { + Some(counter) => { + u128::decode(&mut counter.as_slice()).ok_or(Error::StateCorruption)? + } + None => 0, + }, + ) + } + + fn write_counter(&self, counter: u128, state: &mut <Self as BlockExecutor>::Externalities) { + state.write_storage(b"counter".to_vec(), counter.encode()); + } } impl BlockExecutor for Executor { - type Error = Error; - type Block = Block; - type Externalities = dyn StorageExternalities + 'static; - - fn execute_block( - &self, - block: &Self::Block, - state: &mut Self::Externalities, - ) -> Result<(), Error> { - if !block.verify_hash() { - return Err(Error::HashMismatch); - } - - let mut counter = self.read_counter(state)?; - - for extrinsic in &block.extrinsics { - match extrinsic { - Extrinsic::Add(add) => counter += add, - } - } - - self.write_counter(counter, state); - - Ok(()) - } + type Error = Error; + type Block = Block; + type Externalities = dyn StorageExternalities + 'static; + + fn execute_block( + &self, + block: &Self::Block, + state: &mut Self::Externalities, + ) -> Result<(), Error> { + if !block.verify_hash() { + return Err(Error::HashMismatch); + } + + let mut counter = self.read_counter(state)?; + + for extrinsic in &block.extrinsics { + match extrinsic { + Extrinsic::Add(add) => counter += add, + } + } + + self.write_counter(counter, state); + + Ok(()) + } } impl BuilderExecutor for Executor { - type Error = Error; - type Block = Block; - type BuildBlock = Block; - type Externalities = dyn StorageExternalities + 'static; - type Extrinsic = Extrinsic; - type Inherent = (); - - fn initialize_block( - &self, - block: &Self::Block, - _state: &mut Self::Externalities, - _inherent: (), - ) -> Result<Self::BuildBlock, Self::Error> { - let mut block = block.clone(); - block.parent_hash = Some(block.hash); - block.fix_hash(); - - Ok(block) - } - - fn apply_extrinsic( - &self, - block: &mut Self::Block, - extrinsic: Self::Extrinsic, - state: &mut Self::Externalities, - ) -> Result<(), Self::Error> { - let mut counter = self.read_counter(state)?; - - match extrinsic { - Extrinsic::Add(add) => { - counter += add; - }, - } - - self.write_counter(counter, state); - block.fix_hash(); - - Ok(()) - } - - fn finalize_block( - &self, - block: &mut Self::Block, - _state: &mut Self::Externalities, - ) -> Result<(), Self::Error> { - block.fix_hash(); - - Ok(()) - } + type Error = Error; + type Block = Block; + type BuildBlock = Block; + type Externalities = dyn StorageExternalities + 'static; + type Extrinsic = Extrinsic; + type Inherent = (); + + fn initialize_block( + &self, + block: &Self::Block, + _state: &mut Self::Externalities, + _inherent: (), + ) -> Result<Self::BuildBlock, Self::Error> { + let mut block = block.clone(); + block.parent_hash = Some(block.hash); + block.fix_hash(); + + Ok(block) + } + + fn apply_extrinsic( + &self, + block: &mut Self::Block, + extrinsic: Self::Extrinsic, + state: &mut Self::Externalities, + ) -> Result<(), Self::Error> { + let mut counter = self.read_counter(state)?; + + match extrinsic { + Extrinsic::Add(add) => { + counter += add; + } + } + + self.write_counter(counter, state); + block.fix_hash(); + + Ok(()) + } + + fn finalize_block( + &self, + block: &mut Self::Block, + _state: &mut Self::Externalities, + ) -> Result<(), Self::Error> { + block.fix_hash(); + + Ok(()) + } } diff --git a/src/backend/memory.rs b/src/backend/memory.rs index 4790402..e928ee6 100644 --- a/src/backend/memory.rs +++ b/src/backend/memory.rs @@ -1,375 +1,369 @@ use std::collections::HashMap; -use std::{fmt, error as stderror}; +use std::{error as stderror, fmt}; +use super::tree_route; use crate::traits::{ - AsExternalities, Backend, NullExternalities, - StorageExternalities, Block, Auxiliary, Operation, - ChainQuery, + AsExternalities, Auxiliary, Backend, Block, ChainQuery, NullExternalities, Operation, + StorageExternalities, }; -use super::tree_route; #[derive(Debug)] pub enum Error { - IO, - InvalidOperation, - ImportingGenesis, - NotExist, + IO, + InvalidOperation, + ImportingGenesis, + NotExist, } impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Error::IO => "IO failure".fmt(f)?, - Error::InvalidOperation => "The operation provided is invalid".fmt(f)?, - Error::NotExist => "Block does not exist".fmt(f)?, - Error::ImportingGenesis => "Trying to import another genesis".fmt(f)?, - } - - Ok(()) - } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Error::IO => "IO failure".fmt(f)?, + Error::InvalidOperation => "The operation provided is invalid".fmt(f)?, + Error::NotExist => "Block does not exist".fmt(f)?, + Error::ImportingGenesis => "Trying to import another genesis".fmt(f)?, + } + + Ok(()) + } } -impl stderror::Error for Error { } +impl stderror::Error for Error {} /// State stored in memory. #[derive(Clone, Default)] pub struct MemoryState { - storage: HashMap<Vec<u8>, Vec<u8>>, + storage: HashMap<Vec<u8>, Vec<u8>>, } -impl NullExternalities for MemoryState { } +impl NullExternalities for MemoryState {} impl AsExternalities<dyn NullExternalities> for MemoryState { - fn as_externalities(&mut self) -> &mut (dyn NullExternalities + 'static) { - self - } + fn as_externalities(&mut self) -> &mut (dyn NullExternalities + 'static) { + self + } } impl StorageExternalities for MemoryState { - fn read_storage(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Box<std::error::Error>> { - Ok(self.storage.get(key).map(|value| value.to_vec())) - } + fn read_storage(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Box<std::error::Error>> { + Ok(self.storage.get(key).map(|value| value.to_vec())) + } - fn write_storage(&mut self, key: Vec<u8>, value: Vec<u8>) { - self.storage.insert(key, value); - } + fn write_storage(&mut self, key: Vec<u8>, value: Vec<u8>) { + self.storage.insert(key, value); + } - fn remove_storage(&mut self, key: &[u8]) { - self.storage.remove(key); - } + fn remove_storage(&mut self, key: &[u8]) { + self.storage.remove(key); + } } impl AsExternalities<dyn StorageExternalities> for MemoryState { - fn as_externalities(&mut self) -> &mut (dyn StorageExternalities + 'static) { - self - } + fn as_externalities(&mut self) -> &mut (dyn StorageExternalities + 'static) { + self + } } struct BlockData<B: Block> { - block: B, - state: MemoryState, - depth: usize, - children: Vec<B::Identifier>, - is_canon: bool, + block: B, + state: MemoryState, + depth: usize, + children: Vec<B::Identifier>, + is_canon: bool, } /// Memory backend. pub struct MemoryBackend<B: Block, A: Auxiliary<B>> { - blocks_and_states: HashMap<B::Identifier, BlockData<B>>, - head: B::Identifier, - genesis: B::Identifier, - canon_depth_mappings: HashMap<usize, B::Identifier>, - auxiliaries: HashMap<A::Key, A>, + blocks_and_states: HashMap<B::Identifier, BlockData<B>>, + head: B::Identifier, + genesis: B::Identifier, + canon_depth_mappings: HashMap<usize, B::Identifier>, + auxiliaries: HashMap<A::Key, A>, } impl<B: Block, A: Auxiliary<B>> Backend<B, A> for MemoryBackend<B, A> { - type State = MemoryState; - type Error = Error; - - fn commit( - &mut self, - operation: Operation<B, Self::State, A>, - ) -> Result<(), Error> { - let mut parent_ides = HashMap::new(); - let mut importing: HashMap<B::Identifier, BlockData<B>> = HashMap::new(); - let mut verifying = operation.import_block; - - // Do precheck to make sure the import operation is valid. - loop { - let mut progress = false; - let mut next_verifying = Vec::new(); - - for op in verifying { - let parent_depth = match op.block.parent_id() { - Some(parent_id) => { - if self.contains(&parent_id)? { - Some(self.depth_at(&parent_id)?) - } else if importing.contains_key(&parent_id) { - importing.get(&parent_id) - .map(|data| data.depth) - } else { - None - } - }, - None => return Err(Error::ImportingGenesis), - }; - let depth = parent_depth.map(|d| d + 1); - - if let Some(depth) = depth { - progress = true; - if let Some(parent_id) = op.block.parent_id() { - parent_ides.insert(op.block.id(), parent_id); - } - importing.insert(op.block.id(), BlockData { - block: op.block, - state: op.state, - depth, - children: Vec::new(), - is_canon: false, - }); - } else { - next_verifying.push(op) - } - } - - if next_verifying.len() == 0 { - break; - } - - if !progress { - return Err(Error::InvalidOperation); - } - - verifying = next_verifying; - } - - // Do precheck to make sure the head going to set exists. - if let Some(new_head) = &operation.set_head { - let head_exists = self.contains(new_head)? || - importing.contains_key(new_head); - - if !head_exists { - return Err(Error::InvalidOperation); - } - } - - // Do precheck to make sure auxiliary is valid. - for aux in &operation.insert_auxiliaries { - for id in aux.associated() { - if !(self.contains(&id)? || importing.contains_key(&id)) { - return Err(Error::InvalidOperation); - } - } - } - - self.blocks_and_states.extend(importing); - - // Fix children at ides. - for (id, parent_id) in parent_ides { - self.blocks_and_states.get_mut(&parent_id) - .expect("Parent id are checked to exist or has been just imported; qed") - .children.push(id); - } - - if let Some(new_head) = operation.set_head { - let route = tree_route(self, &self.head, &new_head) - .expect("Blocks are checked to exist or importing; qed"); - - for id in route.retracted() { - let mut block = self.blocks_and_states.get_mut(id) - .expect("Block is fetched from tree_route; it must exist; qed"); - block.is_canon = false; - self.canon_depth_mappings.remove(&block.depth); - } - - for id in route.enacted() { - let mut block = self.blocks_and_states.get_mut(id) - .expect("Block is fetched from tree_route; it must exist; qed"); - block.is_canon = true; - self.canon_depth_mappings.insert(block.depth, *id); - } - - self.head = new_head; - } - - for aux_key in operation.remove_auxiliaries { - self.auxiliaries.remove(&aux_key); - } - - for aux in operation.insert_auxiliaries { - self.auxiliaries.insert(aux.key(), aux); - } - - Ok(()) - } + type State = MemoryState; + type Error = Error; + + fn commit(&mut self, operation: Operation<B, Self::State, A>) -> Result<(), Error> { + let mut parent_ides = HashMap::new(); + let mut importing: HashMap<B::Identifier, BlockData<B>> = HashMap::new(); + let mut verifying = operation.import_block; + + // Do precheck to make sure the import operation is valid. + loop { + let mut progress = false; + let mut next_verifying = Vec::new(); + + for op in verifying { + let parent_depth = match op.block.parent_id() { + Some(parent_id) => { + if self.contains(&parent_id)? { + Some(self.depth_at(&parent_id)?) + } else if importing.contains_key(&parent_id) { + importing.get(&parent_id).map(|data| data.depth) + } else { + None + } + } + None => return Err(Error::ImportingGenesis), + }; + let depth = parent_depth.map(|d| d + 1); + + if let Some(depth) = depth { + progress = true; + if let Some(parent_id) = op.block.parent_id() { + parent_ides.insert(op.block.id(), parent_id); + } + importing.insert( + op.block.id(), + BlockData { + block: op.block, + state: op.state, + depth, + children: Vec::new(), + is_canon: false, + }, + ); + } else { + next_verifying.push(op) + } + } + + if next_verifying.len() == 0 { + break; + } + + if !progress { + return Err(Error::InvalidOperation); + } + + verifying = next_verifying; + } + + // Do precheck to make sure the head going to set exists. + if let Some(new_head) = &operation.set_head { + let head_exists = self.contains(new_head)? || importing.contains_key(new_head); + + if !head_exists { + return Err(Error::InvalidOperation); + } + } + + // Do precheck to make sure auxiliary is valid. + for aux in &operation.insert_auxiliaries { + for id in aux.associated() { + if !(self.contains(&id)? || importing.contains_key(&id)) { + return Err(Error::InvalidOperation); + } + } + } + + self.blocks_and_states.extend(importing); + + // Fix children at ides. + for (id, parent_id) in parent_ides { + self.blocks_and_states + .get_mut(&parent_id) + .expect("Parent id are checked to exist or has been just imported; qed") + .children + .push(id); + } + + if let Some(new_head) = operation.set_head { + let route = tree_route(self, &self.head, &new_head) + .expect("Blocks are checked to exist or importing; qed"); + + for id in route.retracted() { + let mut block = self + .blocks_and_states + .get_mut(id) + .expect("Block is fetched from tree_route; it must exist; qed"); + block.is_canon = false; + self.canon_depth_mappings.remove(&block.depth); + } + + for id in route.enacted() { + let mut block = self + .blocks_and_states + .get_mut(id) + .expect("Block is fetched from tree_route; it must exist; qed"); + block.is_canon = true; + self.canon_depth_mappings.insert(block.depth, *id); + } + + self.head = new_head; + } + + for aux_key in operation.remove_auxiliaries { + self.auxiliaries.remove(&aux_key); + } + + for aux in operation.insert_auxiliaries { + self.auxiliaries.insert(aux.key(), aux); + } + + Ok(()) + } } impl<B: Block, A: Auxiliary<B>> ChainQuery<B, A> for MemoryBackend<B, A> { - fn head(&self) -> B::Identifier { - self.head - } - - fn genesis(&self) -> B::Identifier { - self.genesis - } - - fn contains( - &self, - id: &B::Identifier - ) -> Result<bool, Error> { - Ok(self.blocks_and_states.contains_key(id)) - } - - fn is_canon( - &self, - id: &B::Identifier - ) -> Result<bool, Error> { - self.blocks_and_states.get(id) - .map(|data| data.is_canon) - .ok_or(Error::NotExist) - } - - fn lookup_canon_depth( - &self, - depth: usize, - ) -> Result<Option<B::Identifier>, Error> { - Ok(self.canon_depth_mappings.get(&depth) - .map(|h| h.clone())) - } - - fn auxiliary( - &self, - key: &A::Key - ) -> Result<Option<A>, Error> { - Ok(self.auxiliaries.get(key).map(|v| v.clone())) - } - - fn children_at( - &self, - id: &B::Identifier, - ) -> Result<Vec<B::Identifier>, Error> { - self.blocks_and_states.get(id) - .map(|data| data.children.clone()) - .ok_or(Error::NotExist) - } - - fn depth_at( - &self, - id: &B::Identifier - ) -> Result<usize, Error> { - self.blocks_and_states.get(id) - .map(|data| data.depth) - .ok_or(Error::NotExist) - } - - fn block_at( - &self, - id: &B::Identifier, - ) -> Result<B, Error> { - self.blocks_and_states.get(id) - .map(|data| data.block.clone()) - .ok_or(Error::NotExist) - } - - fn state_at( - &self, - id: &B::Identifier, - ) -> Result<MemoryState, Error> { - self.blocks_and_states.get(id) - .map(|data| data.state.clone()) - .ok_or(Error::NotExist) - } + fn head(&self) -> B::Identifier { + self.head + } + + fn genesis(&self) -> B::Identifier { + self.genesis + } + + fn contains(&self, id: &B::Identifier) -> Result<bool, Error> { + Ok(self.blocks_and_states.contains_key(id)) + } + + fn is_canon(&self, id: &B::Identifier) -> Result<bool, Error> { + self.blocks_and_states + .get(id) + .map(|data| data.is_canon) + .ok_or(Error::NotExist) + } + + fn lookup_canon_depth(&self, depth: usize) -> Result<Option<B::Identifier>, Error> { + Ok(self.canon_depth_mappings.get(&depth).map(|h| h.clone())) + } + + fn auxiliary(&self, key: &A::Key) -> Result<Option<A>, Error> { + Ok(self.auxiliaries.get(key).map(|v| v.clone())) + } + + fn children_at(&self, id: &B::Identifier) -> Result<Vec<B::Identifier>, Error> { + self.blocks_and_states + .get(id) + .map(|data| data.children.clone()) + .ok_or(Error::NotExist) + } + + fn depth_at(&self, id: &B::Identifier) -> Result<usize, Error> { + self.blocks_and_states + .get(id) + .map(|data| data.depth) + .ok_or(Error::NotExist) + } + + fn block_at(&self, id: &B::Identifier) -> Result<B, Error> { + self.blocks_and_states + .get(id) + .map(|data| data.block.clone()) + .ok_or(Error::NotExist) + } + + fn state_at(&self, id: &B::Identifier) -> Result<MemoryState, Error> { + self.blocks_and_states + .get(id) + .map(|data| data.state.clone()) + .ok_or(Error::NotExist) + } } impl<B: Block, A: Auxiliary<B>> MemoryBackend<B, A> { - /// Create a new memory backend from a genesis block. - pub fn with_genesis(block: B, genesis_storage: HashMap<Vec<u8>, Vec<u8>>) -> Self { - assert!(block.parent_id().is_none(), "with_genesis must be provided with a genesis block"); - - let genesis_id = block.id(); - let genesis_state = MemoryState { - storage: genesis_storage, - }; - let mut blocks_and_states = HashMap::new(); - blocks_and_states.insert( - block.id(), - BlockData { - block, - state: genesis_state, - depth: 0, - children: Vec::new(), - is_canon: true, - } - ); - let mut canon_depth_mappings = HashMap::new(); - canon_depth_mappings.insert(0, genesis_id); - - MemoryBackend { - blocks_and_states, - canon_depth_mappings, - auxiliaries: Default::default(), - genesis: genesis_id, - head: genesis_id, - } - } + /// Create a new memory backend from a genesis block. + pub fn with_genesis(block: B, genesis_storage: HashMap<Vec<u8>, Vec<u8>>) -> Self { + assert!( + block.parent_id().is_none(), + "with_genesis must be provided with a genesis block" + ); + + let genesis_id = block.id(); + let genesis_state = MemoryState { + storage: genesis_storage, + }; + let mut blocks_and_states = HashMap::new(); + blocks_and_states.insert( + block.id(), + BlockData { + block, + state: genesis_state, + depth: 0, + children: Vec::new(), + is_canon: true, + }, + ); + let mut canon_depth_mappings = HashMap::new(); + canon_depth_mappings.insert(0, genesis_id); + + MemoryBackend { + blocks_and_states, + canon_depth_mappings, + auxiliaries: Default::default(), + genesis: genesis_id, + head: genesis_id, + } + } } #[cfg(test)] mod tests { - use super::*; - use crate::traits::*; - use crate::chain::SharedBackend; - - #[derive(Clone)] - pub struct DummyBlock { - id: usize, - parent_id: usize, - } - - impl Block for DummyBlock { - type Identifier = usize; - - fn id(&self) -> usize { self.id } - fn parent_id(&self) -> Option<usize> { if self.parent_id == 0 { None } else { Some(self.parent_id) } } - } - - pub trait CombinedExternalities: NullExternalities + StorageExternalities { } - - impl<T: NullExternalities + StorageExternalities> CombinedExternalities for T { } - - impl<T: CombinedExternalities + 'static> AsExternalities<dyn CombinedExternalities> for T { - fn as_externalities(&mut self) -> &mut (dyn CombinedExternalities + 'static) { - self - } - } - - pub struct DummyExecutor; - - impl BlockExecutor for DummyExecutor { - type Error = Error; - type Block = DummyBlock; - type Externalities = dyn CombinedExternalities + 'static; - - fn execute_block( - &self, - _block: &DummyBlock, - _state: &mut (dyn CombinedExternalities + 'static), - ) -> Result<(), Error> { - Ok(()) - } - } - - #[test] - fn all_traits_for_importer_are_satisfied() { - let backend = MemoryBackend::<_, ()>::with_genesis( - DummyBlock { - id: 1, - parent_id: 0, - }, - Default::default() - ); - let executor = DummyExecutor; - let shared = SharedBackend::new(backend); - let _ = shared.begin_import(&executor); - } + use super::*; + use crate::chain::SharedBackend; + use crate::traits::*; + + #[derive(Clone)] + pub struct DummyBlock { + id: usize, + parent_id: usize, + } + + impl Block for DummyBlock { + type Identifier = usize; + + fn id(&self) -> usize { + self.id + } + fn parent_id(&self) -> Option<usize> { + if self.parent_id == 0 { + None + } else { + Some(self.parent_id) + } + } + } + + pub trait CombinedExternalities: NullExternalities + StorageExternalities {} + + impl<T: NullExternalities + StorageExternalities> CombinedExternalities for T {} + + impl<T: CombinedExternalities + 'static> AsExternalities<dyn CombinedExternalities> for T { + fn as_externalities(&mut self) -> &mut (dyn CombinedExternalities + 'static) { + self + } + } + + pub struct DummyExecutor; + + impl BlockExecutor for DummyExecutor { + type Error = Error; + type Block = DummyBlock; + type Externalities = dyn CombinedExternalities + 'static; + + fn execute_block( + &self, + _block: &DummyBlock, + _state: &mut (dyn CombinedExternalities + 'static), + ) -> Result<(), Error> { + Ok(()) + } + } + + #[test] + fn all_traits_for_importer_are_satisfied() { + let backend = MemoryBackend::<_, ()>::with_genesis( + DummyBlock { + id: 1, + parent_id: 0, + }, + Default::default(), + ); + let executor = DummyExecutor; + let shared = SharedBackend::new(backend); + let _ = shared.begin_import(&executor); + } } diff --git a/src/backend/mod.rs b/src/backend/mod.rs index d0c76ee..bd412eb 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -3,5 +3,5 @@ mod memory; mod route; -pub use self::memory::{MemoryState, MemoryBackend}; +pub use self::memory::{MemoryBackend, MemoryState}; pub use self::route::{tree_route, TreeRoute}; diff --git a/src/backend/route.rs b/src/backend/route.rs index 1c033f9..48fecdb 100644 --- a/src/backend/route.rs +++ b/src/backend/route.rs @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see <http://www.gnu.org/licenses/>. -use crate::traits::{ChainQuery, Block, Auxiliary}; +use crate::traits::{Auxiliary, Block, ChainQuery}; /// A tree-route from one block to another in the chain. /// @@ -42,104 +42,106 @@ use crate::traits::{ChainQuery, Block, Auxiliary}; /// C -> E1 -> E2 /// ``` pub struct TreeRoute<B: Block> { - route: Vec<B::Identifier>, - pivot: usize, + route: Vec<B::Identifier>, + pivot: usize, } impl<B: Block> TreeRoute<B> { - /// Get a slice of all retracted blocks in reverse order (towards common ancestor) - pub fn retracted(&self) -> &[B::Identifier] { - &self.route[..self.pivot] - } - - /// Get the common ancestor block. This might be one of the two blocks of the - /// route. - pub fn common_block(&self) -> &B::Identifier { - self.route.get(self.pivot).expect("tree-routes are computed between blocks; \ - which are included in the route; \ - thus it is never empty; qed") - } - - /// Get a slice of enacted blocks (descendents of the common ancestor) - pub fn enacted(&self) -> &[B::Identifier] { - &self.route[self.pivot + 1 ..] - } + /// Get a slice of all retracted blocks in reverse order (towards common ancestor) + pub fn retracted(&self) -> &[B::Identifier] { + &self.route[..self.pivot] + } + + /// Get the common ancestor block. This might be one of the two blocks of the + /// route. + pub fn common_block(&self) -> &B::Identifier { + self.route.get(self.pivot).expect( + "tree-routes are computed between blocks; \ + which are included in the route; \ + thus it is never empty; qed", + ) + } + + /// Get a slice of enacted blocks (descendents of the common ancestor) + pub fn enacted(&self) -> &[B::Identifier] { + &self.route[self.pivot + 1..] + } } /// Compute a tree-route between two blocks. See tree-route docs for more details. pub fn tree_route<B: Block, A: Auxiliary<B>, Ba: ChainQuery<B, A>>( - backend: &Ba, - from_id: &B::Identifier, - to_id: &B::Identifier, + backend: &Ba, + from_id: &B::Identifier, + to_id: &B::Identifier, ) -> Result<TreeRoute<B>, Ba::Error> { - let mut from = backend.block_at(from_id)?; - let mut to = backend.block_at(to_id)?; - - let mut from_branch = Vec::new(); - let mut to_branch = Vec::new(); - - { - let mut from_depth = backend.depth_at(from_id)?; - let mut to_depth = backend.depth_at(to_id)?; - - while to_depth > from_depth { - let to_parent_id = match to.parent_id() { - Some(parent_id) => parent_id, - None => { - assert!(to_depth == 0, "When parent_id is None, depth should be 0"); - break; - } - }; - - to_branch.push(to.id()); - to = backend.block_at(&to_parent_id)?; - to_depth = backend.depth_at(&to_parent_id)?; - } - - while from_depth > to_depth { - let from_parent_id = match from.parent_id() { - Some(parent_id) => parent_id, - None => { - assert!(to_depth == 0, "When parent_id is None, depth should be 0"); - break; - } - }; - - from_branch.push(from.id()); - from = backend.block_at(&from_parent_id)?; - from_depth = backend.depth_at(&from_parent_id)?; - } - } - - while from.id() != to.id() { - let to_parent_id = match to.parent_id() { - Some(parent_id) => parent_id, - None => { - panic!("During backend import, all blocks are checked to have parent; this branch is when common parent does not exist; qed"); - } - }; - - let from_parent_id = match from.parent_id() { - Some(parent_id) => parent_id, - None => { - panic!("During backend import, all blocks are checked to have parent; this branch is when common parent does not exist; qed"); - } - }; - - to_branch.push(to.id()); - to = backend.block_at(&to_parent_id)?; - - from_branch.push(from.id()); - from = backend.block_at(&from_parent_id)?; - } - - // add the pivot block. and append the reversed to-branch (note that it's reverse order originalls) - let pivot = from_branch.len(); - from_branch.push(to.id()); - from_branch.extend(to_branch.into_iter().rev()); - - Ok(TreeRoute { - route: from_branch, - pivot, - }) + let mut from = backend.block_at(from_id)?; + let mut to = backend.block_at(to_id)?; + + let mut from_branch = Vec::new(); + let mut to_branch = Vec::new(); + + { + let mut from_depth = backend.depth_at(from_id)?; + let mut to_depth = backend.depth_at(to_id)?; + + while to_depth > from_depth { + let to_parent_id = match to.parent_id() { + Some(parent_id) => parent_id, + None => { + assert!(to_depth == 0, "When parent_id is None, depth should be 0"); + break; + } + }; + + to_branch.push(to.id()); + to = backend.block_at(&to_parent_id)?; + to_depth = backend.depth_at(&to_parent_id)?; + } + + while from_depth > to_depth { + let from_parent_id = match from.parent_id() { + Some(parent_id) => parent_id, + None => { + assert!(to_depth == 0, "When parent_id is None, depth should be 0"); + break; + } + }; + + from_branch.push(from.id()); + from = backend.block_at(&from_parent_id)?; + from_depth = backend.depth_at(&from_parent_id)?; + } + } + + while from.id() != to.id() { + let to_parent_id = match to.parent_id() { + Some(parent_id) => parent_id, + None => { + panic!("During backend import, all blocks are checked to have parent; this branch is when common parent does not exist; qed"); + } + }; + + let from_parent_id = match from.parent_id() { + Some(parent_id) => parent_id, + None => { + panic!("During backend import, all blocks are checked to have parent; this branch is when common parent does not exist; qed"); + } + }; + + to_branch.push(to.id()); + to = backend.block_at(&to_parent_id)?; + + from_branch.push(from.id()); + from = backend.block_at(&from_parent_id)?; + } + + // add the pivot block. and append the reversed to-branch (note that it's reverse order originalls) + let pivot = from_branch.len(); + from_branch.push(to.id()); + from_branch.extend(to_branch.into_iter().rev()); + + Ok(TreeRoute { + route: from_branch, + pivot, + }) } diff --git a/src/chain/block_builder.rs b/src/chain/block_builder.rs index e9bf03f..3020637 100644 --- a/src/chain/block_builder.rs +++ b/src/chain/block_builder.rs @@ -1,57 +1,71 @@ use super::{Error, SharedBackend}; use crate::traits::{ - Backend, BuilderExecutor, AsExternalities, - ImportOperation, Block, Auxiliary, ChainQuery, + AsExternalities, Auxiliary, Backend, Block, BuilderExecutor, ChainQuery, ImportOperation, }; /// Block builder. pub struct BlockBuilder<'a, E: BuilderExecutor, A: Auxiliary<E::Block>, Ba: Backend<E::Block, A>> { - executor: &'a E, - pending_block: E::BuildBlock, - pending_state: Ba::State, + executor: &'a E, + pending_block: E::BuildBlock, + pending_state: Ba::State, } -impl<'a, E: BuilderExecutor, A: Auxiliary<E::Block>, Ba: ChainQuery<E::Block, A>> BlockBuilder<'a, E, A, Ba> where - <Ba as Backend<E::Block, A>>::State: AsExternalities<E::Externalities>, +impl<'a, E: BuilderExecutor, A: Auxiliary<E::Block>, Ba: ChainQuery<E::Block, A>> + BlockBuilder<'a, E, A, Ba> +where + <Ba as Backend<E::Block, A>>::State: AsExternalities<E::Externalities>, { - /// Create a new block builder. - pub fn new(backend: &SharedBackend<E::Block, A, Ba>, executor: &'a E, parent_hash: &<E::Block as Block>::Identifier, inherent: E::Inherent) -> Result<Self, Error> { - let parent_block = backend.read().block_at(parent_hash) - .map_err(|e| Error::Backend(Box::new(e)))?; - - let mut pending_state = backend.read().state_at(parent_hash) - .map_err(|e| Error::Backend(Box::new(e)))?; - - let pending_block = executor.initialize_block( - &parent_block, - pending_state.as_externalities(), - inherent - ).map_err(|e| Error::Executor(Box::new(e)))?; - - Ok(Self { - executor, pending_block, pending_state, - }) - } - - /// Apply extrinsic to the block builder. - pub fn apply_extrinsic(&mut self, extrinsic: E::Extrinsic) -> Result<(), Error> { - self.executor.apply_extrinsic( - &mut self.pending_block, - extrinsic, - self.pending_state.as_externalities() - ).map_err(|e| Error::Executor(Box::new(e))) - } - - /// Finalize the block. - pub fn finalize(mut self) -> Result<ImportOperation<E::BuildBlock, Ba::State>, Error> { - self.executor.finalize_block( - &mut self.pending_block, - self.pending_state.as_externalities() - ).map_err(|e| Error::Executor(Box::new(e)))?; - - Ok(ImportOperation { - block: self.pending_block, - state: self.pending_state, - }) - } + /// Create a new block builder. + pub fn new( + backend: &SharedBackend<E::Block, A, Ba>, + executor: &'a E, + parent_hash: &<E::Block as Block>::Identifier, + inherent: E::Inherent, + ) -> Result<Self, Error> { + let parent_block = backend + .read() + .block_at(parent_hash) + .map_err(|e| Error::Backend(Box::new(e)))?; + + let mut pending_state = backend + .read() + .state_at(parent_hash) + .map_err(|e| Error::Backend(Box::new(e)))?; + + let pending_block = executor + .initialize_block(&parent_block, pending_state.as_externalities(), inherent) + .map_err(|e| Error::Executor(Box::new(e)))?; + + Ok(Self { + executor, + pending_block, + pending_state, + }) + } + + /// Apply extrinsic to the block builder. + pub fn apply_extrinsic(&mut self, extrinsic: E::Extrinsic) -> Result<(), Error> { + self.executor + .apply_extrinsic( + &mut self.pending_block, + extrinsic, + self.pending_state.as_externalities(), + ) + .map_err(|e| Error::Executor(Box::new(e))) + } + + /// Finalize the block. + pub fn finalize(mut self) -> Result<ImportOperation<E::BuildBlock, Ba::State>, Error> { + self.executor + .finalize_block( + &mut self.pending_block, + self.pending_state.as_externalities(), + ) + .map_err(|e| Error::Executor(Box::new(e)))?; + + Ok(ImportOperation { + block: self.pending_block, + state: self.pending_state, + }) + } } diff --git a/src/chain/importer.rs b/src/chain/importer.rs index 9c59ef0..93a5bac 100644 --- a/src/chain/importer.rs +++ b/src/chain/importer.rs @@ -1,113 +1,131 @@ -use std::sync::{Arc, RwLock, Mutex, MutexGuard}; -use std::ops::Deref; -use std::marker::PhantomData; use super::Error; -use crate::traits::{Operation, ImportOperation, Block, BlockExecutor, Backend, AsExternalities, Auxiliary, ChainQuery}; +use crate::traits::{ + AsExternalities, Auxiliary, Backend, Block, BlockExecutor, ChainQuery, ImportOperation, + Operation, +}; +use std::marker::PhantomData; +use std::ops::Deref; +use std::sync::{Arc, Mutex, MutexGuard, RwLock}; /// A shared backend that also allows atomic import operation. pub struct SharedBackend<B: Block, A: Auxiliary<B>, Ba: Backend<B, A>> { - backend: Arc<RwLock<Ba>>, - import_lock: Arc<Mutex<()>>, - _marker: PhantomData<(B, A)>, + backend: Arc<RwLock<Ba>>, + import_lock: Arc<Mutex<()>>, + _marker: PhantomData<(B, A)>, } -impl<B: Block, A: Auxiliary<B>, Ba> SharedBackend<B, A, Ba> where - Ba: Backend<B, A> +impl<B: Block, A: Auxiliary<B>, Ba> SharedBackend<B, A, Ba> +where + Ba: Backend<B, A>, { - /// Create a new shared backend. - pub fn new(backend: Ba) -> Self { - Self { - backend: Arc::new(RwLock::new(backend)), - import_lock: Arc::new(Mutex::new(())), - _marker: PhantomData, - } - } + /// Create a new shared backend. + pub fn new(backend: Ba) -> Self { + Self { + backend: Arc::new(RwLock::new(backend)), + import_lock: Arc::new(Mutex::new(())), + _marker: PhantomData, + } + } - /// Return a read handle of the backend. - pub fn read<'a>(&'a self) -> impl Deref<Target=Ba> + 'a { - self.backend.read().expect("backend lock is poisoned") - } + /// Return a read handle of the backend. + pub fn read<'a>(&'a self) -> impl Deref<Target = Ba> + 'a { + self.backend.read().expect("backend lock is poisoned") + } - /// Begin an import operation, returns an importer. - pub fn begin_import<'a, 'executor, E: BlockExecutor<Block=B>>( - &'a self, - executor: &'executor E - ) -> Importer<'a, 'executor, E, A, Ba> where - Ba::State: AsExternalities<E::Externalities> - { - Importer { - executor, - backend: self, - pending: Default::default(), - _guard: self.import_lock.lock().expect("Import mutex is poisoned"), - } - } + /// Begin an import operation, returns an importer. + pub fn begin_import<'a, 'executor, E: BlockExecutor<Block = B>>( + &'a self, + executor: &'executor E, + ) -> Importer<'a, 'executor, E, A, Ba> + where + Ba::State: AsExternalities<E::Externalities>, + { + Importer { + executor, + backend: self, + pending: Default::default(), + _guard: self.import_lock.lock().expect("Import mutex is poisoned"), + } + } } impl<B: Block, A: Auxiliary<B>, Ba: Backend<B, A>> Clone for SharedBackend<B, A, Ba> { - fn clone(&self) -> Self { - SharedBackend { - backend: self.backend.clone(), - import_lock: self.import_lock.clone(), - _marker: PhantomData, - } - } + fn clone(&self) -> Self { + SharedBackend { + backend: self.backend.clone(), + import_lock: self.import_lock.clone(), + _marker: PhantomData, + } + } } /// Block importer. -pub struct Importer<'a, 'executor, E: BlockExecutor, A: Auxiliary<E::Block>, Ba: Backend<E::Block, A>> { - executor: &'executor E, - backend: &'a SharedBackend<E::Block, A, Ba>, - pending: Operation<E::Block, Ba::State, A>, - _guard: MutexGuard<'a, ()>, +pub struct Importer< + 'a, + 'executor, + E: BlockExecutor, + A: Auxiliary<E::Block>, + Ba: Backend<E::Block, A>, +> { + executor: &'executor E, + backend: &'a SharedBackend<E::Block, A, Ba>, + pending: Operation<E::Block, Ba::State, A>, + _guard: MutexGuard<'a, ()>, } -impl<'a, 'executor, E: BlockExecutor, A: Auxiliary<E::Block>, Ba: ChainQuery<E::Block, A>> Importer<'a, 'executor, E, A, Ba> where - <Ba as Backend<E::Block, A>>::State: AsExternalities<E::Externalities>, +impl<'a, 'executor, E: BlockExecutor, A: Auxiliary<E::Block>, Ba: ChainQuery<E::Block, A>> + Importer<'a, 'executor, E, A, Ba> +where + <Ba as Backend<E::Block, A>>::State: AsExternalities<E::Externalities>, { - /// Get the associated backend of the importer. - pub fn backend(&self) -> &'a SharedBackend<E::Block, A, Ba> { - self.backend - } + /// Get the associated backend of the importer. + pub fn backend(&self) -> &'a SharedBackend<E::Block, A, Ba> { + self.backend + } - /// Import a new block. - pub fn import_block(&mut self, block: E::Block) -> Result<(), Error> { - let mut state = self.backend - .read() - .state_at(&block.parent_id().ok_or(Error::IsGenesis)?) - .map_err(|e| Error::Backend(Box::new(e)))?; - self.executor.execute_block(&block, state.as_externalities()) - .map_err(|e| Error::Executor(Box::new(e)))?; + /// Import a new block. + pub fn import_block(&mut self, block: E::Block) -> Result<(), Error> { + let mut state = self + .backend + .read() + .state_at(&block.parent_id().ok_or(Error::IsGenesis)?) + .map_err(|e| Error::Backend(Box::new(e)))?; + self.executor + .execute_block(&block, state.as_externalities()) + .map_err(|e| Error::Executor(Box::new(e)))?; - let operation = ImportOperation { block, state }; - self.import_raw(operation); + let operation = ImportOperation { block, state }; + self.import_raw(operation); - Ok(()) - } + Ok(()) + } - /// Import a raw block. - pub fn import_raw(&mut self, operation: ImportOperation<E::Block, Ba::State>) { - self.pending.import_block.push(operation); - } + /// Import a raw block. + pub fn import_raw(&mut self, operation: ImportOperation<E::Block, Ba::State>) { + self.pending.import_block.push(operation); + } - /// Set head to given hash. - pub fn set_head(&mut self, head: <E::Block as Block>::Identifier) { - self.pending.set_head = Some(head); - } + /// Set head to given hash. + pub fn set_head(&mut self, head: <E::Block as Block>::Identifier) { + self.pending.set_head = Some(head); + } - /// Insert auxiliary value. - pub fn insert_auxiliary(&mut self, aux: A) { - self.pending.insert_auxiliaries.push(aux); - } + /// Insert auxiliary value. + pub fn insert_auxiliary(&mut self, aux: A) { + self.pending.insert_auxiliaries.push(aux); + } - /// Remove auxiliary value. - pub fn remove_auxiliary(&mut self, aux_key: A::Key) { - self.pending.remove_auxiliaries.push(aux_key); - } + /// Remove auxiliary value. + pub fn remove_auxiliary(&mut self, aux_key: A::Key) { + self.pending.remove_auxiliaries.push(aux_key); + } - /// Commit operation and drop import lock. - pub fn commit(self) -> Result<(), Ba::Error> { - self.backend.backend.write().expect("backend lock is poisoned") - .commit(self.pending) - } + /// Commit operation and drop import lock. + pub fn commit(self) -> Result<(), Ba::Error> { + self.backend + .backend + .write() + .expect("backend lock is poisoned") + .commit(self.pending) + } } diff --git a/src/chain/mod.rs b/src/chain/mod.rs index 3e8c8b8..9a00699 100644 --- a/src/chain/mod.rs +++ b/src/chain/mod.rs @@ -1,45 +1,45 @@ //! Chain importer and block builder. -mod importer; mod block_builder; +mod importer; -pub use self::importer::{SharedBackend, Importer}; pub use self::block_builder::BlockBuilder; +pub use self::importer::{Importer, SharedBackend}; -use std::{fmt, error as stderror}; +use std::{error as stderror, fmt}; /// Error type for chain. #[derive(Debug)] pub enum Error { - /// Backend error. - Backend(Box<stderror::Error>), - /// Executor error. - Executor(Box<stderror::Error>), - /// Block is genesis block and cannot be imported. - IsGenesis, - /// Parent is not in the backend so block cannot be imported. - ParentNotFound, + /// Backend error. + Backend(Box<stderror::Error>), + /// Executor error. + Executor(Box<stderror::Error>), + /// Block is genesis block and cannot be imported. + IsGenesis, + /// Parent is not in the backend so block cannot be imported. + ParentNotFound, } impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Error::Backend(_) => "Backend failure".fmt(f)?, - Error::Executor(_) => "Executor failure".fmt(f)?, - Error::IsGenesis => "Block is genesis block and cannot be imported".fmt(f)?, - Error::ParentNotFound => "Parent block cannot be found".fmt(f)?, - } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Error::Backend(_) => "Backend failure".fmt(f)?, + Error::Executor(_) => "Executor failure".fmt(f)?, + Error::IsGenesis => "Block is genesis block and cannot be imported".fmt(f)?, + Error::ParentNotFound => "Parent block cannot be found".fmt(f)?, + } - Ok(()) - } + Ok(()) + } } impl stderror::Error for Error { - fn source(&self) -> Option<&(dyn stderror::Error + 'static)> { - match self { - Error::Backend(e) => Some(e.as_ref()), - Error::Executor(e) => Some(e.as_ref()), - Error::IsGenesis | Error::ParentNotFound => None, - } - } + fn source(&self) -> Option<&(dyn stderror::Error + 'static)> { + match self { + Error::Backend(e) => Some(e.as_ref()), + Error::Executor(e) => Some(e.as_ref()), + Error::IsGenesis | Error::ParentNotFound => None, + } + } } diff --git a/src/lib.rs b/src/lib.rs index f180042..dcddefb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,6 @@ #![warn(missing_docs)] -pub mod traits; -pub mod chain; pub mod backend; +pub mod chain; +pub mod traits; diff --git a/src/traits.rs b/src/traits.rs index 9a87e4f..a6d4d6a 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -19,218 +19,202 @@ use std::hash; /// A block contains a hash, and reference a parent block via parent hash. pub trait Block: Clone { - /// Hash type of the block. - type Identifier: Copy + Eq + hash::Hash; + /// Hash type of the block. + type Identifier: Copy + Eq + hash::Hash; - /// Get the block hash. - fn id(&self) -> Self::Identifier; - /// Get the parent block hash. None if this block is genesis. - fn parent_id(&self) -> Option<Self::Identifier>; + /// Get the block hash. + fn id(&self) -> Self::Identifier; + /// Get the parent block hash. None if this block is genesis. + fn parent_id(&self) -> Option<Self::Identifier>; } /// A value where the key is contained in. pub trait Auxiliary<B: Block>: Clone { - /// Key type - type Key: Copy + Eq + hash::Hash; - - /// Return the key of this object. - fn key(&self) -> Self::Key; - /// Return block ids associated with this auxiliary. If the backend - /// removes any of the blocks listed here, it is expected to remove - /// this auxiliary entry, and trigger a recalculation for the - /// consensus engine. - fn associated(&self) -> Vec<B::Identifier> { - Vec::new() - } + /// Key type + type Key: Copy + Eq + hash::Hash; + + /// Return the key of this object. + fn key(&self) -> Self::Key; + /// Return block ids associated with this auxiliary. If the backend + /// removes any of the blocks listed here, it is expected to remove + /// this auxiliary entry, and trigger a recalculation for the + /// consensus engine. + fn associated(&self) -> Vec<B::Identifier> { + Vec::new() + } } impl<B: Block> Auxiliary<B> for () { - type Key = (); + type Key = (); - fn key(&self) -> () { () } + fn key(&self) -> () { + () + } } /// Trait that allows conversion into externalities. pub trait AsExternalities<E: ?Sized> { - /// Turn this object into externalities. - fn as_externalities(&mut self) -> &mut E; + /// Turn this object into externalities. + fn as_externalities(&mut self) -> &mut E; } /// Null externalities. -pub trait NullExternalities { } +pub trait NullExternalities {} /// Externalities for reading a key value based storage. pub trait StorageExternalities { - /// Read storage value. - fn read_storage(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Box<std::error::Error>>; - /// Write storage value. - fn write_storage(&mut self, key: Vec<u8>, value: Vec<u8>); - /// Remove storage value. - fn remove_storage(&mut self, key: &[u8]); + /// Read storage value. + fn read_storage(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Box<std::error::Error>>; + /// Write storage value. + fn write_storage(&mut self, key: Vec<u8>, value: Vec<u8>); + /// Remove storage value. + fn remove_storage(&mut self, key: &[u8]); } /// Import operation. pub struct ImportOperation<B, S> { - /// Block to be imported. - pub block: B, - /// Associated state of the block. - pub state: S, + /// Block to be imported. + pub block: B, + /// Associated state of the block. + pub state: S, } /// Operation for a backend. pub struct Operation<B: Block, S, A: Auxiliary<B>> { - /// Import operation. - pub import_block: Vec<ImportOperation<B, S>>, - /// Set head operation. - pub set_head: Option<B::Identifier>, - /// Auxiliaries insertion operation. - pub insert_auxiliaries: Vec<A>, - /// Auxiliaries removal operation. - pub remove_auxiliaries: Vec<A::Key>, + /// Import operation. + pub import_block: Vec<ImportOperation<B, S>>, + /// Set head operation. + pub set_head: Option<B::Identifier>, + /// Auxiliaries insertion operation. + pub insert_auxiliaries: Vec<A>, + /// Auxiliaries removal operation. + pub remove_auxiliaries: Vec<A::Key>, } impl<B: Block, S, A: Auxiliary<B>> Default for Operation<B, S, A> { - fn default() -> Self { - Self { - import_block: Vec::new(), - set_head: None, - insert_auxiliaries: Vec::new(), - remove_auxiliaries: Vec::new(), - } - } + fn default() -> Self { + Self { + import_block: Vec::new(), + set_head: None, + insert_auxiliaries: Vec::new(), + remove_auxiliaries: Vec::new(), + } + } } /// Commit-able backend for a block context. pub trait Backend<B: Block, A: Auxiliary<B>> { - /// State type - type State; - /// Error type - type Error: stderror::Error + 'static; - - /// Commit operation. - fn commit( - &mut self, - operation: Operation<B, Self::State, A>, - ) -> Result<(), Self::Error>; + /// State type + type State; + /// Error type + type Error: stderror::Error + 'static; + + /// Commit operation. + fn commit(&mut self, operation: Operation<B, Self::State, A>) -> Result<(), Self::Error>; } /// Chain query interface for a backend. pub trait ChainQuery<B: Block, A: Auxiliary<B>>: Backend<B, A> { - /// Get the genesis hash of the chain. - fn genesis(&self) -> B::Identifier; - /// Get the head of the chain. - fn head(&self) -> B::Identifier; - - /// Check whether a hash is contained in the chain. - fn contains( - &self, - hash: &B::Identifier, - ) -> Result<bool, <Self as Backend<B, A>>::Error>; - - /// Check whether a block is canonical. - fn is_canon( - &self, - hash: &B::Identifier, - ) -> Result<bool, Self::Error>; - - /// Look up a canonical block via its depth. - fn lookup_canon_depth( - &self, - depth: usize, - ) -> Result<Option<B::Identifier>, <Self as Backend<B, A>>::Error>; - - /// Get the auxiliary value by key. - fn auxiliary( - &self, - key: &A::Key, - ) -> Result<Option<A>, <Self as Backend<B, A>>::Error>; - - /// Get the depth of a block. - fn depth_at( - &self, - hash: &B::Identifier, - ) -> Result<usize, <Self as Backend<B, A>>::Error>; - - /// Get children of a block. - fn children_at( - &self, - hash: &B::Identifier, - ) -> Result<Vec<B::Identifier>, <Self as Backend<B, A>>::Error>; - - /// Get the state object of a block. - fn state_at( - &self, - hash: &B::Identifier, - ) -> Result<<Self as Backend<B, A>>::State, <Self as Backend<B, A>>::Error>; - - /// Get the object of a block. - fn block_at( - &self, - hash: &B::Identifier, - ) -> Result<B, <Self as Backend<B, A>>::Error>; + /// Get the genesis hash of the chain. + fn genesis(&self) -> B::Identifier; + /// Get the head of the chain. + fn head(&self) -> B::Identifier; + + /// Check whether a hash is contained in the chain. + fn contains(&self, hash: &B::Identifier) -> Result<bool, <Self as Backend<B, A>>::Error>; + + /// Check whether a block is canonical. + fn is_canon(&self, hash: &B::Identifier) -> Result<bool, Self::Error>; + + /// Look up a canonical block via its depth. + fn lookup_canon_depth( + &self, + depth: usize, + ) -> Result<Option<B::Identifier>, <Self as Backend<B, A>>::Error>; + + /// Get the auxiliary value by key. + fn auxiliary(&self, key: &A::Key) -> Result<Option<A>, <Self as Backend<B, A>>::Error>; + + /// Get the depth of a block. + fn depth_at(&self, hash: &B::Identifier) -> Result<usize, <Self as Backend<B, A>>::Error>; + + /// Get children of a block. + fn children_at( + &self, + hash: &B::Identifier, + ) -> Result<Vec<B::Identifier>, <Self as Backend<B, A>>::Error>; + + /// Get the state object of a block. + fn state_at( + &self, + hash: &B::Identifier, + ) -> Result<<Self as Backend<B, A>>::State, <Self as Backend<B, A>>::Error>; + + /// Get the object of a block. + fn block_at(&self, hash: &B::Identifier) -> Result<B, <Self as Backend<B, A>>::Error>; } /// Trait used for committing block, usually built on top of a backend. pub trait ImportBlock<B: Block> { - /// Error type - type Error: stderror::Error + 'static; + /// Error type + type Error: stderror::Error + 'static; - /// Commit a block into the backend, and handle consensus and auxiliary. - fn import_block(&mut self, block: B) -> Result<(), Self::Error>; + /// Commit a block into the backend, and handle consensus and auxiliary. + fn import_block(&mut self, block: B) -> Result<(), Self::Error>; } /// Block executor pub trait BlockExecutor { - /// Error type - type Error: stderror::Error + 'static; - /// Block type - type Block: Block; - /// Externalities type - type Externalities: ?Sized; - - /// Execute the block via a block object and given state. - fn execute_block( - &self, - block: &Self::Block, - state: &mut Self::Externalities - ) -> Result<(), Self::Error>; + /// Error type + type Error: stderror::Error + 'static; + /// Block type + type Block: Block; + /// Externalities type + type Externalities: ?Sized; + + /// Execute the block via a block object and given state. + fn execute_block( + &self, + block: &Self::Block, + state: &mut Self::Externalities, + ) -> Result<(), Self::Error>; } /// Builder executor pub trait BuilderExecutor { - /// Error type - type Error: stderror::Error + 'static; - /// Block type - type Block: Block; - /// Build block type - type BuildBlock; - /// Externalities type - type Externalities: ?Sized; - /// Inherent - type Inherent; - /// Extrinsic - type Extrinsic; - - /// Initialize a block from the parent block, and given state. - fn initialize_block( - &self, - parent_block: &Self::Block, - state: &mut Self::Externalities, - inherent: Self::Inherent, - ) -> Result<Self::BuildBlock, Self::Error>; - - /// Apply extrinsic to a given block. - fn apply_extrinsic( - &self, - block: &mut Self::BuildBlock, - extrinsic: Self::Extrinsic, - state: &mut Self::Externalities, - ) -> Result<(), Self::Error>; - - /// Finalize a block. - fn finalize_block( - &self, - block: &mut Self::BuildBlock, - state: &mut Self::Externalities, - ) -> Result<(), Self::Error>; + /// Error type + type Error: stderror::Error + 'static; + /// Block type + type Block: Block; + /// Build block type + type BuildBlock; + /// Externalities type + type Externalities: ?Sized; + /// Inherent + type Inherent; + /// Extrinsic + type Extrinsic; + + /// Initialize a block from the parent block, and given state. + fn initialize_block( + &self, + parent_block: &Self::Block, + state: &mut Self::Externalities, + inherent: Self::Inherent, + ) -> Result<Self::BuildBlock, Self::Error>; + + /// Apply extrinsic to a given block. + fn apply_extrinsic( + &self, + block: &mut Self::BuildBlock, + extrinsic: Self::Extrinsic, + state: &mut Self::Externalities, + ) -> Result<(), Self::Error>; + + /// Finalize a block. + fn finalize_block( + &self, + block: &mut Self::BuildBlock, + state: &mut Self::Externalities, + ) -> Result<(), Self::Error>; }