diff --git a/docker/hub/Dockerfile b/docker/hub/Dockerfile index 88b11a524..eb007dc10 100644 --- a/docker/hub/Dockerfile +++ b/docker/hub/Dockerfile @@ -34,12 +34,12 @@ RUN apt-get update && \ RUST_BACKTRACE=1 && \ # build parity cd /build&&git clone https://github.com/paritytech/parity-ethereum && \ - cd parity && \ + cd parity-ethereum&& \ git pull&& \ git checkout $BUILD_TAG && \ cargo build --verbose --release --features final && \ - strip /build/parity/target/release/parity && \ - file /build/parity/target/release/parity&&mkdir -p /parity&& cp /build/parity/target/release/parity /parity&&\ + strip /build/parity-ethereum/target/release/parity && \ + file /build/parity-ethereum/target/release/parity&&mkdir -p /parity&& cp /build/parity-ethereum/target/release/parity /parity&&\ #cleanup Docker image rm -rf /root/.cargo&&rm -rf /root/.multirust&&rm -rf /root/.rustup&&rm -rf /build&&\ apt-get purge -y \ diff --git a/ethcore/evm/src/instructions.rs b/ethcore/evm/src/instructions.rs index 7a41ed33c..3be455694 100644 --- a/ethcore/evm/src/instructions.rs +++ b/ethcore/evm/src/instructions.rs @@ -134,6 +134,8 @@ enum_with_from_u8! { RETURNDATASIZE = 0x3d, #[doc = "copy return data buffer to memory"] RETURNDATACOPY = 0x3e, + #[doc = "return the keccak256 hash of contract code"] + EXTCODEHASH = 0x3f, #[doc = "get hash of most recent complete block"] BLOCKHASH = 0x40, @@ -492,6 +494,7 @@ lazy_static! { arr[CALLDATALOAD as usize] = Some(InstructionInfo::new("CALLDATALOAD", 1, 1, GasPriceTier::VeryLow)); arr[CALLDATASIZE as usize] = Some(InstructionInfo::new("CALLDATASIZE", 0, 1, GasPriceTier::Base)); arr[CALLDATACOPY as usize] = Some(InstructionInfo::new("CALLDATACOPY", 3, 0, GasPriceTier::VeryLow)); + arr[EXTCODEHASH as usize] = Some(InstructionInfo::new("EXTCODEHASH", 1, 1, GasPriceTier::Special)); arr[CODESIZE as usize] = Some(InstructionInfo::new("CODESIZE", 0, 1, GasPriceTier::Base)); arr[CODECOPY as usize] = Some(InstructionInfo::new("CODECOPY", 3, 0, GasPriceTier::VeryLow)); arr[GASPRICE as usize] = Some(InstructionInfo::new("GASPRICE", 0, 1, GasPriceTier::Base)); diff --git a/ethcore/evm/src/interpreter/gasometer.rs b/ethcore/evm/src/interpreter/gasometer.rs index dbb333837..943a8320b 100644 --- a/ethcore/evm/src/interpreter/gasometer.rs +++ b/ethcore/evm/src/interpreter/gasometer.rs @@ -143,6 +143,9 @@ impl Gasometer { instructions::EXTCODESIZE => { Request::Gas(Gas::from(schedule.extcodesize_gas)) }, + instructions::EXTCODEHASH => { + Request::Gas(Gas::from(schedule.extcodehash_gas)) + }, instructions::SUICIDE => { let mut gas = Gas::from(schedule.suicide_gas); diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 111986913..6b8abcc17 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -230,8 +230,9 @@ impl Interpreter { (instruction == instructions::STATICCALL && !schedule.have_static_call) || ((instruction == instructions::RETURNDATACOPY || instruction == instructions::RETURNDATASIZE) && !schedule.have_return_data) || (instruction == instructions::REVERT && !schedule.have_revert) || - ((instruction == instructions::SHL || instruction == instructions::SHR || instruction == instructions::SAR) && !schedule.have_bitwise_shifting) { - + ((instruction == instructions::SHL || instruction == instructions::SHR || instruction == instructions::SAR) && !schedule.have_bitwise_shifting) || + (instruction == instructions::EXTCODEHASH && !schedule.have_extcodehash) + { return Err(vm::Error::BadInstruction { instruction: instruction as u8 }); @@ -568,9 +569,14 @@ impl Interpreter { }, instructions::EXTCODESIZE => { let address = u256_to_address(&stack.pop_back()); - let len = ext.extcodesize(&address)?; + let len = ext.extcodesize(&address)?.unwrap_or(0); stack.push(U256::from(len)); }, + instructions::EXTCODEHASH => { + let address = u256_to_address(&stack.pop_back()); + let hash = ext.extcodehash(&address)?.unwrap_or_else(H256::zero); + stack.push(U256::from(hash)); + }, instructions::CALLDATACOPY => { Self::copy_data_to_memory(&mut self.mem, stack, params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8])); }, @@ -591,7 +597,11 @@ impl Interpreter { instructions::EXTCODECOPY => { let address = u256_to_address(&stack.pop_back()); let code = ext.extcode(&address)?; - Self::copy_data_to_memory(&mut self.mem, stack, &code); + Self::copy_data_to_memory( + &mut self.mem, + stack, + code.as_ref().map(|c| &(*c)[..]).unwrap_or(&[]) + ); }, instructions::GASPRICE => { stack.push(params.gas_price.clone()); diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 2cd2fef70..6f1ba7a2f 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -116,10 +116,6 @@ pub struct ExecutedBlock { pub traces: Tracing, /// Hashes of last 256 blocks. pub last_hashes: Arc, - /// Finalization flag. - pub is_finalized: bool, - /// Block metadata. - pub metadata: Option>, } impl ExecutedBlock { @@ -138,8 +134,6 @@ impl ExecutedBlock { Tracing::Disabled }, last_hashes: last_hashes, - is_finalized: false, - metadata: None, } } @@ -228,26 +222,6 @@ impl ::parity_machine::Transactions for ExecutedBlock { } } -impl ::parity_machine::Finalizable for ExecutedBlock { - fn is_finalized(&self) -> bool { - self.is_finalized - } - - fn mark_finalized(&mut self) { - self.is_finalized = true; - } -} - -impl ::parity_machine::WithMetadata for ExecutedBlock { - fn metadata(&self) -> Option<&[u8]> { - self.metadata.as_ref().map(|v| v.as_ref()) - } - - fn set_metadata(&mut self, value: Option>) { - self.metadata = value; - } -} - /// Block that is ready for transactions to be added. /// /// It's a bit like a Vec, except that whenever a transaction is pushed, we execute it and @@ -264,10 +238,7 @@ pub struct OpenBlock<'x> { #[derive(Clone)] pub struct ClosedBlock { block: ExecutedBlock, - uncle_bytes: Bytes, unclosed_state: State, - unclosed_finalization_state: bool, - unclosed_metadata: Option>, } /// Just like `ClosedBlock` except that we can't reopen it and it's faster. @@ -276,7 +247,6 @@ pub struct ClosedBlock { #[derive(Clone)] pub struct LockedBlock { block: ExecutedBlock, - uncle_bytes: Bytes, } /// A block that has a valid seal. @@ -284,7 +254,6 @@ pub struct LockedBlock { /// The block's header has valid seal arguments. The block cannot be reversed into a `ClosedBlock` or `OpenBlock`. pub struct SealedBlock { block: ExecutedBlock, - uncle_bytes: Bytes, } impl<'x> OpenBlock<'x> { @@ -432,14 +401,12 @@ impl<'x> OpenBlock<'x> { let mut s = self; let unclosed_state = s.block.state.clone(); - let unclosed_metadata = s.block.metadata.clone(); - let unclosed_finalization_state = s.block.is_finalized; s.engine.on_close_block(&mut s.block)?; s.block.state.commit()?; s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes()))); - let uncle_bytes = encode_list(&s.block.uncles).into_vec(); + let uncle_bytes = encode_list(&s.block.uncles); s.block.header.set_uncles_hash(keccak(&uncle_bytes)); s.block.header.set_state_root(s.block.state.root().clone()); s.block.header.set_receipts_root(ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes()))); @@ -451,10 +418,7 @@ impl<'x> OpenBlock<'x> { Ok(ClosedBlock { block: s.block, - uncle_bytes, unclosed_state, - unclosed_metadata, - unclosed_finalization_state, }) } @@ -468,8 +432,8 @@ impl<'x> OpenBlock<'x> { if s.block.header.transactions_root().is_zero() || s.block.header.transactions_root() == &KECCAK_NULL_RLP { s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes()))); } - let uncle_bytes = encode_list(&s.block.uncles).into_vec(); if s.block.header.uncles_hash().is_zero() || s.block.header.uncles_hash() == &KECCAK_EMPTY_LIST_RLP { + let uncle_bytes = encode_list(&s.block.uncles); s.block.header.set_uncles_hash(keccak(&uncle_bytes)); } if s.block.header.receipts_root().is_zero() || s.block.header.receipts_root() == &KECCAK_NULL_RLP { @@ -485,7 +449,6 @@ impl<'x> OpenBlock<'x> { Ok(LockedBlock { block: s.block, - uncle_bytes, }) } @@ -514,7 +477,6 @@ impl ClosedBlock { pub fn lock(self) -> LockedBlock { LockedBlock { block: self.block, - uncle_bytes: self.uncle_bytes, } } @@ -523,8 +485,6 @@ impl ClosedBlock { // revert rewards (i.e. set state back at last transaction's state). let mut block = self.block; block.state = self.unclosed_state; - block.metadata = self.unclosed_metadata; - block.is_finalized = self.unclosed_finalization_state; OpenBlock { block: block, engine: engine, @@ -533,7 +493,6 @@ impl ClosedBlock { } impl LockedBlock { - /// Removes outcomes from receipts and updates the receipt root. /// /// This is done after the block is enacted for historical reasons. @@ -566,7 +525,9 @@ impl LockedBlock { } s.block.header.set_seal(seal); s.block.header.compute_hash(); - Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }) + Ok(SealedBlock { + block: s.block + }) } /// Provide a valid seal in order to turn this into a `SealedBlock`. @@ -584,7 +545,9 @@ impl LockedBlock { // TODO: passing state context to avoid engines owning it? match engine.verify_local_seal(&s.block.header) { Err(e) => Err((e, s)), - _ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }), + _ => Ok(SealedBlock { + block: s.block + }), } } } @@ -601,7 +564,7 @@ impl SealedBlock { let mut block_rlp = RlpStream::new_list(3); block_rlp.append(&self.block.header); block_rlp.append_list(&self.block.transactions); - block_rlp.append_raw(&self.uncle_bytes, 1); + block_rlp.append_list(&self.block.uncles); block_rlp.out() } } diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 5977a0a81..01becd182 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -450,9 +450,7 @@ impl<'a> Iterator for AncestryWithMetadataIter<'a> { Some(ExtendedHeader { parent_total_difficulty: details.total_difficulty - *header.difficulty(), is_finalized: details.is_finalized, - metadata: details.metadata, - - header: header, + header, }) }, _ => { @@ -555,7 +553,6 @@ impl BlockChain { parent: header.parent_hash(), children: vec![], is_finalized: false, - metadata: None, }; let mut batch = DBTransaction::new(); @@ -759,10 +756,11 @@ impl BlockChain { /// `parent_td` is a parent total diffuculty /// Supply a dummy parent total difficulty when the parent block may not be in the chain. /// Returns true if the block is disconnected. - pub fn insert_unordered_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, parent_td: Option, is_best: bool, is_ancient: bool) -> bool { - let block = view!(BlockView, bytes); - let header = block.header_view(); - let hash = header.hash(); + pub fn insert_unordered_block(&self, batch: &mut DBTransaction, block: encoded::Block, receipts: Vec, parent_td: Option, is_best: bool, is_ancient: bool) -> bool { + let block_number = block.header_view().number(); + let block_parent_hash = block.header_view().parent_hash(); + let block_difficulty = block.header_view().difficulty(); + let hash = block.header_view().hash(); if self.is_known(&hash) { return false; @@ -770,45 +768,45 @@ impl BlockChain { assert!(self.pending_best_block.read().is_none()); - let compressed_header = compress(block.header_rlp().as_raw(), blocks_swapper()); - let compressed_body = compress(&Self::block_to_body(bytes), blocks_swapper()); + let compressed_header = compress(block.header_view().rlp().as_raw(), blocks_swapper()); + let compressed_body = compress(&Self::block_to_body(block.raw()), blocks_swapper()); // store block in db batch.put(db::COL_HEADERS, &hash, &compressed_header); batch.put(db::COL_BODIES, &hash, &compressed_body); - let maybe_parent = self.block_details(&header.parent_hash()); + let maybe_parent = self.block_details(&block_parent_hash); if let Some(parent_details) = maybe_parent { // parent known to be in chain. let info = BlockInfo { hash: hash, - number: header.number(), - total_difficulty: parent_details.total_difficulty + header.difficulty(), + number: block_number, + total_difficulty: parent_details.total_difficulty + block_difficulty, location: BlockLocation::CanonChain, }; self.prepare_update(batch, ExtrasUpdate { - block_hashes: self.prepare_block_hashes_update(bytes, &info), - block_details: self.prepare_block_details_update(bytes, &info, false, None), + block_hashes: self.prepare_block_hashes_update(&info), + block_details: self.prepare_block_details_update(block_parent_hash, &info, false), block_receipts: self.prepare_block_receipts_update(receipts, &info), - blocks_blooms: self.prepare_block_blooms_update(bytes, &info), - transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), + blocks_blooms: self.prepare_block_blooms_update(block.header_view().log_bloom(), &info), + transactions_addresses: self.prepare_transaction_addresses_update(block.view().transaction_hashes(), &info), info: info, - block: bytes + block, }, is_best); if is_ancient { let mut best_ancient_block = self.best_ancient_block.write(); let ancient_number = best_ancient_block.as_ref().map_or(0, |b| b.number); - if self.block_hash(header.number() + 1).is_some() { + if self.block_hash(block_number + 1).is_some() { batch.delete(db::COL_EXTRA, b"ancient"); *best_ancient_block = None; - } else if header.number() > ancient_number { + } else if block_number > ancient_number { batch.put(db::COL_EXTRA, b"ancient", &hash); *best_ancient_block = Some(BestAncientBlock { hash: hash, - number: header.number(), + number: block_number, }); } } @@ -821,32 +819,31 @@ impl BlockChain { let info = BlockInfo { hash: hash, - number: header.number(), - total_difficulty: d + header.difficulty(), + number: block_number, + total_difficulty: d + block_difficulty, location: BlockLocation::CanonChain, }; // TODO [sorpaas] support warp sync insertion of finalization and metadata. let block_details = BlockDetails { - number: header.number(), + number: block_number, total_difficulty: info.total_difficulty, - parent: header.parent_hash(), + parent: block_parent_hash, children: Vec::new(), is_finalized: false, - metadata: None, }; let mut update = HashMap::new(); update.insert(hash, block_details); self.prepare_update(batch, ExtrasUpdate { - block_hashes: self.prepare_block_hashes_update(bytes, &info), + block_hashes: self.prepare_block_hashes_update(&info), block_details: update, block_receipts: self.prepare_block_receipts_update(receipts, &info), - blocks_blooms: self.prepare_block_blooms_update(bytes, &info), - transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), + blocks_blooms: self.prepare_block_blooms_update(block.header_view().log_bloom(), &info), + transactions_addresses: self.prepare_transaction_addresses_update(block.view().transaction_hashes(), &info), info: info, - block: bytes, + block, }, is_best); true } @@ -958,41 +955,36 @@ impl BlockChain { /// Inserts the block into backing cache database. /// Expects the block to be valid and already verified. /// If the block is already known, does nothing. - pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, extras: ExtrasInsert) -> ImportRoute { - let block = view!(BlockView, bytes); - let header = block.header_view(); - - let parent_hash = header.parent_hash(); + pub fn insert_block(&self, batch: &mut DBTransaction, block: encoded::Block, receipts: Vec, extras: ExtrasInsert) -> ImportRoute { + let parent_hash = block.header_view().parent_hash(); let best_hash = self.best_block_hash(); let route = self.tree_route(best_hash, parent_hash).expect("forks are only kept when it has common ancestors; tree route from best to prospective's parent always exists; qed"); - self.insert_block_with_route(batch, bytes, receipts, route, extras) + self.insert_block_with_route(batch, block, receipts, route, extras) } /// Inserts the block into backing cache database with already generated route information. /// Expects the block to be valid and already verified and route is tree route information from current best block to new block's parent. /// If the block is already known, does nothing. - pub fn insert_block_with_route(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, route: TreeRoute, extras: ExtrasInsert) -> ImportRoute { - // create views onto rlp - let block = view!(BlockView, bytes); - let header = block.header_view(); - let hash = header.hash(); + pub fn insert_block_with_route(&self, batch: &mut DBTransaction, block: encoded::Block, receipts: Vec, route: TreeRoute, extras: ExtrasInsert) -> ImportRoute { + let hash = block.header_view().hash(); + let parent_hash = block.header_view().parent_hash(); - if self.is_known_child(&header.parent_hash(), &hash) { + if self.is_known_child(&parent_hash, &hash) { return ImportRoute::none(); } assert!(self.pending_best_block.read().is_none()); - let compressed_header = compress(block.header_rlp().as_raw(), blocks_swapper()); - let compressed_body = compress(&Self::block_to_body(bytes), blocks_swapper()); + let compressed_header = compress(block.header_view().rlp().as_raw(), blocks_swapper()); + let compressed_body = compress(&Self::block_to_body(block.raw()), blocks_swapper()); // store block in db batch.put(db::COL_HEADERS, &hash, &compressed_header); batch.put(db::COL_BODIES, &hash, &compressed_body); - let info = self.block_info(&header, route, &extras); + let info = self.block_info(&block.header_view(), route, &extras); if let BlockLocation::BranchBecomingCanonChain(ref d) = info.location { info!(target: "reorg", "Reorg to {} ({} {} {})", @@ -1004,13 +996,13 @@ impl BlockChain { } self.prepare_update(batch, ExtrasUpdate { - block_hashes: self.prepare_block_hashes_update(bytes, &info), - block_details: self.prepare_block_details_update(bytes, &info, extras.is_finalized, extras.metadata), + block_hashes: self.prepare_block_hashes_update(&info), + block_details: self.prepare_block_details_update(parent_hash, &info, extras.is_finalized), block_receipts: self.prepare_block_receipts_update(receipts, &info), - blocks_blooms: self.prepare_block_blooms_update(bytes, &info), - transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), + blocks_blooms: self.prepare_block_blooms_update(block.header_view().log_bloom(), &info), + transactions_addresses: self.prepare_transaction_addresses_update(block.view().transaction_hashes(), &info), info: info.clone(), - block: bytes, + block, }, true); ImportRoute::from(info) @@ -1090,11 +1082,10 @@ impl BlockChain { let mut best_block = self.pending_best_block.write(); if is_best && update.info.location != BlockLocation::Branch { batch.put(db::COL_EXTRA, b"best", &update.info.hash); - let block = encoded::Block::new(update.block.to_vec()); *best_block = Some(BestBlock { total_difficulty: update.info.total_difficulty, - header: block.decode_header(), - block, + header: update.block.decode_header(), + block: update.block, }); } @@ -1214,16 +1205,13 @@ impl BlockChain { } /// This function returns modified block hashes. - fn prepare_block_hashes_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { + fn prepare_block_hashes_update(&self, info: &BlockInfo) -> HashMap { let mut block_hashes = HashMap::new(); - let block = view!(BlockView, block_bytes); - let header = block.header_view(); - let number = header.number(); match info.location { BlockLocation::Branch => (), BlockLocation::CanonChain => { - block_hashes.insert(number, info.hash); + block_hashes.insert(info.number, info.hash); }, BlockLocation::BranchBecomingCanonChain(ref data) => { let ancestor_number = self.block_number(&data.ancestor).expect("Block number of ancestor is always in DB"); @@ -1233,7 +1221,7 @@ impl BlockChain { block_hashes.insert(start_number + index as BlockNumber, hash); } - block_hashes.insert(number, info.hash); + block_hashes.insert(info.number, info.hash); } } @@ -1242,23 +1230,18 @@ impl BlockChain { /// This function returns modified block details. /// Uses the given parent details or attempts to load them from the database. - fn prepare_block_details_update(&self, block_bytes: &[u8], info: &BlockInfo, is_finalized: bool, metadata: Option>) -> HashMap { - let block = view!(BlockView, block_bytes); - let header = block.header_view(); - let parent_hash = header.parent_hash(); - + fn prepare_block_details_update(&self, parent_hash: H256, info: &BlockInfo, is_finalized: bool) -> HashMap { // update parent let mut parent_details = self.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); parent_details.children.push(info.hash); // create current block details. let details = BlockDetails { - number: header.number(), + number: info.number, total_difficulty: info.total_difficulty, parent: parent_hash, children: vec![], is_finalized: is_finalized, - metadata: metadata, }; // write to batch @@ -1276,10 +1259,7 @@ impl BlockChain { } /// This function returns modified transaction addresses. - fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap> { - let block = view!(BlockView, block_bytes); - let transaction_hashes = block.transaction_hashes(); - + fn prepare_transaction_addresses_update(&self, transaction_hashes: Vec, info: &BlockInfo) -> HashMap> { match info.location { BlockLocation::CanonChain => { transaction_hashes.into_iter() @@ -1344,14 +1324,10 @@ impl BlockChain { /// Later, BloomIndexer is used to map bloom location on filter layer (BloomIndex) /// to bloom location in database (BlocksBloomLocation). /// - fn prepare_block_blooms_update(&self, block_bytes: &[u8], info: &BlockInfo) -> Option<(u64, Vec)> { - let block = view!(BlockView, block_bytes); - let header = block.header_view(); - + fn prepare_block_blooms_update(&self, log_bloom: Bloom, info: &BlockInfo) -> Option<(u64, Vec)> { match info.location { BlockLocation::Branch => None, BlockLocation::CanonChain => { - let log_bloom = header.log_bloom(); if log_bloom.is_zero() { None } else { @@ -1369,7 +1345,7 @@ impl BlockChain { .map(|h| h.log_bloom()) .collect(); - blooms.push(header.log_bloom()); + blooms.push(log_bloom); Some((start_number, blooms)) } } @@ -1505,18 +1481,19 @@ mod tests { use log_entry::{LogEntry, LocalizedLogEntry}; use ethkey::Secret; use test_helpers::new_db; + use encoded; - fn new_chain(genesis: &[u8], db: Arc) -> BlockChain { - BlockChain::new(Config::default(), genesis, db) + fn new_chain(genesis: encoded::Block, db: Arc) -> BlockChain { + BlockChain::new(Config::default(), genesis.raw(), db) } - fn insert_block(db: &Arc, bc: &BlockChain, bytes: &[u8], receipts: Vec) -> ImportRoute { - insert_block_commit(db, bc, bytes, receipts, true) + fn insert_block(db: &Arc, bc: &BlockChain, block: encoded::Block, receipts: Vec) -> ImportRoute { + insert_block_commit(db, bc, block, receipts, true) } - fn insert_block_commit(db: &Arc, bc: &BlockChain, bytes: &[u8], receipts: Vec, commit: bool) -> ImportRoute { + fn insert_block_commit(db: &Arc, bc: &BlockChain, block: encoded::Block, receipts: Vec, commit: bool) -> ImportRoute { let mut batch = db.key_value().transaction(); - let res = insert_block_batch(&mut batch, bc, bytes, receipts); + let res = insert_block_batch(&mut batch, bc, block, receipts); db.key_value().write(batch).unwrap(); if commit { bc.commit(); @@ -1524,25 +1501,24 @@ mod tests { res } - fn insert_block_batch(batch: &mut DBTransaction, bc: &BlockChain, bytes: &[u8], receipts: Vec) -> ImportRoute { - use views::BlockView; + fn insert_block_batch(batch: &mut DBTransaction, bc: &BlockChain, block: encoded::Block, receipts: Vec) -> ImportRoute { use blockchain::ExtrasInsert; - let block = view!(BlockView, bytes); - let header = block.header_view(); - let parent_hash = header.parent_hash(); - let parent_details = bc.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); - let block_total_difficulty = parent_details.total_difficulty + header.difficulty(); - let fork_choice = if block_total_difficulty > bc.best_block_total_difficulty() { - ::engines::ForkChoice::New - } else { - ::engines::ForkChoice::Old + let fork_choice = { + let header = block.header_view(); + let parent_hash = header.parent_hash(); + let parent_details = bc.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); + let block_total_difficulty = parent_details.total_difficulty + header.difficulty(); + if block_total_difficulty > bc.best_block_total_difficulty() { + ::engines::ForkChoice::New + } else { + ::engines::ForkChoice::Old + } }; - bc.insert_block(batch, bytes, receipts, ExtrasInsert { + bc.insert_block(batch, block, receipts, ExtrasInsert { fork_choice: fork_choice, is_finalized: false, - metadata: None }) } @@ -1553,11 +1529,11 @@ mod tests { let first = genesis.add_block(); let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); assert_eq!(bc.best_block_number(), 0); // when - insert_block_commit(&db, &bc, &first.last().encoded(), vec![], false); + insert_block_commit(&db, &bc, first.last().encoded(), vec![], false); assert_eq!(bc.best_block_number(), 0); bc.commit(); // NOTE no db.write here (we want to check if best block is cached) @@ -1578,7 +1554,7 @@ mod tests { let first_hash = first.hash(); let db = new_db(); - let bc = new_chain(&genesis.encoded(), db.clone()); + let bc = new_chain(genesis.encoded(), db.clone()); assert_eq!(bc.genesis_hash(), genesis_hash); assert_eq!(bc.best_block_hash(), genesis_hash); @@ -1587,7 +1563,7 @@ mod tests { assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![]); let mut batch = db.key_value().transaction(); - insert_block_batch(&mut batch, &bc, &first.encoded(), vec![]); + insert_block_batch(&mut batch, &bc, first.encoded(), vec![]); db.key_value().write(batch).unwrap(); bc.commit(); @@ -1607,13 +1583,13 @@ mod tests { let generator = BlockGenerator::new(vec![first_10]); let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); let mut block_hashes = vec![genesis.last().hash()]; let mut batch = db.key_value().transaction(); for block in generator { block_hashes.push(block.hash()); - insert_block_batch(&mut batch, &bc, &block.encoded(), vec![]); + insert_block_batch(&mut batch, &bc, block.encoded(), vec![]); bc.commit(); } db.key_value().write(batch).unwrap(); @@ -1651,10 +1627,10 @@ mod tests { ); let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); for b in generator { - insert_block(&db, &bc, &b.encoded(), vec![]); + insert_block(&db, &bc, b.encoded(), vec![]); } assert_eq!(uncle_headers, bc.find_uncle_headers(&b4a_hash, 3).unwrap()); @@ -1687,12 +1663,12 @@ mod tests { let b2_hash = b2.last().hash(); let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); let mut batch = db.key_value().transaction(); - let _ = insert_block_batch(&mut batch, &bc, &b1a.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, b1a.last().encoded(), vec![]); bc.commit(); - let _ = insert_block_batch(&mut batch, &bc, &b1b.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, b1b.last().encoded(), vec![]); bc.commit(); db.key_value().write(batch).unwrap(); @@ -1704,7 +1680,7 @@ mod tests { // now let's make forked chain the canon chain let mut batch = db.key_value().transaction(); - let _ = insert_block_batch(&mut batch, &bc, &b2.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, b2.last().encoded(), vec![]); bc.commit(); db.key_value().write(batch).unwrap(); @@ -1762,12 +1738,12 @@ mod tests { let t3_hash = t3.hash(); let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); let mut batch = db.key_value().transaction(); - let _ = insert_block_batch(&mut batch, &bc, &b1a.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, b1a.last().encoded(), vec![]); bc.commit(); - let _ = insert_block_batch(&mut batch, &bc, &b1b.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, b1b.last().encoded(), vec![]); bc.commit(); db.key_value().write(batch).unwrap(); @@ -1783,7 +1759,7 @@ mod tests { // now let's make forked chain the canon chain let mut batch = db.key_value().transaction(); - let _ = insert_block_batch(&mut batch, &bc, &b2.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, b2.last().encoded(), vec![]); bc.commit(); db.key_value().write(batch).unwrap(); @@ -1820,19 +1796,19 @@ mod tests { let best_block_hash = b3a_hash; let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); let mut batch = db.key_value().transaction(); - let ir1 = insert_block_batch(&mut batch, &bc, &b1.last().encoded(), vec![]); + let ir1 = insert_block_batch(&mut batch, &bc, b1.last().encoded(), vec![]); bc.commit(); - let ir2 = insert_block_batch(&mut batch, &bc, &b2.last().encoded(), vec![]); + let ir2 = insert_block_batch(&mut batch, &bc, b2.last().encoded(), vec![]); bc.commit(); - let ir3b = insert_block_batch(&mut batch, &bc, &b3b.last().encoded(), vec![]); + let ir3b = insert_block_batch(&mut batch, &bc, b3b.last().encoded(), vec![]); bc.commit(); db.key_value().write(batch).unwrap(); assert_eq!(bc.block_hash(3).unwrap(), b3b_hash); let mut batch = db.key_value().transaction(); - let ir3a = insert_block_batch(&mut batch, &bc, &b3a.last().encoded(), vec![]); + let ir3a = insert_block_batch(&mut batch, &bc, b3a.last().encoded(), vec![]); bc.commit(); db.key_value().write(batch).unwrap(); @@ -1934,17 +1910,17 @@ mod tests { let db = new_db(); { - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); assert_eq!(bc.best_block_hash(), genesis_hash); let mut batch = db.key_value().transaction(); - insert_block_batch(&mut batch, &bc, &first.last().encoded(), vec![]); + insert_block_batch(&mut batch, &bc, first.last().encoded(), vec![]); db.key_value().write(batch).unwrap(); bc.commit(); assert_eq!(bc.best_block_hash(), first_hash); } { - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); assert_eq!(bc.best_block_hash(), first_hash); } @@ -1994,9 +1970,9 @@ mod tests { let b1_hash: H256 = "f53f268d23a71e85c7d6d83a9504298712b84c1a2ba220441c86eeda0bf0b6e3".into(); let db = new_db(); - let bc = new_chain(&genesis, db.clone()); + let bc = new_chain(encoded::Block::new(genesis), db.clone()); let mut batch = db.key_value().transaction(); - insert_block_batch(&mut batch, &bc, &b1, vec![]); + insert_block_batch(&mut batch, &bc, encoded::Block::new(b1), vec![]); db.key_value().write(batch).unwrap(); bc.commit(); @@ -2062,8 +2038,8 @@ mod tests { let b3_number = b3.last().number(); let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); - insert_block(&db, &bc, &b1.last().encoded(), vec![Receipt { + let bc = new_chain(genesis.last().encoded(), db.clone()); + insert_block(&db, &bc, b1.last().encoded(), vec![Receipt { outcome: TransactionOutcome::StateRoot(H256::default()), gas_used: 10_000.into(), log_bloom: Default::default(), @@ -2080,7 +2056,7 @@ mod tests { LogEntry { address: Default::default(), topics: vec![], data: vec![3], }, ], }]); - insert_block(&db, &bc, &b2.last().encoded(), vec![ + insert_block(&db, &bc, b2.last().encoded(), vec![ Receipt { outcome: TransactionOutcome::StateRoot(H256::default()), gas_used: 10_000.into(), @@ -2090,7 +2066,7 @@ mod tests { ], } ]); - insert_block(&db, &bc, &b3.last().encoded(), vec![ + insert_block(&db, &bc, b3.last().encoded(), vec![ Receipt { outcome: TransactionOutcome::StateRoot(H256::default()), gas_used: 10_000.into(), @@ -2190,27 +2166,27 @@ mod tests { let b2a = b1a.add_block_with_bloom(bloom_ba); let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); let blocks_b1 = bc.blocks_with_bloom(Some(&bloom_b1), 0, 5); let blocks_b2 = bc.blocks_with_bloom(Some(&bloom_b2), 0, 5); assert!(blocks_b1.is_empty()); assert!(blocks_b2.is_empty()); - insert_block(&db, &bc, &b1.last().encoded(), vec![]); + insert_block(&db, &bc, b1.last().encoded(), vec![]); let blocks_b1 = bc.blocks_with_bloom(Some(&bloom_b1), 0, 5); let blocks_b2 = bc.blocks_with_bloom(Some(&bloom_b2), 0, 5); assert_eq!(blocks_b1, vec![1]); assert!(blocks_b2.is_empty()); - insert_block(&db, &bc, &b2.last().encoded(), vec![]); + insert_block(&db, &bc, b2.last().encoded(), vec![]); let blocks_b1 = bc.blocks_with_bloom(Some(&bloom_b1), 0, 5); let blocks_b2 = bc.blocks_with_bloom(Some(&bloom_b2), 0, 5); assert_eq!(blocks_b1, vec![1]); assert_eq!(blocks_b2, vec![2]); // hasn't been forked yet - insert_block(&db, &bc, &b1a.last().encoded(), vec![]); + insert_block(&db, &bc, b1a.last().encoded(), vec![]); let blocks_b1 = bc.blocks_with_bloom(Some(&bloom_b1), 0, 5); let blocks_b2 = bc.blocks_with_bloom(Some(&bloom_b2), 0, 5); let blocks_ba = bc.blocks_with_bloom(Some(&bloom_ba), 0, 5); @@ -2219,7 +2195,7 @@ mod tests { assert!(blocks_ba.is_empty()); // fork has happend - insert_block(&db, &bc, &b2a.last().encoded(), vec![]); + insert_block(&db, &bc, b2a.last().encoded(), vec![]); let blocks_b1 = bc.blocks_with_bloom(Some(&bloom_b1), 0, 5); let blocks_b2 = bc.blocks_with_bloom(Some(&bloom_b2), 0, 5); let blocks_ba = bc.blocks_with_bloom(Some(&bloom_ba), 0, 5); @@ -2228,7 +2204,7 @@ mod tests { assert_eq!(blocks_ba, vec![1, 2]); // fork back - insert_block(&db, &bc, &b3.last().encoded(), vec![]); + insert_block(&db, &bc, b3.last().encoded(), vec![]); let blocks_b1 = bc.blocks_with_bloom(Some(&bloom_b1), 0, 5); let blocks_b2 = bc.blocks_with_bloom(Some(&bloom_b2), 0, 5); let blocks_ba = bc.blocks_with_bloom(Some(&bloom_ba), 0, 5); @@ -2252,13 +2228,13 @@ mod tests { let b1_total_difficulty = genesis.last().difficulty() + b1.last().difficulty(); let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); let mut batch = db.key_value().transaction(); - bc.insert_unordered_block(&mut batch, &b2.last().encoded(), vec![], Some(b1_total_difficulty), false, false); + bc.insert_unordered_block(&mut batch, b2.last().encoded(), vec![], Some(b1_total_difficulty), false, false); bc.commit(); - bc.insert_unordered_block(&mut batch, &b3.last().encoded(), vec![], None, true, false); + bc.insert_unordered_block(&mut batch, b3.last().encoded(), vec![], None, true, false); bc.commit(); - bc.insert_unordered_block(&mut batch, &b1.last().encoded(), vec![], None, false, false); + bc.insert_unordered_block(&mut batch, b1.last().encoded(), vec![], None, false, false); bc.commit(); db.key_value().write(batch).unwrap(); @@ -2285,23 +2261,23 @@ mod tests { let db = new_db(); { - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); let mut batch = db.key_value().transaction(); // create a longer fork for block in generator { - insert_block_batch(&mut batch, &bc, &block.encoded(), vec![]); + insert_block_batch(&mut batch, &bc, block.encoded(), vec![]); bc.commit(); } assert_eq!(bc.best_block_number(), 5); - insert_block_batch(&mut batch, &bc, &uncle.last().encoded(), vec![]); + insert_block_batch(&mut batch, &bc, uncle.last().encoded(), vec![]); db.key_value().write(batch).unwrap(); bc.commit(); } // re-loading the blockchain should load the correct best block. - let bc = new_chain(&genesis.last().encoded(), db); + let bc = new_chain(genesis.last().encoded(), db); assert_eq!(bc.best_block_number(), 5); } @@ -2316,13 +2292,13 @@ mod tests { let db = new_db(); { - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); let mut batch = db.key_value().transaction(); // create a longer fork for (i, block) in generator.into_iter().enumerate() { - insert_block_batch(&mut batch, &bc, &block.encoded(), vec![]); + insert_block_batch(&mut batch, &bc, block.encoded(), vec![]); bc.insert_epoch_transition(&mut batch, i as u64, EpochTransition { block_hash: block.hash(), block_number: i as u64 + 1, @@ -2333,7 +2309,7 @@ mod tests { assert_eq!(bc.best_block_number(), 5); - insert_block_batch(&mut batch, &bc, &uncle.last().encoded(), vec![]); + insert_block_batch(&mut batch, &bc, uncle.last().encoded(), vec![]); bc.insert_epoch_transition(&mut batch, 999, EpochTransition { block_hash: uncle.last().hash(), block_number: 1, @@ -2348,7 +2324,7 @@ mod tests { } // re-loading the blockchain should load the correct best block. - let bc = new_chain(&genesis.last().encoded(), db); + let bc = new_chain(genesis.last().encoded(), db); assert_eq!(bc.best_block_number(), 5); assert_eq!(bc.epoch_transitions().map(|(i, _)| i).collect::>(), vec![0, 1, 2, 3, 4]); @@ -2369,7 +2345,7 @@ mod tests { let db = new_db(); - let bc = new_chain(&genesis.last().encoded(), db.clone()); + let bc = new_chain(genesis.last().encoded(), db.clone()); let mut batch = db.key_value().transaction(); bc.insert_epoch_transition(&mut batch, 0, EpochTransition { @@ -2383,7 +2359,7 @@ mod tests { // and a non-canonical fork of 8 from genesis. let fork_hash = { for block in fork_generator { - insert_block(&db, &bc, &block.encoded(), vec![]); + insert_block(&db, &bc, block.encoded(), vec![]); } assert_eq!(bc.best_block_number(), 7); @@ -2391,7 +2367,7 @@ mod tests { }; for block in next_generator { - insert_block(&db, &bc, &block.encoded(), vec![]); + insert_block(&db, &bc, block.encoded(), vec![]); } assert_eq!(bc.best_block_number(), 10); diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index bbf67374a..1dd51b7c7 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -152,17 +152,15 @@ pub struct BlockDetails { pub children: Vec, /// Whether the block is considered finalized pub is_finalized: bool, - /// Additional block metadata - pub metadata: Option>, } impl rlp::Encodable for BlockDetails { fn rlp_append(&self, stream: &mut rlp::RlpStream) { - let use_short_version = self.metadata.is_none() && !self.is_finalized; + let use_short_version = !self.is_finalized; match use_short_version { true => { stream.begin_list(4); }, - false => { stream.begin_list(6); }, + false => { stream.begin_list(5); }, } stream.append(&self.number); @@ -171,7 +169,6 @@ impl rlp::Encodable for BlockDetails { stream.append_list(&self.children); if !use_short_version { stream.append(&self.is_finalized); - stream.append(&self.metadata); } } } @@ -180,7 +177,7 @@ impl rlp::Decodable for BlockDetails { fn decode(rlp: &rlp::Rlp) -> Result { let use_short_version = match rlp.item_count()? { 4 => true, - 6 => false, + 5 => false, _ => return Err(rlp::DecoderError::RlpIncorrectListLen), }; @@ -194,11 +191,6 @@ impl rlp::Decodable for BlockDetails { } else { rlp.val_at(4)? }, - metadata: if use_short_version { - None - } else { - rlp.val_at(5)? - }, }) } } @@ -252,7 +244,7 @@ pub struct EpochTransitions { #[cfg(test)] mod tests { use rlp::*; - + use super::BlockReceipts; #[test] diff --git a/ethcore/src/blockchain/generator.rs b/ethcore/src/blockchain/generator.rs index 5a97f37f9..44d4e038c 100644 --- a/ethcore/src/blockchain/generator.rs +++ b/ethcore/src/blockchain/generator.rs @@ -19,11 +19,11 @@ use std::collections::VecDeque; use ethereum_types::{U256, H256, Bloom}; -use bytes::Bytes; use header::Header; use rlp::encode; use transaction::SignedTransaction; use views::BlockView; +use encoded; /// Helper structure, used for encoding blocks. #[derive(Default, Clone, RlpEncodable)] @@ -41,7 +41,7 @@ impl Block { #[inline] pub fn hash(&self) -> H256 { - view!(BlockView, &self.encoded()).header_view().hash() + view!(BlockView, &self.encoded().raw()).header_view().hash() } #[inline] @@ -50,8 +50,8 @@ impl Block { } #[inline] - pub fn encoded(&self) -> Bytes { - encode(self).into_vec() + pub fn encoded(&self) -> encoded::Block { + encoded::Block::new(encode(self).into_vec()) } #[inline] diff --git a/ethcore/src/blockchain/update.rs b/ethcore/src/blockchain/update.rs index 0a2d0e774..897abb59b 100644 --- a/ethcore/src/blockchain/update.rs +++ b/ethcore/src/blockchain/update.rs @@ -19,13 +19,14 @@ use ethereum_types::{H256, Bloom}; use header::BlockNumber; use blockchain::block_info::BlockInfo; use blockchain::extras::{BlockDetails, BlockReceipts, TransactionAddress}; +use encoded::Block; /// Block extras update info. -pub struct ExtrasUpdate<'a> { +pub struct ExtrasUpdate { /// Block info. pub info: BlockInfo, /// Current block uncompressed rlp bytes - pub block: &'a [u8], + pub block: Block, /// Modified block hashes. pub block_hashes: HashMap, /// Modified block details. @@ -44,6 +45,4 @@ pub struct ExtrasInsert { pub fork_choice: ::engines::ForkChoice, /// Is the inserted block considered finalized. pub is_finalized: bool, - /// New block local metadata. - pub metadata: Option>, } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 8278b2ca8..a68c1e495 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -74,7 +74,6 @@ use types::filter::Filter; use types::ancestry_action::AncestryAction; use verification; use verification::{PreverifiedBlock, Verifier, BlockQueue}; -use views::BlockView; // re-export pub use types::blockchain_info::BlockChainInfo; @@ -210,7 +209,7 @@ pub struct Client { /// Queued ancient blocks, make sure they are imported in order. queued_ancient_blocks: Arc, - VecDeque<(Header, Bytes, Bytes)> + VecDeque<(Header, encoded::Block, Bytes)> )>>, ancient_blocks_import_lock: Arc>, /// Consensus messages import queue @@ -297,7 +296,7 @@ impl Importer { let transactions_len = closed_block.transactions().len(); - let route = self.commit_block(closed_block, &header, &bytes, client); + let route = self.commit_block(closed_block, &header, encoded::Block::new(bytes), client); import_results.push(route); client.report.write().accrue_block(&header, transactions_len); @@ -430,9 +429,8 @@ impl Importer { /// /// The block is guaranteed to be the next best blocks in the /// first block sequence. Does no sealing or transaction validation. - fn import_old_block(&self, header: &Header, block_bytes: &[u8], receipts_bytes: &[u8], db: &KeyValueDB, chain: &BlockChain) -> Result { + fn import_old_block(&self, header: &Header, block: encoded::Block, receipts_bytes: &[u8], db: &KeyValueDB, chain: &BlockChain) -> Result<(), ::error::Error> { let receipts = ::rlp::decode_list(receipts_bytes); - let hash = header.hash(); let _import_lock = self.import_lock.lock(); { @@ -443,28 +441,29 @@ impl Importer { // Commit results let mut batch = DBTransaction::new(); - chain.insert_unordered_block(&mut batch, block_bytes, receipts, None, false, true); + chain.insert_unordered_block(&mut batch, block, receipts, None, false, true); // Final commit to the DB db.write_buffered(batch); chain.commit(); } db.flush().expect("DB flush failed."); - Ok(hash) + Ok(()) } // NOTE: the header of the block passed here is not necessarily sealed, as // it is for reconstructing the state transition. // // The header passed is from the original block data and is sealed. - fn commit_block(&self, block: B, header: &Header, block_data: &[u8], client: &Client) -> ImportRoute where B: Drain { + fn commit_block(&self, block: B, header: &Header, block_data: encoded::Block, client: &Client) -> ImportRoute where B: Drain { let hash = &header.hash(); let number = header.number(); let parent = header.parent_hash(); let chain = client.chain.read(); + let is_finalized = false; // Commit results let block = block.drain(); - assert_eq!(header.hash(), view!(BlockView, block_data).header_view().hash()); + debug_assert_eq!(header.hash(), block_data.header_view().hash()); let mut batch = DBTransaction::new(); @@ -476,8 +475,7 @@ impl Importer { let new = ExtendedHeader { header: header.clone(), - is_finalized: block.is_finalized, - metadata: block.metadata, + is_finalized, parent_total_difficulty: chain.block_details(&parent).expect("Parent block is in the database; qed").total_difficulty }; @@ -493,8 +491,6 @@ impl Importer { ExtendedHeader { parent_total_difficulty: details.total_difficulty - *header.difficulty(), is_finalized: details.is_finalized, - metadata: details.metadata, - header: header, } }; @@ -515,7 +511,7 @@ impl Importer { // state. self.check_epoch_end_signal( &header, - block_data, + block_data.raw(), &receipts, &state, &chain, @@ -532,8 +528,7 @@ impl Importer { let route = chain.insert_block(&mut batch, block_data, receipts.clone(), ExtrasInsert { fork_choice: fork_choice, - is_finalized: block.is_finalized, - metadata: new.metadata, + is_finalized, }); client.tracedb.read().import(&mut batch, TraceImportRequest { @@ -1327,7 +1322,7 @@ impl ChainInfo for Client { } impl BlockInfo for Client { - fn block_header(&self, id: BlockId) -> Option<::encoded::Header> { + fn block_header(&self, id: BlockId) -> Option { let chain = self.chain.read(); Self::block_hash(&chain, id).and_then(|hash| chain.block_header_data(&hash)) @@ -1344,7 +1339,7 @@ impl BlockInfo for Client { } fn code_hash(&self, address: &Address, id: BlockId) -> Option { - self.state_at(id).and_then(|s| s.code_hash(address).ok()) + self.state_at(id).and_then(|s| s.code_hash(address).unwrap_or(None)) } } @@ -2053,7 +2048,7 @@ impl IoClient for Client { { let mut queued = self.queued_ancient_blocks.write(); queued.0.insert(hash); - queued.1.push_back((header, block_bytes, receipts_bytes)); + queued.1.push_back((header, encoded::Block::new(block_bytes), receipts_bytes)); } let queued = self.queued_ancient_blocks.clone(); @@ -2069,7 +2064,7 @@ impl IoClient for Client { let hash = header.hash(); let result = client.importer.import_old_block( &header, - &block_bytes, + block_bytes, &receipts_bytes, &**client.db.read().key_value(), &*client.chain.read(), @@ -2194,7 +2189,7 @@ impl ImportSealedBlock for Client { let block_data = block.rlp_bytes(); let header = block.header().clone(); - let route = self.importer.commit_block(block, &header, &block_data, self); + let route = self.importer.commit_block(block, &header, encoded::Block::new(block_data), self); trace!(target: "client", "Imported sealed block #{} ({})", number, h); self.state_db.write().sync_cache(&route.enacted, &route.retracted, false); route @@ -2380,6 +2375,7 @@ mod tests { use std::sync::atomic::{AtomicBool, Ordering}; use kvdb::DBTransaction; use blockchain::ExtrasInsert; + use encoded; let client = generate_dummy_client(0); let genesis = client.chain_info().best_block_hash; @@ -2392,10 +2388,9 @@ mod tests { let another_client = client.clone(); thread::spawn(move || { let mut batch = DBTransaction::new(); - another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new(), ExtrasInsert { + another_client.chain.read().insert_block(&mut batch, encoded::Block::new(new_block), Vec::new(), ExtrasInsert { fork_choice: ::engines::ForkChoice::New, is_finalized: false, - metadata: None, }); go_thread.store(true, Ordering::SeqCst); }); diff --git a/ethcore/src/encoded.rs b/ethcore/src/encoded.rs index 5bd723f0e..9573bb5d1 100644 --- a/ethcore/src/encoded.rs +++ b/ethcore/src/encoded.rs @@ -222,6 +222,11 @@ impl Block { /// Consume the view and return the raw bytes. pub fn into_inner(self) -> Vec { self.0 } + + /// Returns the reference to slice of bytes + pub fn raw(&self) -> &[u8] { + &self.0 + } } // forwarders to borrowed header view. diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 1243eeea3..9bb0bc8f9 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -323,7 +323,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { gas_price: t.gas_price, value: ActionValue::Transfer(t.value), code: self.state.code(address)?, - code_hash: Some(self.state.code_hash(address)?), + code_hash: self.state.code_hash(address)?, data: Some(t.data.clone()), call_type: CallType::Call, params_type: vm::ParamsType::Separate, diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 9aa308a23..c1bd785c4 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -165,7 +165,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> gas: self.machine.params().eip210_contract_gas, gas_price: 0.into(), code: code, - code_hash: Some(code_hash), + code_hash: code_hash, data: Some(H256::from(number).to_vec()), call_type: CallType::Call, params_type: vm::ParamsType::Separate, @@ -272,7 +272,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> gas: *gas, gas_price: self.origin_info.gas_price, code: code, - code_hash: Some(code_hash), + code_hash: code_hash, data: Some(data.to_vec()), call_type: call_type, params_type: vm::ParamsType::Separate, @@ -291,12 +291,16 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> } } - fn extcode(&self, address: &Address) -> vm::Result> { - Ok(self.state.code(address)?.unwrap_or_else(|| Arc::new(vec![]))) + fn extcode(&self, address: &Address) -> vm::Result>> { + Ok(self.state.code(address)?) } - fn extcodesize(&self, address: &Address) -> vm::Result { - Ok(self.state.code_size(address)?.unwrap_or(0)) + fn extcodehash(&self, address: &Address) -> vm::Result> { + Ok(self.state.code_hash(address)?) + } + + fn extcodesize(&self, address: &Address) -> vm::Result> { + Ok(self.state.code_size(address)?) } fn ret(mut self, gas: &U256, data: &ReturnData, apply_state: bool) -> vm::Result diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index 5aa4be323..7896282fc 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -43,8 +43,6 @@ pub struct ExtendedHeader { pub is_finalized: bool, /// The parent block difficulty. pub parent_total_difficulty: U256, - /// The block metadata information. - pub metadata: Option>, } /// A block header. @@ -418,10 +416,6 @@ impl ::parity_machine::FinalizableHeader for ExtendedHeader { fn is_finalized(&self) -> bool { self.is_finalized } } -impl ::parity_machine::WithMetadataHeader for ExtendedHeader { - fn metadata(&self) -> Option<&[u8]> { self.metadata.as_ref().map(|v| v.as_ref()) } -} - #[cfg(test)] mod tests { use rustc_hex::FromHex; diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index 3fc14be2a..a8fd4b453 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -166,14 +166,18 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for TestExt<'a, T, V, B> MessageCallResult::Success(*gas, ReturnData::empty()) } - fn extcode(&self, address: &Address) -> vm::Result> { + fn extcode(&self, address: &Address) -> vm::Result>> { self.ext.extcode(address) } - fn extcodesize(&self, address: &Address) -> vm::Result { + fn extcodesize(&self, address: &Address) -> vm::Result> { self.ext.extcodesize(address) } + fn extcodehash(&self, address: &Address) -> vm::Result> { + self.ext.extcodehash(address) + } + fn log(&mut self, topics: Vec, data: &[u8]) -> vm::Result<()> { self.ext.log(topics, data) } diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index 633f837dc..d58a3878d 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -140,7 +140,7 @@ impl EthereumMachine { gas_price: 0.into(), value: ActionValue::Transfer(0.into()), code: state.code(&contract_address)?, - code_hash: Some(state.code_hash(&contract_address)?), + code_hash: state.code_hash(&contract_address)?, data: data, call_type: CallType::Call, params_type: ParamsType::Separate, diff --git a/ethcore/src/snapshot/consensus/authority.rs b/ethcore/src/snapshot/consensus/authority.rs index 8ae4cc33c..72d828643 100644 --- a/ethcore/src/snapshot/consensus/authority.rs +++ b/ethcore/src/snapshot/consensus/authority.rs @@ -37,6 +37,7 @@ use rlp::{RlpStream, Rlp}; use ethereum_types::{H256, U256}; use kvdb::KeyValueDB; use bytes::Bytes; +use encoded; /// Snapshot creation and restoration for PoA chains. @@ -339,7 +340,7 @@ impl Rebuilder for ChunkRebuilder { let parent_td: U256 = last_rlp.val_at(4)?; let mut batch = self.db.transaction(); - self.chain.insert_unordered_block(&mut batch, &block_data, receipts, Some(parent_td), true, false); + self.chain.insert_unordered_block(&mut batch, encoded::Block::new(block_data), receipts, Some(parent_td), true, false); self.db.write_buffered(batch); self.warp_target = Some(block.header); diff --git a/ethcore/src/snapshot/consensus/work.rs b/ethcore/src/snapshot/consensus/work.rs index 963a96a7f..ded004fe8 100644 --- a/ethcore/src/snapshot/consensus/work.rs +++ b/ethcore/src/snapshot/consensus/work.rs @@ -35,6 +35,7 @@ use kvdb::KeyValueDB; use bytes::Bytes; use rlp::{RlpStream, Rlp}; use rand::OsRng; +use encoded; /// Snapshot creation and restoration for PoW chains. /// This includes blocks from the head of the chain as a @@ -220,7 +221,6 @@ impl Rebuilder for PowRebuilder { /// Feed the rebuilder an uncompressed block chunk. /// Returns the number of blocks fed or any errors. fn feed(&mut self, chunk: &[u8], engine: &EthEngine, abort_flag: &AtomicBool) -> Result<(), ::error::Error> { - use views::BlockView; use snapshot::verify_old_block; use ethereum_types::U256; use triehash::ordered_trie_root; @@ -250,7 +250,7 @@ impl Rebuilder for PowRebuilder { let receipts_root = ordered_trie_root(pair.at(1)?.iter().map(|r| r.as_raw())); let block = abridged_block.to_block(parent_hash, cur_number, receipts_root)?; - let block_bytes = block.rlp_bytes(); + let block_bytes = encoded::Block::new(block.rlp_bytes()); let is_best = cur_number == self.best_number; if is_best { @@ -275,16 +275,16 @@ impl Rebuilder for PowRebuilder { // special-case the first block in each chunk. if idx == 3 { - if self.chain.insert_unordered_block(&mut batch, &block_bytes, receipts, Some(parent_total_difficulty), is_best, false) { + if self.chain.insert_unordered_block(&mut batch, block_bytes, receipts, Some(parent_total_difficulty), is_best, false) { self.disconnected.push((cur_number, block.header.hash())); } } else { - self.chain.insert_unordered_block(&mut batch, &block_bytes, receipts, None, is_best, false); + self.chain.insert_unordered_block(&mut batch, block_bytes, receipts, None, is_best, false); } self.db.write_buffered(batch); self.chain.commit(); - parent_hash = view!(BlockView, &block_bytes).hash(); + parent_hash = block.header.hash(); cur_number += 1; } diff --git a/ethcore/src/snapshot/tests/proof_of_work.rs b/ethcore/src/snapshot/tests/proof_of_work.rs index 40733c328..257269968 100644 --- a/ethcore/src/snapshot/tests/proof_of_work.rs +++ b/ethcore/src/snapshot/tests/proof_of_work.rs @@ -43,15 +43,14 @@ fn chunk_and_restore(amount: u64) { let snapshot_path = tempdir.path().join("SNAP"); let old_db = test_helpers::new_db(); - let bc = BlockChain::new(Default::default(), &genesis.encoded(), old_db.clone()); + let bc = BlockChain::new(Default::default(), genesis.encoded().raw(), old_db.clone()); // build the blockchain. let mut batch = DBTransaction::new(); for block in generator { - bc.insert_block(&mut batch, &block.encoded(), vec![], ExtrasInsert { + bc.insert_block(&mut batch, block.encoded(), vec![], ExtrasInsert { fork_choice: ::engines::ForkChoice::New, is_finalized: false, - metadata: None, }); bc.commit(); } @@ -83,7 +82,7 @@ fn chunk_and_restore(amount: u64) { // restore it. let new_db = test_helpers::new_db(); - let new_chain = BlockChain::new(Default::default(), &genesis.encoded(), new_db.clone()); + let new_chain = BlockChain::new(Default::default(), genesis.encoded().raw(), new_db.clone()); let mut rebuilder = SNAPSHOT_MODE.rebuilder(new_chain, new_db.clone(), &manifest).unwrap(); let reader = PackedReader::new(&snapshot_path).unwrap().unwrap(); @@ -98,7 +97,7 @@ fn chunk_and_restore(amount: u64) { drop(rebuilder); // and test it. - let new_chain = BlockChain::new(Default::default(), &genesis.encoded(), new_db); + let new_chain = BlockChain::new(Default::default(), genesis.encoded().raw(), new_db); assert_eq!(new_chain.best_block_hash(), best_hash); } @@ -130,7 +129,7 @@ fn checks_flag() { let db = test_helpers::new_db(); let engine = ::spec::Spec::new_test().engine; - let chain = BlockChain::new(Default::default(), &genesis.last().encoded(), db.clone()); + let chain = BlockChain::new(Default::default(), genesis.last().encoded().raw(), db.clone()); let manifest = ::snapshot::ManifestData { version: 2, diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 015755f83..d79775f78 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -115,6 +115,8 @@ pub struct CommonParams { pub eip214_transition: BlockNumber, /// Number of first block where EIP-145 rules begin. pub eip145_transition: BlockNumber, + /// Number of first block where EIP-1052 rules begin. + pub eip1052_transition: BlockNumber, /// Number of first block where dust cleanup rules (EIP-168 and EIP169) begin. pub dust_protection_transition: BlockNumber, /// Nonce cap increase per block. Nonce cap is only checked if dust protection is enabled. @@ -174,6 +176,7 @@ impl CommonParams { schedule.have_static_call = block_number >= self.eip214_transition; schedule.have_return_data = block_number >= self.eip211_transition; schedule.have_bitwise_shifting = block_number >= self.eip145_transition; + schedule.have_extcodehash = block_number >= self.eip1052_transition; if block_number >= self.eip210_transition { schedule.blockhash_gas = 800; } @@ -270,6 +273,10 @@ impl From for CommonParams { BlockNumber::max_value, Into::into, ), + eip1052_transition: p.eip1052_transition.map_or_else( + BlockNumber::max_value, + Into::into, + ), dust_protection_transition: p.dust_protection_transition.map_or_else( BlockNumber::max_value, Into::into, diff --git a/ethcore/src/state/account.rs b/ethcore/src/state/account.rs index 359b84b1e..eec713a4e 100644 --- a/ethcore/src/state/account.rs +++ b/ethcore/src/state/account.rs @@ -278,12 +278,13 @@ impl Account { !self.code_cache.is_empty() || (self.code_cache.is_empty() && self.code_hash == KECCAK_EMPTY) } - /// Provide a database to get `code_hash`. Should not be called if it is a contract without code. + /// Provide a database to get `code_hash`. Should not be called if it is a contract without code. Returns the cached code, if successful. + #[must_use] pub fn cache_code(&mut self, db: &HashDB) -> Option> { // TODO: fill out self.code_cache; trace!("Account::cache_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty()); - if self.is_cached() { return Some(self.code_cache.clone()) } + if self.is_cached() { return Some(self.code_cache.clone()); } match db.get(&self.code_hash) { Some(x) => { @@ -298,8 +299,7 @@ impl Account { } } - /// Provide code to cache. For correctness, should be the correct code for the - /// account. + /// Provide code to cache. For correctness, should be the correct code for the account. pub fn cache_given_code(&mut self, code: Arc) { trace!("Account::cache_given_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty()); @@ -307,7 +307,9 @@ impl Account { self.code_cache = code; } - /// Provide a database to get `code_size`. Should not be called if it is a contract without code. + /// Provide a database to get `code_size`. Should not be called if it is a contract without code. Returns whether + /// the cache succeeds. + #[must_use] pub fn cache_code_size(&mut self, db: &HashDB) -> bool { // TODO: fill out self.code_cache; trace!("Account::cache_code_size: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty()); @@ -324,7 +326,9 @@ impl Account { }, } } else { - false + // If the code hash is empty hash, then the code size is zero. + self.code_size = Some(0); + true } } diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 796ec0c1d..323e11ccb 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -608,9 +608,9 @@ impl State { } /// Get an account's code hash. - pub fn code_hash(&self, a: &Address) -> TrieResult { + pub fn code_hash(&self, a: &Address) -> TrieResult> { self.ensure_cached(a, RequireCache::None, true, - |a| a.as_ref().map_or(KECCAK_EMPTY, |a| a.code_hash())) + |a| a.as_ref().map(|a| a.code_hash())) } /// Get accounts' code size. @@ -911,31 +911,38 @@ impl State { Ok(pod_state::diff_pod(&pod_state_pre, &pod_state_post)) } - // load required account data from the databases. - fn update_account_cache(require: RequireCache, account: &mut Account, state_db: &B, db: &HashDB) { + /// Load required account data from the databases. Returns whether the cache succeeds. + #[must_use] + fn update_account_cache(require: RequireCache, account: &mut Account, state_db: &B, db: &HashDB) -> bool { if let RequireCache::None = require { - return; + return true; } if account.is_cached() { - return; + return true; } // if there's already code in the global cache, always cache it localy let hash = account.code_hash(); match state_db.get_cached_code(&hash) { - Some(code) => account.cache_given_code(code), + Some(code) => { + account.cache_given_code(code); + true + }, None => match require { - RequireCache::None => {}, + RequireCache::None => true, RequireCache::Code => { if let Some(code) = account.cache_code(db) { // propagate code loaded from the database to // the global code cache. - state_db.cache_code(hash, code) + state_db.cache_code(hash, code); + true + } else { + false } }, RequireCache::CodeSize => { - account.cache_code_size(db); + account.cache_code_size(db) } } } @@ -950,8 +957,11 @@ impl State { if let Some(ref mut maybe_acc) = self.cache.borrow_mut().get_mut(a) { if let Some(ref mut account) = maybe_acc.account { let accountdb = self.factories.accountdb.readonly(self.db.as_hashdb(), account.address_hash(a)); - Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb()); - return Ok(f(Some(account))); + if Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb()) { + return Ok(f(Some(account))); + } else { + return Err(Box::new(TrieError::IncompleteDatabase(H256::from(a)))); + } } return Ok(f(None)); } @@ -959,12 +969,14 @@ impl State { let result = self.db.get_cached(a, |mut acc| { if let Some(ref mut account) = acc { let accountdb = self.factories.accountdb.readonly(self.db.as_hashdb(), account.address_hash(a)); - Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb()); + if !Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb()) { + return Err(Box::new(TrieError::IncompleteDatabase(H256::from(a)))); + } } - f(acc.map(|a| &*a)) + Ok(f(acc.map(|a| &*a))) }); match result { - Some(r) => Ok(r), + Some(r) => Ok(r?), None => { // first check if it is not in database for sure if check_null && self.db.is_known_null(a) { return Ok(f(None)); } @@ -975,7 +987,9 @@ impl State { let mut maybe_acc = db.get_with(a, from_rlp)?; if let Some(ref mut account) = maybe_acc.as_mut() { let accountdb = self.factories.accountdb.readonly(self.db.as_hashdb(), account.address_hash(a)); - Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb()); + if !Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb()) { + return Err(Box::new(TrieError::IncompleteDatabase(H256::from(a)))); + } } let r = f(maybe_acc.as_ref()); self.insert_cache(a, AccountEntry::new_clean(maybe_acc)); diff --git a/ethcore/src/test_helpers.rs b/ethcore/src/test_helpers.rs index 443e0418b..408714571 100644 --- a/ethcore/src/test_helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -43,6 +43,7 @@ use blooms_db; use kvdb::KeyValueDB; use kvdb_rocksdb; use tempdir::TempDir; +use encoded; /// Creates test block with corresponding header pub fn create_test_block(header: &Header) -> Bytes { @@ -354,10 +355,9 @@ pub fn generate_dummy_blockchain(block_number: u32) -> BlockChain { let mut batch = db.key_value().transaction(); for block_order in 1..block_number { // Total difficulty is always 0 here. - bc.insert_block(&mut batch, &create_unverifiable_block(block_order, bc.best_block_hash()), vec![], ExtrasInsert { + bc.insert_block(&mut batch, encoded::Block::new(create_unverifiable_block(block_order, bc.best_block_hash())), vec![], ExtrasInsert { fork_choice: ::engines::ForkChoice::New, is_finalized: false, - metadata: None, }); bc.commit(); } @@ -373,10 +373,9 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> BlockChain { let mut batch = db.key_value().transaction(); for block_order in 1..block_number { // Total difficulty is always 0 here. - bc.insert_block(&mut batch, &create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), vec![], ExtrasInsert { + bc.insert_block(&mut batch, encoded::Block::new(create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None)), vec![], ExtrasInsert { fork_choice: ::engines::ForkChoice::New, is_finalized: false, - metadata: None, }); bc.commit(); } diff --git a/ethcore/src/trace/mod.rs b/ethcore/src/trace/mod.rs index 569b2a679..90ea64b5d 100644 --- a/ethcore/src/trace/mod.rs +++ b/ethcore/src/trace/mod.rs @@ -49,15 +49,21 @@ pub trait Tracer: Send { type Output; /// Prepares call trace for given params. Noop tracer should return None. + /// + /// This is called before a call has been executed. fn prepare_trace_call(&self, params: &ActionParams) -> Option; /// Prepares create trace for given params. Noop tracer should return None. + /// + /// This is called before a create has been executed. fn prepare_trace_create(&self, params: &ActionParams) -> Option; /// Prepare trace output. Noop tracer should return None. fn prepare_trace_output(&self) -> Option; /// Stores trace call info. + /// + /// This is called after a call has completed successfully. fn trace_call( &mut self, call: Option, @@ -67,6 +73,8 @@ pub trait Tracer: Send { ); /// Stores trace create info. + /// + /// This is called after a create has completed successfully. fn trace_create( &mut self, create: Option, @@ -77,9 +85,13 @@ pub trait Tracer: Send { ); /// Stores failed call trace. + /// + /// This is called after a call has completed erroneously. fn trace_failed_call(&mut self, call: Option, subs: Vec, error: TraceError); /// Stores failed create trace. + /// + /// This is called after a create has completed erroneously. fn trace_failed_create(&mut self, create: Option, subs: Vec, error: TraceError); /// Stores suicide info. diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index a02101354..a0ecf9634 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -467,7 +467,6 @@ mod tests { parent: header.parent_hash().clone(), children: Vec::new(), is_finalized: false, - metadata: None, } }) } diff --git a/ethcore/vm/src/ext.rs b/ethcore/vm/src/ext.rs index 166e8712a..b6d41a395 100644 --- a/ethcore/vm/src/ext.rs +++ b/ethcore/vm/src/ext.rs @@ -106,10 +106,13 @@ pub trait Ext { ) -> MessageCallResult; /// Returns code at given address - fn extcode(&self, address: &Address) -> Result>; + fn extcode(&self, address: &Address) -> Result>>; + + /// Returns code hash at given address + fn extcodehash(&self, address: &Address) -> Result>; /// Returns code size at given address - fn extcodesize(&self, address: &Address) -> Result; + fn extcodesize(&self, address: &Address) -> Result>; /// Creates log entry with given topics and data fn log(&mut self, topics: Vec, data: &[u8]) -> Result<()>; diff --git a/ethcore/vm/src/schedule.rs b/ethcore/vm/src/schedule.rs index 960821e72..6215aed78 100644 --- a/ethcore/vm/src/schedule.rs +++ b/ethcore/vm/src/schedule.rs @@ -26,6 +26,8 @@ pub struct Schedule { pub have_create2: bool, /// Does it have a REVERT instruction pub have_revert: bool, + /// Does it have a EXTCODEHASH instruction + pub have_extcodehash: bool, /// VM stack limit pub stack_limit: usize, /// Max number of nested calls/creates @@ -92,6 +94,8 @@ pub struct Schedule { pub extcodecopy_base_gas: usize, /// Price of BALANCE pub balance_gas: usize, + /// Price of EXTCODEHASH + pub extcodehash_gas: usize, /// Price of SUICIDE pub suicide_gas: usize, /// Amount of additional gas to pay when SUICIDE credits a non-existant account @@ -197,6 +201,7 @@ impl Schedule { have_revert: false, have_return_data: false, have_bitwise_shifting: false, + have_extcodehash: false, stack_limit: 1024, max_depth: 1024, tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], @@ -229,6 +234,7 @@ impl Schedule { copy_gas: 3, extcodesize_gas: 700, extcodecopy_base_gas: 700, + extcodehash_gas: 400, balance_gas: 400, suicide_gas: 5000, suicide_to_new_account_cost: 25000, @@ -268,6 +274,7 @@ impl Schedule { have_revert: false, have_return_data: false, have_bitwise_shifting: false, + have_extcodehash: false, stack_limit: 1024, max_depth: 1024, tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], @@ -300,6 +307,7 @@ impl Schedule { copy_gas: 3, extcodesize_gas: 20, extcodecopy_base_gas: 20, + extcodehash_gas: 400, balance_gas: 20, suicide_gas: 0, suicide_to_new_account_cost: 0, diff --git a/ethcore/vm/src/tests.rs b/ethcore/vm/src/tests.rs index 9a17e0d3d..d83e6881a 100644 --- a/ethcore/vm/src/tests.rs +++ b/ethcore/vm/src/tests.rs @@ -24,6 +24,7 @@ use { ReturnData, Ext, ContractCreateResult, MessageCallResult, CreateContractAddress, Result, GasLeft, }; +use hash::keccak; pub struct FakeLogEntry { pub topics: Vec, @@ -168,12 +169,16 @@ impl Ext for FakeExt { MessageCallResult::Success(*gas, ReturnData::empty()) } - fn extcode(&self, address: &Address) -> Result> { - Ok(self.codes.get(address).unwrap_or(&Arc::new(Bytes::new())).clone()) + fn extcode(&self, address: &Address) -> Result>> { + Ok(self.codes.get(address).cloned()) } - fn extcodesize(&self, address: &Address) -> Result { - Ok(self.codes.get(address).map_or(0, |c| c.len())) + fn extcodesize(&self, address: &Address) -> Result> { + Ok(self.codes.get(address).map(|c| c.len())) + } + + fn extcodehash(&self, address: &Address) -> Result> { + Ok(self.codes.get(address).map(|c| keccak(c.as_ref()))) } fn log(&mut self, topics: Vec, data: &[u8]) -> Result<()> { diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index e03fe7081..a37e4f23b 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -109,6 +109,9 @@ pub struct Params { #[serde(rename="eip658Transition")] pub eip658_transition: Option, /// See `CommonParams` docs. + #[serde(rename="eip1052Transition")] + pub eip1052_transition: Option, + /// See `CommonParams` docs. #[serde(rename="dustProtectionTransition")] pub dust_protection_transition: Option, /// See `CommonParams` docs. diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 6d152851d..a3f640fe5 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -95,22 +95,6 @@ pub trait Transactions: LiveBlock { fn transactions(&self) -> &[Self::Transaction]; } -/// Trait for blocks which have finalized information. -pub trait Finalizable: LiveBlock { - /// Get whether the block is finalized. - fn is_finalized(&self) -> bool; - /// Mark the block as finalized. - fn mark_finalized(&mut self); -} - -/// A state machine with block metadata. -pub trait WithMetadata: LiveBlock { - /// Get the current live block metadata. - fn metadata(&self) -> Option<&[u8]>; - /// Set the current live block metadata. - fn set_metadata(&mut self, value: Option>); -} - /// Generalization of types surrounding blockchain-suitable state machines. pub trait Machine: for<'a> LocalizedMachine<'a> { /// The block header type.