Install trigger for DAO-rescue soft-fork.

Soft-fork should only be primed to trigger if the gas-limit of
block #1760000 is at most 4,000,000.

To accomplish this we pass in the gas limit of that block to
EnvInfo so it can inform Schedule. This gets marshalled through
`OpenBlock`/`ClosedBlock` and the `enact` functions much like
`last_hashes`. `block.rs`'s `env_info()` takes care to ensure
that if the current block happens to be #1760000, then we
populate with the current `gas_limit`.
This commit is contained in:
Gav Wood 2016-06-18 20:26:44 +02:00
parent 2b65011706
commit 2582253f95
9 changed files with 89 additions and 27 deletions

View File

@ -215,8 +215,9 @@ mod tests {
timestamp: 0, timestamp: 0,
difficulty: 0.into(), difficulty: 0.into(),
last_hashes: vec![], last_hashes: vec![],
dao_rescue_block_gas_limit: None,
gas_used: 0.into(), gas_used: 0.into(),
gas_limit: 0.into() gas_limit: 0.into(),
}); });
assert!(schedule.stack_limit > 0); assert!(schedule.stack_limit > 0);
@ -278,7 +279,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default(); 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 b = b.close_and_lock();
let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap(); let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap();

View File

@ -177,6 +177,7 @@ pub struct OpenBlock<'x> {
engine: &'x Engine, engine: &'x Engine,
vm_factory: &'x EvmFactory, vm_factory: &'x EvmFactory,
last_hashes: LastHashes, last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
} }
/// Just like `OpenBlock`, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields, /// 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, block: ExecutedBlock,
uncle_bytes: Bytes, uncle_bytes: Bytes,
last_hashes: LastHashes, last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
unclosed_state: State, unclosed_state: State,
} }
@ -198,7 +200,6 @@ pub struct ClosedBlock {
pub struct LockedBlock { pub struct LockedBlock {
block: ExecutedBlock, block: ExecutedBlock,
uncle_bytes: Bytes, uncle_bytes: Bytes,
last_hashes: LastHashes,
} }
/// A block that has a valid seal. /// A block that has a valid seal.
@ -219,9 +220,10 @@ impl<'x> OpenBlock<'x> {
db: Box<JournalDB>, db: Box<JournalDB>,
parent: &Header, parent: &Header,
last_hashes: LastHashes, last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
author: Address, author: Address,
gas_floor_target: U256, gas_floor_target: U256,
extra_data: Bytes extra_data: Bytes,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let state = try!(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce())); let state = try!(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()));
let mut r = OpenBlock { let mut r = OpenBlock {
@ -229,6 +231,7 @@ impl<'x> OpenBlock<'x> {
engine: engine, engine: engine,
vm_factory: vm_factory, vm_factory: vm_factory,
last_hashes: last_hashes, last_hashes: last_hashes,
dao_rescue_block_gas_limit: dao_rescue_block_gas_limit,
}; };
r.block.base.header.parent_hash = parent.hash(); 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. 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_used: self.block.receipts.last().map_or(U256::zero(), |r| r.gas_used),
gas_limit: self.block.base.header.gas_limit.clone(), 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, block: s.block,
uncle_bytes: uncle_bytes, uncle_bytes: uncle_bytes,
last_hashes: s.last_hashes, last_hashes: s.last_hashes,
dao_rescue_block_gas_limit: s.dao_rescue_block_gas_limit,
unclosed_state: unclosed_state, unclosed_state: unclosed_state,
} }
} }
@ -360,7 +365,6 @@ impl<'x> OpenBlock<'x> {
LockedBlock { LockedBlock {
block: s.block, block: s.block,
uncle_bytes: uncle_bytes, uncle_bytes: uncle_bytes,
last_hashes: s.last_hashes,
} }
} }
} }
@ -386,7 +390,6 @@ impl ClosedBlock {
LockedBlock { LockedBlock {
block: self.block, block: self.block,
uncle_bytes: self.uncle_bytes, uncle_bytes: self.uncle_bytes,
last_hashes: self.last_hashes,
} }
} }
@ -400,6 +403,7 @@ impl ClosedBlock {
engine: engine, engine: engine,
vm_factory: vm_factory, vm_factory: vm_factory,
last_hashes: self.last_hashes, 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 /// Enact the block given by block header, transactions and uncles
#[cfg_attr(feature="dev", allow(too_many_arguments))] #[cfg_attr(feature="dev", allow(too_many_arguments))]
pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result<LockedBlock, Error> { pub fn enact(
header: &Header,
transactions: &[SignedTransaction],
uncles: &[Header],
engine: &Engine,
tracing: bool,
db: Box<JournalDB>,
parent: &Header,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory
) -> Result<LockedBlock, Error> {
{ {
if ::log::max_log_level() >= ::log::LogLevel::Trace { 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())); 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_difficulty(*header.difficulty());
b.set_gas_limit(*header.gas_limit()); b.set_gas_limit(*header.gas_limit());
b.set_timestamp(header.timestamp()); 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 /// 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<JournalDB>, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result<LockedBlock, Error> { pub fn enact_bytes(
block_bytes: &[u8],
engine: &Engine,
tracing: bool,
db: Box<JournalDB>,
parent: &Header,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory
) -> Result<LockedBlock, Error> {
let block = BlockView::new(block_bytes); let block = BlockView::new(block_bytes);
let header = block.header(); 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 /// 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<JournalDB>, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result<LockedBlock, Error> { pub fn enact_verified(
block: &PreverifiedBlock,
engine: &Engine,
tracing: bool,
db: Box<JournalDB>,
parent: &Header,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory
) -> Result<LockedBlock, Error> {
let view = BlockView::new(&block.bytes); 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 /// 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<JournalDB>, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result<SealedBlock, Error> { pub fn enact_and_seal(
block_bytes: &[u8],
engine: &Engine,
tracing: bool,
db: Box<JournalDB>,
parent: &Header,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory
) -> Result<SealedBlock, Error> {
let header = BlockView::new(block_bytes).header_view(); 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)] #[cfg(test)]
@ -509,7 +551,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default(); 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 = b.close_and_lock();
let _ = b.seal(engine.deref(), vec![]); let _ = b.seal(engine.deref(), vec![]);
} }
@ -525,7 +567,7 @@ mod tests {
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default(); 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(); .close_and_lock().seal(engine.deref(), vec![]).unwrap();
let orig_bytes = b.rlp_bytes(); let orig_bytes = b.rlp_bytes();
let orig_db = b.drain(); let orig_db = b.drain();
@ -533,7 +575,7 @@ mod tests {
let mut db_result = get_temp_journal_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); 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); assert_eq!(e.rlp_bytes(), orig_bytes);
@ -553,7 +595,7 @@ mod tests {
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default(); 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(); let mut uncle1_header = Header::new();
uncle1_header.extra_data = b"uncle1".to_vec(); uncle1_header.extra_data = b"uncle1".to_vec();
let mut uncle2_header = Header::new(); let mut uncle2_header = Header::new();
@ -568,7 +610,7 @@ mod tests {
let mut db_result = get_temp_journal_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); 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(); let bytes = e.rlp_bytes();
assert_eq!(bytes, orig_bytes); assert_eq!(bytes, orig_bytes);

View File

@ -220,7 +220,7 @@ impl<V> Client<V> where V: Verifier {
let last_hashes = self.build_last_hashes(header.parent_hash.clone()); let last_hashes = self.build_last_hashes(header.parent_hash.clone());
let db = self.state_db.lock().unwrap().boxed_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 { if let Err(e) = enact_result {
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
return Err(()); return Err(());
@ -462,6 +462,7 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
last_hashes: last_hashes, last_hashes: last_hashes,
gas_used: U256::zero(), gas_used: U256::zero(),
gas_limit: U256::max_value(), gas_limit: U256::max_value(),
dao_rescue_block_gas_limit: self.dao_rescue_block_gas_limit(),
}; };
// that's just a copy of the state. // that's just a copy of the state.
let mut state = self.state(); let mut state = self.state();
@ -767,6 +768,7 @@ impl<V> MiningBlockChainClient for Client<V> where V: Verifier {
self.state_db.lock().unwrap().boxed_clone(), 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.chain.block_header(&h).expect("h is best block hash: so it's header must exist: qed"),
self.build_last_hashes(h.clone()), self.build_last_hashes(h.clone()),
self.dao_rescue_block_gas_limit(),
author, author,
gas_floor_target, gas_floor_target,
extra_data, extra_data,

View File

@ -42,7 +42,7 @@ use header::{BlockNumber, Header};
use transaction::{LocalizedTransaction, SignedTransaction}; use transaction::{LocalizedTransaction, SignedTransaction};
use log_entry::LocalizedLogEntry; use log_entry::LocalizedLogEntry;
use filter::Filter; use filter::Filter;
use views::BlockView; use views::{HeaderView, BlockView};
use error::{ImportResult, ExecutionError}; use error::{ImportResult, ExecutionError};
use receipt::LocalizedReceipt; use receipt::LocalizedReceipt;
use trace::LocalizedTrace; use trace::LocalizedTrace;
@ -221,6 +221,13 @@ pub trait BlockChainClient : Sync + Send {
Err(()) 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<U256> {
self.block_header(BlockID::Number(1_760_000))
.map(|header| HeaderView::new(&header).gas_limit())
}
} }
/// Extended client interface used for mining /// Extended client interface used for mining

View File

@ -39,6 +39,9 @@ pub struct EnvInfo {
pub last_hashes: LastHashes, pub last_hashes: LastHashes,
/// The gas used. /// The gas used.
pub gas_used: U256, 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<U256>,
} }
impl Default for EnvInfo { impl Default for EnvInfo {
@ -51,6 +54,7 @@ impl Default for EnvInfo {
gas_limit: 0.into(), gas_limit: 0.into(),
last_hashes: vec![], last_hashes: vec![],
gas_used: 0.into(), gas_used: 0.into(),
dao_rescue_block_gas_limit: None,
} }
} }
} }
@ -66,6 +70,7 @@ impl From<ethjson::vm::Env> for EnvInfo {
timestamp: e.timestamp.into(), timestamp: e.timestamp.into(),
last_hashes: (1..cmp::min(number + 1, 257)).map(|i| format!("{}", number - i).as_bytes().sha3()).collect(), last_hashes: (1..cmp::min(number + 1, 257)).map(|i| format!("{}", number - i).as_bytes().sha3()).collect(),
gas_used: U256::zero(), gas_used: U256::zero(),
dao_rescue_block_gas_limit: None,
} }
} }
} }

