* DAO hard-fork (#1483) * Minor additions to allow resetting of code. * Add test. * Provisional DAO hard-fork proposal. * Change to reflect latest HF spec. * Include extradata restrictions and overrides. * Introduce new tests. * Update tests to new spec format. * Allow JSON chain spec fields to be optional. * Remove superfluous definitions. Fix overflow risk. * Fix build. * Add missing file. * Remove old flag. * Update to latest address set. * Update tests and test spec to latest. Change the mining default to release only on own transactions. * Updated tests submodule
This commit is contained in:
@@ -494,10 +494,12 @@ pub fn enact(
|
||||
}
|
||||
}
|
||||
|
||||
let mut b = try!(OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, header.author().clone(), (3141562.into(), 31415620.into()), header.extra_data().clone()));
|
||||
let mut b = try!(OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, Address::new(), (3141562.into(), 31415620.into()), vec![]));
|
||||
b.set_difficulty(*header.difficulty());
|
||||
b.set_gas_limit(*header.gas_limit());
|
||||
b.set_timestamp(header.timestamp());
|
||||
b.set_author(header.author().clone());
|
||||
b.set_extra_data(header.extra_data().clone()).unwrap_or_else(|e| warn!("Couldn't set extradata: {}. Ignoring.", e));
|
||||
for t in transactions { try!(b.push_transaction(t.clone(), None)); }
|
||||
for u in uncles { try!(b.push_uncle(u.clone())); }
|
||||
Ok(b.close_and_lock())
|
||||
|
||||
@@ -39,6 +39,12 @@ pub struct EthashParams {
|
||||
pub registrar: Address,
|
||||
/// Homestead transition block number.
|
||||
pub frontier_compatibility_mode_limit: u64,
|
||||
/// DAO hard-fork transition block (X).
|
||||
pub dao_hardfork_transition: u64,
|
||||
/// DAO hard-fork refund contract address (C).
|
||||
pub dao_hardfork_beneficiary: Address,
|
||||
/// DAO hard-fork DAO accounts list (L)
|
||||
pub dao_hardfork_accounts: Vec<Address>,
|
||||
}
|
||||
|
||||
impl From<ethjson::spec::EthashParams> for EthashParams {
|
||||
@@ -49,8 +55,11 @@ impl From<ethjson::spec::EthashParams> for EthashParams {
|
||||
difficulty_bound_divisor: p.difficulty_bound_divisor.into(),
|
||||
duration_limit: p.duration_limit.into(),
|
||||
block_reward: p.block_reward.into(),
|
||||
registrar: p.registrar.into(),
|
||||
frontier_compatibility_mode_limit: p.frontier_compatibility_mode_limit.into(),
|
||||
registrar: p.registrar.map(Into::into).unwrap_or(Address::new()),
|
||||
frontier_compatibility_mode_limit: p.frontier_compatibility_mode_limit.map(Into::into).unwrap_or(0),
|
||||
dao_hardfork_transition: p.dao_hardfork_transition.map(Into::into).unwrap_or(0x7fffffffffffffff),
|
||||
dao_hardfork_beneficiary: p.dao_hardfork_beneficiary.map(Into::into).unwrap_or(Address::new()),
|
||||
dao_hardfork_accounts: p.dao_hardfork_accounts.unwrap_or(vec![]).into_iter().map(Into::into).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,10 +128,27 @@ impl Engine for Ethash {
|
||||
(header.gas_used * 6.into() / 5.into()) / bound_divisor))
|
||||
}
|
||||
};
|
||||
if header.number >= self.ethash_params.dao_hardfork_transition &&
|
||||
header.number <= self.ethash_params.dao_hardfork_transition + 9 {
|
||||
header.extra_data = b"dao-hard-fork"[..].to_owned();
|
||||
}
|
||||
header.note_dirty();
|
||||
// info!("ethash: populate_from_parent #{}: difficulty={} and gas_limit={}", header.number, header.difficulty, header.gas_limit);
|
||||
}
|
||||
|
||||
fn on_new_block(&self, block: &mut ExecutedBlock) {
|
||||
if block.fields().header.number == self.ethash_params.dao_hardfork_transition {
|
||||
// TODO: enable trigger function maybe?
|
||||
// if block.fields().header.gas_limit <= 4_000_000.into() {
|
||||
let mut state = block.fields_mut().state;
|
||||
for child in self.ethash_params.dao_hardfork_accounts.iter() {
|
||||
let b = state.balance(child);
|
||||
state.transfer_balance(child, &self.ethash_params.dao_hardfork_beneficiary, &b);
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply the block reward on finalisation of the block.
|
||||
/// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current).
|
||||
fn on_close_block(&self, block: &mut ExecutedBlock) {
|
||||
@@ -164,6 +190,17 @@ impl Engine for Ethash {
|
||||
if difficulty < header.difficulty {
|
||||
return Err(From::from(BlockError::InvalidProofOfWork(OutOfBounds { min: Some(header.difficulty), max: None, found: difficulty })));
|
||||
}
|
||||
|
||||
if header.number >= self.ethash_params.dao_hardfork_transition &&
|
||||
header.number <= self.ethash_params.dao_hardfork_transition + 9 &&
|
||||
header.extra_data[..] != b"dao-hard-fork"[..] {
|
||||
return Err(From::from(BlockError::ExtraDataOutOfBounds(OutOfBounds { min: None, max: None, found: 0 })));
|
||||
}
|
||||
|
||||
if header.gas_limit > 0x7fffffffffffffffu64.into() {
|
||||
return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: None, max: Some(0x7fffffffffffffffu64.into()), found: header.gas_limit })));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -37,12 +37,20 @@ pub fn new_frontier() -> Spec {
|
||||
Spec::load(include_bytes!("../../res/ethereum/frontier.json"))
|
||||
}
|
||||
|
||||
/// Create a new Frontier mainnet chain spec without the DAO hardfork.
|
||||
pub fn new_frontier_dogmatic() -> Spec {
|
||||
Spec::load(include_bytes!("../../res/ethereum/frontier-dogmatic.json"))
|
||||
}
|
||||
|
||||
/// Create a new Frontier chain spec as though it never changes to Homestead.
|
||||
pub fn new_frontier_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/frontier_test.json")) }
|
||||
|
||||
/// Create a new Homestead chain spec as though it never changed from Frontier.
|
||||
pub fn new_homestead_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/homestead_test.json")) }
|
||||
|
||||
/// Create a new Frontier/Homestead/DAO chain spec with transition points at #5 and #8.
|
||||
pub fn new_daohardfork_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/daohardfork_test.json")) }
|
||||
|
||||
/// Create a new Frontier main net chain spec without genesis accounts.
|
||||
pub fn new_mainnet_like() -> Spec { Spec::load(include_bytes!("../../res/ethereum/frontier_like_test.json")) }
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
|
||||
let mut spec = match era {
|
||||
ChainEra::Frontier => ethereum::new_frontier_test(),
|
||||
ChainEra::Homestead => ethereum::new_homestead_test(),
|
||||
ChainEra::DaoHardfork => ethereum::new_daohardfork_test(),
|
||||
};
|
||||
spec.set_genesis_state(state);
|
||||
spec.overwrite_genesis_params(genesis);
|
||||
@@ -84,26 +85,43 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
|
||||
failed
|
||||
}
|
||||
|
||||
fn do_json_test(json_data: &[u8]) -> Vec<String> {
|
||||
json_chain_test(json_data, ChainEra::Frontier)
|
||||
mod frontier_era_tests {
|
||||
use tests::helpers::*;
|
||||
use super::json_chain_test;
|
||||
|
||||
fn do_json_test(json_data: &[u8]) -> Vec<String> {
|
||||
json_chain_test(json_data, ChainEra::Frontier)
|
||||
}
|
||||
|
||||
declare_test!{BlockchainTests_bcBlockGasLimitTest, "BlockchainTests/bcBlockGasLimitTest"}
|
||||
declare_test!{BlockchainTests_bcForkBlockTest, "BlockchainTests/bcForkBlockTest"}
|
||||
declare_test!{BlockchainTests_bcForkStressTest, "BlockchainTests/bcForkStressTest"}
|
||||
declare_test!{BlockchainTests_bcForkUncle, "BlockchainTests/bcForkUncle"}
|
||||
declare_test!{BlockchainTests_bcGasPricerTest, "BlockchainTests/bcGasPricerTest"}
|
||||
declare_test!{BlockchainTests_bcInvalidHeaderTest, "BlockchainTests/bcInvalidHeaderTest"}
|
||||
// TODO [ToDr] Ignored because of incorrect JSON (https://github.com/ethereum/tests/pull/113)
|
||||
declare_test!{ignore => BlockchainTests_bcInvalidRLPTest, "BlockchainTests/bcInvalidRLPTest"}
|
||||
declare_test!{BlockchainTests_bcMultiChainTest, "BlockchainTests/bcMultiChainTest"}
|
||||
declare_test!{BlockchainTests_bcRPC_API_Test, "BlockchainTests/bcRPC_API_Test"}
|
||||
declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"}
|
||||
declare_test!{BlockchainTests_bcTotalDifficultyTest, "BlockchainTests/bcTotalDifficultyTest"}
|
||||
declare_test!{BlockchainTests_bcUncleHeaderValiditiy, "BlockchainTests/bcUncleHeaderValiditiy"}
|
||||
declare_test!{BlockchainTests_bcUncleTest, "BlockchainTests/bcUncleTest"}
|
||||
declare_test!{BlockchainTests_bcValidBlockTest, "BlockchainTests/bcValidBlockTest"}
|
||||
declare_test!{BlockchainTests_bcWalletTest, "BlockchainTests/bcWalletTest"}
|
||||
|
||||
declare_test!{BlockchainTests_RandomTests_bl10251623GO, "BlockchainTests/RandomTests/bl10251623GO"}
|
||||
declare_test!{BlockchainTests_RandomTests_bl201507071825GO, "BlockchainTests/RandomTests/bl201507071825GO"}
|
||||
}
|
||||
|
||||
declare_test!{BlockchainTests_bcBlockGasLimitTest, "BlockchainTests/bcBlockGasLimitTest"}
|
||||
declare_test!{BlockchainTests_bcForkBlockTest, "BlockchainTests/bcForkBlockTest"}
|
||||
declare_test!{BlockchainTests_bcForkStressTest, "BlockchainTests/bcForkStressTest"}
|
||||
declare_test!{BlockchainTests_bcForkUncle, "BlockchainTests/bcForkUncle"}
|
||||
declare_test!{BlockchainTests_bcGasPricerTest, "BlockchainTests/bcGasPricerTest"}
|
||||
declare_test!{BlockchainTests_bcInvalidHeaderTest, "BlockchainTests/bcInvalidHeaderTest"}
|
||||
// TODO [ToDr] Ignored because of incorrect JSON (https://github.com/ethereum/tests/pull/113)
|
||||
declare_test!{ignore => BlockchainTests_bcInvalidRLPTest, "BlockchainTests/bcInvalidRLPTest"}
|
||||
declare_test!{BlockchainTests_bcMultiChainTest, "BlockchainTests/bcMultiChainTest"}
|
||||
declare_test!{BlockchainTests_bcRPC_API_Test, "BlockchainTests/bcRPC_API_Test"}
|
||||
declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"}
|
||||
declare_test!{BlockchainTests_bcTotalDifficultyTest, "BlockchainTests/bcTotalDifficultyTest"}
|
||||
declare_test!{BlockchainTests_bcUncleHeaderValiditiy, "BlockchainTests/bcUncleHeaderValiditiy"}
|
||||
declare_test!{BlockchainTests_bcUncleTest, "BlockchainTests/bcUncleTest"}
|
||||
declare_test!{BlockchainTests_bcValidBlockTest, "BlockchainTests/bcValidBlockTest"}
|
||||
declare_test!{BlockchainTests_bcWalletTest, "BlockchainTests/bcWalletTest"}
|
||||
mod daohardfork_tests {
|
||||
use tests::helpers::*;
|
||||
use super::json_chain_test;
|
||||
|
||||
declare_test!{BlockchainTests_RandomTests_bl10251623GO, "BlockchainTests/RandomTests/bl10251623GO"}
|
||||
declare_test!{BlockchainTests_RandomTests_bl201507071825GO, "BlockchainTests/RandomTests/bl201507071825GO"}
|
||||
fn do_json_test(json_data: &[u8]) -> Vec<String> {
|
||||
json_chain_test(json_data, ChainEra::DaoHardfork)
|
||||
}
|
||||
|
||||
declare_test!{BlockchainTests_TestNetwork_bcSimpleTransitionTest, "BlockchainTests/TestNetwork/bcSimpleTransitionTest"}
|
||||
declare_test!{BlockchainTests_TestNetwork_bcTheDaoTest, "BlockchainTests/TestNetwork/bcTheDaoTest"}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,9 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
|
||||
let mut failed = Vec::new();
|
||||
let engine = match era {
|
||||
ChainEra::Frontier => ethereum::new_mainnet_like().engine,
|
||||
ChainEra::Homestead => ethereum::new_homestead_test().engine
|
||||
};
|
||||
ChainEra::Homestead => ethereum::new_homestead_test().engine,
|
||||
ChainEra::DaoHardfork => ethereum::new_daohardfork_test().engine,
|
||||
};
|
||||
|
||||
for (name, test) in tests.into_iter() {
|
||||
let mut fail = false;
|
||||
|
||||
@@ -30,6 +30,7 @@ use miner::Miner;
|
||||
pub enum ChainEra {
|
||||
Frontier,
|
||||
Homestead,
|
||||
DaoHardfork,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user