diff --git a/ethcore/res/constructor.json b/ethcore/res/constructor.json new file mode 100644 index 000000000..0be5b3be4 --- /dev/null +++ b/ethcore/res/constructor.json @@ -0,0 +1,30 @@ +{ + "name": "GenesisConstructor", + "engine": { + "null": null + }, + "params": { + "accountStartNonce": "0x0", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x2" + }, + "genesis": { + "seal": { + "generic": "0x" + }, + "difficulty": "0x20000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x2fefd8" + }, + "accounts": { + "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "0000000000000000000000000000000000000005": { "balance": "1", "constructor": "60606040526000805460ff19166001179055346000575b6075806100246000396000f300606060405263ffffffff60e060020a60003504166394b91deb81146022575b6000565b34600057602c6040565b604080519115158252519081900360200190f35b60005460ff16815600a165627a7a723058207882eb60ebce23178b3fa06d4cd8e5adc17711937ccddacb18a04abca2a2c9ee0029" } + } +} diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 743167a75..04fd556d7 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -595,9 +595,8 @@ mod tests { use factory::Factories; use state_db::StateDB; use views::BlockView; - use util::{Address, TrieFactory}; + use util::Address; use util::hash::FixedHash; - use util::trie::TrieSpec; use std::sync::Arc; /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header @@ -637,8 +636,7 @@ mod tests { let spec = Spec::new_test(); let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); - let mut db = db_result.take(); - spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); + let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(&*spec.engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close_and_lock(); @@ -653,8 +651,7 @@ mod tests { let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); - let mut db = db_result.take(); - spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); + let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap() .close_and_lock().seal(engine, vec![]).unwrap(); @@ -662,8 +659,7 @@ mod tests { let orig_db = b.drain(); let mut db_result = get_temp_state_db(); - let mut db = db_result.take(); - spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); + let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, Default::default()).unwrap(); assert_eq!(e.rlp_bytes(), orig_bytes); @@ -681,8 +677,7 @@ mod tests { let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); - let mut db = db_result.take(); - spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); + let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let mut open_block = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let mut uncle1_header = Header::new(); @@ -697,8 +692,7 @@ mod tests { let orig_db = b.drain(); let mut db_result = get_temp_state_db(); - let mut db = db_result.take(); - spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); + let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, Default::default()).unwrap(); let bytes = e.rlp_bytes(); diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index c023cbdfb..00c8dd8de 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -167,26 +167,33 @@ impl Client { ) -> Result, ClientError> { let path = path.to_path_buf(); - let gb = spec.genesis_block(); - let db = Arc::new(try!(Database::open(&db_config, &path.to_str().expect("DB path could not be converted to string.")).map_err(ClientError::Database))); - let chain = Arc::new(BlockChain::new(config.blockchain.clone(), &gb, db.clone(), spec.engine.clone())); - let tracedb = RwLock::new(TraceDB::new(config.tracing.clone(), db.clone(), chain.clone())); - let trie_spec = match config.fat_db { true => TrieSpec::Fat, false => TrieSpec::Secure, }; let trie_factory = TrieFactory::new(trie_spec); + let factories = Factories { + vm: EvmFactory::new(config.vm_type.clone(), config.jump_table_size), + trie: trie_factory, + accountdb: Default::default(), + }; + let journal_db = journaldb::new(db.clone(), config.pruning, ::db::COL_STATE); let mut state_db = StateDB::new(journal_db, config.state_cache_size); - if state_db.journal_db().is_empty() && try!(spec.ensure_db_good(&mut state_db, &trie_factory)) { + if state_db.journal_db().is_empty() { + // Sets the correct state root. + state_db = spec.ensure_db_good(state_db, &factories)?; let mut batch = DBTransaction::new(&db); try!(state_db.journal_under(&mut batch, 0, &spec.genesis_header().hash())); try!(db.write(batch).map_err(ClientError::Database)); } + let gb = spec.genesis_block(); + let chain = Arc::new(BlockChain::new(config.blockchain.clone(), &gb, db.clone(), spec.engine.clone())); + let tracedb = RwLock::new(TraceDB::new(config.tracing.clone(), db.clone(), chain.clone())); + trace!("Cleanup journal: DB Earliest = {:?}, Latest = {:?}", state_db.journal_db().earliest_era(), state_db.journal_db().latest_era()); let history = if config.history < MIN_HISTORY_SIZE { @@ -221,12 +228,6 @@ impl Client { let awake = match config.mode { Mode::Dark(..) | Mode::Off => false, _ => true }; - let factories = Factories { - vm: EvmFactory::new(config.vm_type.clone(), config.jump_table_size), - trie: trie_factory, - accountdb: Default::default(), - }; - let client = Arc::new(Client { enabled: AtomicBool::new(true), sleep_state: Mutex::new(SleepState::new(awake)), diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index b9a51babd..e482b418a 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -344,8 +344,7 @@ impl MiningBlockChainClient for TestBlockChainClient { let engine = &*self.spec.engine; let genesis_header = self.spec.genesis_header(); let mut db_result = get_temp_state_db(); - let mut db = db_result.take(); - self.spec.ensure_db_good(&mut db, &TrieFactory::default()).unwrap(); + let db = self.spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); let last_hashes = vec![genesis_header.hash()]; let mut open_block = OpenBlock::new( diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs index 11d77bc78..f94fb3a0e 100644 --- a/ethcore/src/engines/authority_round.rs +++ b/ethcore/src/engines/authority_round.rs @@ -339,7 +339,6 @@ impl Engine for AuthorityRound { #[cfg(test)] mod tests { use util::*; - use util::trie::TrieSpec; use env_info::EnvInfo; use header::Header; use error::{Error, BlockError}; @@ -407,10 +406,8 @@ mod tests { let engine = &*spec.engine; engine.register_account_provider(Arc::new(tap)); let genesis_header = spec.genesis_header(); - let mut db1 = get_temp_state_db().take(); - spec.ensure_db_good(&mut db1, &TrieFactory::new(TrieSpec::Secure)).unwrap(); - let mut db2 = get_temp_state_db().take(); - spec.ensure_db_good(&mut db2, &TrieFactory::new(TrieSpec::Secure)).unwrap(); + let db1 = spec.ensure_db_good(get_temp_state_db().take(), &Default::default()).unwrap(); + let db2 = spec.ensure_db_good(get_temp_state_db().take(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![]).unwrap(); let b1 = b1.close_and_lock(); diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 37ac4066b..fe8336886 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -191,7 +191,6 @@ impl Engine for BasicAuthority { #[cfg(test)] mod tests { use util::*; - use util::trie::TrieSpec; use block::*; use env_info::EnvInfo; use error::{BlockError, Error}; @@ -265,8 +264,7 @@ mod tests { engine.register_account_provider(Arc::new(tap)); let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); - let mut db = db_result.take(); - spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); + let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close_and_lock(); diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 74f71168c..ff32f87ec 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -66,7 +66,6 @@ impl Engine for InstantSeal { #[cfg(test)] mod tests { use util::*; - use util::trie::TrieSpec; use tests::helpers::*; use spec::Spec; use header::Header; @@ -79,8 +78,7 @@ mod tests { let engine = &*spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); - let mut db = db_result.take(); - spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); + let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close_and_lock(); diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index bb6d54ca5..ffbc40cc3 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -656,7 +656,6 @@ impl Engine for Tendermint { #[cfg(test)] mod tests { use util::*; - use util::trie::TrieSpec; use io::{IoContext, IoHandler}; use block::*; use error::{Error, BlockError}; @@ -681,8 +680,7 @@ mod tests { fn propose_default(spec: &Spec, proposer: Address) -> (LockedBlock, Vec) { let mut db_result = get_temp_state_db(); - let mut db = db_result.take(); - spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); + let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); let genesis_header = spec.genesis_header(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(spec.engine.as_ref(), Default::default(), false, db.boxed_clone(), &genesis_header, last_hashes, proposer, (3141562.into(), 31415620.into()), vec![]).unwrap(); @@ -889,9 +887,6 @@ mod tests { fn relays_messages() { let (spec, tap) = setup(); let engine = spec.engine.clone(); - let mut db_result = get_temp_state_db(); - let mut db = db_result.take(); - spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); let v0 = insert_and_register(&tap, &engine, "0"); let v1 = insert_and_register(&tap, &engine, "1"); @@ -925,9 +920,6 @@ mod tests { fn seal_submission() { let (spec, tap) = setup(); let engine = spec.engine.clone(); - let mut db_result = get_temp_state_db(); - let mut db = db_result.take(); - spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); let v0 = insert_and_register(&tap, &engine, "0"); let v1 = insert_and_register(&tap, &engine, "1"); diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 372ac0533..1535f9783 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -433,7 +433,6 @@ impl Header { #[cfg(test)] mod tests { use util::*; - use util::trie::TrieSpec; use block::*; use tests::helpers::*; use env_info::EnvInfo; @@ -449,8 +448,7 @@ mod tests { let engine = &*spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); - let mut db = db_result.take(); - spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); + let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close(); @@ -463,8 +461,7 @@ mod tests { let engine = &*spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); - let mut db = db_result.take(); - spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); + let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let mut b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let mut uncle = Header::new(); diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index 0f7683046..cf7f4ba06 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -78,7 +78,6 @@ pub fn new_morden() -> Spec { load(include_bytes!("../../res/ethereum/morden.jso #[cfg(test)] mod tests { use util::*; - use util::trie::TrieSpec; use state::*; use super::*; use tests::helpers::*; @@ -90,8 +89,7 @@ mod tests { let engine = &spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); - let mut db = db_result.take(); - spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); + let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); let s = State::from_existing(db, genesis_header.state_root().clone(), engine.account_start_nonce(), Default::default()).unwrap(); assert_eq!(s.balance(&"0000000000000000000000000000000000000001".into()), 1u64.into()); assert_eq!(s.balance(&"0000000000000000000000000000000000000002".into()), 1u64.into()); diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index d3ba52b2e..9749ff770 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -19,6 +19,13 @@ use util::*; use builtin::Builtin; use engines::{Engine, NullEngine, InstantSeal, BasicAuthority, AuthorityRound, Tendermint}; +use factory::Factories; +use executive::Executive; +use trace::{NoopTracer, NoopVMTracer}; +use action_params::{ActionValue, ActionParams}; +use types::executed::CallType; +use state::{State, Substate}; +use env_info::EnvInfo; use pod_state::*; use account_db::*; use header::{BlockNumber, Header}; @@ -99,10 +106,13 @@ pub struct Spec { /// Each seal field, expressed as RLP, concatenated. pub seal_rlp: Bytes, - // May be prepopulated if we know this in advance. + /// Contract constructors to be executed on genesis. + constructors: Vec<(Address, Bytes)>, + + /// May be prepopulated if we know this in advance. state_root_memo: RwLock>, - // Genesis state as plain old data. + /// Genesis state as plain old data. genesis_state: PodState, } @@ -128,6 +138,7 @@ impl From for Spec { timestamp: g.timestamp, extra_data: g.extra_data, seal_rlp: seal_rlp, + constructors: s.accounts.constructors().into_iter().map(|(a, c)| (a.into(), c.into())).collect(), state_root_memo: RwLock::new(g.state_root), genesis_state: From::from(s.accounts), } @@ -238,25 +249,71 @@ impl Spec { } /// Ensure that the given state DB has the trie nodes in for the genesis state. - pub fn ensure_db_good(&self, db: &mut StateDB, factory: &TrieFactory) -> Result> { - if !db.as_hashdb().contains(&self.state_root()) { - trace!(target: "spec", "ensure_db_good: Fresh database? Cannot find state root {}", self.state_root()); - let mut root = H256::new(); + pub fn ensure_db_good(&self, mut db: StateDB, factories: &Factories) -> Result> { + if db.as_hashdb().contains(&self.state_root()) { + return Ok(db) + } + trace!(target: "spec", "ensure_db_good: Fresh database? Cannot find state root {}", self.state_root()); + let mut root = H256::new(); + { + let mut t = factories.trie.create(db.as_hashdb_mut(), &mut root); + for (address, account) in self.genesis_state.get().iter() { + try!(t.insert(&**address, &account.rlp())); + } + } + + trace!(target: "spec", "ensure_db_good: Populated sec trie; root is {}", root); + for (address, account) in self.genesis_state.get().iter() { + db.note_non_null_account(address); + account.insert_additional(&mut AccountDBMut::new(db.as_hashdb_mut(), address), &factories.trie); + } + + // Execute contract constructors. + let env_info = EnvInfo { + number: 0, + author: self.author, + timestamp: self.timestamp, + difficulty: self.difficulty, + last_hashes: Default::default(), + gas_used: U256::zero(), + gas_limit: U256::max_value(), + }; + let from = Address::default(); + let start_nonce = self.engine.account_start_nonce(); + + let mut state = State::from_existing(db, root, start_nonce, factories.clone())?; + // Mutate the state with each constructor. + for &(ref address, ref constructor) in self.constructors.iter() { + trace!(target: "spec", "ensure_db_good: Creating a contract at {}.", address); + let params = ActionParams { + code_address: address.clone(), + code_hash: constructor.sha3(), + address: address.clone(), + sender: from.clone(), + origin: from.clone(), + gas: U256::max_value(), + gas_price: Default::default(), + value: ActionValue::Transfer(Default::default()), + code: Some(Arc::new(constructor.clone())), + data: None, + call_type: CallType::None, + }; + let mut substate = Substate::new(); { - let mut t = factory.create(db.as_hashdb_mut(), &mut root); - for (address, account) in self.genesis_state.get().iter() { - try!(t.insert(&**address, &account.rlp())); + let mut exec = Executive::new(&mut state, &env_info, self.engine.as_ref(), &factories.vm); + if let Err(e) = exec.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer) { + warn!(target: "spec", "Genesis constructor execution at {} failed: {}.", address, e); } } - trace!(target: "spec", "ensure_db_good: Populated sec trie; root is {}", root); - for (address, account) in self.genesis_state.get().iter() { - db.note_non_null_account(address); - account.insert_additional(&mut AccountDBMut::new(db.as_hashdb_mut(), address), factory); + if let Err(e) = state.commit() { + warn!(target: "spec", "Genesis constructor trie commit at {} failed: {}.", address, e); } - assert!(db.as_hashdb().contains(&self.state_root())); - Ok(true) - } else { Ok(false) } + } + let (root, db) = state.drop(); + + *self.state_root_memo.write() = Some(root); + Ok(db) } /// Loads spec from json file. @@ -273,6 +330,9 @@ impl Spec { /// Create a new Spec which is a NullEngine consensus with a premine of address whose secret is sha3(''). pub fn new_null() -> Spec { load_bundled!("null") } + /// Create a new Spec which constructs a contract at address 5 with storage at 0 equal to 1. + pub fn new_test_constructor() -> Spec { load_bundled!("constructor") } + /// Create a new Spec with InstantSeal consensus which does internal sealing (not requiring work). pub fn new_instant() -> Spec { load_bundled!("instant_seal") } @@ -287,10 +347,10 @@ impl Spec { #[cfg(test)] mod tests { - use std::str::FromStr; - use util::hash::*; - use util::sha3::*; + use util::*; use views::*; + use tests::helpers::get_temp_state_db; + use state::State; use super::*; // https://github.com/ethcore/parity/issues/1840 @@ -307,4 +367,14 @@ mod tests { let genesis = test_spec.genesis_block(); assert_eq!(BlockView::new(&genesis).header_view().sha3(), H256::from_str("0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303").unwrap()); } + + #[test] + fn genesis_constructor() { + let spec = Spec::new_test_constructor(); + let mut db_result = get_temp_state_db(); + let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); + let state = State::from_existing(db.boxed_clone(), spec.state_root(), spec.engine.account_start_nonce(), Default::default()).unwrap(); + let expected = H256::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap(); + assert_eq!(state.storage_at(&Address::from_str("0000000000000000000000000000000000000005").unwrap(), &H256::zero()), expected); + } } diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 602217d88..d08261306 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -18,7 +18,6 @@ use ethkey::KeyPair; use io::*; use client::{BlockChainClient, Client, ClientConfig}; use util::*; -use util::trie::TrieSpec; use spec::*; use state_db::StateDB; use block::{OpenBlock, Drain}; @@ -157,8 +156,7 @@ pub fn generate_dummy_client_with_spec_and_data(get_test_spec: F, block_numbe let test_engine = &*test_spec.engine; let mut db_result = get_temp_state_db(); - let mut db = db_result.take(); - test_spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); + let mut db = test_spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); let genesis_header = test_spec.genesis_header(); let mut rolling_timestamp = 40; diff --git a/json/src/spec/account.rs b/json/src/spec/account.rs index b3e0ecbae..858129151 100644 --- a/json/src/spec/account.rs +++ b/json/src/spec/account.rs @@ -32,8 +32,10 @@ pub struct Account { pub nonce: Option, /// Code. pub code: Option, - /// Storage + /// Storage. pub storage: Option>, + /// Constructor. + pub constructor: Option, } impl Account { diff --git a/json/src/spec/state.rs b/json/src/spec/state.rs index cff03db54..e1aa9aea4 100644 --- a/json/src/spec/state.rs +++ b/json/src/spec/state.rs @@ -18,6 +18,7 @@ use std::collections::BTreeMap; use hash::Address; +use bytes::Bytes; use spec::{Account, Builtin}; /// Blockchain test state deserializer. @@ -29,7 +30,15 @@ impl State { pub fn builtins(&self) -> BTreeMap { self.0 .iter() - .filter_map(|ref pair| pair.1.builtin.clone().map(|b| (pair.0.clone(), b.clone()))) + .filter_map(|(add, ref acc)| acc.builtin.clone().map(|b| (add.clone(), b))) + .collect() + } + + /// Returns all constructors. + pub fn constructors(&self) -> BTreeMap { + self.0 + .iter() + .filter_map(|(add, ref acc)| acc.constructor.clone().map(|b| (add.clone(), b))) .collect() } }