Allow contract constructors in chain spec (#3932)

* constructor spec

* execute under wrong address

* create under correct address

* revert

* move genesis block lookup

* remove env_logger
This commit is contained in:
keorn 2016-12-23 18:44:39 +01:00 committed by Gav Wood
parent 5a3c3bcb45
commit afc4cd2785
14 changed files with 161 additions and 78 deletions

View File

@ -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" }
}
}

View File

@ -595,9 +595,8 @@ mod tests {
use factory::Factories; use factory::Factories;
use state_db::StateDB; use state_db::StateDB;
use views::BlockView; use views::BlockView;
use util::{Address, TrieFactory}; use util::Address;
use util::hash::FixedHash; use util::hash::FixedHash;
use util::trie::TrieSpec;
use std::sync::Arc; use std::sync::Arc;
/// 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
@ -637,8 +636,7 @@ mod tests {
let spec = Spec::new_test(); let spec = Spec::new_test();
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let mut db_result = get_temp_state_db(); let mut db_result = get_temp_state_db();
let mut db = db_result.take(); let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]); 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 = 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(); let b = b.close_and_lock();
@ -653,8 +651,7 @@ mod tests {
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let mut db_result = get_temp_state_db(); let mut db_result = get_temp_state_db();
let mut db = db_result.take(); let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]); 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() 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(); .close_and_lock().seal(engine, vec![]).unwrap();
@ -662,8 +659,7 @@ mod tests {
let orig_db = b.drain(); let orig_db = b.drain();
let mut db_result = get_temp_state_db(); let mut db_result = get_temp_state_db();
let mut db = db_result.take(); let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, 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); assert_eq!(e.rlp_bytes(), orig_bytes);
@ -681,8 +677,7 @@ mod tests {
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let mut db_result = get_temp_state_db(); let mut db_result = get_temp_state_db();
let mut db = db_result.take(); let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]); 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 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(); let mut uncle1_header = Header::new();
@ -697,8 +692,7 @@ mod tests {
let orig_db = b.drain(); let orig_db = b.drain();
let mut db_result = get_temp_state_db(); let mut db_result = get_temp_state_db();
let mut db = db_result.take(); let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, 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(); let bytes = e.rlp_bytes();

View File

@ -167,26 +167,33 @@ impl Client {
) -> Result<Arc<Client>, ClientError> { ) -> Result<Arc<Client>, ClientError> {
let path = path.to_path_buf(); 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 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 { let trie_spec = match config.fat_db {
true => TrieSpec::Fat, true => TrieSpec::Fat,
false => TrieSpec::Secure, false => TrieSpec::Secure,
}; };
let trie_factory = TrieFactory::new(trie_spec); 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 journal_db = journaldb::new(db.clone(), config.pruning, ::db::COL_STATE);
let mut state_db = StateDB::new(journal_db, config.state_cache_size); 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); let mut batch = DBTransaction::new(&db);
try!(state_db.journal_under(&mut batch, 0, &spec.genesis_header().hash())); try!(state_db.journal_under(&mut batch, 0, &spec.genesis_header().hash()));
try!(db.write(batch).map_err(ClientError::Database)); 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()); 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 { 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 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 { let client = Arc::new(Client {
enabled: AtomicBool::new(true), enabled: AtomicBool::new(true),
sleep_state: Mutex::new(SleepState::new(awake)), sleep_state: Mutex::new(SleepState::new(awake)),

View File

@ -344,8 +344,7 @@ impl MiningBlockChainClient for TestBlockChainClient {
let engine = &*self.spec.engine; let engine = &*self.spec.engine;
let genesis_header = self.spec.genesis_header(); let genesis_header = self.spec.genesis_header();
let mut db_result = get_temp_state_db(); let mut db_result = get_temp_state_db();
let mut db = db_result.take(); let db = self.spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
self.spec.ensure_db_good(&mut db, &TrieFactory::default()).unwrap();
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let mut open_block = OpenBlock::new( let mut open_block = OpenBlock::new(

View File

@ -339,7 +339,6 @@ impl Engine for AuthorityRound {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use util::*; use util::*;
use util::trie::TrieSpec;
use env_info::EnvInfo; use env_info::EnvInfo;
use header::Header; use header::Header;
use error::{Error, BlockError}; use error::{Error, BlockError};
@ -407,10 +406,8 @@ mod tests {
let engine = &*spec.engine; let engine = &*spec.engine;
engine.register_account_provider(Arc::new(tap)); engine.register_account_provider(Arc::new(tap));
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let mut db1 = get_temp_state_db().take(); let db1 = spec.ensure_db_good(get_temp_state_db().take(), &Default::default()).unwrap();
spec.ensure_db_good(&mut db1, &TrieFactory::new(TrieSpec::Secure)).unwrap(); let db2 = spec.ensure_db_good(get_temp_state_db().take(), &Default::default()).unwrap();
let mut db2 = get_temp_state_db().take();
spec.ensure_db_good(&mut db2, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]); 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 = 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(); let b1 = b1.close_and_lock();

View File

@ -191,7 +191,6 @@ impl Engine for BasicAuthority {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use util::*; use util::*;
use util::trie::TrieSpec;
use block::*; use block::*;
use env_info::EnvInfo; use env_info::EnvInfo;
use error::{BlockError, Error}; use error::{BlockError, Error};
@ -265,8 +264,7 @@ mod tests {
engine.register_account_provider(Arc::new(tap)); engine.register_account_provider(Arc::new(tap));
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let mut db_result = get_temp_state_db(); let mut db_result = get_temp_state_db();
let mut db = db_result.take(); let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]); 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 = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close_and_lock(); let b = b.close_and_lock();

View File

@ -66,7 +66,6 @@ impl Engine for InstantSeal {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use util::*; use util::*;
use util::trie::TrieSpec;
use tests::helpers::*; use tests::helpers::*;
use spec::Spec; use spec::Spec;
use header::Header; use header::Header;
@ -79,8 +78,7 @@ mod tests {
let engine = &*spec.engine; let engine = &*spec.engine;
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let mut db_result = get_temp_state_db(); let mut db_result = get_temp_state_db();
let mut db = db_result.take(); let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]); 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 = 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(); let b = b.close_and_lock();

View File

@ -656,7 +656,6 @@ impl Engine for Tendermint {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use util::*; use util::*;
use util::trie::TrieSpec;
use io::{IoContext, IoHandler}; use io::{IoContext, IoHandler};
use block::*; use block::*;
use error::{Error, BlockError}; use error::{Error, BlockError};
@ -681,8 +680,7 @@ mod tests {
fn propose_default(spec: &Spec, proposer: Address) -> (LockedBlock, Vec<Bytes>) { fn propose_default(spec: &Spec, proposer: Address) -> (LockedBlock, Vec<Bytes>) {
let mut db_result = get_temp_state_db(); let mut db_result = get_temp_state_db();
let mut db = db_result.take(); let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let last_hashes = Arc::new(vec![genesis_header.hash()]); 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(); 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() { fn relays_messages() {
let (spec, tap) = setup(); let (spec, tap) = setup();
let engine = spec.engine.clone(); 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 v0 = insert_and_register(&tap, &engine, "0");
let v1 = insert_and_register(&tap, &engine, "1"); let v1 = insert_and_register(&tap, &engine, "1");
@ -925,9 +920,6 @@ mod tests {
fn seal_submission() { fn seal_submission() {
let (spec, tap) = setup(); let (spec, tap) = setup();
let engine = spec.engine.clone(); 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 v0 = insert_and_register(&tap, &engine, "0");
let v1 = insert_and_register(&tap, &engine, "1"); let v1 = insert_and_register(&tap, &engine, "1");

View File

@ -433,7 +433,6 @@ impl Header {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use util::*; use util::*;
use util::trie::TrieSpec;
use block::*; use block::*;
use tests::helpers::*; use tests::helpers::*;
use env_info::EnvInfo; use env_info::EnvInfo;
@ -449,8 +448,7 @@ mod tests {
let engine = &*spec.engine; let engine = &*spec.engine;
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let mut db_result = get_temp_state_db(); let mut db_result = get_temp_state_db();
let mut db = db_result.take(); let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]); 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 = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close(); let b = b.close();
@ -463,8 +461,7 @@ mod tests {
let engine = &*spec.engine; let engine = &*spec.engine;
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let mut db_result = get_temp_state_db(); let mut db_result = get_temp_state_db();
let mut db = db_result.take(); let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]); 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 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(); let mut uncle = Header::new();

View File

@ -78,7 +78,6 @@ pub fn new_morden() -> Spec { load(include_bytes!("../../res/ethereum/morden.jso
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use util::*; use util::*;
use util::trie::TrieSpec;
use state::*; use state::*;
use super::*; use super::*;
use tests::helpers::*; use tests::helpers::*;
@ -90,8 +89,7 @@ mod tests {
let engine = &spec.engine; let engine = &spec.engine;
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let mut db_result = get_temp_state_db(); let mut db_result = get_temp_state_db();
let mut db = db_result.take(); let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let s = State::from_existing(db, genesis_header.state_root().clone(), engine.account_start_nonce(), 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(&"0000000000000000000000000000000000000001".into()), 1u64.into());
assert_eq!(s.balance(&"0000000000000000000000000000000000000002".into()), 1u64.into()); assert_eq!(s.balance(&"0000000000000000000000000000000000000002".into()), 1u64.into());

View File

@ -19,6 +19,13 @@
use util::*; use util::*;
use builtin::Builtin; use builtin::Builtin;
use engines::{Engine, NullEngine, InstantSeal, BasicAuthority, AuthorityRound, Tendermint}; 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 pod_state::*;
use account_db::*; use account_db::*;
use header::{BlockNumber, Header}; use header::{BlockNumber, Header};
@ -99,10 +106,13 @@ pub struct Spec {
/// Each seal field, expressed as RLP, concatenated. /// Each seal field, expressed as RLP, concatenated.
pub seal_rlp: Bytes, 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<Option<H256>>, state_root_memo: RwLock<Option<H256>>,
// Genesis state as plain old data. /// Genesis state as plain old data.
genesis_state: PodState, genesis_state: PodState,
} }
@ -128,6 +138,7 @@ impl From<ethjson::spec::Spec> for Spec {
timestamp: g.timestamp, timestamp: g.timestamp,
extra_data: g.extra_data, extra_data: g.extra_data,
seal_rlp: seal_rlp, 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), state_root_memo: RwLock::new(g.state_root),
genesis_state: From::from(s.accounts), 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. /// 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<bool, Box<TrieError>> { pub fn ensure_db_good(&self, mut db: StateDB, factories: &Factories) -> Result<StateDB, Box<TrieError>> {
if !db.as_hashdb().contains(&self.state_root()) { if db.as_hashdb().contains(&self.state_root()) {
trace!(target: "spec", "ensure_db_good: Fresh database? Cannot find state root {}", self.state_root()); return Ok(db)
let mut root = H256::new(); }
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); let mut exec = Executive::new(&mut state, &env_info, self.engine.as_ref(), &factories.vm);
for (address, account) in self.genesis_state.get().iter() { if let Err(e) = exec.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer) {
try!(t.insert(&**address, &account.rlp())); warn!(target: "spec", "Genesis constructor execution at {} failed: {}.", address, e);
} }
} }
trace!(target: "spec", "ensure_db_good: Populated sec trie; root is {}", root); if let Err(e) = state.commit() {
for (address, account) in self.genesis_state.get().iter() { warn!(target: "spec", "Genesis constructor trie commit at {} failed: {}.", address, e);
db.note_non_null_account(address);
account.insert_additional(&mut AccountDBMut::new(db.as_hashdb_mut(), address), factory);
} }
assert!(db.as_hashdb().contains(&self.state_root())); }
Ok(true) let (root, db) = state.drop();
} else { Ok(false) }
*self.state_root_memo.write() = Some(root);
Ok(db)
} }
/// Loads spec from json file. /// 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(''). /// 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") } 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). /// Create a new Spec with InstantSeal consensus which does internal sealing (not requiring work).
pub fn new_instant() -> Spec { load_bundled!("instant_seal") } pub fn new_instant() -> Spec { load_bundled!("instant_seal") }
@ -287,10 +347,10 @@ impl Spec {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::str::FromStr; use util::*;
use util::hash::*;
use util::sha3::*;
use views::*; use views::*;
use tests::helpers::get_temp_state_db;
use state::State;
use super::*; use super::*;
// https://github.com/ethcore/parity/issues/1840 // https://github.com/ethcore/parity/issues/1840
@ -307,4 +367,14 @@ mod tests {
let genesis = test_spec.genesis_block(); let genesis = test_spec.genesis_block();
assert_eq!(BlockView::new(&genesis).header_view().sha3(), H256::from_str("0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303").unwrap()); 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);
}
} }

View File

@ -18,7 +18,6 @@ use ethkey::KeyPair;
use io::*; use io::*;
use client::{BlockChainClient, Client, ClientConfig}; use client::{BlockChainClient, Client, ClientConfig};
use util::*; use util::*;
use util::trie::TrieSpec;
use spec::*; use spec::*;
use state_db::StateDB; use state_db::StateDB;
use block::{OpenBlock, Drain}; use block::{OpenBlock, Drain};
@ -157,8 +156,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
let test_engine = &*test_spec.engine; let test_engine = &*test_spec.engine;
let mut db_result = get_temp_state_db(); let mut db_result = get_temp_state_db();
let mut db = db_result.take(); let mut db = test_spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
test_spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let genesis_header = test_spec.genesis_header(); let genesis_header = test_spec.genesis_header();
let mut rolling_timestamp = 40; let mut rolling_timestamp = 40;

View File

@ -32,8 +32,10 @@ pub struct Account {
pub nonce: Option<Uint>, pub nonce: Option<Uint>,
/// Code. /// Code.
pub code: Option<Bytes>, pub code: Option<Bytes>,
/// Storage /// Storage.
pub storage: Option<BTreeMap<Uint, Uint>>, pub storage: Option<BTreeMap<Uint, Uint>>,
/// Constructor.
pub constructor: Option<Bytes>,
} }
impl Account { impl Account {

View File

@ -18,6 +18,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use hash::Address; use hash::Address;
use bytes::Bytes;
use spec::{Account, Builtin}; use spec::{Account, Builtin};
/// Blockchain test state deserializer. /// Blockchain test state deserializer.
@ -29,7 +30,15 @@ impl State {
pub fn builtins(&self) -> BTreeMap<Address, Builtin> { pub fn builtins(&self) -> BTreeMap<Address, Builtin> {
self.0 self.0
.iter() .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<Address, Bytes> {
self.0
.iter()
.filter_map(|(add, ref acc)| acc.constructor.clone().map(|b| (add.clone(), b)))
.collect() .collect()
} }
} }