State::new_contract.

This commit is contained in:
Gav Wood 2016-01-09 14:19:35 +01:00
parent 23d22db95c
commit 2b022e11e1
4 changed files with 54 additions and 36 deletions

View File

@ -70,8 +70,15 @@ impl Account {
} }
} }
/// Reset this account to the status of a not-yet-initialised contract.
/// NOTE: Account should have `init_code()` called on it later.
pub fn reset_code(&mut self) {
self.code_hash = None;
self.code_cache = vec![];
}
/// Set this account's code to the given code. /// Set this account's code to the given code.
/// NOTE: Account should have been created with `new_contract`. /// NOTE: Account should have been created with `new_contract()` or have `reset_code()` called on it.
pub fn init_code(&mut self, code: Bytes) { pub fn init_code(&mut self, code: Bytes) {
assert!(self.code_hash.is_none()); assert!(self.code_hash.is_none());
self.code_cache = code; self.code_cache = code;

View File

@ -36,5 +36,5 @@ fn playpen() {
let genesis_header = engine.spec().genesis_header(); let genesis_header = engine.spec().genesis_header();
let mut db = OverlayDB::new_temp(); let mut db = OverlayDB::new_temp();
engine.spec().ensure_db_good(&mut db); engine.spec().ensure_db_good(&mut db);
let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()]); // let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()]);
} }

View File

