Merge branch 'master' into client-api-refact2
This commit is contained in:
@@ -214,8 +214,8 @@ impl Account {
|
||||
}
|
||||
|
||||
/// Commit the `storage_overlay` to the backing DB and update `storage_root`.
|
||||
pub fn commit_storage(&mut self, db: &mut AccountDBMut) {
|
||||
let mut t = SecTrieDBMut::from_existing(db, &mut self.storage_root)
|
||||
pub fn commit_storage(&mut self, trie_factory: &TrieFactory, db: &mut AccountDBMut) {
|
||||
let mut t = trie_factory.from_existing(db, &mut self.storage_root)
|
||||
.expect("Account storage_root initially set to zero (valid) and only altered by SecTrieDBMut. \
|
||||
SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \
|
||||
using it will not fail.");
|
||||
@@ -275,7 +275,7 @@ mod tests {
|
||||
let rlp = {
|
||||
let mut a = Account::new_contract(69.into(), 0.into());
|
||||
a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64)));
|
||||
a.commit_storage(&mut db);
|
||||
a.commit_storage(&Default::default(), &mut db);
|
||||
a.init_code(vec![]);
|
||||
a.commit_code(&mut db);
|
||||
a.rlp()
|
||||
@@ -313,7 +313,7 @@ mod tests {
|
||||
let mut db = AccountDBMut::new(&mut db, &Address::new());
|
||||
a.set_storage(0.into(), 0x1234.into());
|
||||
assert_eq!(a.storage_root(), None);
|
||||
a.commit_storage(&mut db);
|
||||
a.commit_storage(&Default::default(), &mut db);
|
||||
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
|
||||
}
|
||||
|
||||
@@ -323,11 +323,11 @@ mod tests {
|
||||
let mut db = MemoryDB::new();
|
||||
let mut db = AccountDBMut::new(&mut db, &Address::new());
|
||||
a.set_storage(0.into(), 0x1234.into());
|
||||
a.commit_storage(&mut db);
|
||||
a.commit_storage(&Default::default(), &mut db);
|
||||
a.set_storage(1.into(), 0x1234.into());
|
||||
a.commit_storage(&mut db);
|
||||
a.commit_storage(&Default::default(), &mut db);
|
||||
a.set_storage(1.into(), 0.into());
|
||||
a.commit_storage(&mut db);
|
||||
a.commit_storage(&Default::default(), &mut db);
|
||||
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
|
||||
}
|
||||
|
||||
|
||||
@@ -254,7 +254,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, None, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||
let b = b.close_and_lock();
|
||||
let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap();
|
||||
assert!(b.try_seal(engine.deref(), seal).is_ok());
|
||||
|
||||
@@ -222,6 +222,7 @@ impl<'x> OpenBlock<'x> {
|
||||
pub fn new(
|
||||
engine: &'x Engine,
|
||||
vm_factory: &'x EvmFactory,
|
||||
trie_factory: TrieFactory,
|
||||
tracing: bool,
|
||||
db: Box<JournalDB>,
|
||||
parent: &Header,
|
||||
@@ -231,7 +232,7 @@ impl<'x> OpenBlock<'x> {
|
||||
gas_range_target: (U256, U256),
|
||||
extra_data: Bytes,
|
||||
) -> 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(), trie_factory));
|
||||
let mut r = OpenBlock {
|
||||
block: ExecutedBlock::new(state, tracing),
|
||||
engine: engine,
|
||||
@@ -481,16 +482,17 @@ pub fn enact(
|
||||
parent: &Header,
|
||||
last_hashes: LastHashes,
|
||||
dao_rescue_block_gas_limit: Option<U256>,
|
||||
vm_factory: &EvmFactory
|
||||
vm_factory: &EvmFactory,
|
||||
trie_factory: TrieFactory,
|
||||
) -> Result<LockedBlock, Error> {
|
||||
{
|
||||
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(), trie_factory.clone()));
|
||||
trace!("enact(): root={}, author={}, author_balance={}\n", s.root(), header.author(), s.balance(&header.author()));
|
||||
}
|
||||
}
|
||||
|
||||
let mut b = try!(OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, header.author().clone(), (3141562.into(), 31415620.into()), header.extra_data().clone()));
|
||||
let mut b = try!(OpenBlock::new(engine, vm_factory, trie_factory, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, header.author().clone(), (3141562.into(), 31415620.into()), header.extra_data().clone()));
|
||||
b.set_difficulty(*header.difficulty());
|
||||
b.set_gas_limit(*header.gas_limit());
|
||||
b.set_timestamp(header.timestamp());
|
||||
@@ -509,11 +511,12 @@ pub fn enact_bytes(
|
||||
parent: &Header,
|
||||
last_hashes: LastHashes,
|
||||
dao_rescue_block_gas_limit: Option<U256>,
|
||||
vm_factory: &EvmFactory
|
||||
vm_factory: &EvmFactory,
|
||||
trie_factory: TrieFactory,
|
||||
) -> Result<LockedBlock, Error> {
|
||||
let block = BlockView::new(block_bytes);
|
||||
let header = block.header();
|
||||
enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)
|
||||
enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory, trie_factory)
|
||||
}
|
||||
|
||||
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
|
||||
@@ -526,10 +529,11 @@ pub fn enact_verified(
|
||||
parent: &Header,
|
||||
last_hashes: LastHashes,
|
||||
dao_rescue_block_gas_limit: Option<U256>,
|
||||
vm_factory: &EvmFactory
|
||||
vm_factory: &EvmFactory,
|
||||
trie_factory: TrieFactory,
|
||||
) -> Result<LockedBlock, Error> {
|
||||
let view = BlockView::new(&block.bytes);
|
||||
enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)
|
||||
enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory, trie_factory)
|
||||
}
|
||||
|
||||
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards
|
||||
@@ -542,10 +546,11 @@ pub fn enact_and_seal(
|
||||
parent: &Header,
|
||||
last_hashes: LastHashes,
|
||||
dao_rescue_block_gas_limit: Option<U256>,
|
||||
vm_factory: &EvmFactory
|
||||
vm_factory: &EvmFactory,
|
||||
trie_factory: TrieFactory,
|
||||
) -> Result<SealedBlock, Error> {
|
||||
let header = BlockView::new(block_bytes).header_view();
|
||||
Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, 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, trie_factory)).seal(engine, header.seal())))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -565,7 +570,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, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||
let b = b.close_and_lock();
|
||||
let _ = b.seal(engine.deref(), vec![]);
|
||||
}
|
||||
@@ -581,7 +586,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()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
|
||||
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
|
||||
.close_and_lock().seal(engine.deref(), vec![]).unwrap();
|
||||
let orig_bytes = b.rlp_bytes();
|
||||
let orig_db = b.drain();
|
||||
@@ -589,7 +594,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()], None, &Default::default()).unwrap();
|
||||
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default(), Default::default()).unwrap();
|
||||
|
||||
assert_eq!(e.rlp_bytes(), orig_bytes);
|
||||
|
||||
@@ -609,7 +614,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()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||
let mut uncle1_header = Header::new();
|
||||
uncle1_header.extra_data = b"uncle1".to_vec();
|
||||
let mut uncle2_header = Header::new();
|
||||
@@ -624,7 +629,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()], None, &Default::default()).unwrap();
|
||||
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default(), Default::default()).unwrap();
|
||||
|
||||
let bytes = e.rlp_bytes();
|
||||
assert_eq!(bytes, orig_bytes);
|
||||
|
||||
@@ -96,6 +96,7 @@ pub struct Client {
|
||||
panic_handler: Arc<PanicHandler>,
|
||||
verifier: Box<Verifier>,
|
||||
vm_factory: Arc<EvmFactory>,
|
||||
trie_factory: TrieFactory,
|
||||
miner: Arc<Miner>,
|
||||
io_channel: IoChannel<NetSyncMessage>,
|
||||
queue_transactions: AtomicUsize,
|
||||
@@ -177,6 +178,7 @@ impl Client {
|
||||
panic_handler: panic_handler,
|
||||
verifier: verification::new(config.verifier_type),
|
||||
vm_factory: Arc::new(EvmFactory::new(config.vm_type)),
|
||||
trie_factory: TrieFactory::new(config.trie_spec),
|
||||
miner: miner,
|
||||
io_channel: message_channel,
|
||||
queue_transactions: AtomicUsize::new(0),
|
||||
@@ -235,7 +237,7 @@ impl Client {
|
||||
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.dao_rescue_block_gas_limit(header.parent_hash.clone()), &self.vm_factory);
|
||||
let enact_result = enact_verified(&block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, self.dao_rescue_block_gas_limit(header.parent_hash.clone()), &self.vm_factory, self.trie_factory.clone());
|
||||
if let Err(e) = enact_result {
|
||||
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
||||
return Err(());
|
||||
@@ -350,7 +352,7 @@ impl Client {
|
||||
imported
|
||||
}
|
||||
|
||||
fn commit_block<B>(&self, block: B, hash: &H256, block_data: &Bytes) -> ImportRoute where B: IsBlock + Drain {
|
||||
fn commit_block<B>(&self, block: B, hash: &H256, block_data: &[u8]) -> ImportRoute where B: IsBlock + Drain {
|
||||
let number = block.header().number();
|
||||
// Are we committing an era?
|
||||
let ancient = if number >= HISTORY {
|
||||
@@ -420,13 +422,17 @@ impl Client {
|
||||
|
||||
let root = HeaderView::new(&header).state_root();
|
||||
|
||||
State::from_existing(db, root, self.engine.account_start_nonce()).ok()
|
||||
State::from_existing(db, root, self.engine.account_start_nonce(), self.trie_factory.clone()).ok()
|
||||
})
|
||||
}
|
||||
|
||||
/// Get a copy of the best block's state.
|
||||
pub fn state(&self) -> State {
|
||||
State::from_existing(self.state_db.lock().unwrap().boxed_clone(), HeaderView::new(&self.best_block_header()).state_root(), self.engine.account_start_nonce())
|
||||
State::from_existing(
|
||||
self.state_db.lock().unwrap().boxed_clone(),
|
||||
HeaderView::new(&self.best_block_header()).state_root(),
|
||||
self.engine.account_start_nonce(),
|
||||
self.trie_factory.clone())
|
||||
.expect("State root of best block header always valid.")
|
||||
}
|
||||
|
||||
@@ -815,6 +821,7 @@ impl MiningBlockChainClient for Client {
|
||||
let mut open_block = OpenBlock::new(
|
||||
engine,
|
||||
&self.vm_factory,
|
||||
self.trie_factory.clone(),
|
||||
false, // TODO: this will need to be parameterised once we want to do immediate mining insertion.
|
||||
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"),
|
||||
|
||||
@@ -20,6 +20,7 @@ pub use trace::{Config as TraceConfig, Switch};
|
||||
pub use evm::VMType;
|
||||
pub use verification::VerifierType;
|
||||
use util::journaldb;
|
||||
use util::trie::TrieSpec;
|
||||
|
||||
/// Client state db compaction profile
|
||||
#[derive(Debug, PartialEq)]
|
||||
@@ -45,6 +46,8 @@ pub struct ClientConfig {
|
||||
pub tracing: TraceConfig,
|
||||
/// VM type.
|
||||
pub vm_type: VMType,
|
||||
/// Trie type.
|
||||
pub trie_spec: TrieSpec,
|
||||
/// The JournalDB ("pruning") algorithm to use.
|
||||
pub pruning: journaldb::Algorithm,
|
||||
/// The name of the client instance.
|
||||
|
||||
@@ -325,7 +325,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, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||
let b = b.close();
|
||||
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap());
|
||||
}
|
||||
@@ -340,7 +340,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, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||
let mut b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||
let mut uncle = Header::new();
|
||||
let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106");
|
||||
uncle.author = uncle_author.clone();
|
||||
|
||||
@@ -67,7 +67,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 s = State::from_existing(db, genesis_header.state_root.clone(), engine.account_start_nonce()).unwrap();
|
||||
let s = State::from_existing(db, genesis_header.state_root.clone(), engine.account_start_nonce(), Default::default()).unwrap();
|
||||
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000001")), U256::from(1u64));
|
||||
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000002")), U256::from(1u64));
|
||||
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000003")), U256::from(1u64));
|
||||
|
||||
@@ -267,6 +267,10 @@ impl Miner {
|
||||
let difficulty = *block.block().fields().header.difficulty();
|
||||
let is_new = original_work_hash.map_or(true, |h| block.block().fields().header.hash() != h);
|
||||
sealing_work.push(block);
|
||||
// If push notifications are enabled we assume all work items are used.
|
||||
if self.work_poster.is_some() && is_new {
|
||||
sealing_work.use_last_ref();
|
||||
}
|
||||
(Some((pow_hash, difficulty, number)), is_new)
|
||||
} else {
|
||||
(None, false)
|
||||
|
||||
@@ -52,10 +52,10 @@ impl WorkPoster {
|
||||
}
|
||||
|
||||
fn create_client() -> Client<PostHandler> {
|
||||
let client = Client::<PostHandler>::configure()
|
||||
Client::<PostHandler>::configure()
|
||||
.keep_alive(true)
|
||||
.build().expect("Error creating HTTP client") as Client<PostHandler>;
|
||||
client
|
||||
.build()
|
||||
.expect("Error creating HTTP client")
|
||||
}
|
||||
|
||||
pub fn notify(&self, pow_hash: H256, difficulty: U256, number: u64) {
|
||||
@@ -63,8 +63,10 @@ impl WorkPoster {
|
||||
let target = Ethash::difficulty_to_boundary(&difficulty);
|
||||
let seed_hash = &self.seed_compute.lock().unwrap().get_seedhash(number);
|
||||
let seed_hash = H256::from_slice(&seed_hash[..]);
|
||||
let body = format!(r#"{{ "result": ["0x{}","0x{}","0x{}","0x{:x}"] }}"#,
|
||||
pow_hash.hex(), seed_hash.hex(), target.hex(), number);
|
||||
let body = format!(
|
||||
r#"{{ "result": ["0x{}","0x{}","0x{}","0x{:x}"] }}"#,
|
||||
pow_hash.hex(), seed_hash.hex(), target.hex(), number
|
||||
);
|
||||
let mut client = self.client.lock().unwrap();
|
||||
for u in &self.urls {
|
||||
if let Err(e) = client.request(u.clone(), PostHandler { body: body.clone() }) {
|
||||
@@ -104,12 +106,12 @@ impl hyper::client::Handler<HttpStream> for PostHandler {
|
||||
}
|
||||
|
||||
fn on_response_readable(&mut self, _decoder: &mut hyper::Decoder<HttpStream>) -> Next {
|
||||
Next::end()
|
||||
Next::end()
|
||||
}
|
||||
|
||||
fn on_error(&mut self, err: hyper::Error) -> Next {
|
||||
fn on_error(&mut self, err: hyper::Error) -> Next {
|
||||
trace!("Error posting work data: {}", err);
|
||||
Next::end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ pub struct State {
|
||||
cache: RefCell<HashMap<Address, Option<Account>>>,
|
||||
snapshots: RefCell<Vec<HashMap<Address, Option<Option<Account>>>>>,
|
||||
account_start_nonce: U256,
|
||||
trie_factory: TrieFactory,
|
||||
}
|
||||
|
||||
const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with valid root. Creating a SecTrieDB with a valid root will not fail. \
|
||||
@@ -50,11 +51,11 @@ const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with v
|
||||
impl State {
|
||||
/// Creates new state with empty state root
|
||||
#[cfg(test)]
|
||||
pub fn new(mut db: Box<JournalDB>, account_start_nonce: U256) -> State {
|
||||
pub fn new(mut db: Box<JournalDB>, account_start_nonce: U256, trie_factory: TrieFactory) -> State {
|
||||
let mut root = H256::new();
|
||||
{
|
||||
// init trie and reset root too null
|
||||
let _ = SecTrieDBMut::new(db.as_hashdb_mut(), &mut root);
|
||||
let _ = trie_factory.create(db.as_hashdb_mut(), &mut root);
|
||||
}
|
||||
|
||||
State {
|
||||
@@ -63,22 +64,26 @@ impl State {
|
||||
cache: RefCell::new(HashMap::new()),
|
||||
snapshots: RefCell::new(Vec::new()),
|
||||
account_start_nonce: account_start_nonce,
|
||||
trie_factory: trie_factory,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates new state with existing state root
|
||||
pub fn from_existing(db: Box<JournalDB>, root: H256, account_start_nonce: U256) -> Result<State, TrieError> {
|
||||
pub fn from_existing(db: Box<JournalDB>, root: H256, account_start_nonce: U256, trie_factory: TrieFactory) -> Result<State, TrieError> {
|
||||
if !db.as_hashdb().contains(&root) {
|
||||
Err(TrieError::InvalidStateRoot)
|
||||
} else {
|
||||
Ok(State {
|
||||
db: db,
|
||||
root: root,
|
||||
cache: RefCell::new(HashMap::new()),
|
||||
snapshots: RefCell::new(Vec::new()),
|
||||
account_start_nonce: account_start_nonce,
|
||||
})
|
||||
return Err(TrieError::InvalidStateRoot);
|
||||
}
|
||||
|
||||
let state = State {
|
||||
db: db,
|
||||
root: root,
|
||||
cache: RefCell::new(HashMap::new()),
|
||||
snapshots: RefCell::new(Vec::new()),
|
||||
account_start_nonce: account_start_nonce,
|
||||
trie_factory: trie_factory,
|
||||
};
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
/// Create a recoverable snaphot of this state
|
||||
@@ -156,7 +161,7 @@ impl State {
|
||||
|
||||
/// Determine whether an account exists.
|
||||
pub fn exists(&self, a: &Address) -> bool {
|
||||
let db = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
|
||||
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
|
||||
self.cache.borrow().get(&a).unwrap_or(&None).is_some() || db.contains(&a)
|
||||
}
|
||||
|
||||
@@ -242,7 +247,10 @@ impl State {
|
||||
for a in &addresses {
|
||||
if self.code(a).map_or(false, |c| c.sha3() == broken_dao) {
|
||||
// Figure out if the balance has been reduced.
|
||||
let maybe_original = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR).get(&a).map(Account::from_rlp);
|
||||
let maybe_original = self.trie_factory
|
||||
.readonly(self.db.as_hashdb(), &self.root)
|
||||
.expect(SEC_TRIE_DB_UNWRAP_STR)
|
||||
.get(&a).map(Account::from_rlp);
|
||||
if maybe_original.map_or(false, |original| *original.balance() > self.balance(a)) {
|
||||
return Err(Error::Transaction(TransactionError::DAORescue));
|
||||
}
|
||||
@@ -262,14 +270,14 @@ impl State {
|
||||
/// Commit accounts to SecTrieDBMut. This is similar to cpp-ethereum's dev::eth::commit.
|
||||
/// `accounts` is mutable because we may need to commit the code or storage and record that.
|
||||
#[cfg_attr(feature="dev", allow(match_ref_pats))]
|
||||
pub fn commit_into(db: &mut HashDB, root: &mut H256, accounts: &mut HashMap<Address, Option<Account>>) {
|
||||
pub fn commit_into(trie_factory: &TrieFactory, db: &mut HashDB, root: &mut H256, accounts: &mut HashMap<Address, Option<Account>>) {
|
||||
// first, commit the sub trees.
|
||||
// TODO: is this necessary or can we dispense with the `ref mut a` for just `a`?
|
||||
for (address, ref mut a) in accounts.iter_mut() {
|
||||
match a {
|
||||
&mut&mut Some(ref mut account) => {
|
||||
let mut account_db = AccountDBMut::new(db, address);
|
||||
account.commit_storage(&mut account_db);
|
||||
account.commit_storage(trie_factory, &mut account_db);
|
||||
account.commit_code(&mut account_db);
|
||||
}
|
||||
&mut&mut None => {}
|
||||
@@ -277,7 +285,7 @@ impl State {
|
||||
}
|
||||
|
||||
{
|
||||
let mut trie = SecTrieDBMut::from_existing(db, root).unwrap();
|
||||
let mut trie = trie_factory.from_existing(db, root).unwrap();
|
||||
for (address, ref a) in accounts.iter() {
|
||||
match **a {
|
||||
Some(ref account) => trie.insert(address, &account.rlp()),
|
||||
@@ -290,7 +298,7 @@ impl State {
|
||||
/// Commits our cached account changes into the trie.
|
||||
pub fn commit(&mut self) {
|
||||
assert!(self.snapshots.borrow().is_empty());
|
||||
Self::commit_into(self.db.as_hashdb_mut(), &mut self.root, self.cache.borrow_mut().deref_mut());
|
||||
Self::commit_into(&self.trie_factory, self.db.as_hashdb_mut(), &mut self.root, self.cache.borrow_mut().deref_mut());
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -340,7 +348,7 @@ impl State {
|
||||
fn get<'a>(&'a self, a: &Address, require_code: bool) -> &'a Option<Account> {
|
||||
let have_key = self.cache.borrow().contains_key(a);
|
||||
if !have_key {
|
||||
let db = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
|
||||
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
|
||||
self.insert_cache(a, db.get(&a).map(Account::from_rlp))
|
||||
}
|
||||
if require_code {
|
||||
@@ -361,7 +369,7 @@ impl State {
|
||||
fn require_or_from<'a, F: FnOnce() -> Account, G: FnOnce(&mut Account)>(&self, a: &Address, require_code: bool, default: F, not_default: G) -> &'a mut Account {
|
||||
let have_key = self.cache.borrow().contains_key(a);
|
||||
if !have_key {
|
||||
let db = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
|
||||
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
|
||||
self.insert_cache(a, db.get(&a).map(Account::from_rlp))
|
||||
} else {
|
||||
self.note_cache(a);
|
||||
@@ -396,6 +404,7 @@ impl Clone for State {
|
||||
cache: RefCell::new(self.cache.borrow().clone()),
|
||||
snapshots: RefCell::new(self.snapshots.borrow().clone()),
|
||||
account_start_nonce: self.account_start_nonce.clone(),
|
||||
trie_factory: self.trie_factory.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1179,7 +1188,7 @@ fn code_from_database() {
|
||||
state.drop()
|
||||
};
|
||||
|
||||
let state = State::from_existing(db, root, U256::from(0u8)).unwrap();
|
||||
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
||||
assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec()));
|
||||
}
|
||||
|
||||
@@ -1194,7 +1203,7 @@ fn storage_at_from_database() {
|
||||
state.drop()
|
||||
};
|
||||
|
||||
let s = State::from_existing(db, root, U256::from(0u8)).unwrap();
|
||||
let s = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
||||
assert_eq!(s.storage_at(&a, &H256::from(&U256::from(01u64))), H256::from(&U256::from(69u64)));
|
||||
}
|
||||
|
||||
@@ -1211,7 +1220,7 @@ fn get_from_database() {
|
||||
state.drop()
|
||||
};
|
||||
|
||||
let state = State::from_existing(db, root, U256::from(0u8)).unwrap();
|
||||
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
||||
assert_eq!(state.nonce(&a), U256::from(1u64));
|
||||
}
|
||||
@@ -1244,7 +1253,7 @@ fn remove_from_database() {
|
||||
};
|
||||
|
||||
let (root, db) = {
|
||||
let mut state = State::from_existing(db, root, U256::from(0u8)).unwrap();
|
||||
let mut state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
||||
assert_eq!(state.exists(&a), true);
|
||||
assert_eq!(state.nonce(&a), U256::from(1u64));
|
||||
state.kill_account(&a);
|
||||
@@ -1254,7 +1263,7 @@ fn remove_from_database() {
|
||||
state.drop()
|
||||
};
|
||||
|
||||
let state = State::from_existing(db, root, U256::from(0u8)).unwrap();
|
||||
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
||||
assert_eq!(state.exists(&a), false);
|
||||
assert_eq!(state.nonce(&a), U256::from(0u64));
|
||||
}
|
||||
|
||||
@@ -175,6 +175,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
|
||||
let mut b = OpenBlock::new(
|
||||
test_engine.deref(),
|
||||
&vm_factory,
|
||||
Default::default(),
|
||||
false,
|
||||
db,
|
||||
&last_header,
|
||||
@@ -315,7 +316,7 @@ pub fn get_temp_state() -> GuardedTempResult<State> {
|
||||
let journal_db = get_temp_journal_db_in(temp.as_path());
|
||||
GuardedTempResult {
|
||||
_temp: temp,
|
||||
result: Some(State::new(journal_db, U256::from(0u8)))
|
||||
result: Some(State::new(journal_db, U256::from(0), Default::default())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +326,7 @@ pub fn get_temp_journal_db_in(path: &Path) -> Box<JournalDB> {
|
||||
|
||||
pub fn get_temp_state_in(path: &Path) -> State {
|
||||
let journal_db = get_temp_journal_db_in(path);
|
||||
State::new(journal_db, U256::from(0u8))
|
||||
State::new(journal_db, U256::from(0), Default::default())
|
||||
}
|
||||
|
||||
pub fn get_good_dummy_block_seq(count: usize) -> Vec<Bytes> {
|
||||
|
||||
Reference in New Issue
Block a user