View File

@ -103,7 +103,7 @@ impl Engine for Ethash {
} else { } else {
let mut s = Schedule::new_homestead(); let mut s = Schedule::new_homestead();
// TODO: make dependent on gaslimit > 4000000 of block 1760000. // 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 s
} }
} }
@ -319,7 +319,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default(); 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(); let b = b.close();
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap()); 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()); spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default(); 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 mut uncle = Header::new();
let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106"); let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106");
uncle.author = uncle_author.clone(); uncle.author = uncle_author.clone();
@ -362,7 +362,8 @@ mod tests {
difficulty: 0.into(), difficulty: 0.into(),
last_hashes: vec![], last_hashes: vec![],
gas_used: 0.into(), gas_used: 0.into(),
gas_limit: 0.into() gas_limit: 0.into(),
dao_rescue_block_gas_limit: None,
}); });
assert!(schedule.stack_limit > 0); assert!(schedule.stack_limit > 0);
@ -374,7 +375,8 @@ mod tests {
difficulty: 0.into(), difficulty: 0.into(),
last_hashes: vec![], last_hashes: vec![],
gas_used: 0.into(), gas_used: 0.into(),
gas_limit: 0.into() gas_limit: 0.into(),
dao_rescue_block_gas_limit: None,
}); });
assert!(!schedule.have_delegate_call); assert!(!schedule.have_delegate_call);

View File

@ -318,7 +318,8 @@ mod tests {
difficulty: 0.into(), difficulty: 0.into(),
last_hashes: vec![], last_hashes: vec![],
gas_used: 0.into(), gas_used: 0.into(),
gas_limit: 0.into() gas_limit: 0.into(),
dao_rescue_block_gas_limit: None,
} }
} }

View File

@ -266,6 +266,7 @@ impl MinerService for Miner {
last_hashes: last_hashes, last_hashes: last_hashes,
gas_used: U256::zero(), gas_used: U256::zero(),
gas_limit: U256::max_value(), gas_limit: U256::max_value(),
dao_rescue_block_gas_limit: chain.dao_rescue_block_gas_limit(),
}; };
// that's just a copy of the state. // that's just a copy of the state.
let mut state = block.state().clone(); let mut state = block.state().clone();

View File

@ -179,6 +179,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
db, db,
&last_header, &last_header,
last_hashes.clone(), last_hashes.clone(),
None,
author.clone(), author.clone(),
3141562.into(), 3141562.into(),
vec![] vec![]