@ -206,15 +206,16 @@ impl Spec {
Spec { Spec {
engine_name: "Ethash".to_string(), engine_name: "Ethash".to_string(),
engine_params: vec![ engine_params: vec![
("block_reward", encode(&(finney() * U256::from(1500u64)))), ("blockReward", encode(&(finney() * U256::from(1500u64)))),
("maximum_extra_data_size", encode(&U256::from(1024u64))), ("frontierCompatibilityModeLimit", encode(&0xffffffffu64)),
("account_start_nonce", encode(&U256::from(0u64))), ("maximumExtraDataSize", encode(&U256::from(1024u64))),
("gas_limit_bounds_divisor", encode(&1024u64)), ("accountStartNonce", encode(&U256::from(0u64))),
("minimum_difficulty", encode(&131_072u64)), ("gasLimitBoundsDivisor", encode(&1024u64)),
("difficulty_bound_divisor", encode(&2048u64)), ("minimumDifficulty", encode(&131_072u64)),
("duration_limit", encode(&8u64)), ("difficultyBoundDivisor", encode(&2048u64)),
("min_gas_limit", encode(&125_000u64)), ("durationLimit", encode(&8u64)),
("gas_floor_target", encode(&3_141_592u64)), ("minGasLimit", encode(&125_000u64)),
("gasFloorTarget", encode(&3_141_592u64)),
].into_iter().fold(HashMap::new(), | mut acc, vec | { ].into_iter().fold(HashMap::new(), | mut acc, vec | {
acc.insert(vec.0.to_string(), vec.1); acc.insert(vec.0.to_string(), vec.1);
acc acc
@ -244,15 +245,16 @@ impl Spec {
Spec { Spec {
engine_name: "Ethash".to_string(), engine_name: "Ethash".to_string(),
engine_params: vec![ engine_params: vec![
("block_reward", encode(&(ether() * U256::from(5u64)))), ("blockReward", encode(&(ether() * U256::from(5u64)))),
("maximum_extra_data_size", encode(&U256::from(32u64))), ("frontierCompatibilityModeLimit", encode(&0xfffa2990u64)),
("account_start_nonce", encode(&U256::from(0u64))), ("maximumExtraDataSize", encode(&U256::from(32u64))),
("gas_limit_bounds_divisor", encode(&1024u64)), ("accountStartNonce", encode(&U256::from(0u64))),
("minimum_difficulty", encode(&131_072u64)), ("gasLimitBoundsDivisor", encode(&1024u64)),
("difficulty_bound_divisor", encode(&2048u64)), ("minimumDifficulty", encode(&131_072u64)),
("duration_limit", encode(&13u64)), ("difficultyBoundDivisor", encode(&2048u64)),
("min_gas_limit", encode(&5000u64)), ("durationLimit", encode(&13u64)),
("gas_floor_target", encode(&3_141_592u64)), ("minGasLimit", encode(&5000u64)),
("gasFloorTarget", encode(&3_141_592u64)),
].into_iter().fold(HashMap::new(), | mut acc, vec | { ].into_iter().fold(HashMap::new(), | mut acc, vec | {
acc.insert(vec.0.to_string(), vec.1); acc.insert(vec.0.to_string(), vec.1);
acc acc
@ -282,15 +284,16 @@ impl Spec {
Spec { Spec {
engine_name: "Ethash".to_string(), engine_name: "Ethash".to_string(),
engine_params: vec![ engine_params: vec![
("block_reward", encode(&(ether() * U256::from(5u64)))), ("blockReward", encode(&(ether() * U256::from(5u64)))),
("maximum_extra_data_size", encode(&U256::from(32u64))), ("frontierCompatibilityModeLimit", encode(&0xfffa2990u64)),
("account_start_nonce", encode(&(U256::from(1u64) << 20))), ("maximumExtraDataSize", encode(&U256::from(32u64))),
("gas_limit_bounds_divisor", encode(&1024u64)), ("accountStartNonce", encode(&(U256::from(1u64) << 20))),
("minimum_difficulty", encode(&131_072u64)), ("gasLimitBoundsDivisor", encode(&1024u64)),
("difficulty_bound_divisor", encode(&2048u64)), ("minimumDifficulty", encode(&131_072u64)),
("duration_limit", encode(&13u64)), ("difficultyBoundDivisor", encode(&2048u64)),
("min_gas_limit", encode(&5000u64)), ("durationLimit", encode(&13u64)),
("gas_floor_target", encode(&3_141_592u64)), ("minGasLimit", encode(&5000u64)),
("gasFloorTarget", encode(&3_141_592u64)),
].into_iter().fold(HashMap::new(), | mut acc, vec | { ].into_iter().fold(HashMap::new(), | mut acc, vec | {
acc.insert(vec.0.to_string(), vec.1); acc.insert(vec.0.to_string(), vec.1);
acc acc

View File

@ -73,6 +73,12 @@ impl State {
&mut self.db &mut self.db
} }
/// Create a new contract at address `contract`. If there is already an account at the address
/// it will have its code reset, ready for `init_code()`.
pub fn new_contract(&mut self, contract: &Address) {
self.require_or_from(contract, false, || Account::new_contract(U256::from(0u8)), |r| r.reset_code());
}
/// Get the balance of account `a`. /// Get the balance of account `a`.
pub fn balance(&self, a: &Address) -> U256 { pub fn balance(&self, a: &Address) -> U256 {
self.get(a, false).as_ref().map(|account| account.balance().clone()).unwrap_or(U256::from(0u8)) self.get(a, false).as_ref().map(|account| account.balance().clone()).unwrap_or(U256::from(0u8))
@ -122,7 +128,7 @@ impl State {
/// Initialise the code of account `a` so that it is `value` for `key`. /// Initialise the code of account `a` so that it is `value` for `key`.
/// NOTE: Account should have been created with `new_contract`. /// NOTE: Account should have been created with `new_contract`.
pub fn init_code(&mut self, a: &Address, code: Bytes) { pub fn init_code(&mut self, a: &Address, code: Bytes) {
self.require_or_from(a, true, || Account::new_contract(U256::from(0u8))).init_code(code); self.require_or_from(a, true, || Account::new_contract(U256::from(0u8)), |_|{}).init_code(code);
} }
/// Execute a given transaction. /// Execute a given transaction.
@ -188,18 +194,20 @@ impl State {
} }
/// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too. /// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too.
/// `force_create` creates a new, empty basic account if there is not currently an active account.
fn require(&self, a: &Address, require_code: bool) -> RefMut<Account> { fn require(&self, a: &Address, require_code: bool) -> RefMut<Account> {
self.require_or_from(a, require_code, || Account::new_basic(U256::from(0u8), self.account_start_nonce)) self.require_or_from(a, require_code, || Account::new_basic(U256::from(0u8), self.account_start_nonce), |_|{})
} }
/// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too. /// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too.
/// `force_create` creates a new, empty basic account if there is not currently an active account. /// If it doesn't exist, make account equal the evaluation of `default`.
fn require_or_from<F: FnOnce() -> Account>(&self, a: &Address, require_code: bool, default: F) -> RefMut<Account> { fn require_or_from<F: FnOnce() -> Account, G: FnOnce(&mut Account)>(&self, a: &Address, require_code: bool, default: F, not_default: G) -> RefMut<Account> {
self.cache.borrow_mut().entry(a.clone()).or_insert_with(|| self.cache.borrow_mut().entry(a.clone()).or_insert_with(||
TrieDB::new(&self.db, &self.root).get(&a).map(|rlp| Account::from_rlp(rlp))); TrieDB::new(&self.db, &self.root).get(&a).map(|rlp| Account::from_rlp(rlp)));
if self.cache.borrow().get(a).unwrap().is_none() { let preexists = self.cache.borrow().get(a).unwrap().is_none();
if preexists {
self.cache.borrow_mut().insert(a.clone(), Some(default())); self.cache.borrow_mut().insert(a.clone(), Some(default()));
} else {
not_default(self.cache.borrow_mut().get_mut(a).unwrap().as_mut().unwrap());
} }
let b = self.cache.borrow_mut(); let b = self.cache.borrow_mut();
@ -228,7 +236,7 @@ fn code_from_database() {
let a = Address::from_str("0000000000000000000000000000000000000000").unwrap(); let a = Address::from_str("0000000000000000000000000000000000000000").unwrap();
let (r, db) = { let (r, db) = {
let mut s = State::new_temp(); let mut s = State::new_temp();
s.require_or_from(&a, false, ||Account::new_contract(U256::from(42u32))); s.require_or_from(&a, false, ||Account::new_contract(U256::from(42u32)), |_|{});
s.init_code(&a, vec![1, 2, 3]); s.init_code(&a, vec![1, 2, 3]);
assert_eq!(s.code(&a), Some([1u8, 2, 3].to_vec())); assert_eq!(s.code(&a), Some([1u8, 2, 3].to_vec()));
s.commit(); s.commit();