diff --git a/src/block.rs b/src/block.rs index 9727d6a37..4663a0b00 100644 --- a/src/block.rs +++ b/src/block.rs @@ -1,6 +1,7 @@ use util::hash::*; use util::hashdb::*; use util::overlaydb::*; +use blockheader::*; use state::*; /// Active model of a block within the blockchain @@ -9,10 +10,22 @@ pub struct Block { } impl Block { - /// Basic state object from database + /// Creates block with empty state root pub fn new(db: OverlayDB) -> Block { Block { state: State::new(db) } } + + /// Creates block with state root + pub fn new_existing(db: OverlayDB, state_root: H256) -> Block { + Block { + state: State::new_existing(db, state_root) + } + } + + /// Returns mutable reference to backing state + pub fn mutable_state<'a>(&'a mut self) -> &'a mut State { + &mut self.state + } } diff --git a/src/blockchain.rs b/src/blockchain.rs index 895a1dfb6..55a8248f7 100644 --- a/src/blockchain.rs +++ b/src/blockchain.rs @@ -2,20 +2,67 @@ use util::hash::*; use util::rlp::*; use util::hashdb::*; use util::overlaydb::*; +use util::sha3::*; use blockheader::*; use block::*; +use verifiedblock::*; +use importroute::*; pub struct BlockChain { - genesis_hash: H256, - genesis_block: Vec + genesis_block: Vec, + genesis_hash: H256 } impl BlockChain { + pub fn new(genesis_block: Vec) -> BlockChain { + // consider creating `GenesisView` for genesis block RLP + let genesis_hash = BlockView::new(&genesis_block).parent_hash().sha3(); + + BlockChain { + genesis_block: genesis_block, + genesis_hash: genesis_hash + } + } + pub fn genesis_block(&self, db: &OverlayDB) -> Block { let root = BlockView::new(&self.genesis_block).state_root(); + if db.exists(&root) { - return Block::new(db.clone()) + return Block::new_existing(db.clone(), root) } + + let mut block = Block::new(db.clone()); + // TODO: commit genesis state (accounts) to block.state + block.mutable_state().commit_db(); + // TODO: set previous block + // TODO: reset current + block + } + + pub fn verify_block<'a>(&self, block: &'a [u8]) -> VerifiedBlock<'a> { + //TODO: verify block + VerifiedBlock::new(block) + } + + pub fn import_block(&self, block: &[u8], db: &OverlayDB) -> ImportRoute { + let view = BlockView::new(block); + + // check if we already know this block + if self.is_known(&view.sha3()) { + + } + + // check if we already know parent of this block + if !self.is_known(&view.parent_hash()) { + } + + unimplemented!(); + } + + /// Returns true if the given block is known + /// (though not necessarily a part of the canon chain). + pub fn is_known(&self, hash: &H256) -> bool { unimplemented!() + // TODO: check is hash exist in hashes } } diff --git a/src/blockheader.rs b/src/blockheader.rs index 0f5010a37..bfa81ed46 100644 --- a/src/blockheader.rs +++ b/src/blockheader.rs @@ -1,6 +1,7 @@ use util::hash::*; use util::uint::*; use util::rlp::*; +use util::sha3; /// view onto block header rlp pub struct BlockView<'a> { @@ -30,7 +31,14 @@ impl<'a> BlockView<'a> { pub fn nonce(&self) -> H64 { self.rlp.val_at(13) } } +impl<'a> sha3::Hashable for BlockView<'a> { + fn sha3(&self) -> H256 { + self.rlp.data().sha3() + } +} + /// Data structure represening block header +/// similar to cpp-ethereum's BlockInfo pub struct BlockHeader { parent_hash: H256, uncles_hash: H256, diff --git a/src/importroute.rs b/src/importroute.rs new file mode 100644 index 000000000..c544f3e07 --- /dev/null +++ b/src/importroute.rs @@ -0,0 +1,8 @@ +use util::hash::*; +use transaction::*; + +pub struct ImportRoute { + dead_blocks: Vec, + live_blocks: Vec, + transactions: Vec +} diff --git a/src/lib.rs b/src/lib.rs index d66351e83..b6afb47f4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,8 +79,11 @@ extern crate evmjit; pub mod block; pub mod blockchain; pub mod blockheader; - pub mod transaction; +pub mod verifiedblock; +pub mod importroute; + + pub mod networkparams; pub mod denominations; diff --git a/src/state.rs b/src/state.rs index 693544bcd..3b2d4cf2c 100644 --- a/src/state.rs +++ b/src/state.rs @@ -4,17 +4,45 @@ use util::overlaydb::*; use util::trie::*; pub struct State { - trie: TrieDB + db: OverlayDB, + root: H256 } impl State { - pub fn new(db: OverlayDB) -> State { + /// Creates new state with empty state root + pub fn new(mut db: OverlayDB) -> State { + let mut root = H256::new(); + { + // init trie and reset root too null + let _ = TrieDB::new(&mut db, &mut root); + } + State { - trie: TrieDB::new(db) + db: db, + root: root } } + /// Creates new state with existing state root + pub fn new_existing(mut db: OverlayDB, mut root: H256) -> State { + { + // trie should panic! if root does not exist + let _ = TrieDB::new_existing(&mut db, &mut root); + } + + State { + db: db, + root: root + } + } + + /// Create temporary state object pub fn new_temp() -> State { Self::new(OverlayDB::new_temp()) } + + /// Commit everything to the disk + pub fn commit_db(&mut self) { + self.db.commit().expect("Number of kills exceeded number of inserts!"); + } } diff --git a/src/verifiedblock.rs b/src/verifiedblock.rs new file mode 100644 index 000000000..49d2340a7 --- /dev/null +++ b/src/verifiedblock.rs @@ -0,0 +1,17 @@ +use blockheader::*; +use transaction::*; + +pub struct VerifiedBlock<'a> { + blockview: BlockView<'a>, + transactions: Vec +} + +impl<'a> VerifiedBlock<'a> { + // todo, new should also take transactions + pub fn new(bytes: &'a [u8]) -> VerifiedBlock<'a> { + VerifiedBlock { + blockview: BlockView::new(bytes), + transactions: vec![] + } + } +}