DAO Rescue soft fork (#1309)

* DAO Rescue soft fork

* Address minor issues.

* Fix tests.
This commit is contained in:
Gav Wood 2016-06-17 22:15:18 +02:00 committed by arkpar
parent 76b413b5f7
commit 42478add64
5 changed files with 29 additions and 1 deletions

View File

@ -58,6 +58,8 @@ pub enum TransactionError {
},
/// Transaction's gas limit (aka gas) is invalid.
InvalidGasLimit(OutOfBounds<U256>),
/// Transaction is invalid for some other reason.
DAORescue,
}
impl fmt::Display for TransactionError {
@ -76,6 +78,7 @@ impl fmt::Display for TransactionError {
GasLimitExceeded { limit, got } =>
format!("Gas limit exceeded. Limit={}, Given={}", limit, got),
InvalidGasLimit(ref err) => format!("Invalid gas limit. {}", err),
DAORescue => "Transaction is invalid due to the DAO rescue.".into(),
};
f.write_fmt(format_args!("Transaction error ({})", msg))

View File

@ -101,7 +101,10 @@ impl Engine for Ethash {
if env_info.number < self.ethash_params.frontier_compatibility_mode_limit {
Schedule::new_frontier()
} else {
Schedule::new_homestead()
let mut s = Schedule::new_homestead();
// TODO: make dependent on gaslimit > 4000000 of block 1760000.
s.block_dao_transactions = env_info.number >= 1760000;
s
}
}

View File

@ -80,6 +80,8 @@ pub struct Schedule {
pub tx_data_non_zero_gas: usize,
/// Gas price for copying memory
pub copy_gas: usize,
/// DAO Rescue softfork block
pub block_dao_transactions: bool,
}
impl Schedule {
@ -126,6 +128,7 @@ impl Schedule {
tx_data_zero_gas: 4,
tx_data_non_zero_gas: 68,
copy_gas: 3,
block_dao_transactions: false,
}
}
}

View File

@ -222,6 +222,24 @@ impl State {
let options = TransactOptions { tracing: tracing, vm_tracing: false, check_nonce: true };
let e = try!(Executive::new(self, env_info, engine, vm_factory).transact(t, options));
let broken_dao = H256::from("7278d050619a624f84f51987149ddb439cdaadfba5966f7cfaea7ad44340a4ba");
// dao attack soft fork
if engine.schedule(&env_info).block_dao_transactions {
// collect all the addresses which have changed.
let addresses = self.cache.borrow().iter().map(|(addr, _)| addr.clone()).collect::<Vec<_>>();
for a in addresses.iter() {
if self.code(a).map(|c| c.sha3() == broken_dao).unwrap_or(false) {
// 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);
if maybe_original.map(|original| *original.balance() > self.balance(a)).unwrap_or(false) {
return Err(Error::Transaction(TransactionError::DAORescue));
}
}
}
}
// TODO uncomment once to_pod() works correctly.
// trace!("Applied transaction. Diff:\n{}\n", state_diff::diff_pod(&old, &self.to_pod()));
self.commit();

View File

@ -134,6 +134,7 @@ fn transaction_error(error: EthcoreError) -> Error {
format!("Transaction cost exceeds current gas limit. Limit: {}, got: {}. Try decreasing supplied gas.", limit, got)
},
InvalidGasLimit(_) => "Supplied gas is beyond limit.".into(),
DAORescue => "Transaction removes funds from a DAO.".into(),
};
Error {
code: ErrorCode::ServerError(error_codes::TRANSACTION_ERROR),