diff --git a/ethcore/src/basic_authority.rs b/ethcore/src/basic_authority.rs index c732ce711..c96179574 100644 --- a/ethcore/src/basic_authority.rs +++ b/ethcore/src/basic_authority.rs @@ -215,8 +215,9 @@ mod tests { timestamp: 0, difficulty: 0.into(), last_hashes: vec![], + dao_rescue_block_gas_limit: None, gas_used: 0.into(), - gas_limit: 0.into() + gas_limit: 0.into(), }); assert!(schedule.stack_limit > 0); @@ -278,7 +279,7 @@ mod tests { spec.ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; let vm_factory = Default::default(); - let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, addr.clone(), 3141562.into(), vec![]).unwrap(); + let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, addr.clone(), 3141562.into(), vec![]).unwrap(); let b = b.close_and_lock(); let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap(); diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 74f54a057..ff05b5af1 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -177,6 +177,7 @@ pub struct OpenBlock<'x> { engine: &'x Engine, vm_factory: &'x EvmFactory, last_hashes: LastHashes, + dao_rescue_block_gas_limit: Option, } /// Just like `OpenBlock`, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields, @@ -188,6 +189,7 @@ pub struct ClosedBlock { block: ExecutedBlock, uncle_bytes: Bytes, last_hashes: LastHashes, + dao_rescue_block_gas_limit: Option, unclosed_state: State, } @@ -198,7 +200,6 @@ pub struct ClosedBlock { pub struct LockedBlock { block: ExecutedBlock, uncle_bytes: Bytes, - last_hashes: LastHashes, } /// A block that has a valid seal. @@ -219,9 +220,10 @@ impl<'x> OpenBlock<'x> { db: Box, parent: &Header, last_hashes: LastHashes, + dao_rescue_block_gas_limit: Option, author: Address, gas_floor_target: U256, - extra_data: Bytes + extra_data: Bytes, ) -> Result { let state = try!(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce())); let mut r = OpenBlock { @@ -229,6 +231,7 @@ impl<'x> OpenBlock<'x> { engine: engine, vm_factory: vm_factory, last_hashes: last_hashes, + dao_rescue_block_gas_limit: dao_rescue_block_gas_limit, }; r.block.base.header.parent_hash = parent.hash(); @@ -293,6 +296,7 @@ impl<'x> OpenBlock<'x> { last_hashes: self.last_hashes.clone(), // TODO: should be a reference. gas_used: self.block.receipts.last().map_or(U256::zero(), |r| r.gas_used), gas_limit: self.block.base.header.gas_limit.clone(), + dao_rescue_block_gas_limit: if self.block.base.header.number == 1760000 { Some(self.block.base.header.gas_limit) } else { self.dao_rescue_block_gas_limit }, } } @@ -339,6 +343,7 @@ impl<'x> OpenBlock<'x> { block: s.block, uncle_bytes: uncle_bytes, last_hashes: s.last_hashes, + dao_rescue_block_gas_limit: s.dao_rescue_block_gas_limit, unclosed_state: unclosed_state, } } @@ -360,7 +365,6 @@ impl<'x> OpenBlock<'x> { LockedBlock { block: s.block, uncle_bytes: uncle_bytes, - last_hashes: s.last_hashes, } } } @@ -386,7 +390,6 @@ impl ClosedBlock { LockedBlock { block: self.block, uncle_bytes: self.uncle_bytes, - last_hashes: self.last_hashes, } } @@ -400,6 +403,7 @@ impl ClosedBlock { engine: engine, vm_factory: vm_factory, last_hashes: self.last_hashes, + dao_rescue_block_gas_limit: self.dao_rescue_block_gas_limit, } } } @@ -456,7 +460,18 @@ impl IsBlock for SealedBlock { /// Enact the block given by block header, transactions and uncles #[cfg_attr(feature="dev", allow(too_many_arguments))] -pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, tracing: bool, db: Box, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result { +pub fn enact( + header: &Header, + transactions: &[SignedTransaction], + uncles: &[Header], + engine: &Engine, + tracing: bool, + db: Box, + parent: &Header, + last_hashes: LastHashes, + dao_rescue_block_gas_limit: Option, + vm_factory: &EvmFactory +) -> Result { { if ::log::max_log_level() >= ::log::LogLevel::Trace { let s = try!(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce())); @@ -464,7 +479,7 @@ pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Head } } - let mut b = try!(OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, header.author().clone(), 3141562.into(), header.extra_data().clone())); + let mut b = try!(OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, header.author().clone(), 3141562.into(), header.extra_data().clone())); b.set_difficulty(*header.difficulty()); b.set_gas_limit(*header.gas_limit()); b.set_timestamp(header.timestamp()); @@ -474,22 +489,49 @@ pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Head } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, tracing: bool, db: Box, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result { +pub fn enact_bytes( + block_bytes: &[u8], + engine: &Engine, + tracing: bool, + db: Box, + parent: &Header, + last_hashes: LastHashes, + dao_rescue_block_gas_limit: Option, + vm_factory: &EvmFactory +) -> Result { let block = BlockView::new(block_bytes); let header = block.header(); - enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, vm_factory) + enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory) } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, tracing: bool, db: Box, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result { +pub fn enact_verified( + block: &PreverifiedBlock, + engine: &Engine, + tracing: bool, + db: Box, + parent: &Header, + last_hashes: LastHashes, + dao_rescue_block_gas_limit: Option, + vm_factory: &EvmFactory +) -> Result { let view = BlockView::new(&block.bytes); - enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, vm_factory) + enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory) } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards -pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, tracing: bool, db: Box, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result { +pub fn enact_and_seal( + block_bytes: &[u8], + engine: &Engine, + tracing: bool, + db: Box, + parent: &Header, + last_hashes: LastHashes, + dao_rescue_block_gas_limit: Option, + vm_factory: &EvmFactory +) -> Result { let header = BlockView::new(block_bytes).header_view(); - Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, vm_factory)).seal(engine, header.seal()))) + Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)).seal(engine, header.seal()))) } #[cfg(test)] @@ -509,7 +551,7 @@ mod tests { spec.ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; let vm_factory = Default::default(); - let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]).unwrap(); + let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), 3141562.into(), vec![]).unwrap(); let b = b.close_and_lock(); let _ = b.seal(engine.deref(), vec![]); } @@ -525,7 +567,7 @@ mod tests { let mut db = db_result.take(); spec.ensure_db_good(db.as_hashdb_mut()); let vm_factory = Default::default(); - let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]).unwrap() + let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), 3141562.into(), vec![]).unwrap() .close_and_lock().seal(engine.deref(), vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); @@ -533,7 +575,7 @@ mod tests { let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); spec.ensure_db_good(db.as_hashdb_mut()); - let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], &Default::default()).unwrap(); + let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default()).unwrap(); assert_eq!(e.rlp_bytes(), orig_bytes); @@ -553,7 +595,7 @@ mod tests { let mut db = db_result.take(); spec.ensure_db_good(db.as_hashdb_mut()); let vm_factory = Default::default(); - let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]).unwrap(); + let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), 3141562.into(), vec![]).unwrap(); let mut uncle1_header = Header::new(); uncle1_header.extra_data = b"uncle1".to_vec(); let mut uncle2_header = Header::new(); @@ -568,7 +610,7 @@ mod tests { let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); spec.ensure_db_good(db.as_hashdb_mut()); - let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], &Default::default()).unwrap(); + let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default()).unwrap(); let bytes = e.rlp_bytes(); assert_eq!(bytes, orig_bytes); diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 85a3d693d..3264ce266 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -220,7 +220,7 @@ impl Client where V: Verifier { let last_hashes = self.build_last_hashes(header.parent_hash.clone()); let db = self.state_db.lock().unwrap().boxed_clone(); - let enact_result = enact_verified(&block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, &self.vm_factory); + let enact_result = enact_verified(&block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, self.dao_rescue_block_gas_limit(), &self.vm_factory); if let Err(e) = enact_result { warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); return Err(()); @@ -462,6 +462,7 @@ impl BlockChainClient for Client where V: Verifier { last_hashes: last_hashes, gas_used: U256::zero(), gas_limit: U256::max_value(), + dao_rescue_block_gas_limit: self.dao_rescue_block_gas_limit(), }; // that's just a copy of the state. let mut state = self.state(); @@ -767,6 +768,7 @@ impl MiningBlockChainClient for Client where V: Verifier { self.state_db.lock().unwrap().boxed_clone(), &self.chain.block_header(&h).expect("h is best block hash: so it's header must exist: qed"), self.build_last_hashes(h.clone()), + self.dao_rescue_block_gas_limit(), author, gas_floor_target, extra_data, diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 3fec68815..fd74f7c47 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -42,7 +42,7 @@ use header::{BlockNumber, Header}; use transaction::{LocalizedTransaction, SignedTransaction}; use log_entry::LocalizedLogEntry; use filter::Filter; -use views::BlockView; +use views::{HeaderView, BlockView}; use error::{ImportResult, ExecutionError}; use receipt::LocalizedReceipt; use trace::LocalizedTrace; @@ -221,6 +221,13 @@ pub trait BlockChainClient : Sync + Send { Err(()) } } + + + /// Get `Some` gas limit of block 1_760_000, or `None` if chain is not yet that long. + fn dao_rescue_block_gas_limit(&self) -> Option { + self.block_header(BlockID::Number(1_760_000)) + .map(|header| HeaderView::new(&header).gas_limit()) + } } /// Extended client interface used for mining diff --git a/ethcore/src/env_info.rs b/ethcore/src/env_info.rs index e6d15cee6..a38a31ff7 100644 --- a/ethcore/src/env_info.rs +++ b/ethcore/src/env_info.rs @@ -39,6 +39,9 @@ pub struct EnvInfo { pub last_hashes: LastHashes, /// The gas used. pub gas_used: U256, + + /// Block gas limit at DAO rescue block #1760000 or None if not yet there. + pub dao_rescue_block_gas_limit: Option, } impl Default for EnvInfo { @@ -51,6 +54,7 @@ impl Default for EnvInfo { gas_limit: 0.into(), last_hashes: vec![], gas_used: 0.into(), + dao_rescue_block_gas_limit: None, } } } @@ -66,6 +70,7 @@ impl From for EnvInfo { timestamp: e.timestamp.into(), last_hashes: (1..cmp::min(number + 1, 257)).map(|i| format!("{}", number - i).as_bytes().sha3()).collect(), gas_used: U256::zero(), + dao_rescue_block_gas_limit: None, } } } diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index d89499872..f3cb95b09 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -103,7 +103,7 @@ impl Engine for Ethash { } else { let mut s = Schedule::new_homestead(); // TODO: make dependent on gaslimit > 4000000 of block 1760000. - s.block_dao_transactions = env_info.number >= 1760000; + s.block_dao_transactions = env_info.dao_rescue_block_gas_limit.map(|x| x <= 4_000_000.into()).unwrap_or(false); s } } @@ -319,7 +319,7 @@ mod tests { spec.ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; let vm_factory = Default::default(); - let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]).unwrap(); + let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), 3141562.into(), vec![]).unwrap(); let b = b.close(); assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap()); } @@ -334,7 +334,7 @@ mod tests { spec.ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; let vm_factory = Default::default(); - let mut b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]).unwrap(); + let mut b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), 3141562.into(), vec![]).unwrap(); let mut uncle = Header::new(); let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106"); uncle.author = uncle_author.clone(); @@ -362,7 +362,8 @@ mod tests { difficulty: 0.into(), last_hashes: vec![], gas_used: 0.into(), - gas_limit: 0.into() + gas_limit: 0.into(), + dao_rescue_block_gas_limit: None, }); assert!(schedule.stack_limit > 0); @@ -374,7 +375,8 @@ mod tests { difficulty: 0.into(), last_hashes: vec![], gas_used: 0.into(), - gas_limit: 0.into() + gas_limit: 0.into(), + dao_rescue_block_gas_limit: None, }); assert!(!schedule.have_delegate_call); diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 66509440a..80941c4b4 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -318,7 +318,8 @@ mod tests { difficulty: 0.into(), last_hashes: vec![], gas_used: 0.into(), - gas_limit: 0.into() + gas_limit: 0.into(), + dao_rescue_block_gas_limit: None, } } diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index ec232d238..c488f9de1 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -266,6 +266,7 @@ impl MinerService for Miner { last_hashes: last_hashes, gas_used: U256::zero(), gas_limit: U256::max_value(), + dao_rescue_block_gas_limit: chain.dao_rescue_block_gas_limit(), }; // that's just a copy of the state. let mut state = block.state().clone(); diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 48ca14bbf..3384bb2ff 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -179,6 +179,7 @@ pub fn generate_dummy_client_with_spec_and_data(get_test_spec: F, block_numbe db, &last_header, last_hashes.clone(), + None, author.clone(), 3141562.into(), vec![]