EIPs 155, 160, 161 (#2976)
* The front-end for each hard-fork, also EIP-160. * Address EIP161 a/c * Include EIP-161b * EIP-161 part d. * Fix test build. * Fix one test, add another. * Fix use of bloom & renaming. * Initial groundwork for EIP-155 * Fix minor bug. * Fix all tests finally. * Rest of EIP-155. * Add tests for EIP-155 algorithm. Update transaction tests validation. * Minor reformat. * Address grumbles. * Remove unused code. * Fix SUICIDE gas mechanism and add consensus tests. * Remove commented code. * Set Frontier hardfork block number * Fix warning. * Transaction tests,
This commit is contained in:
parent
7e592e5389
commit
d3de475205
2
.gitignore
vendored
2
.gitignore
vendored
@ -30,3 +30,5 @@
|
||||
|
||||
# Build artifacts
|
||||
out/
|
||||
|
||||
.vscode
|
||||
|
@ -11,7 +11,11 @@
|
||||
"blockReward": "0x4563918244F40000",
|
||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||
"homesteadTransition": "0x118c30",
|
||||
"eip150Transition": "0x2625a0"
|
||||
"eip150Transition": "0x2625a0",
|
||||
"eip155Transition": "0x7fffffffffffffff",
|
||||
"eip160Transition": "0x7fffffffffffffff",
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -10,7 +10,11 @@
|
||||
"blockReward": "0x4563918244F40000",
|
||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||
"homesteadTransition": "0x0",
|
||||
"eip150Transition": "0x0"
|
||||
"eip150Transition": "0x0",
|
||||
"eip155Transition": "0x7fffffffffffffff",
|
||||
"eip160Transition": "0x7fffffffffffffff",
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
47
ethcore/res/ethereum/eip161_test.json
Normal file
47
ethcore/res/ethereum/eip161_test.json
Normal file
@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "Homestead (Test)",
|
||||
"engine": {
|
||||
"Ethash": {
|
||||
"params": {
|
||||
"gasLimitBoundDivisor": "0x0400",
|
||||
"minimumDifficulty": "0x020000",
|
||||
"difficultyBoundDivisor": "0x0800",
|
||||
"durationLimit": "0x0d",
|
||||
"blockReward": "0x4563918244F40000",
|
||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||
"homesteadTransition": "0x0",
|
||||
"eip150Transition": "0x0",
|
||||
"eip155Transition": "0x7fffffffffffffff",
|
||||
"eip160Transition": "0x0",
|
||||
"eip161abcTransition": "0x0",
|
||||
"eip161dTransition": "0x0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"params": {
|
||||
"accountStartNonce": "0x00",
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID" : "0x1"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
"ethereum": {
|
||||
"nonce": "0x0000000000000042",
|
||||
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
},
|
||||
"difficulty": "0x400000000",
|
||||
"author": "0x0000000000000000000000000000000000000000",
|
||||
"timestamp": "0x00",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
|
||||
"gasLimit": "0x1388"
|
||||
},
|
||||
"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 } } } }
|
||||
}
|
||||
}
|
@ -15,7 +15,11 @@
|
||||
"difficultyHardforkTransition": "0x59d9",
|
||||
"difficultyHardforkBoundDivisor": "0x0200",
|
||||
"bombDefuseTransition": "0x30d40",
|
||||
"eip150Transition": "0x7fffffffffffffff"
|
||||
"eip150Transition": "0x7fffffffffffffff",
|
||||
"eip155Transition": "0x7fffffffffffffff",
|
||||
"eip160Transition": "0x7fffffffffffffff",
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -130,7 +130,11 @@
|
||||
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
|
||||
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
|
||||
],
|
||||
"eip150Transition": "0x259518"
|
||||
"eip150Transition": "0x259518",
|
||||
"eip155Transition": 2642462,
|
||||
"eip160Transition": 2642462,
|
||||
"eip161abcTransition": 2642462,
|
||||
"eip161dTransition": 2642462
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -130,7 +130,11 @@
|
||||
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
|
||||
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
|
||||
],
|
||||
"eip150Transition": "0x7fffffffffffffff"
|
||||
"eip150Transition": "0x7fffffffffffffff",
|
||||
"eip155Transition": "0x7fffffffffffffff",
|
||||
"eip160Transition": "0x7fffffffffffffff",
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -10,7 +10,11 @@
|
||||
"blockReward": "0x4563918244F40000",
|
||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||
"homesteadTransition": "0x7fffffffffffffff",
|
||||
"eip150Transition": "0x7fffffffffffffff"
|
||||
"eip150Transition": "0x7fffffffffffffff",
|
||||
"eip155Transition": "0x7fffffffffffffff",
|
||||
"eip160Transition": "0x7fffffffffffffff",
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -10,7 +10,11 @@
|
||||
"blockReward": "0x4563918244F40000",
|
||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||
"homesteadTransition": "0x0",
|
||||
"eip150Transition": "0x7fffffffffffffff"
|
||||
"eip150Transition": "0x7fffffffffffffff",
|
||||
"eip155Transition": "0x7fffffffffffffff",
|
||||
"eip160Transition": "0x7fffffffffffffff",
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -10,7 +10,11 @@
|
||||
"blockReward": "0x4563918244F40000",
|
||||
"registrar": "0x52dff57a8a1532e6afb3dc07e2af58bb9eb05b3d",
|
||||
"homesteadTransition": "0x789b0",
|
||||
"eip150Transition": "0x1b34d8"
|
||||
"eip150Transition": "0x1b34d8",
|
||||
"eip155Transition": "0x7fffffffffffffff",
|
||||
"eip160Transition": "0x7fffffffffffffff",
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -10,7 +10,11 @@
|
||||
"blockReward": "0x14D1120D7B160000",
|
||||
"registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050",
|
||||
"homesteadTransition": "0x7fffffffffffffff",
|
||||
"eip150Transition": "0x7fffffffffffffff"
|
||||
"eip150Transition": "0x7fffffffffffffff",
|
||||
"eip155Transition": "0x7fffffffffffffff",
|
||||
"eip160Transition": "0x7fffffffffffffff",
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 97066e40ccd061f727deb5cd860e4d9135aa2551
|
||||
Subproject commit 853333e7da312775fb8f32f2c2771b8578cd0d79
|
@ -130,7 +130,11 @@
|
||||
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
|
||||
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
|
||||
],
|
||||
"eip150Transition": "0xa"
|
||||
"eip150Transition": "0xa",
|
||||
"eip155Transition": "0x7fffffffffffffff",
|
||||
"eip160Transition": "0x7fffffffffffffff",
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1468,7 +1468,7 @@ mod tests {
|
||||
action: Action::Create,
|
||||
value: 100.into(),
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
|
||||
let b1a = canon_chain
|
||||
@ -1532,7 +1532,7 @@ mod tests {
|
||||
action: Action::Create,
|
||||
value: 100.into(),
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
let t2 = Transaction {
|
||||
nonce: 1.into(),
|
||||
@ -1541,7 +1541,7 @@ mod tests {
|
||||
action: Action::Create,
|
||||
value: 100.into(),
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
let t3 = Transaction {
|
||||
nonce: 2.into(),
|
||||
@ -1550,7 +1550,7 @@ mod tests {
|
||||
action: Action::Create,
|
||||
value: 100.into(),
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
let b1a = canon_chain
|
||||
.with_transaction(t1.clone())
|
||||
@ -1856,7 +1856,7 @@ mod tests {
|
||||
action: Action::Create,
|
||||
value: 101.into(),
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
let t2 = Transaction {
|
||||
nonce: 0.into(),
|
||||
gas_price: 0.into(),
|
||||
@ -1864,7 +1864,7 @@ mod tests {
|
||||
action: Action::Create,
|
||||
value: 102.into(),
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
let t3 = Transaction {
|
||||
nonce: 0.into(),
|
||||
gas_price: 0.into(),
|
||||
@ -1872,7 +1872,7 @@ mod tests {
|
||||
action: Action::Create,
|
||||
value: 103.into(),
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
let tx_hash1 = t1.hash();
|
||||
let tx_hash2 = t2.hash();
|
||||
let tx_hash3 = t3.hash();
|
||||
|
@ -33,7 +33,7 @@ use io::*;
|
||||
use views::{HeaderView, BodyView, BlockView};
|
||||
use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError};
|
||||
use header::BlockNumber;
|
||||
use state::State;
|
||||
use state::{State, CleanupMode};
|
||||
use spec::Spec;
|
||||
use basic_types::Seal;
|
||||
use engines::Engine;
|
||||
@ -268,6 +268,22 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
/// The env info as of the best block.
|
||||
fn latest_env_info(&self) -> EnvInfo {
|
||||
let header_data = self.best_block_header();
|
||||
let view = HeaderView::new(&header_data);
|
||||
|
||||
EnvInfo {
|
||||
number: view.number(),
|
||||
author: view.author(),
|
||||
timestamp: view.timestamp(),
|
||||
difficulty: view.difficulty(),
|
||||
last_hashes: self.build_last_hashes(view.hash()),
|
||||
gas_used: U256::default(),
|
||||
gas_limit: view.gas_limit(),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_last_hashes(&self, parent_hash: H256) -> Arc<LastHashes> {
|
||||
{
|
||||
let hashes = self.last_hashes.read();
|
||||
@ -790,7 +806,7 @@ impl BlockChainClient for Client {
|
||||
let needed_balance = t.value + t.gas * t.gas_price;
|
||||
if balance < needed_balance {
|
||||
// give the sender a sufficient balance
|
||||
state.add_balance(&sender, &(needed_balance - balance));
|
||||
state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty);
|
||||
}
|
||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
||||
let mut ret = try!(Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(t, options));
|
||||
@ -1167,24 +1183,16 @@ impl BlockChainClient for Client {
|
||||
fn pending_transactions(&self) -> Vec<SignedTransaction> {
|
||||
self.miner.pending_transactions(self.chain.read().best_block_number())
|
||||
}
|
||||
|
||||
fn signing_network_id(&self) -> Option<u8> {
|
||||
self.engine.signing_network_id(&self.latest_env_info())
|
||||
}
|
||||
}
|
||||
|
||||
impl MiningBlockChainClient for Client {
|
||||
|
||||
fn latest_schedule(&self) -> Schedule {
|
||||
let header_data = self.best_block_header();
|
||||
let view = HeaderView::new(&header_data);
|
||||
|
||||
let env_info = EnvInfo {
|
||||
number: view.number(),
|
||||
author: view.author(),
|
||||
timestamp: view.timestamp(),
|
||||
difficulty: view.difficulty(),
|
||||
last_hashes: self.build_last_hashes(view.hash()),
|
||||
gas_used: U256::default(),
|
||||
gas_limit: view.gas_limit(),
|
||||
};
|
||||
self.engine.schedule(&env_info)
|
||||
self.engine.schedule(&self.latest_env_info())
|
||||
}
|
||||
|
||||
fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock {
|
||||
|
@ -227,7 +227,7 @@ impl TestBlockChainClient {
|
||||
gas_price: U256::one(),
|
||||
nonce: U256::zero()
|
||||
};
|
||||
let signed_tx = tx.sign(keypair.secret());
|
||||
let signed_tx = tx.sign(keypair.secret(), None);
|
||||
txs.append(&signed_tx);
|
||||
txs.out()
|
||||
},
|
||||
@ -293,7 +293,7 @@ impl TestBlockChainClient {
|
||||
gas_price: U256::one(),
|
||||
nonce: U256::zero()
|
||||
};
|
||||
let signed_tx = tx.sign(keypair.secret());
|
||||
let signed_tx = tx.sign(keypair.secret(), None);
|
||||
self.set_balance(signed_tx.sender().unwrap(), 10_000_000.into());
|
||||
let res = self.miner.import_external_transactions(self, vec![signed_tx]);
|
||||
let res = res.into_iter().next().unwrap().expect("Successful import");
|
||||
@ -314,7 +314,7 @@ pub fn get_temp_state_db() -> GuardedTempResult<StateDB> {
|
||||
|
||||
impl MiningBlockChainClient for TestBlockChainClient {
|
||||
fn latest_schedule(&self) -> Schedule {
|
||||
Schedule::new_homestead_gas_fix()
|
||||
Schedule::new_post_eip150(true, true, true)
|
||||
}
|
||||
|
||||
fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock {
|
||||
@ -633,6 +633,8 @@ impl BlockChainClient for TestBlockChainClient {
|
||||
self.miner.pending_transactions(self.chain_info().best_block_number)
|
||||
}
|
||||
|
||||
fn signing_network_id(&self) -> Option<u8> { None }
|
||||
|
||||
fn mode(&self) -> Mode { Mode::Active }
|
||||
|
||||
fn set_mode(&self, _: Mode) { unimplemented!(); }
|
||||
|
@ -227,8 +227,13 @@ pub trait BlockChainClient : Sync + Send {
|
||||
Histogram::new(corpus, bucket_number)
|
||||
}
|
||||
|
||||
/// Get the preferred network ID to sign on
|
||||
fn signing_network_id(&self) -> Option<u8>;
|
||||
|
||||
/// Get the mode.
|
||||
fn mode(&self) -> Mode;
|
||||
|
||||
/// Set the mode.
|
||||
fn set_mode(&self, mode: Mode);
|
||||
}
|
||||
|
||||
|
@ -108,6 +108,9 @@ pub trait Engine : Sync + Send {
|
||||
/// Verify a particular transaction is valid.
|
||||
fn verify_transaction(&self, _t: &SignedTransaction, _header: &Header) -> Result<(), Error> { Ok(()) }
|
||||
|
||||
/// The network ID that transactions should be signed with.
|
||||
fn signing_network_id(&self, _env_info: &EnvInfo) -> Option<u8> { None }
|
||||
|
||||
/// Verify the seal of a block. This is an auxilliary method that actually just calls other `verify_` methods
|
||||
/// to get the job done. By default it must pass `verify_basic` and `verify_block_unordered`. If more or fewer
|
||||
/// methods are needed for an Engine, this may be overridden.
|
||||
|
@ -76,6 +76,8 @@ pub enum TransactionError {
|
||||
RecipientBanned,
|
||||
/// Contract creation code is banned.
|
||||
CodeBanned,
|
||||
/// Invalid network ID given.
|
||||
InvalidNetworkId,
|
||||
}
|
||||
|
||||
impl fmt::Display for TransactionError {
|
||||
@ -99,6 +101,7 @@ impl fmt::Display for TransactionError {
|
||||
SenderBanned => "Sender is temporarily banned.".into(),
|
||||
RecipientBanned => "Recipient is temporarily banned.".into(),
|
||||
CodeBanned => "Contract code is temporarily banned.".into(),
|
||||
InvalidNetworkId => "Transaction of this network ID is not allowed on this chain.".into(),
|
||||
};
|
||||
|
||||
f.write_fmt(format_args!("Transaction error ({})", msg))
|
||||
|
@ -19,8 +19,9 @@ use util::*;
|
||||
use block::*;
|
||||
use builtin::Builtin;
|
||||
use env_info::EnvInfo;
|
||||
use error::{BlockError, Error};
|
||||
use error::{BlockError, TransactionError, Error};
|
||||
use header::Header;
|
||||
use state::CleanupMode;
|
||||
use spec::CommonParams;
|
||||
use transaction::SignedTransaction;
|
||||
use engines::Engine;
|
||||
@ -59,8 +60,16 @@ pub struct EthashParams {
|
||||
pub difficulty_hardfork_bound_divisor: U256,
|
||||
/// Block on which there is no additional difficulty from the exponential bomb.
|
||||
pub bomb_defuse_transition: u64,
|
||||
/// Bad gas transition block number.
|
||||
/// Number of first block where EIP-150 rules begin.
|
||||
pub eip150_transition: u64,
|
||||
/// Number of first block where EIP-155 rules begin.
|
||||
pub eip155_transition: u64,
|
||||
/// Number of first block where EIP-160 rules begin.
|
||||
pub eip160_transition: u64,
|
||||
/// Number of first block where EIP-161.abc begin.
|
||||
pub eip161abc_transition: u64,
|
||||
/// Number of first block where EIP-161.d begins.
|
||||
pub eip161d_transition: u64,
|
||||
}
|
||||
|
||||
impl From<ethjson::spec::EthashParams> for EthashParams {
|
||||
@ -81,6 +90,10 @@ impl From<ethjson::spec::EthashParams> for EthashParams {
|
||||
difficulty_hardfork_bound_divisor: p.difficulty_hardfork_bound_divisor.map_or(p.difficulty_bound_divisor.into(), Into::into),
|
||||
bomb_defuse_transition: p.bomb_defuse_transition.map_or(0x7fffffffffffffff, Into::into),
|
||||
eip150_transition: p.eip150_transition.map_or(0, Into::into),
|
||||
eip155_transition: p.eip155_transition.map_or(0, Into::into),
|
||||
eip160_transition: p.eip160_transition.map_or(0, Into::into),
|
||||
eip161abc_transition: p.eip161abc_transition.map_or(0, Into::into),
|
||||
eip161d_transition: p.eip161d_transition.map_or(0x7fffffffffffffff, Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -132,7 +145,19 @@ impl Engine for Ethash {
|
||||
} else if env_info.number < self.ethash_params.eip150_transition {
|
||||
Schedule::new_homestead()
|
||||
} else {
|
||||
Schedule::new_homestead_gas_fix()
|
||||
Schedule::new_post_eip150(
|
||||
env_info.number >= self.ethash_params.eip160_transition,
|
||||
env_info.number >= self.ethash_params.eip161abc_transition,
|
||||
env_info.number >= self.ethash_params.eip161d_transition
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn signing_network_id(&self, env_info: &EnvInfo) -> Option<u8> {
|
||||
if env_info.number >= self.ethash_params.eip155_transition && self.params().network_id < 127 {
|
||||
Some(self.params().network_id as u8)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,7 +194,7 @@ impl Engine for Ethash {
|
||||
let mut state = block.fields_mut().state;
|
||||
for child in &self.ethash_params.dao_hardfork_accounts {
|
||||
let b = state.balance(child);
|
||||
state.transfer_balance(child, &self.ethash_params.dao_hardfork_beneficiary, &b);
|
||||
state.transfer_balance(child, &self.ethash_params.dao_hardfork_beneficiary, &b, CleanupMode::NoEmpty);
|
||||
}
|
||||
// }
|
||||
}
|
||||
@ -182,12 +207,12 @@ impl Engine for Ethash {
|
||||
let fields = block.fields_mut();
|
||||
|
||||
// Bestow block reward
|
||||
fields.state.add_balance(fields.header.author(), &(reward + reward / U256::from(32) * U256::from(fields.uncles.len())));
|
||||
fields.state.add_balance(fields.header.author(), &(reward + reward / U256::from(32) * U256::from(fields.uncles.len())), CleanupMode::NoEmpty);
|
||||
|
||||
// Bestow uncle rewards
|
||||
let current_number = fields.header.number();
|
||||
for u in fields.uncles.iter() {
|
||||
fields.state.add_balance(u.author(), &(reward * U256::from(8 + u.number() - current_number) / U256::from(8)));
|
||||
fields.state.add_balance(u.author(), &(reward * U256::from(8 + u.number() - current_number) / U256::from(8)), CleanupMode::NoEmpty);
|
||||
}
|
||||
|
||||
// Commit state so that we can actually figure out the state root.
|
||||
@ -277,6 +302,13 @@ impl Engine for Ethash {
|
||||
if header.number() >= self.ethash_params.homestead_transition {
|
||||
try!(t.check_low_s());
|
||||
}
|
||||
|
||||
if let Some(n) = t.network_id() {
|
||||
if header.number() < self.ethash_params.eip155_transition || n as usize != self.params().network_id {
|
||||
return Err(TransactionError::InvalidNetworkId.into())
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,9 @@ pub fn new_homestead_test() -> Spec { load(include_bytes!("../../res/ethereum/ho
|
||||
/// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier.
|
||||
pub fn new_eip150_test() -> Spec { load(include_bytes!("../../res/ethereum/eip150_test.json")) }
|
||||
|
||||
/// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier.
|
||||
pub fn new_eip161_test() -> Spec { load(include_bytes!("../../res/ethereum/eip161_test.json")) }
|
||||
|
||||
/// Create a new Frontier/Homestead/DAO chain spec with transition points at #5 and #8.
|
||||
pub fn new_transition_test() -> Spec { load(include_bytes!("../../res/ethereum/transition_test.json")) }
|
||||
|
||||
|
@ -52,6 +52,12 @@ pub trait Ext {
|
||||
/// Determine whether an account exists.
|
||||
fn exists(&self, address: &Address) -> bool;
|
||||
|
||||
/// Determine whether an account exists and is not null (zero balance/nonce, no code).
|
||||
fn exists_and_not_null(&self, address: &Address) -> bool;
|
||||
|
||||
/// Balance of the origin account.
|
||||
fn origin_balance(&self) -> U256;
|
||||
|
||||
/// Returns address balance.
|
||||
fn balance(&self, address: &Address) -> U256;
|
||||
|
||||
|
@ -146,8 +146,13 @@ impl<Gas: CostType> Gasometer<Gas> {
|
||||
instructions::SUICIDE => {
|
||||
let mut gas = Gas::from(schedule.suicide_gas);
|
||||
|
||||
let is_value_transfer = !ext.origin_balance().is_zero();
|
||||
let address = u256_to_address(stack.peek(0));
|
||||
if !ext.exists(&address) {
|
||||
if (
|
||||
!schedule.no_empty && !ext.exists(&address)
|
||||
) || (
|
||||
schedule.no_empty && is_value_transfer && !ext.exists_and_not_null(&address)
|
||||
) {
|
||||
gas = overflowing!(gas.overflow_add(schedule.suicide_to_new_account_cost.into()));
|
||||
}
|
||||
|
||||
@ -190,12 +195,19 @@ impl<Gas: CostType> Gasometer<Gas> {
|
||||
);
|
||||
|
||||
let address = u256_to_address(stack.peek(1));
|
||||
let is_value_transfer = !stack.peek(2).is_zero();
|
||||
|
||||
if instruction == instructions::CALL && !ext.exists(&address) {
|
||||
if instruction == instructions::CALL {
|
||||
if (
|
||||
!schedule.no_empty && !ext.exists(&address)
|
||||
) || (
|
||||
schedule.no_empty && is_value_transfer && !ext.exists_and_not_null(&address)
|
||||
) {
|
||||
gas = overflowing!(gas.overflow_add(schedule.call_new_account_gas.into()));
|
||||
}
|
||||
};
|
||||
|
||||
if !stack.peek(2).is_zero() {
|
||||
if is_value_transfer {
|
||||
gas = overflowing!(gas.overflow_add(schedule.call_value_transfer_gas.into()));
|
||||
};
|
||||
|
||||
|
@ -93,6 +93,10 @@ pub struct Schedule {
|
||||
/// If Some(x): let limit = GAS * (x - 1) / x; let CALL's gas = min(requested, limit). let CREATE's gas = limit.
|
||||
/// If None: let CALL's gas = (requested > GAS ? [OOG] : GAS). let CREATE's gas = GAS
|
||||
pub sub_gas_cap_divisor: Option<usize>,
|
||||
/// Don't ever make empty accounts; contracts start with nonce=1. Also, don't charge 25k when sending/suicide zero-value.
|
||||
pub no_empty: bool,
|
||||
/// Kill empty accounts if touched.
|
||||
pub kill_empty: bool,
|
||||
}
|
||||
|
||||
impl Schedule {
|
||||
@ -106,8 +110,8 @@ impl Schedule {
|
||||
Self::new(true, true, 53000)
|
||||
}
|
||||
|
||||
/// Schedule for the Homestead-era of the Ethereum main net.
|
||||
pub fn new_homestead_gas_fix() -> Schedule {
|
||||
/// Schedule for the post-EIP-150-era of the Ethereum main net.
|
||||
pub fn new_post_eip150(fix_exp: bool, no_empty: bool, kill_empty: bool) -> Schedule {
|
||||
Schedule {
|
||||
exceptional_failed_code_deposit: true,
|
||||
have_delegate_call: true,
|
||||
@ -115,7 +119,7 @@ impl Schedule {
|
||||
max_depth: 1024,
|
||||
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
|
||||
exp_gas: 10,
|
||||
exp_byte_gas: 10,
|
||||
exp_byte_gas: if fix_exp {50} else {10},
|
||||
sha3_gas: 30,
|
||||
sha3_word_gas: 6,
|
||||
sload_gas: 200,
|
||||
@ -146,6 +150,8 @@ impl Schedule {
|
||||
suicide_gas: 5000,
|
||||
suicide_to_new_account_cost: 25000,
|
||||
sub_gas_cap_divisor: Some(64),
|
||||
no_empty: no_empty,
|
||||
kill_empty: kill_empty,
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,6 +194,8 @@ impl Schedule {
|
||||
suicide_gas: 0,
|
||||
suicide_to_new_account_cost: 0,
|
||||
sub_gas_cap_divisor: None,
|
||||
no_empty: false,
|
||||
kill_empty: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,6 +94,14 @@ impl Ext for FakeExt {
|
||||
self.balances.contains_key(address)
|
||||
}
|
||||
|
||||
fn exists_and_not_null(&self, address: &Address) -> bool {
|
||||
self.balances.get(address).map_or(false, |b| !b.is_zero())
|
||||
}
|
||||
|
||||
fn origin_balance(&self) -> U256 {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn balance(&self, address: &Address) -> U256 {
|
||||
*self.balances.get(address).unwrap()
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
//! Transaction Execution environment.
|
||||
use util::*;
|
||||
use action_params::{ActionParams, ActionValue};
|
||||
use state::{State, Substate};
|
||||
use state::{State, Substate, CleanupMode};
|
||||
use engines::Engine;
|
||||
use types::executed::CallType;
|
||||
use env_info::EnvInfo;
|
||||
@ -256,9 +256,11 @@ impl<'a> Executive<'a> {
|
||||
// backup used in case of running out of gas
|
||||
self.state.checkpoint();
|
||||
|
||||
let schedule = self.engine.schedule(self.info);
|
||||
|
||||
// at first, transfer value to destination
|
||||
if let ActionValue::Transfer(val) = params.value {
|
||||
self.state.transfer_balance(¶ms.sender, ¶ms.address, &val);
|
||||
self.state.transfer_balance(¶ms.sender, ¶ms.address, &val, substate.to_cleanup_mode(&schedule));
|
||||
}
|
||||
trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);
|
||||
|
||||
@ -364,12 +366,14 @@ impl<'a> Executive<'a> {
|
||||
let mut unconfirmed_substate = Substate::new();
|
||||
|
||||
// create contract and transfer value to it if necessary
|
||||
let schedule = self.engine.schedule(self.info);
|
||||
let nonce_offset = if schedule.no_empty {1} else {0}.into();
|
||||
let prev_bal = self.state.balance(¶ms.address);
|
||||
if let ActionValue::Transfer(val) = params.value {
|
||||
self.state.sub_balance(¶ms.sender, &val);
|
||||
self.state.new_contract(¶ms.address, val + prev_bal);
|
||||
self.state.new_contract(¶ms.address, val + prev_bal, nonce_offset);
|
||||
} else {
|
||||
self.state.new_contract(¶ms.address, prev_bal);
|
||||
self.state.new_contract(¶ms.address, prev_bal, nonce_offset);
|
||||
}
|
||||
|
||||
let trace_info = tracer.prepare_trace_create(¶ms);
|
||||
@ -405,7 +409,7 @@ impl<'a> Executive<'a> {
|
||||
fn finalize(
|
||||
&mut self,
|
||||
t: &SignedTransaction,
|
||||
substate: Substate,
|
||||
mut substate: Substate,
|
||||
result: evm::Result<U256>,
|
||||
output: Bytes,
|
||||
trace: Vec<FlatTrace>,
|
||||
@ -440,15 +444,23 @@ impl<'a> Executive<'a> {
|
||||
};
|
||||
|
||||
trace!("exec::finalize: Refunding refund_value={}, sender={}\n", refund_value, sender);
|
||||
self.state.add_balance(&sender, &refund_value);
|
||||
// Below: NoEmpty is safe since the sender must already be non-null to have sent this transaction
|
||||
self.state.add_balance(&sender, &refund_value, CleanupMode::NoEmpty);
|
||||
trace!("exec::finalize: Compensating author: fees_value={}, author={}\n", fees_value, &self.info.author);
|
||||
self.state.add_balance(&self.info.author, &fees_value);
|
||||
self.state.add_balance(&self.info.author, &fees_value, substate.to_cleanup_mode(&schedule));
|
||||
|
||||
// perform suicides
|
||||
for address in &substate.suicides {
|
||||
self.state.kill_account(address);
|
||||
}
|
||||
|
||||
// perform garbage-collection
|
||||
for address in &substate.garbage {
|
||||
if self.state.exists(address) && !self.state.exists_and_not_null(address) {
|
||||
self.state.kill_account(address);
|
||||
}
|
||||
}
|
||||
|
||||
match result {
|
||||
Err(evm::Error::Internal) => Err(ExecutionError::Internal),
|
||||
Err(_) => {
|
||||
@ -509,7 +521,7 @@ mod tests {
|
||||
use env_info::EnvInfo;
|
||||
use evm::{Factory, VMType};
|
||||
use error::ExecutionError;
|
||||
use state::Substate;
|
||||
use state::{Substate, CleanupMode};
|
||||
use tests::helpers::*;
|
||||
use trace::trace;
|
||||
use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer};
|
||||
@ -538,7 +550,7 @@ mod tests {
|
||||
params.value = ActionValue::Transfer(U256::from(0x7));
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
state.add_balance(&sender, &U256::from(0x100u64));
|
||||
state.add_balance(&sender, &U256::from(0x100u64), CleanupMode::NoEmpty);
|
||||
let info = EnvInfo::default();
|
||||
let engine = TestEngine::new(0);
|
||||
let mut substate = Substate::new();
|
||||
@ -597,7 +609,7 @@ mod tests {
|
||||
params.value = ActionValue::Transfer(U256::from(100));
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
state.add_balance(&sender, &U256::from(100));
|
||||
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
|
||||
let info = EnvInfo::default();
|
||||
let engine = TestEngine::new(0);
|
||||
let mut substate = Substate::new();
|
||||
@ -656,7 +668,7 @@ mod tests {
|
||||
params.call_type = CallType::Call;
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
state.add_balance(&sender, &U256::from(100));
|
||||
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
|
||||
let info = EnvInfo::default();
|
||||
let engine = TestEngine::new(5);
|
||||
let mut substate = Substate::new();
|
||||
@ -767,7 +779,7 @@ mod tests {
|
||||
params.value = ActionValue::Transfer(100.into());
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
state.add_balance(&sender, &U256::from(100));
|
||||
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
|
||||
let info = EnvInfo::default();
|
||||
let engine = TestEngine::new(5);
|
||||
let mut substate = Substate::new();
|
||||
@ -855,7 +867,7 @@ mod tests {
|
||||
params.value = ActionValue::Transfer(U256::from(100));
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
state.add_balance(&sender, &U256::from(100));
|
||||
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
|
||||
let info = EnvInfo::default();
|
||||
let engine = TestEngine::new(0);
|
||||
let mut substate = Substate::new();
|
||||
@ -907,7 +919,7 @@ mod tests {
|
||||
params.value = ActionValue::Transfer(U256::from(100));
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
state.add_balance(&sender, &U256::from(100));
|
||||
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
|
||||
let info = EnvInfo::default();
|
||||
let engine = TestEngine::new(1024);
|
||||
let mut substate = Substate::new();
|
||||
@ -967,7 +979,7 @@ mod tests {
|
||||
let mut state = state_result.reference_mut();
|
||||
state.init_code(&address_a, code_a.clone());
|
||||
state.init_code(&address_b, code_b.clone());
|
||||
state.add_balance(&sender, &U256::from(100_000));
|
||||
state.add_balance(&sender, &U256::from(100_000), CleanupMode::NoEmpty);
|
||||
|
||||
let info = EnvInfo::default();
|
||||
let engine = TestEngine::new(0);
|
||||
@ -1040,13 +1052,13 @@ mod tests {
|
||||
gas: U256::from(100_000),
|
||||
gas_price: U256::zero(),
|
||||
nonce: U256::zero()
|
||||
}.sign(keypair.secret());
|
||||
}.sign(keypair.secret(), None);
|
||||
let sender = t.sender().unwrap();
|
||||
let contract = contract_address(&sender, &U256::zero());
|
||||
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
state.add_balance(&sender, &U256::from(18));
|
||||
state.add_balance(&sender, &U256::from(18), CleanupMode::NoEmpty);
|
||||
let mut info = EnvInfo::default();
|
||||
info.gas_limit = U256::from(100_000);
|
||||
let engine = TestEngine::new(0);
|
||||
@ -1107,12 +1119,12 @@ mod tests {
|
||||
gas: U256::from(100_000),
|
||||
gas_price: U256::zero(),
|
||||
nonce: U256::one()
|
||||
}.sign(keypair.secret());
|
||||
}.sign(keypair.secret(), None);
|
||||
let sender = t.sender().unwrap();
|
||||
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
state.add_balance(&sender, &U256::from(17));
|
||||
state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty);
|
||||
let mut info = EnvInfo::default();
|
||||
info.gas_limit = U256::from(100_000);
|
||||
let engine = TestEngine::new(0);
|
||||
@ -1140,12 +1152,12 @@ mod tests {
|
||||
gas: U256::from(80_001),
|
||||
gas_price: U256::zero(),
|
||||
nonce: U256::zero()
|
||||
}.sign(keypair.secret());
|
||||
}.sign(keypair.secret(), None);
|
||||
let sender = t.sender().unwrap();
|
||||
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
state.add_balance(&sender, &U256::from(17));
|
||||
state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty);
|
||||
let mut info = EnvInfo::default();
|
||||
info.gas_used = U256::from(20_000);
|
||||
info.gas_limit = U256::from(100_000);
|
||||
@ -1175,12 +1187,12 @@ mod tests {
|
||||
gas: U256::from(100_000),
|
||||
gas_price: U256::one(),
|
||||
nonce: U256::zero()
|
||||
}.sign(keypair.secret());
|
||||
}.sign(keypair.secret(), None);
|
||||
let sender = t.sender().unwrap();
|
||||
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
state.add_balance(&sender, &U256::from(100_017));
|
||||
state.add_balance(&sender, &U256::from(100_017), CleanupMode::NoEmpty);
|
||||
let mut info = EnvInfo::default();
|
||||
info.gas_limit = U256::from(100_000);
|
||||
let engine = TestEngine::new(0);
|
||||
@ -1215,7 +1227,7 @@ mod tests {
|
||||
params.value = ActionValue::Transfer(U256::from_str("0de0b6b3a7640000").unwrap());
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap());
|
||||
state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap(), CleanupMode::NoEmpty);
|
||||
let info = EnvInfo::default();
|
||||
let engine = TestEngine::new(0);
|
||||
let mut substate = Substate::new();
|
||||
|
@ -114,6 +114,12 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
|
||||
self.state.exists(address)
|
||||
}
|
||||
|
||||
fn exists_and_not_null(&self, address: &Address) -> bool {
|
||||
self.state.exists_and_not_null(address)
|
||||
}
|
||||
|
||||
fn origin_balance(&self) -> U256 { self.balance(&self.origin_info.address) }
|
||||
|
||||
fn balance(&self, address: &Address) -> U256 {
|
||||
self.state.balance(address)
|
||||
}
|
||||
@ -269,11 +275,11 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
|
||||
let address = self.origin_info.address.clone();
|
||||
let balance = self.balance(&address);
|
||||
if &address == refund_address {
|
||||
// TODO [todr] To be consisted with CPP client we set balance to 0 in that case.
|
||||
// TODO [todr] To be consistent with CPP client we set balance to 0 in that case.
|
||||
self.state.sub_balance(&address, &balance);
|
||||
} else {
|
||||
trace!("Suiciding {} -> {} (xfer: {})", address, refund_address, balance);
|
||||
self.state.transfer_balance(&address, refund_address, &balance);
|
||||
trace!(target: "ext", "Suiciding {} -> {} (xfer: {})", address, refund_address, balance);
|
||||
self.state.transfer_balance(&address, refund_address, &balance, self.substate.to_cleanup_mode(&self.schedule));
|
||||
}
|
||||
|
||||
self.tracer.trace_suicide(address, balance, refund_address.clone());
|
||||
|
@ -49,6 +49,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
|
||||
ChainEra::Frontier => ethereum::new_frontier_test(),
|
||||
ChainEra::Homestead => ethereum::new_homestead_test(),
|
||||
ChainEra::Eip150 => ethereum::new_eip150_test(),
|
||||
ChainEra::Eip161 => ethereum::new_eip161_test(),
|
||||
ChainEra::TransitionTest => ethereum::new_transition_test(),
|
||||
};
|
||||
spec.set_genesis_state(state);
|
||||
|
51
ethcore/src/json_tests/eip161_state.rs
Normal file
51
ethcore/src/json_tests/eip161_state.rs
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use super::test_common::*;
|
||||
use tests::helpers::*;
|
||||
use super::state::json_chain_test;
|
||||
|
||||
fn do_json_test(json_data: &[u8]) -> Vec<String> {
|
||||
json_chain_test(json_data, ChainEra::Eip161)
|
||||
}
|
||||
|
||||
declare_test!{StateTests_EIP158_stEIP158SpecificTest, "StateTests/EIP158/stEIP158SpecificTest"}
|
||||
declare_test!{StateTests_EIP158_stNonZeroCallsTest, "StateTests/EIP158/stNonZeroCallsTest"}
|
||||
declare_test!{StateTests_EIP158_stZeroCallsTest, "StateTests/EIP158/stZeroCallsTest"}
|
||||
|
||||
declare_test!{StateTests_EIP158_EIP150_stMemExpandingEIPCalls, "StateTests/EIP158/EIP150/stMemExpandingEIPCalls"}
|
||||
declare_test!{StateTests_EIP158_EIP150_stEIPSpecificTest, "StateTests/EIP158/EIP150/stEIPSpecificTest"}
|
||||
declare_test!{StateTests_EIP158_EIP150_stEIPsingleCodeGasPrices, "StateTests/EIP158/EIP150/stEIPsingleCodeGasPrices"}
|
||||
declare_test!{StateTests_EIP158_EIP150_stChangedTests, "StateTests/EIP158/EIP150/stChangedTests"}
|
||||
|
||||
declare_test!{StateTests_EIP158_Homestead_stBoundsTest, "StateTests/EIP158/Homestead/stBoundsTest"}
|
||||
declare_test!{StateTests_EIP158_Homestead_stCallCodes, "StateTests/EIP158/Homestead/stCallCodes"}
|
||||
declare_test!{StateTests_EIP158_Homestead_stCallCreateCallCodeTest, "StateTests/EIP158/Homestead/stCallCreateCallCodeTest"}
|
||||
declare_test!{StateTests_EIP158_Homestead_stCallDelegateCodes, "StateTests/EIP158/Homestead/stCallDelegateCodes"}
|
||||
declare_test!{StateTests_EIP158_Homestead_stCallDelegateCodesCallCode, "StateTests/EIP158/Homestead/stCallDelegateCodesCallCode"}
|
||||
declare_test!{StateTests_EIP158_Homestead_stDelegatecallTest, "StateTests/EIP158/Homestead/stDelegatecallTest"}
|
||||
declare_test!{StateTests_EIP158_Homestead_stHomeSteadSpecific, "StateTests/EIP158/Homestead/stHomeSteadSpecific"}
|
||||
declare_test!{StateTests_EIP158_Homestead_stInitCodeTest, "StateTests/EIP158/Homestead/stInitCodeTest"}
|
||||
declare_test!{StateTests_EIP158_Homestead_stLogTests, "StateTests/EIP158/Homestead/stLogTests"}
|
||||
declare_test!{heavy => StateTests_EIP158_Homestead_stMemoryTest, "StateTests/EIP158/Homestead/stMemoryTest"}
|
||||
declare_test!{StateTests_EIP158_Homestead_stPreCompiledContracts, "StateTests/EIP158/Homestead/stPreCompiledContracts"}
|
||||
declare_test!{heavy => StateTests_EIP158_Homestead_stQuadraticComplexityTest, "StateTests/EIP158/Homestead/stQuadraticComplexityTest"}
|
||||
declare_test!{StateTests_EIP158_Homestead_stRecursiveCreate, "StateTests/EIP158/Homestead/stRecursiveCreate"}
|
||||
declare_test!{StateTests_EIP158_Homestead_stRefundTest, "StateTests/EIP158/Homestead/stRefundTest"}
|
||||
declare_test!{StateTests_EIP158_Homestead_stSpecialTest, "StateTests/EIP158/Homestead/stSpecialTest"}
|
||||
declare_test!{StateTests_EIP158_Homestead_stSystemOperationsTest, "StateTests/EIP158/Homestead/stSystemOperationsTest"}
|
||||
declare_test!{StateTests_EIP158_Homestead_stTransactionTest, "StateTests/EIP158/Homestead/stTransactionTest"}
|
||||
declare_test!{StateTests_EIP158_Homestead_stWalletTest, "StateTests/EIP158/Homestead/stWalletTest"}
|
@ -92,10 +92,18 @@ impl<'a, T, V> Ext for TestExt<'a, T, V> where T: Tracer, V: VMTracer {
|
||||
self.ext.exists(address)
|
||||
}
|
||||
|
||||
fn exists_and_not_null(&self, address: &Address) -> bool {
|
||||
self.ext.exists_and_not_null(address)
|
||||
}
|
||||
|
||||
fn balance(&self, address: &Address) -> U256 {
|
||||
self.ext.balance(address)
|
||||
}
|
||||
|
||||
fn origin_balance(&self) -> U256 {
|
||||
self.ext.origin_balance()
|
||||
}
|
||||
|
||||
fn blockhash(&self, number: &U256) -> H256 {
|
||||
self.ext.blockhash(number)
|
||||
}
|
||||
|
@ -24,4 +24,5 @@ mod chain;
|
||||
mod homestead_state;
|
||||
mod homestead_chain;
|
||||
mod eip150_state;
|
||||
mod eip161_state;
|
||||
mod trie;
|
||||
|
@ -29,6 +29,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
|
||||
ChainEra::Frontier => ethereum::new_mainnet_like().engine,
|
||||
ChainEra::Homestead => ethereum::new_homestead_test().engine,
|
||||
ChainEra::Eip150 => ethereum::new_eip150_test().engine,
|
||||
ChainEra::Eip161 => ethereum::new_eip161_test().engine,
|
||||
ChainEra::TransitionTest => ethereum::new_transition_test().engine,
|
||||
};
|
||||
|
||||
|
@ -35,17 +35,24 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
|
||||
Some(x) if x < 1_150_000 => &old_schedule,
|
||||
Some(_) => &new_schedule
|
||||
};
|
||||
let allow_network_id_of_one = number.map_or(false, |n| n > 2600000);
|
||||
|
||||
let rlp: Vec<u8> = test.rlp.into();
|
||||
let res = UntrustedRlp::new(&rlp)
|
||||
.as_val()
|
||||
.map_err(From::from)
|
||||
.and_then(|t: SignedTransaction| t.validate(schedule, schedule.have_delegate_call));
|
||||
.and_then(|t: SignedTransaction| t.validate(schedule, schedule.have_delegate_call, allow_network_id_of_one));
|
||||
|
||||
fail_unless(test.transaction.is_none() == res.is_err());
|
||||
if let (Some(tx), Some(sender)) = (test.transaction, test.sender) {
|
||||
let t = res.unwrap();
|
||||
fail_unless(t.sender().unwrap() == sender.into());
|
||||
let is_acceptable_network_id = match t.network_id() {
|
||||
None => true,
|
||||
Some(1) if allow_network_id_of_one => true,
|
||||
_ => false,
|
||||
};
|
||||
fail_unless(is_acceptable_network_id);
|
||||
let data: Vec<u8> = tx.data.into();
|
||||
fail_unless(t.data == data);
|
||||
fail_unless(t.gas_price == tx.gas_price.into());
|
||||
|
@ -245,7 +245,7 @@ mod tests {
|
||||
gas: U256::from(100_000),
|
||||
gas_price: U256::from(10),
|
||||
nonce: U256::from(0),
|
||||
}.sign(keypair.secret())
|
||||
}.sign(keypair.secret(), None)
|
||||
}
|
||||
|
||||
fn unwrap_err(res: Result<TransactionImportResult, Error>) -> TransactionError {
|
||||
|
@ -21,7 +21,7 @@ use util::*;
|
||||
use util::using_queue::{UsingQueue, GetAction};
|
||||
use account_provider::AccountProvider;
|
||||
use views::{BlockView, HeaderView};
|
||||
use state::State;
|
||||
use state::{State, CleanupMode};
|
||||
use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockID, CallAnalytics};
|
||||
use executive::contract_address;
|
||||
use block::{ClosedBlock, SealedBlock, IsBlock, Block};
|
||||
@ -650,7 +650,7 @@ impl MinerService for Miner {
|
||||
let needed_balance = t.value + t.gas * t.gas_price;
|
||||
if balance < needed_balance {
|
||||
// give the sender a sufficient balance
|
||||
state.add_balance(&sender, &(needed_balance - balance));
|
||||
state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty);
|
||||
}
|
||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
||||
let mut ret = try!(Executive::new(&mut state, &env_info, &*self.engine, chain.vm_factory()).transact(t, options));
|
||||
@ -1173,7 +1173,7 @@ mod tests {
|
||||
gas: U256::from(100_000),
|
||||
gas_price: U256::zero(),
|
||||
nonce: U256::zero(),
|
||||
}.sign(keypair.secret())
|
||||
}.sign(keypair.secret(), None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -42,8 +42,8 @@
|
||||
//! let t2 = Transaction { action: Action::Create, value: U256::from(100), data: "3331600055".from_hex().unwrap(),
|
||||
//! gas: U256::from(100_000), gas_price: U256::one(), nonce: U256::from(11) };
|
||||
//!
|
||||
//! let st1 = t1.sign(&key.secret());
|
||||
//! let st2 = t2.sign(&key.secret());
|
||||
//! let st1 = t1.sign(&key.secret(), None);
|
||||
//! let st2 = t2.sign(&key.secret(), None);
|
||||
//! let default_account_details = |_a: &Address| AccountDetails {
|
||||
//! nonce: U256::from(10),
|
||||
//! balance: U256::from(1_000_000),
|
||||
@ -1104,12 +1104,12 @@ mod test {
|
||||
|
||||
fn new_tx(nonce: U256, gas_price: U256) -> SignedTransaction {
|
||||
let keypair = Random.generate().unwrap();
|
||||
new_unsigned_tx(nonce, default_gas_val(), gas_price).sign(keypair.secret())
|
||||
new_unsigned_tx(nonce, default_gas_val(), gas_price).sign(keypair.secret(), None)
|
||||
}
|
||||
|
||||
fn new_tx_with_gas(gas: U256, gas_price: U256) -> SignedTransaction {
|
||||
let keypair = Random.generate().unwrap();
|
||||
new_unsigned_tx(default_nonce(), gas, gas_price).sign(keypair.secret())
|
||||
new_unsigned_tx(default_nonce(), gas, gas_price).sign(keypair.secret(), None)
|
||||
}
|
||||
|
||||
fn new_tx_default() -> SignedTransaction {
|
||||
@ -1133,7 +1133,7 @@ mod test {
|
||||
|
||||
let keypair = Random.generate().unwrap();
|
||||
let secret = &keypair.secret();
|
||||
(tx1.sign(secret), tx2.sign(secret))
|
||||
(tx1.sign(secret, None), tx2.sign(secret, None))
|
||||
}
|
||||
|
||||
/// Returns two consecutive transactions, both with increased gas price
|
||||
@ -1144,7 +1144,7 @@ mod test {
|
||||
|
||||
let keypair = Random.generate().unwrap();
|
||||
let secret = &keypair.secret();
|
||||
(tx1.sign(secret), tx2.sign(secret))
|
||||
(tx1.sign(secret, None), tx2.sign(secret, None))
|
||||
}
|
||||
|
||||
fn new_tx_pair_default(nonce_increment: U256, gas_price_increment: U256) -> (SignedTransaction, SignedTransaction) {
|
||||
@ -1798,9 +1798,9 @@ mod test {
|
||||
let mut txq = TransactionQueue::default();
|
||||
let kp = Random.generate().unwrap();
|
||||
let secret = kp.secret();
|
||||
let tx = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(secret);
|
||||
let tx1 = new_unsigned_tx(124.into(), default_gas_val(), 1.into()).sign(secret);
|
||||
let tx2 = new_unsigned_tx(125.into(), default_gas_val(), 1.into()).sign(secret);
|
||||
let tx = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(secret, None);
|
||||
let tx1 = new_unsigned_tx(124.into(), default_gas_val(), 1.into()).sign(secret, None);
|
||||
let tx2 = new_unsigned_tx(125.into(), default_gas_val(), 1.into()).sign(secret, None);
|
||||
|
||||
txq.add(tx, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
|
||||
assert_eq!(txq.status().pending, 1);
|
||||
@ -2038,11 +2038,11 @@ mod test {
|
||||
// given
|
||||
let mut txq = TransactionQueue::default();
|
||||
let keypair = Random.generate().unwrap();
|
||||
let tx = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(keypair.secret());
|
||||
let tx = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(keypair.secret(), None);
|
||||
let tx2 = {
|
||||
let mut tx2 = (*tx).clone();
|
||||
tx2.gas_price = U256::from(200);
|
||||
tx2.sign(keypair.secret())
|
||||
tx2.sign(keypair.secret(), None)
|
||||
};
|
||||
|
||||
// when
|
||||
@ -2061,16 +2061,16 @@ mod test {
|
||||
// given
|
||||
let mut txq = TransactionQueue::default();
|
||||
let keypair = Random.generate().unwrap();
|
||||
let tx0 = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(keypair.secret());
|
||||
let tx0 = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(keypair.secret(), None);
|
||||
let tx1 = {
|
||||
let mut tx1 = (*tx0).clone();
|
||||
tx1.nonce = U256::from(124);
|
||||
tx1.sign(keypair.secret())
|
||||
tx1.sign(keypair.secret(), None)
|
||||
};
|
||||
let tx2 = {
|
||||
let mut tx2 = (*tx1).clone();
|
||||
tx2.gas_price = U256::from(200);
|
||||
tx2.sign(keypair.secret())
|
||||
tx2.sign(keypair.secret(), None)
|
||||
};
|
||||
|
||||
// when
|
||||
@ -2223,7 +2223,7 @@ mod test {
|
||||
let tx3 = new_unsigned_tx(nonce + 2.into(), gas, 1.into());
|
||||
|
||||
|
||||
(tx.sign(secret), tx2.sign(secret), tx2_2.sign(secret), tx3.sign(secret))
|
||||
(tx.sign(secret, None), tx2.sign(secret, None), tx2_2.sign(secret, None), tx3.sign(secret, None))
|
||||
};
|
||||
let sender = tx1.sender().unwrap();
|
||||
txq.add(tx1, TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap();
|
||||
|
@ -38,7 +38,7 @@ pub struct CommonParams {
|
||||
/// Maximum size of extra data.
|
||||
pub maximum_extra_data_size: usize,
|
||||
/// Network id.
|
||||
pub network_id: U256,
|
||||
pub network_id: usize,
|
||||
/// Main subprotocol name.
|
||||
pub subprotocol_name: String,
|
||||
/// Minimum gas limit.
|
||||
@ -160,7 +160,7 @@ impl Spec {
|
||||
pub fn nodes(&self) -> &[String] { &self.nodes }
|
||||
|
||||
/// Get the configured Network ID.
|
||||
pub fn network_id(&self) -> U256 { self.params.network_id }
|
||||
pub fn network_id(&self) -> usize { self.params.network_id }
|
||||
|
||||
/// Get the configured Network ID.
|
||||
pub fn subprotocol_name(&self) -> String { self.params.subprotocol_name.clone() }
|
||||
@ -250,7 +250,7 @@ impl Spec {
|
||||
}
|
||||
trace!(target: "spec", "ensure_db_good: Populated sec trie; root is {}", root);
|
||||
for (address, account) in self.genesis_state.get().iter() {
|
||||
db.note_account_bloom(address);
|
||||
db.note_non_null_account(address);
|
||||
account.insert_additional(&mut AccountDBMut::new(db.as_hashdb_mut(), address));
|
||||
}
|
||||
assert!(db.as_hashdb().contains(&self.state_root()));
|
||||
|
@ -300,11 +300,17 @@ impl Account {
|
||||
pub fn storage_is_clean(&self) -> bool { self.storage_changes.is_empty() }
|
||||
|
||||
/// Check if account has zero nonce, balance, no code and no storage.
|
||||
///
|
||||
/// NOTE: Will panic if `!self.storage_is_clean()`
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.storage_changes.is_empty() &&
|
||||
assert!(self.storage_is_clean(), "Account::is_empty() may only legally be called when storage is clean.");
|
||||
self.is_null() && self.storage_root == SHA3_NULL_RLP
|
||||
}
|
||||
|
||||
/// Check if account has zero nonce, balance, no code.
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.balance.is_zero() &&
|
||||
self.nonce.is_zero() &&
|
||||
self.storage_root == SHA3_NULL_RLP &&
|
||||
self.code_hash == SHA3_EMPTY
|
||||
}
|
||||
|
||||
|
@ -199,6 +199,13 @@ enum RequireCache {
|
||||
Code,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum CleanupMode<'a> {
|
||||
ForceCreate,
|
||||
NoEmpty,
|
||||
KillEmpty(&'a mut HashSet<Address>),
|
||||
}
|
||||
|
||||
const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with valid root. Creating a SecTrieDB with a valid root will not fail. \
|
||||
Therefore creating a SecTrieDB with this state's root will not fail.";
|
||||
|
||||
@ -329,8 +336,8 @@ impl State {
|
||||
|
||||
/// 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, balance: U256) {
|
||||
self.insert_cache(contract, AccountEntry::new_dirty(Some(Account::new_contract(balance, self.account_start_nonce))));
|
||||
pub fn new_contract(&mut self, contract: &Address, balance: U256, nonce_offset: U256) {
|
||||
self.insert_cache(contract, AccountEntry::new_dirty(Some(Account::new_contract(balance, self.account_start_nonce + nonce_offset))));
|
||||
}
|
||||
|
||||
/// Remove an existing account.
|
||||
@ -341,10 +348,15 @@ impl State {
|
||||
/// Determine whether an account exists.
|
||||
pub fn exists(&self, a: &Address) -> bool {
|
||||
// Bloom filter does not contain empty accounts, so it is important here to
|
||||
// check if account exists in the database directly before EIP-158 is in effect.
|
||||
// check if account exists in the database directly before EIP-161 is in effect.
|
||||
self.ensure_cached(a, RequireCache::None, false, |a| a.is_some())
|
||||
}
|
||||
|
||||
/// Determine whether an account exists and if not empty.
|
||||
pub fn exists_and_not_null(&self, a: &Address) -> bool {
|
||||
self.ensure_cached(a, RequireCache::None, false, |a| a.map_or(false, |a| !a.is_null()))
|
||||
}
|
||||
|
||||
/// Get the balance of account `a`.
|
||||
pub fn balance(&self, a: &Address) -> U256 {
|
||||
self.ensure_cached(a, RequireCache::None, true,
|
||||
@ -399,7 +411,7 @@ impl State {
|
||||
}
|
||||
|
||||
// check bloom before any requests to trie
|
||||
if !self.db.check_account_bloom(address) { return H256::zero() }
|
||||
if !self.db.check_non_null_bloom(address) { return H256::zero() }
|
||||
|
||||
// account is not found in the global cache, get from the DB and insert into local
|
||||
let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
|
||||
@ -433,10 +445,18 @@ impl State {
|
||||
}
|
||||
|
||||
/// Add `incr` to the balance of account `a`.
|
||||
pub fn add_balance(&mut self, a: &Address, incr: &U256) {
|
||||
pub fn add_balance(&mut self, a: &Address, incr: &U256, cleanup_mode: CleanupMode) {
|
||||
trace!(target: "state", "add_balance({}, {}): {}", a, incr, self.balance(a));
|
||||
if !incr.is_zero() || !self.exists(a) {
|
||||
let is_value_transfer = !incr.is_zero();
|
||||
if is_value_transfer || (cleanup_mode == CleanupMode::ForceCreate && !self.exists(a)) {
|
||||
self.require(a, false).add_balance(incr);
|
||||
} else {
|
||||
match cleanup_mode {
|
||||
CleanupMode::KillEmpty(set) => if !is_value_transfer && self.exists(a) && !self.exists_and_not_null(a) {
|
||||
set.insert(a.clone());
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -449,9 +469,9 @@ impl State {
|
||||
}
|
||||
|
||||
/// Subtracts `by` from the balance of `from` and adds it to that of `to`.
|
||||
pub fn transfer_balance(&mut self, from: &Address, to: &Address, by: &U256) {
|
||||
pub fn transfer_balance(&mut self, from: &Address, to: &Address, by: &U256, cleanup_mode: CleanupMode) {
|
||||
self.sub_balance(from, by);
|
||||
self.add_balance(to, by);
|
||||
self.add_balance(to, by, cleanup_mode);
|
||||
}
|
||||
|
||||
/// Increment the nonce of account `a` by 1.
|
||||
@ -507,14 +527,16 @@ impl State {
|
||||
// first, commit the sub trees.
|
||||
for (address, ref mut a) in accounts.iter_mut().filter(|&(_, ref a)| a.is_dirty()) {
|
||||
if let Some(ref mut account) = a.account {
|
||||
if !account.is_empty() {
|
||||
db.note_account_bloom(address);
|
||||
}
|
||||
let addr_hash = account.address_hash(address);
|
||||
{
|
||||
let mut account_db = factories.accountdb.create(db.as_hashdb_mut(), addr_hash);
|
||||
account.commit_storage(&factories.trie, account_db.as_hashdb_mut());
|
||||
account.commit_code(account_db.as_hashdb_mut());
|
||||
}
|
||||
if !account.is_empty() {
|
||||
db.note_non_null_account(address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@ -653,7 +675,7 @@ impl State {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
// first check bloom if it is not in database for sure
|
||||
if check_bloom && !self.db.check_account_bloom(a) { return f(None); }
|
||||
if check_bloom && !self.db.check_non_null_bloom(a) { return f(None); }
|
||||
|
||||
// not found in the global cache, get from the DB and insert into local
|
||||
let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
|
||||
@ -687,7 +709,7 @@ impl State {
|
||||
match self.db.get_cached_account(a) {
|
||||
Some(acc) => self.insert_cache(a, AccountEntry::new_clean_cached(acc)),
|
||||
None => {
|
||||
let maybe_acc = if self.db.check_account_bloom(a) {
|
||||
let maybe_acc = if self.db.check_non_null_bloom(a) {
|
||||
let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
|
||||
match db.get(a) {
|
||||
Ok(Some(acc)) => AccountEntry::new_clean(Some(Account::from_rlp(&acc))),
|
||||
@ -793,9 +815,9 @@ fn should_apply_create_transaction() {
|
||||
action: Action::Create,
|
||||
value: 100.into(),
|
||||
data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(),
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||
let expected_trace = vec![FlatTrace {
|
||||
trace_address: Default::default(),
|
||||
@ -853,9 +875,9 @@ fn should_trace_failed_create_transaction() {
|
||||
action: Action::Create,
|
||||
value: 100.into(),
|
||||
data: FromHex::from_hex("5b600056").unwrap(),
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||
let expected_trace = vec![FlatTrace {
|
||||
trace_address: Default::default(),
|
||||
@ -890,10 +912,10 @@ fn should_trace_call_transaction() {
|
||||
action: Action::Call(0xa.into()),
|
||||
value: 100.into(),
|
||||
data: vec![],
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
state.init_code(&0xa.into(), FromHex::from_hex("6000").unwrap());
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||
let expected_trace = vec![FlatTrace {
|
||||
trace_address: Default::default(),
|
||||
@ -933,9 +955,9 @@ fn should_trace_basic_call_transaction() {
|
||||
action: Action::Call(0xa.into()),
|
||||
value: 100.into(),
|
||||
data: vec![],
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||
let expected_trace = vec![FlatTrace {
|
||||
trace_address: Default::default(),
|
||||
@ -975,7 +997,7 @@ fn should_trace_call_transaction_to_builtin() {
|
||||
action: Action::Call(0x1.into()),
|
||||
value: 0.into(),
|
||||
data: vec![],
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
let result = state.apply(&info, engine, &t, true).unwrap();
|
||||
|
||||
@ -1017,7 +1039,7 @@ fn should_not_trace_subcall_transaction_to_builtin() {
|
||||
action: Action::Call(0xa.into()),
|
||||
value: 0.into(),
|
||||
data: vec![],
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060006001610be0f1").unwrap());
|
||||
let result = state.apply(&info, engine, &t, true).unwrap();
|
||||
@ -1060,7 +1082,7 @@ fn should_not_trace_callcode() {
|
||||
action: Action::Call(0xa.into()),
|
||||
value: 0.into(),
|
||||
data: vec![],
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b611000f2").unwrap());
|
||||
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
|
||||
@ -1122,7 +1144,7 @@ fn should_not_trace_delegatecall() {
|
||||
action: Action::Call(0xa.into()),
|
||||
value: 0.into(),
|
||||
data: vec![],
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap());
|
||||
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
|
||||
@ -1181,10 +1203,10 @@ fn should_trace_failed_call_transaction() {
|
||||
action: Action::Call(0xa.into()),
|
||||
value: 100.into(),
|
||||
data: vec![],
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
state.init_code(&0xa.into(), FromHex::from_hex("5b600056").unwrap());
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||
let expected_trace = vec![FlatTrace {
|
||||
trace_address: Default::default(),
|
||||
@ -1221,11 +1243,11 @@ fn should_trace_call_with_subcall_transaction() {
|
||||
action: Action::Call(0xa.into()),
|
||||
value: 100.into(),
|
||||
data: vec![],
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
|
||||
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||
|
||||
let expected_trace = vec![FlatTrace {
|
||||
@ -1281,10 +1303,10 @@ fn should_trace_call_with_basic_subcall_transaction() {
|
||||
action: Action::Call(0xa.into()),
|
||||
value: 100.into(),
|
||||
data: vec![],
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006045600b6000f1").unwrap());
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||
let expected_trace = vec![FlatTrace {
|
||||
trace_address: Default::default(),
|
||||
@ -1336,10 +1358,10 @@ fn should_not_trace_call_with_invalid_basic_subcall_transaction() {
|
||||
action: Action::Call(0xa.into()),
|
||||
value: 100.into(),
|
||||
data: vec![],
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds.
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||
let expected_trace = vec![FlatTrace {
|
||||
trace_address: Default::default(),
|
||||
@ -1379,11 +1401,11 @@ fn should_trace_failed_subcall_transaction() {
|
||||
action: Action::Call(0xa.into()),
|
||||
value: 100.into(),
|
||||
data: vec![],//600480600b6000396000f35b600056
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
|
||||
state.init_code(&0xb.into(), FromHex::from_hex("5b600056").unwrap());
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||
let expected_trace = vec![FlatTrace {
|
||||
trace_address: Default::default(),
|
||||
@ -1435,12 +1457,12 @@ fn should_trace_call_with_subcall_with_subcall_transaction() {
|
||||
action: Action::Call(0xa.into()),
|
||||
value: 100.into(),
|
||||
data: vec![],
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
|
||||
state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap());
|
||||
state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap());
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||
let expected_trace = vec![FlatTrace {
|
||||
trace_address: Default::default(),
|
||||
@ -1510,12 +1532,12 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
|
||||
action: Action::Call(0xa.into()),
|
||||
value: 100.into(),
|
||||
data: vec![],//600480600b6000396000f35b600056
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
|
||||
state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap());
|
||||
state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap());
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||
|
||||
let expected_trace = vec![FlatTrace {
|
||||
@ -1583,11 +1605,11 @@ fn should_trace_suicide() {
|
||||
action: Action::Call(0xa.into()),
|
||||
value: 100.into(),
|
||||
data: vec![],
|
||||
}.sign(&"".sha3());
|
||||
}.sign(&"".sha3(), None);
|
||||
|
||||
state.init_code(&0xa.into(), FromHex::from_hex("73000000000000000000000000000000000000000bff").unwrap());
|
||||
state.add_balance(&0xa.into(), &50.into());
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &100.into());
|
||||
state.add_balance(&0xa.into(), &50.into(), CleanupMode::NoEmpty);
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &100.into(), CleanupMode::NoEmpty);
|
||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||
let expected_trace = vec![FlatTrace {
|
||||
trace_address: Default::default(),
|
||||
@ -1658,7 +1680,7 @@ fn get_from_database() {
|
||||
let (root, db) = {
|
||||
let mut state = get_temp_state_in(temp.as_path());
|
||||
state.inc_nonce(&a);
|
||||
state.add_balance(&a, &U256::from(69u64));
|
||||
state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty);
|
||||
state.commit().unwrap();
|
||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
||||
state.drop()
|
||||
@ -1675,27 +1697,47 @@ fn remove() {
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
assert_eq!(state.exists(&a), false);
|
||||
assert_eq!(state.exists_and_not_null(&a), false);
|
||||
state.inc_nonce(&a);
|
||||
assert_eq!(state.exists(&a), true);
|
||||
assert_eq!(state.exists_and_not_null(&a), true);
|
||||
assert_eq!(state.nonce(&a), U256::from(1u64));
|
||||
state.kill_account(&a);
|
||||
assert_eq!(state.exists(&a), false);
|
||||
assert_eq!(state.exists_and_not_null(&a), false);
|
||||
assert_eq!(state.nonce(&a), U256::from(0u64));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_account_exists() {
|
||||
fn empty_account_is_not_created() {
|
||||
let a = Address::zero();
|
||||
let path = RandomTempPath::new();
|
||||
let db = get_temp_state_db_in(path.as_path());
|
||||
let (root, db) = {
|
||||
let mut state = State::new(db, U256::from(0), Default::default());
|
||||
state.add_balance(&a, &U256::default()); // create an empty account
|
||||
state.add_balance(&a, &U256::default(), CleanupMode::NoEmpty); // create an empty account
|
||||
state.commit().unwrap();
|
||||
state.drop()
|
||||
};
|
||||
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
||||
assert!(!state.exists(&a));
|
||||
assert!(!state.exists_and_not_null(&a));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_account_exists_when_creation_forced() {
|
||||
let a = Address::zero();
|
||||
let path = RandomTempPath::new();
|
||||
let db = get_temp_state_db_in(path.as_path());
|
||||
let (root, db) = {
|
||||
let mut state = State::new(db, U256::from(0), Default::default());
|
||||
state.add_balance(&a, &U256::default(), CleanupMode::ForceCreate); // create an empty account
|
||||
state.commit().unwrap();
|
||||
state.drop()
|
||||
};
|
||||
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
||||
assert!(state.exists(&a));
|
||||
assert!(!state.exists_and_not_null(&a));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1733,7 +1775,7 @@ fn alter_balance() {
|
||||
let mut state = state_result.reference_mut();
|
||||
let a = Address::zero();
|
||||
let b = 1u64.into();
|
||||
state.add_balance(&a, &U256::from(69u64));
|
||||
state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty);
|
||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
||||
state.commit().unwrap();
|
||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
||||
@ -1741,7 +1783,7 @@ fn alter_balance() {
|
||||
assert_eq!(state.balance(&a), U256::from(27u64));
|
||||
state.commit().unwrap();
|
||||
assert_eq!(state.balance(&a), U256::from(27u64));
|
||||
state.transfer_balance(&a, &b, &U256::from(18u64));
|
||||
state.transfer_balance(&a, &b, &U256::from(18u64), CleanupMode::NoEmpty);
|
||||
assert_eq!(state.balance(&a), U256::from(9u64));
|
||||
assert_eq!(state.balance(&b), U256::from(18u64));
|
||||
state.commit().unwrap();
|
||||
@ -1794,12 +1836,12 @@ fn checkpoint_basic() {
|
||||
let mut state = state_result.reference_mut();
|
||||
let a = Address::zero();
|
||||
state.checkpoint();
|
||||
state.add_balance(&a, &U256::from(69u64));
|
||||
state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty);
|
||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
||||
state.discard_checkpoint();
|
||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
||||
state.checkpoint();
|
||||
state.add_balance(&a, &U256::from(1u64));
|
||||
state.add_balance(&a, &U256::from(1u64), CleanupMode::NoEmpty);
|
||||
assert_eq!(state.balance(&a), U256::from(70u64));
|
||||
state.revert_to_checkpoint();
|
||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
||||
@ -1812,7 +1854,7 @@ fn checkpoint_nested() {
|
||||
let a = Address::zero();
|
||||
state.checkpoint();
|
||||
state.checkpoint();
|
||||
state.add_balance(&a, &U256::from(69u64));
|
||||
state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty);
|
||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
||||
state.discard_checkpoint();
|
||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
||||
@ -1835,7 +1877,7 @@ fn should_not_panic_on_state_diff_with_storage() {
|
||||
|
||||
let a: Address = 0xa.into();
|
||||
state.init_code(&a, b"abcdefg".to_vec());
|
||||
state.add_balance(&a, &256.into());
|
||||
state.add_balance(&a, &256.into(), CleanupMode::NoEmpty);
|
||||
state.set_storage(&a, 0xb.into(), 0xc.into());
|
||||
|
||||
let mut new_state = state.clone();
|
||||
|
@ -18,6 +18,8 @@
|
||||
use std::collections::HashSet;
|
||||
use util::{Address, U256};
|
||||
use log_entry::LogEntry;
|
||||
use evm::Schedule;
|
||||
use super::CleanupMode;
|
||||
|
||||
/// State changes which should be applied in finalize,
|
||||
/// after transaction is fully executed.
|
||||
@ -26,6 +28,9 @@ pub struct Substate {
|
||||
/// Any accounts that have suicided.
|
||||
pub suicides: HashSet<Address>,
|
||||
|
||||
/// Any accounts that are tagged for garbage collection.
|
||||
pub garbage: HashSet<Address>,
|
||||
|
||||
/// Any logs.
|
||||
pub logs: Vec<LogEntry>,
|
||||
|
||||
@ -45,10 +50,20 @@ impl Substate {
|
||||
/// Merge secondary substate `s` into self, accruing each element correspondingly.
|
||||
pub fn accrue(&mut self, s: Substate) {
|
||||
self.suicides.extend(s.suicides.into_iter());
|
||||
self.garbage.extend(s.garbage.into_iter());
|
||||
self.logs.extend(s.logs.into_iter());
|
||||
self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count;
|
||||
self.contracts_created.extend(s.contracts_created.into_iter());
|
||||
}
|
||||
|
||||
/// Get the cleanup mode object from this.
|
||||
pub fn to_cleanup_mode(&mut self, schedule: &Schedule) -> CleanupMode {
|
||||
match (schedule.no_empty, schedule.kill_empty) {
|
||||
(false, _) => CleanupMode::ForceCreate,
|
||||
(true, false) => CleanupMode::NoEmpty,
|
||||
(true, true) => CleanupMode::KillEmpty(&mut self.garbage),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -165,13 +165,13 @@ impl StateDB {
|
||||
bloom
|
||||
}
|
||||
|
||||
pub fn check_account_bloom(&self, address: &Address) -> bool {
|
||||
pub fn check_non_null_bloom(&self, address: &Address) -> bool {
|
||||
trace!(target: "account_bloom", "Check account bloom: {:?}", address);
|
||||
let bloom = self.account_bloom.lock();
|
||||
bloom.check(&*address.sha3())
|
||||
}
|
||||
|
||||
pub fn note_account_bloom(&self, address: &Address) {
|
||||
pub fn note_non_null_account(&self, address: &Address) {
|
||||
trace!(target: "account_bloom", "Note account bloom: {:?}", address);
|
||||
let mut bloom = self.account_bloom.lock();
|
||||
bloom.set(&*address.sha3());
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
use io::IoChannel;
|
||||
use client::{BlockChainClient, MiningBlockChainClient, Client, ClientConfig, BlockID};
|
||||
use state::CleanupMode;
|
||||
use ethereum;
|
||||
use block::IsBlock;
|
||||
use tests::helpers::*;
|
||||
@ -272,7 +273,7 @@ fn change_history_size() {
|
||||
let client = Client::new(ClientConfig::default(), &test_spec, dir.as_path(), Arc::new(Miner::with_spec(&test_spec)), IoChannel::disconnected(), &db_config).unwrap();
|
||||
for _ in 0..20 {
|
||||
let mut b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]);
|
||||
b.block_mut().fields_mut().state.add_balance(&address, &5.into());
|
||||
b.block_mut().fields_mut().state.add_balance(&address, &5.into(), CleanupMode::NoEmpty);
|
||||
b.block_mut().fields_mut().state.commit().unwrap();
|
||||
let b = b.close_and_lock().seal(&*test_spec.engine, vec![]).unwrap();
|
||||
client.import_sealed_block(b).unwrap(); // account change is in the journal overlay
|
||||
|
@ -40,6 +40,7 @@ pub enum ChainEra {
|
||||
Frontier,
|
||||
Homestead,
|
||||
Eip150,
|
||||
Eip161,
|
||||
TransitionTest,
|
||||
}
|
||||
|
||||
@ -194,7 +195,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
|
||||
action: Action::Create,
|
||||
data: vec![],
|
||||
value: U256::zero(),
|
||||
}.sign(kp.secret()), None).unwrap();
|
||||
}.sign(kp.secret(), None), None).unwrap();
|
||||
n += 1;
|
||||
}
|
||||
|
||||
|
@ -72,8 +72,8 @@ pub struct Transaction {
|
||||
|
||||
impl Transaction {
|
||||
/// Append object with a without signature into RLP stream
|
||||
pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream) {
|
||||
s.begin_list(6);
|
||||
pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream, network_id: Option<u8>) {
|
||||
s.begin_list(if let None = network_id { 6 } else { 9 });
|
||||
s.append(&self.nonce);
|
||||
s.append(&self.gas_price);
|
||||
s.append(&self.gas);
|
||||
@ -83,6 +83,11 @@ impl Transaction {
|
||||
};
|
||||
s.append(&self.value);
|
||||
s.append(&self.data);
|
||||
if let Some(n) = network_id {
|
||||
s.append(&n);
|
||||
s.append(&0u8);
|
||||
s.append(&0u8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,7 +110,7 @@ impl From<ethjson::state::Transaction> for SignedTransaction {
|
||||
},
|
||||
value: t.value.into(),
|
||||
data: t.data.into(),
|
||||
}.sign(&t.secret.into())
|
||||
}.sign(&t.secret.into(), None)
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,26 +140,26 @@ impl From<ethjson::transaction::Transaction> for SignedTransaction {
|
||||
|
||||
impl Transaction {
|
||||
/// The message hash of the transaction.
|
||||
pub fn hash(&self) -> H256 {
|
||||
pub fn hash(&self, network_id: Option<u8>) -> H256 {
|
||||
let mut stream = RlpStream::new();
|
||||
self.rlp_append_unsigned_transaction(&mut stream);
|
||||
self.rlp_append_unsigned_transaction(&mut stream, network_id);
|
||||
stream.out().sha3()
|
||||
}
|
||||
|
||||
/// Signs the transaction as coming from `sender`.
|
||||
pub fn sign(self, secret: &Secret) -> SignedTransaction {
|
||||
let sig = ::ethkey::sign(secret, &self.hash())
|
||||
pub fn sign(self, secret: &Secret, network_id: Option<u8>) -> SignedTransaction {
|
||||
let sig = ::ethkey::sign(secret, &self.hash(network_id))
|
||||
.expect("data is valid and context has signing capabilities; qed");
|
||||
self.with_signature(sig)
|
||||
self.with_signature(sig, network_id)
|
||||
}
|
||||
|
||||
/// Signs the transaction with signature.
|
||||
pub fn with_signature(self, sig: Signature) -> SignedTransaction {
|
||||
pub fn with_signature(self, sig: Signature, network_id: Option<u8>) -> SignedTransaction {
|
||||
SignedTransaction {
|
||||
unsigned: self,
|
||||
r: sig.r().into(),
|
||||
s: sig.s().into(),
|
||||
v: sig.v() + 27,
|
||||
v: sig.v() + if let Some(n) = network_id { 1 + n * 2 } else { 27 },
|
||||
hash: Cell::new(None),
|
||||
sender: Cell::new(None),
|
||||
}
|
||||
@ -204,7 +209,8 @@ impl Transaction {
|
||||
pub struct SignedTransaction {
|
||||
/// Plain Transaction.
|
||||
unsigned: Transaction,
|
||||
/// The V field of the signature, either 27 or 28; helps describe the point on the curve.
|
||||
/// The V field of the signature; the LS bit described which half of the curve our point falls
|
||||
/// in. The MS bits describe which network this transaction is for. If 27/28, its for all networks.
|
||||
v: u8,
|
||||
/// The R field of the signature; helps describe the point on the curve.
|
||||
r: U256,
|
||||
@ -266,7 +272,7 @@ impl HeapSizeOf for SignedTransaction {
|
||||
|
||||
impl SignedTransaction {
|
||||
/// Append object with a signature into RLP stream
|
||||
pub fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) {
|
||||
fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) {
|
||||
s.begin_list(9);
|
||||
s.append(&self.nonce);
|
||||
s.append(&self.gas_price);
|
||||
@ -295,8 +301,16 @@ impl SignedTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
/// 0 is `v` is 27, 1 if 28, and 4 otherwise.
|
||||
pub fn standard_v(&self) -> u8 { match self.v { 27 => 0, 28 => 1, _ => 4 } }
|
||||
/// 0 if `v` would have been 27 under "Electrum" notation, 1 if 28 or 4 if invalid.
|
||||
pub fn standard_v(&self) -> u8 { match self.v { 0 => 4, v => (v - 1) & 1, } }
|
||||
|
||||
/// The network ID, or `None` if this is a global transaction.
|
||||
pub fn network_id(&self) -> Option<u8> {
|
||||
match self.v {
|
||||
0 | 27 | 28 => None,
|
||||
v => Some((v - 1) / 2),
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a signature object from the sig.
|
||||
pub fn signature(&self) -> Signature {
|
||||
@ -327,20 +341,25 @@ impl SignedTransaction {
|
||||
|
||||
/// Returns the public key of the sender.
|
||||
pub fn public_key(&self) -> Result<Public, Error> {
|
||||
Ok(try!(recover(&self.signature(), &self.unsigned.hash())))
|
||||
Ok(try!(recover(&self.signature(), &self.unsigned.hash(self.network_id()))))
|
||||
}
|
||||
|
||||
/// Do basic validation, checking for valid signature and minimum gas,
|
||||
// TODO: consider use in block validation.
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "json-tests")]
|
||||
pub fn validate(self, schedule: &Schedule, require_low: bool) -> Result<SignedTransaction, Error> {
|
||||
pub fn validate(self, schedule: &Schedule, require_low: bool, allow_network_id_of_one: bool) -> Result<SignedTransaction, Error> {
|
||||
if require_low && !self.signature().is_low_s() {
|
||||
return Err(EthkeyError::InvalidSignature.into())
|
||||
}
|
||||
match self.network_id() {
|
||||
None => {},
|
||||
Some(1) if allow_network_id_of_one => {},
|
||||
_ => return Err(TransactionError::InvalidNetworkId.into()),
|
||||
}
|
||||
try!(self.sender());
|
||||
if self.gas < U256::from(self.gas_required(&schedule)) {
|
||||
Err(From::from(TransactionError::InvalidGasLimit(::util::OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas})))
|
||||
Err(TransactionError::InvalidGasLimit(::util::OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas}).into())
|
||||
} else {
|
||||
Ok(self)
|
||||
}
|
||||
@ -380,6 +399,7 @@ fn sender_test() {
|
||||
} else { panic!(); }
|
||||
assert_eq!(t.value, U256::from(0x0au64));
|
||||
assert_eq!(t.sender().unwrap(), "0f65fe9276bc9a24ae7083ae28e2660ef72df99e".into());
|
||||
assert_eq!(t.network_id(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -394,8 +414,9 @@ fn signing() {
|
||||
gas: U256::from(50_000),
|
||||
value: U256::from(1),
|
||||
data: b"Hello!".to_vec()
|
||||
}.sign(&key.secret());
|
||||
}.sign(&key.secret(), None);
|
||||
assert_eq!(Address::from(key.public().sha3()), t.sender().unwrap());
|
||||
assert_eq!(t.network_id(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -409,7 +430,47 @@ fn fake_signing() {
|
||||
data: b"Hello!".to_vec()
|
||||
}.fake_sign(Address::from(0x69));
|
||||
assert_eq!(Address::from(0x69), t.sender().unwrap());
|
||||
assert_eq!(t.network_id(), None);
|
||||
|
||||
let t = t.clone();
|
||||
assert_eq!(Address::from(0x69), t.sender().unwrap());
|
||||
assert_eq!(t.network_id(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_recover_from_network_specific_signing() {
|
||||
use ethkey::{Random, Generator};
|
||||
let key = Random.generate().unwrap();
|
||||
let t = Transaction {
|
||||
action: Action::Create,
|
||||
nonce: U256::from(42),
|
||||
gas_price: U256::from(3000),
|
||||
gas: U256::from(50_000),
|
||||
value: U256::from(1),
|
||||
data: b"Hello!".to_vec()
|
||||
}.sign(&key.secret(), Some(69));
|
||||
assert_eq!(Address::from(key.public().sha3()), t.sender().unwrap());
|
||||
assert_eq!(t.network_id(), Some(69));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_agree_with_vitalik() {
|
||||
use rustc_serialize::hex::FromHex;
|
||||
use std::str::FromStr;
|
||||
|
||||
let test_vector = |tx_data: &str, address: &'static str| {
|
||||
let signed: SignedTransaction = decode(&FromHex::from_hex(tx_data).unwrap());
|
||||
assert_eq!(signed.sender().unwrap(), address.into());
|
||||
};
|
||||
|
||||
test_vector("f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0xda39a520355857fdb37ecb527fe814230fa9962c");
|
||||
test_vector("f864018504a817c80182a410943535353535353535353535353535353535353535018025a0c89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc8a0c89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", "0xd240215f30eafee2aaa5184d8f051ebb41c90b19");
|
||||
test_vector("f864028504a817c80282f618943535353535353535353535353535353535353535088025a0ad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a8a0ad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", "0x2f2822c55d894df1ba32961c43325dcb3d614ee8");
|
||||
test_vector("f865038504a817c803830148209435353535353535353535353535353535353535351b8025a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", "0xc21df0434ceab6e18a1300d18206e54e807b4456");
|
||||
test_vector("f865048504a817c80483019a28943535353535353535353535353535353535353535408025a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", "0xf975cee81edae2ab5883f4e2fb2a7f2fd56f4131");
|
||||
test_vector("f865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a0ceebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a0ceebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", "0xd477474c9f48dcbfde5d97f30646242ab7a17e06");
|
||||
test_vector("f866068504a817c80683023e3894353535353535353535353535353535353535353581d88025a0e455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2da0e455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", "0xb49948deb719ca21e38d29e3360f534b39db0e76");
|
||||
test_vector("f867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", "0xbddfc81a8ce87b2360837049a6eda68ab2f58999");
|
||||
test_vector("f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a0e4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c11a0e4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", "0x8f2edcf67f329a146dd4cb1e6b3a072daff85b38");
|
||||
test_vector("f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a0d2f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba0d2f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", "0x4ec38d4782fd4a6ff85c1cde77ccf1ae3c54472c");
|
||||
}
|
@ -395,7 +395,7 @@ mod tests {
|
||||
gas: U256::from(30_000),
|
||||
gas_price: U256::from(40_000),
|
||||
nonce: U256::one()
|
||||
}.sign(keypair.secret());
|
||||
}.sign(keypair.secret(), None);
|
||||
|
||||
let tr2 = Transaction {
|
||||
action: Action::Create,
|
||||
@ -404,7 +404,7 @@ mod tests {
|
||||
gas: U256::from(30_000),
|
||||
gas_price: U256::from(40_000),
|
||||
nonce: U256::from(2)
|
||||
}.sign(keypair.secret());
|
||||
}.sign(keypair.secret(), None);
|
||||
|
||||
let good_transactions = [ tr1.clone(), tr2.clone() ];
|
||||
|
||||
|
@ -51,6 +51,14 @@ impl Ext for FakeExt {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn exists_and_not_null(&self, address: &Address) -> bool {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn origin_balance(&self) -> U256 {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn balance(&self, _address: &Address) -> U256 {
|
||||
unimplemented!();
|
||||
}
|
||||
|
@ -70,6 +70,21 @@ pub struct EthashParams {
|
||||
/// See main EthashParams docs.
|
||||
#[serde(rename="eip150Transition")]
|
||||
pub eip150_transition: Option<Uint>,
|
||||
|
||||
/// See main EthashParams docs.
|
||||
#[serde(rename="eip155Transition")]
|
||||
pub eip155_transition: Option<Uint>,
|
||||
|
||||
/// See main EthashParams docs.
|
||||
#[serde(rename="eip160Transition")]
|
||||
pub eip160_transition: Option<Uint>,
|
||||
|
||||
/// See main EthashParams docs.
|
||||
#[serde(rename="eip161abcTransition")]
|
||||
pub eip161abc_transition: Option<Uint>,
|
||||
/// See main EthashParams docs.
|
||||
#[serde(rename="eip161dTransition")]
|
||||
pub eip161d_transition: Option<Uint>,
|
||||
}
|
||||
|
||||
/// Ethash engine deserialization.
|
||||
@ -122,7 +137,11 @@ mod tests {
|
||||
"difficultyHardforkTransition": "0x59d9",
|
||||
"difficultyHardforkBoundDivisor": "0x0200",
|
||||
"bombDefuseTransition": "0x42",
|
||||
"eip150Transition": "0x42"
|
||||
"eip150Transition": "0x42",
|
||||
"eip155Transition": "0x42",
|
||||
"eip160Transition": "0x42",
|
||||
"eip161abcTransition": "0x42",
|
||||
"eip161dTransition": "0x42"
|
||||
}
|
||||
}"#;
|
||||
|
||||
|
@ -28,15 +28,17 @@ pub struct Params {
|
||||
/// Maximum size of extra data.
|
||||
#[serde(rename="maximumExtraDataSize")]
|
||||
pub maximum_extra_data_size: Uint,
|
||||
/// Minimum gas limit.
|
||||
#[serde(rename="minGasLimit")]
|
||||
pub min_gas_limit: Uint,
|
||||
|
||||
/// Network id.
|
||||
#[serde(rename="networkID")]
|
||||
pub network_id: Uint,
|
||||
/// Name of the main ("eth") subprotocol.
|
||||
#[serde(rename="subprotocolName")]
|
||||
pub subprotocol_name: Option<String>,
|
||||
/// Minimum gas limit.
|
||||
#[serde(rename="minGasLimit")]
|
||||
pub min_gas_limit: Uint,
|
||||
|
||||
/// Option fork block number to check.
|
||||
#[serde(rename="forkBlock")]
|
||||
pub fork_block: Option<Uint>,
|
||||
|
@ -25,7 +25,7 @@ port = 30303
|
||||
min_peers = 25
|
||||
max_peers = 50
|
||||
nat = "any"
|
||||
id = "0x1"
|
||||
id = 1
|
||||
bootnodes = []
|
||||
discovery = true
|
||||
warp = true
|
||||
|
@ -46,7 +46,7 @@ usage! {
|
||||
flag_testnet: bool,
|
||||
flag_import_geth_keys: bool,
|
||||
flag_datadir: Option<String>,
|
||||
flag_networkid: Option<String>,
|
||||
flag_networkid: Option<usize>,
|
||||
flag_peers: Option<u16>,
|
||||
flag_nodekey: Option<String>,
|
||||
flag_nodiscover: bool,
|
||||
@ -122,7 +122,7 @@ usage! {
|
||||
or |c: &Config| otry!(c.network).nat.clone(),
|
||||
flag_allow_ips: String = "all",
|
||||
or |c: &Config| otry!(c.network).allow_ips.clone(),
|
||||
flag_network_id: Option<String> = None,
|
||||
flag_network_id: Option<usize> = None,
|
||||
or |c: &Config| otry!(c.network).id.clone().map(Some),
|
||||
flag_bootnodes: Option<String> = None,
|
||||
or |c: &Config| otry!(c.network).bootnodes.clone().map(|vec| Some(vec.join(","))),
|
||||
@ -323,7 +323,7 @@ struct Network {
|
||||
max_pending_peers: Option<u16>,
|
||||
nat: Option<String>,
|
||||
allow_ips: Option<String>,
|
||||
id: Option<String>,
|
||||
id: Option<usize>,
|
||||
bootnodes: Option<Vec<String>>,
|
||||
discovery: Option<bool>,
|
||||
node_key: Option<String>,
|
||||
@ -530,7 +530,7 @@ mod tests {
|
||||
flag_snapshot_peers: 0u16,
|
||||
flag_allow_ips: "all".into(),
|
||||
flag_nat: "any".into(),
|
||||
flag_network_id: Some("0x1".into()),
|
||||
flag_network_id: Some(1),
|
||||
flag_bootnodes: Some("".into()),
|
||||
flag_no_discovery: false,
|
||||
flag_node_key: None,
|
||||
|
@ -5,5 +5,6 @@ License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law.
|
||||
|
||||
By Wood/Paronyan/Kotewicz/Drwięga/Volf.
|
||||
By Wood/Paronyan/Kotewicz/Drwięga/Volf
|
||||
Habermeier/Czaban/Greeff/Gotchac/Redmann
|
||||
|
||||
|
@ -86,7 +86,7 @@ impl Configuration {
|
||||
let http_conf = try!(self.http_config());
|
||||
let ipc_conf = try!(self.ipc_config());
|
||||
let net_conf = try!(self.net_config());
|
||||
let network_id = try!(self.network_id());
|
||||
let network_id = self.network_id();
|
||||
let cache_config = self.cache_config();
|
||||
let spec = try!(self.chain().parse());
|
||||
let tracing = try!(self.args.flag_tracing.parse());
|
||||
@ -517,12 +517,8 @@ impl Configuration {
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
fn network_id(&self) -> Result<Option<U256>, String> {
|
||||
let net_id = self.args.flag_network_id.as_ref().or(self.args.flag_networkid.as_ref());
|
||||
match net_id {
|
||||
Some(id) => Ok(Some(try!(to_u256(id)))),
|
||||
None => Ok(None),
|
||||
}
|
||||
fn network_id(&self) -> Option<usize> {
|
||||
self.args.flag_network_id.or(self.args.flag_networkid)
|
||||
}
|
||||
|
||||
fn rpc_apis(&self) -> String {
|
||||
|
@ -20,7 +20,7 @@ use ctrlc::CtrlC;
|
||||
use fdlimit::raise_fd_limit;
|
||||
use ethcore_rpc::{NetworkSettings, is_major_importing};
|
||||
use ethsync::NetworkConfiguration;
|
||||
use util::{Colour, version, U256, RotatingLogger};
|
||||
use util::{Colour, version, RotatingLogger};
|
||||
use io::{MayPanic, ForwardPanic, PanicHandler};
|
||||
use ethcore_logger::{Config as LogConfig};
|
||||
use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, ChainNotify, BlockChainClient};
|
||||
@ -70,7 +70,7 @@ pub struct RunCmd {
|
||||
pub http_conf: HttpConfiguration,
|
||||
pub ipc_conf: IpcConfiguration,
|
||||
pub net_conf: NetworkConfiguration,
|
||||
pub network_id: Option<U256>,
|
||||
pub network_id: Option<usize>,
|
||||
pub warp_sync: bool,
|
||||
pub acc_conf: AccountsConfig,
|
||||
pub gas_pricer: GasPricerConfig,
|
||||
|
@ -63,15 +63,16 @@ pub fn decrypt(accounts: &AccountProvider, address: Address, password: Option<St
|
||||
pub fn sign_and_dispatch<C, M>(client: &C, miner: &M, accounts: &AccountProvider, request: TransactionRequest, password: Option<String>) -> Result<RpcH256, Error>
|
||||
where C: MiningBlockChainClient, M: MinerService {
|
||||
|
||||
let network_id = client.signing_network_id();
|
||||
let address = request.from;
|
||||
let signed_transaction = {
|
||||
let t = prepare_transaction(client, miner, request);
|
||||
let hash = t.hash();
|
||||
let hash = t.hash(network_id);
|
||||
let signature = try!(signature(accounts, address, password, hash));
|
||||
t.with_signature(signature)
|
||||
t.with_signature(signature, network_id)
|
||||
};
|
||||
|
||||
trace!(target: "miner", "send_transaction: dispatching tx: {}", ::rlp::encode(&signed_transaction).to_vec().pretty());
|
||||
trace!(target: "miner", "send_transaction: dispatching tx: {} for network ID {:?}", ::rlp::encode(&signed_transaction).to_vec().pretty(), network_id);
|
||||
dispatch_transaction(&*client, &*miner, signed_transaction)
|
||||
}
|
||||
|
||||
|
@ -255,6 +255,7 @@ pub fn from_transaction_error(error: EthcoreError) -> Error {
|
||||
SenderBanned => "Sender is banned in local queue.".into(),
|
||||
RecipientBanned => "Recipient is banned in local queue.".into(),
|
||||
CodeBanned => "Code is banned in local queue.".into(),
|
||||
e => format!("{}", e).into(),
|
||||
};
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::TRANSACTION_ERROR),
|
||||
|
@ -45,7 +45,7 @@ fn account_provider() -> Arc<AccountProvider> {
|
||||
|
||||
fn sync_provider() -> Arc<TestSyncProvider> {
|
||||
Arc::new(TestSyncProvider::new(Config {
|
||||
network_id: U256::from(3),
|
||||
network_id: 3,
|
||||
num_peers: 120,
|
||||
}))
|
||||
}
|
||||
|
@ -16,13 +16,13 @@
|
||||
|
||||
//! Test implementation of SyncProvider.
|
||||
|
||||
use util::{RwLock, U256};
|
||||
use util::{RwLock};
|
||||
use ethsync::{SyncProvider, SyncStatus, SyncState, PeerInfo};
|
||||
|
||||
/// TestSyncProvider config.
|
||||
pub struct Config {
|
||||
/// Protocol version.
|
||||
pub network_id: U256,
|
||||
pub network_id: usize,
|
||||
/// Number of peers.
|
||||
pub num_peers: usize,
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ fn accounts_provider() -> Arc<AccountProvider> {
|
||||
|
||||
fn sync_provider() -> Arc<TestSyncProvider> {
|
||||
Arc::new(TestSyncProvider::new(Config {
|
||||
network_id: U256::from(3),
|
||||
network_id: 3,
|
||||
num_peers: 120,
|
||||
}))
|
||||
}
|
||||
@ -737,8 +737,8 @@ fn rpc_eth_send_transaction() {
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![]
|
||||
};
|
||||
let signature = tester.accounts_provider.sign(address, None, t.hash()).unwrap();
|
||||
let t = t.with_signature(signature);
|
||||
let signature = tester.accounts_provider.sign(address, None, t.hash(None)).unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#;
|
||||
|
||||
@ -754,8 +754,8 @@ fn rpc_eth_send_transaction() {
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![]
|
||||
};
|
||||
let signature = tester.accounts_provider.sign(address, None, t.hash()).unwrap();
|
||||
let t = t.with_signature(signature);
|
||||
let signature = tester.accounts_provider.sign(address, None, t.hash(None)).unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#;
|
||||
|
||||
@ -819,8 +819,8 @@ fn rpc_eth_send_raw_transaction() {
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![]
|
||||
};
|
||||
let signature = tester.accounts_provider.sign(address, None, t.hash()).unwrap();
|
||||
let t = t.with_signature(signature);
|
||||
let signature = tester.accounts_provider.sign(address, None, t.hash(None)).unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
let rlp = ::rlp::encode(&t).to_vec().to_hex();
|
||||
|
||||
|
@ -246,8 +246,8 @@ fn should_dispatch_transaction_if_account_is_unlock() {
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![]
|
||||
};
|
||||
let signature = tester.accounts.sign(acc, None, t.hash()).unwrap();
|
||||
let t = t.with_signature(signature);
|
||||
let signature = tester.accounts.sign(acc, None, t.hash(None)).unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
// when
|
||||
let request = r#"{
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
use util::log::RotatingLogger;
|
||||
use util::{U256, Address};
|
||||
use util::{Address};
|
||||
use ethsync::ManageNetwork;
|
||||
use ethcore::client::{TestBlockChainClient};
|
||||
use ethstore::ethkey::{Generator, Random};
|
||||
@ -46,7 +46,7 @@ impl Dependencies {
|
||||
miner: Arc::new(TestMinerService::default()),
|
||||
client: Arc::new(TestBlockChainClient::default()),
|
||||
sync: Arc::new(TestSyncProvider::new(Config {
|
||||
network_id: U256::from(3),
|
||||
network_id: 3,
|
||||
num_peers: 120,
|
||||
})),
|
||||
logger: Arc::new(RotatingLogger::new("rpc=trace".to_owned())),
|
||||
|
@ -21,7 +21,7 @@ use v1::tests::helpers::{Config, TestSyncProvider};
|
||||
|
||||
fn sync_provider() -> Arc<TestSyncProvider> {
|
||||
Arc::new(TestSyncProvider::new(Config {
|
||||
network_id: 3.into(),
|
||||
network_id: 3,
|
||||
num_peers: 120,
|
||||
}))
|
||||
}
|
||||
|
@ -201,8 +201,8 @@ fn sign_and_send_transaction() {
|
||||
data: vec![]
|
||||
};
|
||||
tester.accounts.unlock_account_temporarily(address, "password123".into()).unwrap();
|
||||
let signature = tester.accounts.sign(address, None, t.hash()).unwrap();
|
||||
let t = t.with_signature(signature);
|
||||
let signature = tester.accounts.sign(address, None, t.hash(None)).unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#;
|
||||
|
||||
@ -219,8 +219,8 @@ fn sign_and_send_transaction() {
|
||||
data: vec![]
|
||||
};
|
||||
tester.accounts.unlock_account_temporarily(address, "password123".into()).unwrap();
|
||||
let signature = tester.accounts.sign(address, None, t.hash()).unwrap();
|
||||
let t = t.with_signature(signature);
|
||||
let signature = tester.accounts.sign(address, None, t.hash(None)).unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#;
|
||||
|
||||
|
@ -186,8 +186,8 @@ fn should_confirm_transaction_and_dispatch() {
|
||||
data: vec![]
|
||||
};
|
||||
tester.accounts.unlock_account_temporarily(address, "test".into()).unwrap();
|
||||
let signature = tester.accounts.sign(address, None, t.hash()).unwrap();
|
||||
let t = t.with_signature(signature);
|
||||
let signature = tester.accounts.sign(address, None, t.hash(None)).unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
assert_eq!(tester.signer.requests().len(), 1);
|
||||
|
||||
|
@ -42,7 +42,7 @@ pub struct SyncConfig {
|
||||
/// Max blocks to download ahead
|
||||
pub max_download_ahead_blocks: usize,
|
||||
/// Network ID
|
||||
pub network_id: U256,
|
||||
pub network_id: usize,
|
||||
/// Main "eth" subprotocol name.
|
||||
pub subprotocol_name: [u8; 3],
|
||||
/// Fork block to check
|
||||
@ -55,7 +55,7 @@ impl Default for SyncConfig {
|
||||
fn default() -> SyncConfig {
|
||||
SyncConfig {
|
||||
max_download_ahead_blocks: 20000,
|
||||
network_id: U256::from(1),
|
||||
network_id: 1,
|
||||
subprotocol_name: *b"eth",
|
||||
fork_block: None,
|
||||
warp_sync: false,
|
||||
|
@ -188,7 +188,7 @@ pub struct SyncStatus {
|
||||
/// Syncing protocol version. That's the maximum protocol version we connect to.
|
||||
pub protocol_version: u8,
|
||||
/// The underlying p2p network version.
|
||||
pub network_id: U256,
|
||||
pub network_id: usize,
|
||||
/// `BlockChain` height for the moment the sync started.
|
||||
pub start_block_number: BlockNumber,
|
||||
/// Last fully downloaded and imported block number (if any).
|
||||
@ -269,7 +269,7 @@ struct PeerInfo {
|
||||
/// Peer chain genesis hash
|
||||
genesis: H256,
|
||||
/// Peer network id
|
||||
network_id: U256,
|
||||
network_id: usize,
|
||||
/// Peer best block hash
|
||||
latest_hash: H256,
|
||||
/// Peer total difficulty if known
|
||||
@ -328,7 +328,7 @@ pub struct ChainSync {
|
||||
/// Last propagated block number
|
||||
last_sent_block_number: BlockNumber,
|
||||
/// Network ID
|
||||
network_id: U256,
|
||||
network_id: usize,
|
||||
/// Optional fork block to check
|
||||
fork_block: Option<(BlockNumber, H256)>,
|
||||
/// Snapshot downloader.
|
||||
@ -2145,7 +2145,7 @@ mod tests {
|
||||
PeerInfo {
|
||||
protocol_version: 0,
|
||||
genesis: H256::zero(),
|
||||
network_id: U256::zero(),
|
||||
network_id: 0,
|
||||
latest_hash: peer_latest_hash,
|
||||
difficulty: None,
|
||||
asking: PeerAsking::Nothing,
|
||||
|
Loading…
Reference in New Issue
Block a user