From aa0760597b1d33615731aa06192595dd3fcf09a7 Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Wed, 20 Jan 2016 16:52:22 +0100 Subject: [PATCH 01/23] Fixing delegatecall --- src/action_params.rs | 11 ++++++---- src/evm/ext.rs | 14 +++++++++++- src/evm/interpreter.rs | 49 +++++++++++++++++++++++++++++++++++------- src/evm/tests.rs | 41 +++++++++++++++++++++-------------- src/executive.rs | 25 +++++++++++++-------- src/externalities.rs | 32 +++++++++++++++++++++++++++ src/tests/executive.rs | 18 +++++++++++++++- 7 files changed, 151 insertions(+), 39 deletions(-) diff --git a/src/action_params.rs b/src/action_params.rs index da1ae0ce0..6f876874b 100644 --- a/src/action_params.rs +++ b/src/action_params.rs @@ -23,15 +23,17 @@ pub struct ActionParams { pub gas_price: U256, /// Transaction value. pub value: U256, + /// Should transfer value from sender to origin + pub is_value_transfer: bool, /// Code being executed. pub code: Option, /// Input data. pub data: Option } -impl ActionParams { - /// TODO [Gav Wood] Please document me - pub fn new() -> ActionParams { +impl Default for ActionParams { + /// Returns default ActionParams initialized with zeros + fn default() -> ActionParams { ActionParams { code_address: Address::new(), address: Address::new(), @@ -41,7 +43,8 @@ impl ActionParams { gas_price: U256::zero(), value: U256::zero(), code: None, - data: None + data: None, + is_value_transfer: true } } } diff --git a/src/evm/ext.rs b/src/evm/ext.rs index 4d2471593..b7bf609ca 100644 --- a/src/evm/ext.rs +++ b/src/evm/ext.rs @@ -26,7 +26,7 @@ pub enum MessageCallResult { Failed } -/// TODO [debris] Please document me +/// Externalities interface for EVMs pub trait Ext { /// Returns a value for given key. fn storage_at(&self, key: &H256) -> H256; @@ -61,6 +61,18 @@ pub trait Ext { code_address: &Address, output: &mut [u8]) -> MessageCallResult; + /// Delegate Message call. + /// + /// Returns Err, if we run out of gas. + /// Otherwise returns call_result which contains gas left + /// and true if subcall was successfull. + fn delegatecall(&mut self, + gas: &U256, + value: &U256, + data: &[u8], + code_address: &Address, + output: &mut [u8]) -> MessageCallResult; + /// Returns code at given address fn extcode(&self, address: &Address) -> Bytes; diff --git a/src/evm/interpreter.rs b/src/evm/interpreter.rs index 88823cbea..c7d2bfda8 100644 --- a/src/evm/interpreter.rs +++ b/src/evm/interpreter.rs @@ -564,17 +564,50 @@ impl Interpreter { } }; }, - instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL => { + instructions::DELEGATECALL => { + let call_gas = stack.pop_back(); + let code_address = stack.pop_back(); + let code_address = u256_to_address(&code_address); + + let value = params.value; + + let in_off = stack.pop_back(); + let in_size = stack.pop_back(); + let out_off = stack.pop_back(); + let out_size = stack.pop_back(); + + let can_call = ext.depth() < ext.schedule().max_depth; + if !can_call { + stack.push(U256::zero()); + return Ok(InstructionResult::UnusedGas(call_gas)); + } + + let call_result = { + // we need to write and read from memory in the same time + // and we don't want to copy + let input = unsafe { ::std::mem::transmute(mem.read_slice(in_off, in_size)) }; + let output = mem.writeable_slice(out_off, out_size); + ext.delegatecall(&call_gas, &value, input, &code_address, output) + }; + + return match call_result { + MessageCallResult::Success(gas_left) => { + stack.push(U256::one()); + Ok(InstructionResult::UnusedGas(gas_left)) + }, + MessageCallResult::Failed => { + stack.push(U256::zero()); + Ok(InstructionResult::Ok) + } + }; + }, + instructions::CALL | instructions::CALLCODE => { assert!(ext.schedule().call_value_transfer_gas > ext.schedule().call_stipend, "overflow possible"); let call_gas = stack.pop_back(); let code_address = stack.pop_back(); let code_address = u256_to_address(&code_address); - let is_delegatecall = instruction == instructions::DELEGATECALL; - let value = match is_delegatecall { - true => params.value, - false => stack.pop_back() - }; + let value = stack.pop_back(); let address = match instruction == instructions::CALL { true => &code_address, @@ -586,12 +619,12 @@ impl Interpreter { let out_off = stack.pop_back(); let out_size = stack.pop_back(); - let call_gas = call_gas + match !is_delegatecall && value > U256::zero() { + let call_gas = call_gas + match value > U256::zero() { true => U256::from(ext.schedule().call_stipend), false => U256::zero() }; - let can_call = (is_delegatecall || ext.balance(¶ms.address) >= value) && ext.depth() < ext.schedule().max_depth; + let can_call = ext.balance(¶ms.address) >= value && ext.depth() < ext.schedule().max_depth; if !can_call { stack.push(U256::zero()); diff --git a/src/evm/tests.rs b/src/evm/tests.rs index 8e1b5eff4..7eb9d484c 100644 --- a/src/evm/tests.rs +++ b/src/evm/tests.rs @@ -69,6 +69,15 @@ impl Ext for FakeExt { unimplemented!(); } + fn delegatecall(&mut self, + _gas: &U256, + _value: &U256, + _data: &[u8], + _address: &Address, + _output: &mut [u8]) -> MessageCallResult { + unimplemented!(); + } + fn extcode(&self, address: &Address) -> Bytes { self.codes.get(address).unwrap_or(&Bytes::new()).clone() } @@ -110,7 +119,7 @@ fn test_stack_underflow() { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let code = "01600055".from_hex().unwrap(); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.address = address.clone(); params.gas = U256::from(100_000); params.code = Some(code); @@ -137,7 +146,7 @@ fn test_add(factory: super::Factory) { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let code = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01600055".from_hex().unwrap(); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.address = address.clone(); params.gas = U256::from(100_000); params.code = Some(code); @@ -157,7 +166,7 @@ fn test_sha3(factory: super::Factory) { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let code = "6000600020600055".from_hex().unwrap(); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.address = address.clone(); params.gas = U256::from(100_000); params.code = Some(code); @@ -177,7 +186,7 @@ fn test_address(factory: super::Factory) { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let code = "30600055".from_hex().unwrap(); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.address = address.clone(); params.gas = U256::from(100_000); params.code = Some(code); @@ -198,7 +207,7 @@ fn test_origin(factory: super::Factory) { let origin = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").unwrap(); let code = "32600055".from_hex().unwrap(); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.address = address.clone(); params.origin = origin.clone(); params.gas = U256::from(100_000); @@ -220,7 +229,7 @@ fn test_sender(factory: super::Factory) { let sender = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").unwrap(); let code = "33600055".from_hex().unwrap(); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.address = address.clone(); params.sender = sender.clone(); params.gas = U256::from(100_000); @@ -254,7 +263,7 @@ fn test_extcodecopy(factory: super::Factory) { let code = "333b60006000333c600051600055".from_hex().unwrap(); let sender_code = "6005600055".from_hex().unwrap(); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.address = address.clone(); params.sender = sender.clone(); params.gas = U256::from(100_000); @@ -276,7 +285,7 @@ fn test_log_empty(factory: super::Factory) { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let code = "60006000a0".from_hex().unwrap(); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.address = address.clone(); params.gas = U256::from(100_000); params.code = Some(code); @@ -307,7 +316,7 @@ fn test_log_sender(factory: super::Factory) { let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); let code = "60ff6000533360206000a1".from_hex().unwrap(); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.address = address.clone(); params.sender = sender.clone(); params.gas = U256::from(100_000); @@ -332,7 +341,7 @@ fn test_blockhash(factory: super::Factory) { let code = "600040600055".from_hex().unwrap(); let blockhash = H256::from_str("123400000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681").unwrap(); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.address = address.clone(); params.gas = U256::from(100_000); params.code = Some(code); @@ -354,7 +363,7 @@ fn test_calldataload(factory: super::Factory) { let code = "600135600055".from_hex().unwrap(); let data = "0123ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff23".from_hex().unwrap(); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.address = address.clone(); params.gas = U256::from(100_000); params.code = Some(code); @@ -376,7 +385,7 @@ fn test_author(factory: super::Factory) { let author = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let code = "41600055".from_hex().unwrap(); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.gas = U256::from(100_000); params.code = Some(code); let mut ext = FakeExt::new(); @@ -396,7 +405,7 @@ fn test_timestamp(factory: super::Factory) { let timestamp = 0x1234; let code = "42600055".from_hex().unwrap(); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.gas = U256::from(100_000); params.code = Some(code); let mut ext = FakeExt::new(); @@ -416,7 +425,7 @@ fn test_number(factory: super::Factory) { let number = 0x1234; let code = "43600055".from_hex().unwrap(); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.gas = U256::from(100_000); params.code = Some(code); let mut ext = FakeExt::new(); @@ -436,7 +445,7 @@ fn test_difficulty(factory: super::Factory) { let difficulty = U256::from(0x1234); let code = "44600055".from_hex().unwrap(); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.gas = U256::from(100_000); params.code = Some(code); let mut ext = FakeExt::new(); @@ -456,7 +465,7 @@ fn test_gas_limit(factory: super::Factory) { let gas_limit = U256::from(0x1234); let code = "45600055".from_hex().unwrap(); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.gas = U256::from(100_000); params.code = Some(code); let mut ext = FakeExt::new(); diff --git a/src/executive.rs b/src/executive.rs index 6c2b29e3f..ea1a8f6de 100644 --- a/src/executive.rs +++ b/src/executive.rs @@ -134,6 +134,7 @@ impl<'a> Executive<'a> { gas: init_gas, gas_price: t.gas_price, value: t.value, + is_value_transfer: true, code: Some(t.data.clone()), data: None, }; @@ -148,6 +149,7 @@ impl<'a> Executive<'a> { gas: init_gas, gas_price: t.gas_price, value: t.value, + is_value_transfer: true, code: self.state.code(address), data: Some(t.data.clone()), }; @@ -166,11 +168,14 @@ impl<'a> Executive<'a> { /// Modifies the substate and the output. /// Returns either gas_left or `evm::Error`. pub fn call(&mut self, params: ActionParams, substate: &mut Substate, mut output: BytesRef) -> evm::Result { + println!("Calling executive. Sender: {}", params.sender); // backup used in case of running out of gas let backup = self.state.clone(); // at first, transfer value to destination - self.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value); + if params.is_value_transfer { + self.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value); + } trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info); if self.engine.is_builtin(¶ms.code_address) { @@ -227,7 +232,9 @@ impl<'a> Executive<'a> { self.state.new_contract(¶ms.address); // then transfer value to it - self.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value); + if params.is_value_transfer { + self.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value); + } let res = { let mut ext = self.to_externalities(OriginInfo::from(¶ms), &mut unconfirmed_substate, OutputPolicy::InitContract); @@ -367,7 +374,7 @@ mod tests { fn test_sender_balance(factory: Factory) { let sender = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let address = contract_address(&sender, &U256::zero()); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.address = address.clone(); params.sender = sender.clone(); params.gas = U256::from(100_000); @@ -424,7 +431,7 @@ mod tests { let address = contract_address(&sender, &U256::zero()); // TODO: add tests for 'callcreate' //let next_address = contract_address(&address, &U256::zero()); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.address = address.clone(); params.sender = sender.clone(); params.origin = sender.clone(); @@ -477,7 +484,7 @@ mod tests { let address = contract_address(&sender, &U256::zero()); // TODO: add tests for 'callcreate' //let next_address = contract_address(&address, &U256::zero()); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.address = address.clone(); params.sender = sender.clone(); params.origin = sender.clone(); @@ -528,7 +535,7 @@ mod tests { let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); let address = contract_address(&sender, &U256::zero()); let next_address = contract_address(&address, &U256::zero()); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.address = address.clone(); params.sender = sender.clone(); params.origin = sender.clone(); @@ -584,7 +591,7 @@ mod tests { let address_b = Address::from_str("945304eb96065b2a98b57a48a06ae28d285a71b5" ).unwrap(); let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.address = address_a.clone(); params.sender = sender.clone(); params.gas = U256::from(100_000); @@ -633,7 +640,7 @@ mod tests { let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); let code = "600160005401600055600060006000600060003060e05a03f1600155".from_hex().unwrap(); let address = contract_address(&sender, &U256::zero()); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.address = address.clone(); params.gas = U256::from(100_000); params.code = Some(code.clone()); @@ -789,7 +796,7 @@ mod tests { let address = contract_address(&sender, &U256::zero()); // TODO: add tests for 'callcreate' //let next_address = contract_address(&address, &U256::zero()); - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); params.address = address.clone(); params.sender = sender.clone(); params.origin = sender.clone(); diff --git a/src/externalities.rs b/src/externalities.rs index 8b16cc72b..110b965d7 100644 --- a/src/externalities.rs +++ b/src/externalities.rs @@ -17,6 +17,7 @@ pub enum OutputPolicy<'a> { /// Transaction properties that externalities need to know about. pub struct OriginInfo { + sender: Address, address: Address, origin: Address, gas_price: U256 @@ -26,6 +27,7 @@ impl OriginInfo { /// Populates origin info from action params. pub fn from(params: &ActionParams) -> Self { OriginInfo { + sender: params.sender.clone(), address: params.address.clone(), origin: params.origin.clone(), gas_price: params.gas_price.clone() @@ -112,6 +114,7 @@ impl<'a> Ext for Externalities<'a> { gas: *gas, gas_price: self.origin_info.gas_price.clone(), value: value.clone(), + is_value_transfer: true, code: Some(code.to_vec()), data: None, }; @@ -129,6 +132,34 @@ impl<'a> Ext for Externalities<'a> { } } + fn delegatecall(&mut self, + gas: &U256, + value: &U256, + data: &[u8], + code_address: &Address, + output: &mut [u8]) -> MessageCallResult { + + let params = ActionParams { + code_address: code_address.clone(), + address: self.origin_info.address.clone(), + sender: self.origin_info.sender.clone(), + origin: self.origin_info.origin.clone(), + gas: *gas, + gas_price: self.origin_info.gas_price.clone(), + value: value.clone(), + is_value_transfer: false, + code: self.state.code(code_address), + data: Some(data.to_vec()), + }; + + let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth); + + match ex.call(params, self.substate, BytesRef::Fixed(output)) { + Ok(gas_left) => MessageCallResult::Success(gas_left), + _ => MessageCallResult::Failed + } + } + fn call(&mut self, gas: &U256, address: &Address, @@ -145,6 +176,7 @@ impl<'a> Ext for Externalities<'a> { gas: *gas, gas_price: self.origin_info.gas_price.clone(), value: value.clone(), + is_value_transfer: true, code: self.state.code(code_address), data: Some(data.to_vec()), }; diff --git a/src/tests/executive.rs b/src/tests/executive.rs index fe428e199..ca18850c4 100644 --- a/src/tests/executive.rs +++ b/src/tests/executive.rs @@ -115,6 +115,22 @@ impl<'a> Ext for TestExt<'a> { MessageCallResult::Success(*gas) } + fn delegatecall(&mut self, + gas: &U256, + value: &U256, + data: &[u8], + _code_address: &Address, + _output: &mut [u8]) -> MessageCallResult { + + self.callcreates.push(CallCreate { + data: data.to_vec(), + destination: None, + gas_limit: *gas, + value: *value + }); + MessageCallResult::Success(*gas) + } + fn extcode(&self, address: &Address) -> Bytes { self.ext.extcode(address) } @@ -200,7 +216,7 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec { let engine = TestEngine::new(1, vm.clone()); // params - let mut params = ActionParams::new(); + let mut params = ActionParams::default(); test.find("exec").map(|exec| { params.address = xjson!(&exec["address"]); params.sender = xjson!(&exec["caller"]); From 8084e1b6d7288db1c6e6f91d8f1ffdb138217ab2 Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Wed, 20 Jan 2016 17:01:58 +0100 Subject: [PATCH 02/23] Removing value from delegatecall function --- src/evm/ext.rs | 1 - src/evm/interpreter.rs | 4 +--- src/evm/tests.rs | 1 - src/externalities.rs | 5 +++-- src/tests/executive.rs | 3 +-- 5 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/evm/ext.rs b/src/evm/ext.rs index b7bf609ca..7e2f0f47f 100644 --- a/src/evm/ext.rs +++ b/src/evm/ext.rs @@ -68,7 +68,6 @@ pub trait Ext { /// and true if subcall was successfull. fn delegatecall(&mut self, gas: &U256, - value: &U256, data: &[u8], code_address: &Address, output: &mut [u8]) -> MessageCallResult; diff --git a/src/evm/interpreter.rs b/src/evm/interpreter.rs index c7d2bfda8..a5e8efc91 100644 --- a/src/evm/interpreter.rs +++ b/src/evm/interpreter.rs @@ -569,8 +569,6 @@ impl Interpreter { let code_address = stack.pop_back(); let code_address = u256_to_address(&code_address); - let value = params.value; - let in_off = stack.pop_back(); let in_size = stack.pop_back(); let out_off = stack.pop_back(); @@ -587,7 +585,7 @@ impl Interpreter { // and we don't want to copy let input = unsafe { ::std::mem::transmute(mem.read_slice(in_off, in_size)) }; let output = mem.writeable_slice(out_off, out_size); - ext.delegatecall(&call_gas, &value, input, &code_address, output) + ext.delegatecall(&call_gas, input, &code_address, output) }; return match call_result { diff --git a/src/evm/tests.rs b/src/evm/tests.rs index 7eb9d484c..83c58bbf8 100644 --- a/src/evm/tests.rs +++ b/src/evm/tests.rs @@ -71,7 +71,6 @@ impl Ext for FakeExt { fn delegatecall(&mut self, _gas: &U256, - _value: &U256, _data: &[u8], _address: &Address, _output: &mut [u8]) -> MessageCallResult { diff --git a/src/externalities.rs b/src/externalities.rs index 110b965d7..20326fe03 100644 --- a/src/externalities.rs +++ b/src/externalities.rs @@ -18,6 +18,7 @@ pub enum OutputPolicy<'a> { /// Transaction properties that externalities need to know about. pub struct OriginInfo { sender: Address, + value: U256, address: Address, origin: Address, gas_price: U256 @@ -28,6 +29,7 @@ impl OriginInfo { pub fn from(params: &ActionParams) -> Self { OriginInfo { sender: params.sender.clone(), + value: params.value.clone(), address: params.address.clone(), origin: params.origin.clone(), gas_price: params.gas_price.clone() @@ -134,7 +136,6 @@ impl<'a> Ext for Externalities<'a> { fn delegatecall(&mut self, gas: &U256, - value: &U256, data: &[u8], code_address: &Address, output: &mut [u8]) -> MessageCallResult { @@ -146,7 +147,7 @@ impl<'a> Ext for Externalities<'a> { origin: self.origin_info.origin.clone(), gas: *gas, gas_price: self.origin_info.gas_price.clone(), - value: value.clone(), + value: self.origin_info.value.clone(), is_value_transfer: false, code: self.state.code(code_address), data: Some(data.to_vec()), diff --git a/src/tests/executive.rs b/src/tests/executive.rs index ca18850c4..17cfb7df5 100644 --- a/src/tests/executive.rs +++ b/src/tests/executive.rs @@ -117,7 +117,6 @@ impl<'a> Ext for TestExt<'a> { fn delegatecall(&mut self, gas: &U256, - value: &U256, data: &[u8], _code_address: &Address, _output: &mut [u8]) -> MessageCallResult { @@ -126,7 +125,7 @@ impl<'a> Ext for TestExt<'a> { data: data.to_vec(), destination: None, gas_limit: *gas, - value: *value + value: U256::zero() }); MessageCallResult::Success(*gas) } From cd9a0e4e588215b6e2839c9e8475b0ddecab3c38 Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Wed, 20 Jan 2016 17:27:33 +0100 Subject: [PATCH 03/23] Changing is_value_transfer to enum --- src/action_params.rs | 19 ++++++++++++------- src/evm/interpreter.rs | 5 ++++- src/executive.rs | 14 ++++++-------- src/externalities.rs | 16 ++++++++-------- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/action_params.rs b/src/action_params.rs index 6f876874b..a56e64f4d 100644 --- a/src/action_params.rs +++ b/src/action_params.rs @@ -3,8 +3,16 @@ use util::hash::*; use util::uint::*; use util::bytes::*; -// TODO: should be a trait, possible to avoid cloning everything from a Transaction(/View). +/// Transaction value +#[derive(Clone, Debug)] +pub enum ActionValue { + /// Value that should be transfered + Transfer(U256), + /// Apparent value for transaction (not transfered) + Apparent(U256) +} +// TODO: should be a trait, possible to avoid cloning everything from a Transaction(/View). /// Action (call/create) input params. Everything else should be specified in Externalities. #[derive(Clone, Debug)] pub struct ActionParams { @@ -22,9 +30,7 @@ pub struct ActionParams { /// Gas price. pub gas_price: U256, /// Transaction value. - pub value: U256, - /// Should transfer value from sender to origin - pub is_value_transfer: bool, + pub value: ActionValue, /// Code being executed. pub code: Option, /// Input data. @@ -41,10 +47,9 @@ impl Default for ActionParams { origin: Address::new(), gas: U256::zero(), gas_price: U256::zero(), - value: U256::zero(), + value: ActionValue::Transfer(U256::zero()), code: None, - data: None, - is_value_transfer: true + data: None } } } diff --git a/src/evm/interpreter.rs b/src/evm/interpreter.rs index a5e8efc91..52509a2c0 100644 --- a/src/evm/interpreter.rs +++ b/src/evm/interpreter.rs @@ -741,7 +741,10 @@ impl Interpreter { stack.push(address_to_u256(params.sender.clone())); }, instructions::CALLVALUE => { - stack.push(params.value.clone()); + stack.push(match params.value { + ActionValue::Transfer(val) => val, + ActionValue::Apparent(val) => val, + }); }, instructions::CALLDATALOAD => { let big_id = stack.pop_back(); diff --git a/src/executive.rs b/src/executive.rs index ea1a8f6de..dd61a5b97 100644 --- a/src/executive.rs +++ b/src/executive.rs @@ -133,8 +133,7 @@ impl<'a> Executive<'a> { origin: sender.clone(), gas: init_gas, gas_price: t.gas_price, - value: t.value, - is_value_transfer: true, + value: ActionValue::Transfer(t.value), code: Some(t.data.clone()), data: None, }; @@ -148,8 +147,7 @@ impl<'a> Executive<'a> { origin: sender.clone(), gas: init_gas, gas_price: t.gas_price, - value: t.value, - is_value_transfer: true, + value: ActionValue::Transfer(t.value), code: self.state.code(address), data: Some(t.data.clone()), }; @@ -173,8 +171,8 @@ impl<'a> Executive<'a> { let backup = self.state.clone(); // at first, transfer value to destination - if params.is_value_transfer { - self.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value); + if let ActionValue::Transfer(val) = params.value { + self.state.transfer_balance(¶ms.sender, ¶ms.address, &val); } trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info); @@ -232,8 +230,8 @@ impl<'a> Executive<'a> { self.state.new_contract(¶ms.address); // then transfer value to it - if params.is_value_transfer { - self.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value); + if let ActionValue::Transfer(val) = params.value { + self.state.transfer_balance(¶ms.sender, ¶ms.address, &val); } let res = { diff --git a/src/externalities.rs b/src/externalities.rs index 20326fe03..a9a14c5c2 100644 --- a/src/externalities.rs +++ b/src/externalities.rs @@ -29,10 +29,13 @@ impl OriginInfo { pub fn from(params: &ActionParams) -> Self { OriginInfo { sender: params.sender.clone(), - value: params.value.clone(), address: params.address.clone(), origin: params.origin.clone(), - gas_price: params.gas_price.clone() + gas_price: params.gas_price.clone(), + value: match params.value { + ActionValue::Transfer(val) => val, + ActionValue::Apparent(val) => val, + } } } } @@ -115,8 +118,7 @@ impl<'a> Ext for Externalities<'a> { origin: self.origin_info.origin.clone(), gas: *gas, gas_price: self.origin_info.gas_price.clone(), - value: value.clone(), - is_value_transfer: true, + value: ActionValue::Transfer(value.clone()), code: Some(code.to_vec()), data: None, }; @@ -147,8 +149,7 @@ impl<'a> Ext for Externalities<'a> { origin: self.origin_info.origin.clone(), gas: *gas, gas_price: self.origin_info.gas_price.clone(), - value: self.origin_info.value.clone(), - is_value_transfer: false, + value: ActionValue::Apparent(self.origin_info.value.clone()), code: self.state.code(code_address), data: Some(data.to_vec()), }; @@ -176,8 +177,7 @@ impl<'a> Ext for Externalities<'a> { origin: self.origin_info.origin.clone(), gas: *gas, gas_price: self.origin_info.gas_price.clone(), - value: value.clone(), - is_value_transfer: true, + value: ActionValue::Transfer(value.clone()), code: self.state.code(code_address), data: Some(data.to_vec()), }; From 651d2d66e04240862df7b00ff0bd765c9a354ac6 Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Wed, 20 Jan 2016 17:31:37 +0100 Subject: [PATCH 04/23] Fixing tests --- src/executive.rs | 12 ++++++------ src/tests/executive.rs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/executive.rs b/src/executive.rs index dd61a5b97..f5fa9cbc7 100644 --- a/src/executive.rs +++ b/src/executive.rs @@ -377,7 +377,7 @@ mod tests { params.sender = sender.clone(); params.gas = U256::from(100_000); params.code = Some("3331600055".from_hex().unwrap()); - params.value = U256::from(0x7); + params.value = ActionValue::Transfer(U256::from(0x7)); let mut state = State::new_temp(); state.add_balance(&sender, &U256::from(0x100u64)); let info = EnvInfo::new(); @@ -435,7 +435,7 @@ mod tests { params.origin = sender.clone(); params.gas = U256::from(100_000); params.code = Some(code.clone()); - params.value = U256::from(100); + params.value = ActionValue::Transfer(U256::from(100)); let mut state = State::new_temp(); state.add_balance(&sender, &U256::from(100)); let info = EnvInfo::new(); @@ -488,7 +488,7 @@ mod tests { params.origin = sender.clone(); params.gas = U256::from(100_000); params.code = Some(code.clone()); - params.value = U256::from(100); + params.value = ActionValue::Transfer(U256::from(100)); let mut state = State::new_temp(); state.add_balance(&sender, &U256::from(100)); let info = EnvInfo::new(); @@ -539,7 +539,7 @@ mod tests { params.origin = sender.clone(); params.gas = U256::from(100_000); params.code = Some(code.clone()); - params.value = U256::from(100); + params.value = ActionValue::Transfer(U256::from(100)); let mut state = State::new_temp(); state.add_balance(&sender, &U256::from(100)); let info = EnvInfo::new(); @@ -594,7 +594,7 @@ mod tests { params.sender = sender.clone(); params.gas = U256::from(100_000); params.code = Some(code_a.clone()); - params.value = U256::from(100_000); + params.value = ActionValue::Transfer(U256::from(100_000)); let mut state = State::new_temp(); state.init_code(&address_a, code_a.clone()); @@ -800,7 +800,7 @@ mod tests { params.origin = sender.clone(); params.gas = U256::from(0x0186a0); params.code = Some(code.clone()); - params.value = U256::from_str("0de0b6b3a7640000").unwrap(); + params.value = ActionValue::Transfer(U256::from_str("0de0b6b3a7640000").unwrap()); let mut state = State::new_temp(); state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap()); let info = EnvInfo::new(); diff --git a/src/tests/executive.rs b/src/tests/executive.rs index 17cfb7df5..bc88a4697 100644 --- a/src/tests/executive.rs +++ b/src/tests/executive.rs @@ -224,7 +224,7 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec { params.data = xjson!(&exec["data"]); params.gas = xjson!(&exec["gas"]); params.gas_price = xjson!(&exec["gasPrice"]); - params.value = xjson!(&exec["value"]); + params.value = ActionValue::Transfer(xjson!(&exec["value"])); }); let out_of_gas = test.find("callcreates").map(|_calls| { From e27d628e753a94924cb32e698fc9e2ef022fe0a7 Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Sat, 23 Jan 2016 10:41:13 +0100 Subject: [PATCH 05/23] Changing delegatecall logic --- Cargo.toml | 2 +- src/evm/ext.rs | 16 +++----------- src/evm/interpreter.rs | 14 ++++++------ src/evm/tests.rs | 13 +++-------- src/externalities.rs | 49 +++++++++++------------------------------- src/tests/executive.rs | 20 +++-------------- 6 files changed, 30 insertions(+), 84 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 714af5693..d8c92e0aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ evmjit = { path = "rust-evmjit", optional = true } ethash = { path = "ethash" } num_cpus = "0.2" ctrlc = "1.0" -clippy = "*" # Always newest, since we use nightly +clippy = "0.0.37" # Always newest, since we use nightly [features] jit = ["evmjit"] diff --git a/src/evm/ext.rs b/src/evm/ext.rs index 7e2f0f47f..748bc89da 100644 --- a/src/evm/ext.rs +++ b/src/evm/ext.rs @@ -55,19 +55,9 @@ pub trait Ext { /// and true if subcall was successfull. fn call(&mut self, gas: &U256, - address: &Address, - value: &U256, - data: &[u8], - code_address: &Address, - output: &mut [u8]) -> MessageCallResult; - - /// Delegate Message call. - /// - /// Returns Err, if we run out of gas. - /// Otherwise returns call_result which contains gas left - /// and true if subcall was successfull. - fn delegatecall(&mut self, - gas: &U256, + sender_address: &Address, + receive_address: &Address, + value: Option<&U256>, data: &[u8], code_address: &Address, output: &mut [u8]) -> MessageCallResult; diff --git a/src/evm/interpreter.rs b/src/evm/interpreter.rs index 7f0db421d..276f2873b 100644 --- a/src/evm/interpreter.rs +++ b/src/evm/interpreter.rs @@ -587,7 +587,7 @@ impl Interpreter { // and we don't want to copy let input = unsafe { ::std::mem::transmute(mem.read_slice(in_off, in_size)) }; let output = mem.writeable_slice(out_off, out_size); - ext.delegatecall(&call_gas, input, &code_address, output) + ext.call(&call_gas, ¶ms.sender, ¶ms.address, None, input, &code_address, output) }; return match call_result { @@ -609,11 +609,6 @@ impl Interpreter { let value = stack.pop_back(); - let address = match instruction == instructions::CALL { - true => &code_address, - false => ¶ms.address - }; - let in_off = stack.pop_back(); let in_size = stack.pop_back(); let out_off = stack.pop_back(); @@ -624,6 +619,11 @@ impl Interpreter { false => U256::zero() }; + let (sender_address, receive_address) = match instruction == instructions::CALL { + true => (¶ms.address, &code_address), + false => (¶ms.address, ¶ms.address) + }; + let can_call = ext.balance(¶ms.address) >= value && ext.depth() < ext.schedule().max_depth; if !can_call { @@ -636,7 +636,7 @@ impl Interpreter { // and we don't want to copy let input = unsafe { ::std::mem::transmute(mem.read_slice(in_off, in_size)) }; let output = mem.writeable_slice(out_off, out_size); - ext.call(&call_gas, address, &value, input, &code_address, output) + ext.call(&call_gas, sender_address, receive_address, Some(&value), input, &code_address, output) }; return match call_result { diff --git a/src/evm/tests.rs b/src/evm/tests.rs index aaf082093..cf4262914 100644 --- a/src/evm/tests.rs +++ b/src/evm/tests.rs @@ -61,22 +61,15 @@ impl Ext for FakeExt { fn call(&mut self, _gas: &U256, - _address: &Address, - _value: &U256, + _sender_address: &Address, + _receive_address: &Address, + _value: Option<&U256>, _data: &[u8], _code_address: &Address, _output: &mut [u8]) -> MessageCallResult { unimplemented!(); } - fn delegatecall(&mut self, - _gas: &U256, - _data: &[u8], - _address: &Address, - _output: &mut [u8]) -> MessageCallResult { - unimplemented!(); - } - fn extcode(&self, address: &Address) -> Bytes { self.codes.get(address).unwrap_or(&Bytes::new()).clone() } diff --git a/src/externalities.rs b/src/externalities.rs index 293a60999..d8b5d6110 100644 --- a/src/externalities.rs +++ b/src/externalities.rs @@ -17,18 +17,16 @@ pub enum OutputPolicy<'a> { /// Transaction properties that externalities need to know about. pub struct OriginInfo { - sender: Address, - value: U256, address: Address, origin: Address, - gas_price: U256 + gas_price: U256, + value: U256 } impl OriginInfo { /// Populates origin info from action params. pub fn from(params: &ActionParams) -> Self { OriginInfo { - sender: params.sender.clone(), address: params.address.clone(), origin: params.origin.clone(), gas_price: params.gas_price.clone(), @@ -136,52 +134,31 @@ impl<'a> Ext for Externalities<'a> { } } - fn delegatecall(&mut self, - gas: &U256, - data: &[u8], - code_address: &Address, - output: &mut [u8]) -> MessageCallResult { - - let params = ActionParams { - code_address: code_address.clone(), - address: self.origin_info.address.clone(), - sender: self.origin_info.sender.clone(), - origin: self.origin_info.origin.clone(), - gas: *gas, - gas_price: self.origin_info.gas_price.clone(), - value: ActionValue::Apparent(self.origin_info.value.clone()), - code: self.state.code(code_address), - data: Some(data.to_vec()), - }; - - let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth); - - match ex.call(params, self.substate, BytesRef::Fixed(output)) { - Ok(gas_left) => MessageCallResult::Success(gas_left), - _ => MessageCallResult::Failed - } - } - fn call(&mut self, gas: &U256, - address: &Address, - value: &U256, + sender_address: &Address, + receive_address: &Address, + value: Option<&U256>, data: &[u8], code_address: &Address, output: &mut [u8]) -> MessageCallResult { - let params = ActionParams { + let mut params = ActionParams { + sender: sender_address.clone(), + address: receive_address.clone(), + value: ActionValue::Apparent(self.origin_info.value.clone()), code_address: code_address.clone(), - address: address.clone(), - sender: self.origin_info.address.clone(), origin: self.origin_info.origin.clone(), gas: *gas, gas_price: self.origin_info.gas_price.clone(), - value: ActionValue::Transfer(value.clone()), code: self.state.code(code_address), data: Some(data.to_vec()), }; + if let Some(value) = value { + params.value = ActionValue::Transfer(value.clone()); + } + let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth); match ex.call(params, self.substate, BytesRef::Fixed(output)) { diff --git a/src/tests/executive.rs b/src/tests/executive.rs index cfca30740..0604c9992 100644 --- a/src/tests/executive.rs +++ b/src/tests/executive.rs @@ -101,8 +101,9 @@ impl<'a> Ext for TestExt<'a> { fn call(&mut self, gas: &U256, + _sender_address: &Address, receive_address: &Address, - value: &U256, + value: Option<&U256>, data: &[u8], _code_address: &Address, _output: &mut [u8]) -> MessageCallResult { @@ -110,22 +111,7 @@ impl<'a> Ext for TestExt<'a> { data: data.to_vec(), destination: Some(receive_address.clone()), gas_limit: *gas, - value: *value - }); - MessageCallResult::Success(*gas) - } - - fn delegatecall(&mut self, - gas: &U256, - data: &[u8], - _code_address: &Address, - _output: &mut [u8]) -> MessageCallResult { - - self.callcreates.push(CallCreate { - data: data.to_vec(), - destination: None, - gas_limit: *gas, - value: U256::zero() + value: *value.unwrap() }); MessageCallResult::Success(*gas) } From 58bda2209c70783de13d5eee0c66078959bdbef5 Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Sat, 23 Jan 2016 10:42:25 +0100 Subject: [PATCH 06/23] Reverting clippy wildcard --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d8c92e0aa..714af5693 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ evmjit = { path = "rust-evmjit", optional = true } ethash = { path = "ethash" } num_cpus = "0.2" ctrlc = "1.0" -clippy = "0.0.37" # Always newest, since we use nightly +clippy = "*" # Always newest, since we use nightly [features] jit = ["evmjit"] From 018abc9dcdf610dc7d88e50a30af526492a19179 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 25 Jan 2016 11:54:15 +0100 Subject: [PATCH 07/23] Autogenerate the Args from the docopt macro. --- Cargo.toml | 1 + res/ethereum/tests | 2 +- src/bin/client/main.rs | 29 +++++++++-------------------- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 82658c6ac..54b1b406e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ evmjit = { path = "rust-evmjit", optional = true } ethash = { path = "ethash" } num_cpus = "0.2" docopt = "0.6" +docopt_macros = "0.6" ctrlc = "1.0" clippy = "0.0.37" diff --git a/res/ethereum/tests b/res/ethereum/tests index e838fd909..dc86e6359 160000 --- a/res/ethereum/tests +++ b/res/ethereum/tests @@ -1 +1 @@ -Subproject commit e838fd90998fc5502d0b7c9427a4c231f9a6953d +Subproject commit dc86e6359675440aea59ddb48648a01c799925d8 diff --git a/src/bin/client/main.rs b/src/bin/client/main.rs index 31bb79d8e..45f45daf7 100644 --- a/src/bin/client/main.rs +++ b/src/bin/client/main.rs @@ -1,7 +1,5 @@ #![feature(plugin)] -// TODO: uncomment once this can be made to work. -//#![plugin(docopt_macros)] - +#![plugin(docopt_macros)] extern crate docopt; extern crate rustc_serialize; extern crate ethcore_util as util; @@ -20,9 +18,8 @@ use ethcore::service::{ClientService, NetSyncMessage}; use ethcore::ethereum; use ethcore::blockchain::CacheSize; use ethcore::sync::EthSync; -use docopt::Docopt; -const USAGE: &'static str = " +docopt!(Args derive Debug, " Parity. Ethereum Client. Usage: @@ -32,15 +29,9 @@ Usage: Options: -l --logging LOGGING Specify the logging level -h --help Show this screen. -"; +"); -#[derive(Debug, RustcDecodable)] -struct Args { - arg_enode: Option>, - flag_logging: Option, -} - -fn setup_log(init: &Option) { +fn setup_log(init: &String) { let mut builder = LogBuilder::new(); builder.filter(None, LogLevelFilter::Info); @@ -48,22 +39,20 @@ fn setup_log(init: &Option) { builder.parse(&env::var("RUST_LOG").unwrap()); } - if let &Some(ref x) = init { - builder.parse(x); - } + builder.parse(init); builder.init().unwrap(); } fn main() { - let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit()); + let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit()); setup_log(&args.flag_logging); let spec = ethereum::new_frontier(); - let init_nodes = match &args.arg_enode { - &None => spec.nodes().clone(), - &Some(ref enodes) => enodes.clone(), + let init_nodes = match args.arg_enode.len() { + 0 => spec.nodes().clone(), + _ => args.arg_enode.clone(), }; let mut net_settings = NetworkConfiguration::new(); net_settings.boot_nodes = init_nodes; From e61d1f810ee6d3b87c2df91521272f6197a144d0 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 25 Jan 2016 13:39:15 +0100 Subject: [PATCH 08/23] U256<->H256 conversion --- util/src/hash.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/util/src/hash.rs b/util/src/hash.rs index 252877a24..0e4139f3c 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -469,6 +469,18 @@ impl<'_> From<&'_ U256> for H256 { } } +impl From for U256 { + fn from(value: H256) -> U256 { + U256::from(value.bytes()) + } +} + +impl<'_> From<&'_ H256> for U256 { + fn from(value: &'_ H256) -> U256 { + U256::from(value.bytes()) + } +} + impl From for Address { fn from(value: H256) -> Address { unsafe { @@ -562,6 +574,7 @@ pub static ZERO_H256: H256 = H256([0x00; 32]); #[cfg(test)] mod tests { use hash::*; + use uint::*; use std::str::FromStr; #[test] @@ -635,5 +648,18 @@ mod tests { // too short. assert_eq!(H64::from(0), H64::from("0x34567890abcdef")); } + + #[test] + fn from_and_to_u256() { + let u: U256 = x!(0x123456789abcdef0u64); + let h = H256::from(u); + assert_eq!(H256::from(u), H256::from("000000000000000000000000000000000000000000000000123456789abcdef0")); + let h_ref = H256::from(&u); + assert_eq!(h, h_ref); + let r_ref: U256 = From::from(&h); + assert_eq!(r_ref, u); + let r: U256 = From::from(h); + assert_eq!(r, u); + } } From 499da19d825d586ac3e82a97d8ff2304333cb726 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 25 Jan 2016 18:56:36 +0100 Subject: [PATCH 09/23] Initial draft of blockchain tests. --- src/block_queue.rs | 7 +++++ src/blockchain.rs | 8 ----- src/client.rs | 22 +++++++++---- src/pod_state.rs | 12 ++++++-- src/spec.rs | 73 ++++++++++++++++++++++---------------------- src/state.rs | 2 +- src/state_diff.rs | 14 ++++----- src/tests/chain.rs | 49 +++++++++++++++++++++++++++++ src/tests/mod.rs | 1 + util/src/standard.rs | 9 +++--- 10 files changed, 133 insertions(+), 64 deletions(-) create mode 100644 src/tests/chain.rs diff --git a/src/block_queue.rs b/src/block_queue.rs index 239c559c5..36539bfff 100644 --- a/src/block_queue.rs +++ b/src/block_queue.rs @@ -21,6 +21,11 @@ pub struct BlockQueueInfo { pub verified_queue_size: usize, } +impl BlockQueueInfo { + /// The total size of the queues. + pub fn total_queue_size(&self) -> usize { self.unverified_queue_size + self.verified_queue_size } +} + /// A queue of blocks. Sits between network or other I/O and the BlockChain. /// Sorts them ready for blockchain insertion. pub struct BlockQueue { @@ -99,6 +104,7 @@ impl BlockQueue { fn verify(verification: Arc>, engine: Arc>, wait: Arc, ready: Arc, deleting: Arc) { while !deleting.load(AtomicOrdering::Relaxed) { + { let mut lock = verification.lock().unwrap(); while lock.unverified.is_empty() && !deleting.load(AtomicOrdering::Relaxed) { @@ -139,6 +145,7 @@ impl BlockQueue { }, Err(err) => { let mut v = verification.lock().unwrap(); + flushln!("Stage 2 block verification failed for {}\nError: {:?}", block_hash, err); warn!(target: "client", "Stage 2 block verification failed for {}\nError: {:?}", block_hash, err); v.bad.insert(block_hash.clone()); v.verifying.retain(|e| e.hash != block_hash); diff --git a/src/blockchain.rs b/src/blockchain.rs index 39390de97..3bd31688a 100644 --- a/src/blockchain.rs +++ b/src/blockchain.rs @@ -283,13 +283,6 @@ impl BlockChain { bc } - /// Ensure that the best block does indeed have a state_root in the state DB. - /// If it doesn't, then rewind down until we find one that does and delete data to ensure that - /// later blocks will be reimported. - pub fn ensure_good(&mut self, _state: &JournalDB) { - unimplemented!(); - } - /// Returns a tree route between `from` and `to`, which is a tuple of: /// /// - a vector of hashes of all blocks, ordered from `from` to `to`. @@ -392,7 +385,6 @@ impl BlockChain { } } - /// Inserts the block into backing cache database. /// Expects the block to be valid and already verified. /// If the block is already known, does nothing. diff --git a/src/client.rs b/src/client.rs index 4461f3d7b..795bca546 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,3 +1,5 @@ +use std::thread; +use std::time; use util::*; use rocksdb::{Options, DB}; use blockchain::{BlockChain, BlockProvider, CacheSize}; @@ -121,6 +123,7 @@ impl ClientReport { } /// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue. +/// Call `import_block()` to import a block asynchronously; `flush_queue()` flushes the queue. pub struct Client { chain: Arc>, engine: Arc>, @@ -140,7 +143,8 @@ impl Client { let mut opts = Options::new(); opts.set_max_open_files(256); opts.create_if_missing(true); - /*opts.set_use_fsync(false); + opts.set_use_fsync(false); + /* opts.set_bytes_per_sync(8388608); opts.set_disable_data_sync(false); opts.set_block_cache_size_mb(1024); @@ -177,16 +181,22 @@ impl Client { })) } + /// Flush the block import queue. + pub fn flush_queue(&self) { + flushln!("Flushing queue {:?}", self.block_queue.read().unwrap().queue_info()); + while self.block_queue.read().unwrap().queue_info().unverified_queue_size > 0 { + thread::sleep(time::Duration::from_millis(20)); + flushln!("Flushing queue [waited] {:?}", self.block_queue.read().unwrap().queue_info()); + } + } + /// This is triggered by a message coming from a block queue when the block is ready for insertion pub fn import_verified_blocks(&self, _io: &IoChannel) { let mut bad = HashSet::new(); let _import_lock = self.import_lock.lock(); - let blocks = self.block_queue.write().unwrap().drain(128); - if blocks.is_empty() { - return; - } - for block in blocks { + for block in self.block_queue.write().unwrap().drain(128) { + flushln!("Importing block..."); if bad.contains(&block.header.parent_hash) { self.block_queue.write().unwrap().mark_as_bad(&block.header.hash()); bad.insert(block.header.hash()); diff --git a/src/pod_state.rs b/src/pod_state.rs index 1ea8382a5..15ae6a8ae 100644 --- a/src/pod_state.rs +++ b/src/pod_state.rs @@ -1,17 +1,25 @@ use util::*; use pod_account::*; -#[derive(Debug,Clone,PartialEq,Eq)] +#[derive(Debug,Clone,PartialEq,Eq,Default)] /// TODO [Gav Wood] Please document me pub struct PodState (BTreeMap); impl PodState { /// Contruct a new object from the `m`. - pub fn new(m: BTreeMap) -> PodState { PodState(m) } + pub fn new() -> PodState { Default::default() } + + /// Contruct a new object from the `m`. + pub fn from(m: BTreeMap) -> PodState { PodState(m) } /// Get the underlying map. pub fn get(&self) -> &BTreeMap { &self.0 } + /// Get the root hash of the trie of the RLP of this. + pub fn root(&self) -> H256 { + sec_trie_root(self.0.iter().map(|(k, v)| (k.to_vec(), v.rlp())).collect()) + } + /// Drain object to get the underlying map. pub fn drain(self) -> BTreeMap { self.0 } } diff --git a/src/spec.rs b/src/spec.rs index 9f98d5e2a..9e97595b9 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -1,6 +1,7 @@ use common::*; use flate2::read::GzDecoder; use engine::*; +use pod_state::*; use null_engine::*; /// Converts file from base64 gzipped bytes to json @@ -40,28 +41,6 @@ fn json_to_rlp_map(json: &Json) -> HashMap { }) } -//TODO: add code and data -#[derive(Debug)] -/// Genesis account data. Does no thave a DB overlay cache -pub struct GenesisAccount { - // Balance of the account. - balance: U256, - // Nonce of the account. - nonce: U256, -} - -impl GenesisAccount { - /// TODO [arkpar] Please document me - pub fn rlp(&self) -> Bytes { - let mut stream = RlpStream::new_list(4); - stream.append(&self.nonce); - stream.append(&self.balance); - stream.append(&SHA3_NULL_RLP); - stream.append(&SHA3_EMPTY); - stream.out() - } -} - /// Parameters for a block chain; includes both those intrinsic to the design of the /// chain and those to be interpreted by the active chain engine. #[derive(Debug)] @@ -83,7 +62,7 @@ pub struct Spec { // Builtin-contracts are here for now but would like to abstract into Engine API eventually. /// TODO [Gav Wood] Please document me - pub builtins: HashMap, + pub builtins: BTreeMap, // Genesis params. /// TODO [Gav Wood] Please document me @@ -101,7 +80,7 @@ pub struct Spec { /// TODO [arkpar] Please document me pub extra_data: Bytes, /// TODO [Gav Wood] Please document me - pub genesis_state: HashMap, + pub genesis_state: PodState, /// TODO [Gav Wood] Please document me pub seal_fields: usize, /// TODO [Gav Wood] Please document me @@ -126,7 +105,7 @@ impl Spec { /// Return the state root for the genesis state, memoising accordingly. pub fn state_root(&self) -> H256 { if self.state_root_memo.read().unwrap().is_none() { - *self.state_root_memo.write().unwrap() = Some(sec_trie_root(self.genesis_state.iter().map(|(k, v)| (k.to_vec(), v.rlp())).collect())); + *self.state_root_memo.write().unwrap() = Some(self.genesis_state.root()); } self.state_root_memo.read().unwrap().as_ref().unwrap().clone() } @@ -174,6 +153,35 @@ impl Spec { ret.append_raw(&empty_list, 1); ret.out() } + + /// Overwrite the genesis components with the given JSON, assuming standard Ethereum test format. + pub fn overwrite_genesis(&mut self, genesis: &Json) { + let (seal_fields, seal_rlp) = { + if genesis.find("mixHash").is_some() && genesis.find("nonce").is_some() { + let mut s = RlpStream::new(); + s.append(&H256::from_json(&genesis["mixHash"])); + s.append(&H64::from_json(&genesis["nonce"])); + (2, s.out()) + } else { + // backup algo that will work with sealFields/sealRlp (and without). + ( + u64::from_json(&genesis["sealFields"]) as usize, + Bytes::from_json(&genesis["sealRlp"]) + ) + } + }; + + self.parent_hash = H256::from_json(&genesis["parentHash"]); + self.author = Address::from_json(&genesis["coinbase"]); + self.difficulty = U256::from_json(&genesis["difficulty"]); + self.gas_limit = U256::from_json(&genesis["gasLimit"]); + self.gas_used = U256::from_json(&genesis["gasUsed"]); + self.timestamp = u64::from_json(&genesis["timestamp"]); + self.extra_data = Bytes::from_json(&genesis["extraData"]); + self.seal_fields = seal_fields; + self.seal_rlp = seal_rlp; + self.state_root_memo = RwLock::new(genesis.find("stateRoot").and_then(|_| Some(H256::from_json(&genesis["stateRoot"])))); + } } impl FromJson for Spec { @@ -181,8 +189,8 @@ impl FromJson for Spec { fn from_json(json: &Json) -> Spec { // once we commit ourselves to some json parsing library (serde?) // move it to proper data structure - let mut state = HashMap::new(); - let mut builtins = HashMap::new(); + let mut builtins = BTreeMap::new(); + let mut state = PodState::new(); if let Some(&Json::Object(ref accounts)) = json.find("accounts") { for (address, acc) in accounts.iter() { @@ -192,15 +200,8 @@ impl FromJson for Spec { builtins.insert(addr.clone(), builtin); } } - let balance = acc.find("balance").and_then(|x| match *x { Json::String(ref b) => U256::from_dec_str(b).ok(), _ => None }); - let nonce = acc.find("nonce").and_then(|x| match *x { Json::String(ref b) => U256::from_dec_str(b).ok(), _ => None }); -// let balance = if let Some(&Json::String(ref b)) = acc.find("balance") {U256::from_dec_str(b).unwrap_or(U256::from(0))} else {U256::from(0)}; -// let nonce = if let Some(&Json::String(ref n)) = acc.find("nonce") {U256::from_dec_str(n).unwrap_or(U256::from(0))} else {U256::from(0)}; - // TODO: handle code & data if they exist. - if balance.is_some() || nonce.is_some() { - state.insert(addr, GenesisAccount { balance: balance.unwrap_or_else(U256::zero), nonce: nonce.unwrap_or_else(U256::zero) }); - } } + state = xjson!(&json["accounts"]); } let nodes = if let Some(&Json::Array(ref ns)) = json.find("nodes") { @@ -253,7 +254,7 @@ impl Spec { let mut root = H256::new(); { let mut t = SecTrieDBMut::new(db, &mut root); - for (address, account) in &self.genesis_state { + for (address, account) in self.genesis_state.get().iter() { t.insert(address.as_slice(), &account.rlp()); } } diff --git a/src/state.rs b/src/state.rs index 4b7e5af34..6e5d586f3 100644 --- a/src/state.rs +++ b/src/state.rs @@ -221,7 +221,7 @@ impl State { /// Populate a PodAccount map from this state. pub fn to_pod(&self) -> PodState { // TODO: handle database rather than just the cache. - PodState::new(self.cache.borrow().iter().fold(BTreeMap::new(), |mut m, (add, opt)| { + PodState::from(self.cache.borrow().iter().fold(BTreeMap::new(), |mut m, (add, opt)| { if let Some(ref acc) = *opt { m.insert(add.clone(), PodAccount::from_account(acc)); } diff --git a/src/state_diff.rs b/src/state_diff.rs index 08fccf3ed..12e2d76ca 100644 --- a/src/state_diff.rs +++ b/src/state_diff.rs @@ -32,8 +32,8 @@ mod test { #[test] fn create_delete() { - let a = PodState::new(map![ x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]) ]); - assert_eq!(StateDiff::diff_pod(&a, &PodState::new(map![])), StateDiff(map![ + let a = PodState::from(map![ x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]) ]); + assert_eq!(StateDiff::diff_pod(&a, &PodState::new()), StateDiff(map![ x!(1) => AccountDiff{ balance: Diff::Died(x!(69)), nonce: Diff::Died(x!(0)), @@ -41,7 +41,7 @@ mod test { storage: map![], } ])); - assert_eq!(StateDiff::diff_pod(&PodState::new(map![]), &a), StateDiff(map![ + assert_eq!(StateDiff::diff_pod(&PodState::new(), &a), StateDiff(map![ x!(1) => AccountDiff{ balance: Diff::Born(x!(69)), nonce: Diff::Born(x!(0)), @@ -53,8 +53,8 @@ mod test { #[test] fn create_delete_with_unchanged() { - let a = PodState::new(map![ x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]) ]); - let b = PodState::new(map![ + let a = PodState::from(map![ x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]) ]); + let b = PodState::from(map![ x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]), x!(2) => PodAccount::new(x!(69), x!(0), vec![], map![]) ]); @@ -78,11 +78,11 @@ mod test { #[test] fn change_with_unchanged() { - let a = PodState::new(map![ + let a = PodState::from(map![ x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]), x!(2) => PodAccount::new(x!(69), x!(0), vec![], map![]) ]); - let b = PodState::new(map![ + let b = PodState::from(map![ x!(1) => PodAccount::new(x!(69), x!(1), vec![], map![]), x!(2) => PodAccount::new(x!(69), x!(0), vec![], map![]) ]); diff --git a/src/tests/chain.rs b/src/tests/chain.rs new file mode 100644 index 000000000..db3e398b0 --- /dev/null +++ b/src/tests/chain.rs @@ -0,0 +1,49 @@ +use std::env; +use super::test_common::*; +use client::{BlockChainClient,Client}; +use pod_state::*; +use ethereum; + +fn do_json_test(json_data: &[u8]) -> Vec { + let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid"); + let mut failed = Vec::new(); + + for (name, test) in json.as_object().unwrap() { + let mut fail = false; + { + let mut fail_unless = |cond: bool| if !cond && !fail { + failed.push(name.clone()); + flush(format!("FAIL\n")); + fail = true; + true + } else {false}; + + flush(format!(" - {}...", name)); + + let blocks: Vec = test["blocks"].as_array().unwrap().iter().map(|e| xjson!(&e["rlp"])).collect(); + let mut spec = ethereum::new_frontier_like_test(); + spec.overwrite_genesis(test.find("genesisBlockHeader").unwrap()); + spec.genesis_state = PodState::from_json(test.find("pre").unwrap()); + + let mut dir = env::temp_dir(); + dir.push(H32::random().hex()); + { + let client = Client::new(spec, &dir, IoChannel::disconnected()).unwrap(); + blocks.into_iter().foreach(|b| { + client.import_block(b).unwrap(); + }); + client.flush_queue(); + client.import_verified_blocks(&IoChannel::disconnected()); + flushln!("Best hash: {}", client.chain_info().best_block_hash); + } + fs::remove_dir_all(&dir).unwrap(); + } + if !fail { + flush(format!("ok\n")); + } + } + println!("!!! {:?} tests from failed.", failed.len()); + failed +} + +declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index c30f7f9b8..799c47230 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -4,3 +4,4 @@ mod test_common; mod transaction; mod executive; mod state; +mod chain; diff --git a/util/src/standard.rs b/util/src/standard.rs index 19a084a2c..873df6cb4 100644 --- a/util/src/standard.rs +++ b/util/src/standard.rs @@ -1,13 +1,14 @@ pub use std::io; +pub use std::fs; pub use std::str; pub use std::fmt; -pub use std::slice; pub use std::cmp; pub use std::ptr; -pub use std::result; -pub use std::option; pub use std::mem; pub use std::ops; +pub use std::slice; +pub use std::result; +pub use std::option; pub use std::path::Path; pub use std::str::{FromStr}; @@ -15,9 +16,9 @@ pub use std::io::{Read,Write}; pub use std::hash::{Hash, Hasher}; pub use std::error::Error as StdError; -pub use std::sync::*; pub use std::ops::*; pub use std::cmp::*; +pub use std::sync::*; pub use std::cell::*; pub use std::collections::*; From a43ca9ae34d7dcd299cd82bc1ee36ac15464f9bb Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 25 Jan 2016 19:20:34 +0100 Subject: [PATCH 10/23] blockqueue flush --- src/block_queue.rs | 22 +++++++++++++++++++--- src/client.rs | 7 +------ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/block_queue.rs b/src/block_queue.rs index 36539bfff..a0e46193b 100644 --- a/src/block_queue.rs +++ b/src/block_queue.rs @@ -35,6 +35,7 @@ pub struct BlockQueue { verifiers: Vec>, deleting: Arc, ready_signal: Arc, + empty: Arc, processing: HashSet } @@ -79,6 +80,7 @@ impl BlockQueue { let more_to_verify = Arc::new(Condvar::new()); let ready_signal = Arc::new(QueueSignal { signalled: AtomicBool::new(false), message_channel: message_channel }); let deleting = Arc::new(AtomicBool::new(false)); + let empty = Arc::new(Condvar::new()); let mut verifiers: Vec> = Vec::new(); let thread_count = max(::num_cpus::get(), 3) - 2; @@ -87,8 +89,9 @@ impl BlockQueue { let engine = engine.clone(); let more_to_verify = more_to_verify.clone(); let ready_signal = ready_signal.clone(); + let empty = empty.clone(); let deleting = deleting.clone(); - verifiers.push(thread::Builder::new().name(format!("Verifier #{}", i)).spawn(move || BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting)) + verifiers.push(thread::Builder::new().name(format!("Verifier #{}", i)).spawn(move || BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty)) .expect("Error starting block verification thread")); } BlockQueue { @@ -99,14 +102,20 @@ impl BlockQueue { verifiers: verifiers, deleting: deleting.clone(), processing: HashSet::new(), + empty: empty.clone(), } } - fn verify(verification: Arc>, engine: Arc>, wait: Arc, ready: Arc, deleting: Arc) { + fn verify(verification: Arc>, engine: Arc>, wait: Arc, ready: Arc, deleting: Arc, empty: Arc) { while !deleting.load(AtomicOrdering::Relaxed) { - { let mut lock = verification.lock().unwrap(); + + if lock.unverified.is_empty() && lock.verifying.is_empty() { + empty.notify_all(); + } + + while lock.unverified.is_empty() && !deleting.load(AtomicOrdering::Relaxed) { lock = wait.wait(lock).unwrap(); } @@ -176,6 +185,13 @@ impl BlockQueue { verification.verifying.clear(); } + /// Wait for queue to be empty + pub fn flush(&mut self) { + let mutex: Mutex<()> = Mutex::new(()); + let lock = mutex.lock().unwrap(); + let _ = self.empty.wait(lock).unwrap(); + } + /// Add a block to the queue. pub fn import_block(&mut self, bytes: Bytes) -> ImportResult { let header = BlockView::new(&bytes).header(); diff --git a/src/client.rs b/src/client.rs index 795bca546..f05819370 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,5 +1,3 @@ -use std::thread; -use std::time; use util::*; use rocksdb::{Options, DB}; use blockchain::{BlockChain, BlockProvider, CacheSize}; @@ -184,10 +182,7 @@ impl Client { /// Flush the block import queue. pub fn flush_queue(&self) { flushln!("Flushing queue {:?}", self.block_queue.read().unwrap().queue_info()); - while self.block_queue.read().unwrap().queue_info().unverified_queue_size > 0 { - thread::sleep(time::Duration::from_millis(20)); - flushln!("Flushing queue [waited] {:?}", self.block_queue.read().unwrap().queue_info()); - } + self.block_queue.write().unwrap().flush(); } /// This is triggered by a message coming from a block queue when the block is ready for insertion From 41508cbd507c4514be48cae43c1eb8d8cef4ab21 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 25 Jan 2016 23:24:51 +0100 Subject: [PATCH 11/23] Fix queue flush and add working tests. --- src/block.rs | 1 + src/block_queue.rs | 19 ++++++++++++------- src/client.rs | 7 +++---- src/spec.rs | 13 ++++++++++++- src/state.rs | 6 +++--- src/sync/tests.rs | 1 + src/tests/chain.rs | 11 ++++++++--- 7 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/block.rs b/src/block.rs index 1ff326430..c63f49bd7 100644 --- a/src/block.rs +++ b/src/block.rs @@ -188,6 +188,7 @@ impl<'x, 'y> OpenBlock<'x, 'y> { // info!("env_info says gas_used={}", env_info.gas_used); match self.block.state.apply(&env_info, self.engine, &t) { Ok(receipt) => { + flushln!("Transaction executed {:?}", receipt); self.block.archive_set.insert(h.unwrap_or_else(||t.hash())); self.block.archive.push(Entry { transaction: t, receipt: receipt }); Ok(&self.block.archive.last().unwrap().receipt) diff --git a/src/block_queue.rs b/src/block_queue.rs index a0e46193b..fa091d0c4 100644 --- a/src/block_queue.rs +++ b/src/block_queue.rs @@ -19,11 +19,16 @@ pub struct BlockQueueInfo { pub unverified_queue_size: usize, /// Number of verified queued blocks pending import pub verified_queue_size: usize, + /// Number of blocks being verified + pub verifying_queue_size: usize, } impl BlockQueueInfo { /// The total size of the queues. - pub fn total_queue_size(&self) -> usize { self.unverified_queue_size + self.verified_queue_size } + pub fn total_queue_size(&self) -> usize { self.unverified_queue_size + self.verified_queue_size + self.verifying_queue_size } + + /// The size of the unverified and verifying queues. + pub fn incomplete_queue_size(&self) -> usize { self.unverified_queue_size + self.verifying_queue_size } } /// A queue of blocks. Sits between network or other I/O and the BlockChain. @@ -91,7 +96,7 @@ impl BlockQueue { let ready_signal = ready_signal.clone(); let empty = empty.clone(); let deleting = deleting.clone(); - verifiers.push(thread::Builder::new().name(format!("Verifier #{}", i)).spawn(move || BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty)) + verifiers.push(thread::Builder::new().name(format!("Verifier #{}", i)).spawn(move || BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty)) .expect("Error starting block verification thread")); } BlockQueue { @@ -115,7 +120,6 @@ impl BlockQueue { empty.notify_all(); } - while lock.unverified.is_empty() && !deleting.load(AtomicOrdering::Relaxed) { lock = wait.wait(lock).unwrap(); } @@ -154,7 +158,6 @@ impl BlockQueue { }, Err(err) => { let mut v = verification.lock().unwrap(); - flushln!("Stage 2 block verification failed for {}\nError: {:?}", block_hash, err); warn!(target: "client", "Stage 2 block verification failed for {}\nError: {:?}", block_hash, err); v.bad.insert(block_hash.clone()); v.verifying.retain(|e| e.hash != block_hash); @@ -187,9 +190,10 @@ impl BlockQueue { /// Wait for queue to be empty pub fn flush(&mut self) { - let mutex: Mutex<()> = Mutex::new(()); - let lock = mutex.lock().unwrap(); - let _ = self.empty.wait(lock).unwrap(); + let mut verification = self.verification.lock().unwrap(); + while !verification.unverified.is_empty() && !verification.verifying.is_empty() { + verification = self.empty.wait(verification).unwrap(); + } } /// Add a block to the queue. @@ -265,6 +269,7 @@ impl BlockQueue { full: false, verified_queue_size: verification.verified.len(), unverified_queue_size: verification.unverified.len(), + verifying_queue_size: verification.verifying.len(), } } } diff --git a/src/client.rs b/src/client.rs index f05819370..2cc6c150d 100644 --- a/src/client.rs +++ b/src/client.rs @@ -181,7 +181,6 @@ impl Client { /// Flush the block import queue. pub fn flush_queue(&self) { - flushln!("Flushing queue {:?}", self.block_queue.read().unwrap().queue_info()); self.block_queue.write().unwrap().flush(); } @@ -189,9 +188,8 @@ impl Client { pub fn import_verified_blocks(&self, _io: &IoChannel) { let mut bad = HashSet::new(); let _import_lock = self.import_lock.lock(); - - for block in self.block_queue.write().unwrap().drain(128) { - flushln!("Importing block..."); + let blocks = self.block_queue.write().unwrap().drain(128); + for block in blocks { if bad.contains(&block.header.parent_hash) { self.block_queue.write().unwrap().mark_as_bad(&block.header.hash()); bad.insert(block.header.hash()); @@ -238,6 +236,7 @@ impl Client { } }; if let Err(e) = verify_block_final(&header, result.block().header()) { + flushln!("Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); self.block_queue.write().unwrap().mark_as_bad(&header.hash()); return; diff --git a/src/spec.rs b/src/spec.rs index 9e97595b9..326552524 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -80,7 +80,7 @@ pub struct Spec { /// TODO [arkpar] Please document me pub extra_data: Bytes, /// TODO [Gav Wood] Please document me - pub genesis_state: PodState, + genesis_state: PodState, /// TODO [Gav Wood] Please document me pub seal_fields: usize, /// TODO [Gav Wood] Please document me @@ -182,6 +182,17 @@ impl Spec { self.seal_rlp = seal_rlp; self.state_root_memo = RwLock::new(genesis.find("stateRoot").and_then(|_| Some(H256::from_json(&genesis["stateRoot"])))); } + + /// Alter the value of the genesis state. + pub fn set_genesis_state(&mut self, s: PodState) { + self.genesis_state = s; + *self.state_root_memo.write().unwrap() = None; + } + + /// Returns `false` if the memoized state root is invalid. `true` otherwise. + pub fn is_state_root_valid(&self) -> bool { + self.state_root_memo.read().unwrap().clone().map_or(true, |sr| sr == self.genesis_state.root()) + } } impl FromJson for Spec { diff --git a/src/state.rs b/src/state.rs index 6e5d586f3..71ae0ecda 100644 --- a/src/state.rs +++ b/src/state.rs @@ -146,15 +146,15 @@ impl State { /// This will change the state accordingly. pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &Transaction) -> ApplyResult { - let old = self.to_pod(); +// let old = self.to_pod(); let e = try!(Executive::new(self, env_info, engine).transact(t)); //println!("Executed: {:?}", e); - trace!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod())); +// trace!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod())); self.commit(); let receipt = Receipt::new(self.root().clone(), e.cumulative_gas_used, e.logs); - trace!("Transaction receipt: {:?}", receipt); +// trace!("Transaction receipt: {:?}", receipt); Ok(receipt) } diff --git a/src/sync/tests.rs b/src/sync/tests.rs index 7f8a1748b..50d6efab2 100644 --- a/src/sync/tests.rs +++ b/src/sync/tests.rs @@ -158,6 +158,7 @@ impl BlockChainClient for TestBlockChainClient { full: false, verified_queue_size: 0, unverified_queue_size: 0, + verifying_queue_size: 0, } } diff --git a/src/tests/chain.rs b/src/tests/chain.rs index db3e398b0..922def6c7 100644 --- a/src/tests/chain.rs +++ b/src/tests/chain.rs @@ -22,8 +22,9 @@ fn do_json_test(json_data: &[u8]) -> Vec { let blocks: Vec = test["blocks"].as_array().unwrap().iter().map(|e| xjson!(&e["rlp"])).collect(); let mut spec = ethereum::new_frontier_like_test(); + spec.set_genesis_state(PodState::from_json(test.find("pre").unwrap())); spec.overwrite_genesis(test.find("genesisBlockHeader").unwrap()); - spec.genesis_state = PodState::from_json(test.find("pre").unwrap()); + assert!(spec.is_state_root_valid()); let mut dir = env::temp_dir(); dir.push(H32::random().hex()); @@ -32,9 +33,12 @@ fn do_json_test(json_data: &[u8]) -> Vec { blocks.into_iter().foreach(|b| { client.import_block(b).unwrap(); }); + flushln!("Imported all"); client.flush_queue(); + flushln!("Flushed"); client.import_verified_blocks(&IoChannel::disconnected()); - flushln!("Best hash: {}", client.chain_info().best_block_hash); + flushln!("Checking..."); + fail_unless(client.chain_info().best_block_hash == H256::from_json(&test["lastblockhash"])); } fs::remove_dir_all(&dir).unwrap(); } @@ -46,4 +50,5 @@ fn do_json_test(json_data: &[u8]) -> Vec { failed } -declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"} +//declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"} +declare_test!{BlockchainTests_bcForkBlockTest, "BlockchainTests/bcForkBlockTest"} From 60af30558c91363239363aef632a41903a5a9cec Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 25 Jan 2016 23:26:42 +0100 Subject: [PATCH 12/23] Cleanups. --- src/tests/chain.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tests/chain.rs b/src/tests/chain.rs index 922def6c7..aeb92d3fd 100644 --- a/src/tests/chain.rs +++ b/src/tests/chain.rs @@ -33,11 +33,8 @@ fn do_json_test(json_data: &[u8]) -> Vec { blocks.into_iter().foreach(|b| { client.import_block(b).unwrap(); }); - flushln!("Imported all"); client.flush_queue(); - flushln!("Flushed"); client.import_verified_blocks(&IoChannel::disconnected()); - flushln!("Checking..."); fail_unless(client.chain_info().best_block_hash == H256::from_json(&test["lastblockhash"])); } fs::remove_dir_all(&dir).unwrap(); @@ -50,5 +47,7 @@ fn do_json_test(json_data: &[u8]) -> Vec { failed } +// Fails. TODO: figure out why. //declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"} + declare_test!{BlockchainTests_bcForkBlockTest, "BlockchainTests/bcForkBlockTest"} From e479e8ca973ccd9e918518dbff5c7f6cf7e78785 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 25 Jan 2016 23:37:49 +0100 Subject: [PATCH 13/23] Tody ups. --- src/state.rs | 4 ++-- src/tests/chain.rs | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/state.rs b/src/state.rs index 71ae0ecda..7310f63a7 100644 --- a/src/state.rs +++ b/src/state.rs @@ -3,7 +3,7 @@ use engine::Engine; use executive::Executive; use pod_account::*; use pod_state::*; -use state_diff::*; +//use state_diff::*; // TODO: uncomment once to_pod() works correctly. /// TODO [Gav Wood] Please document me pub type ApplyResult = Result; @@ -145,12 +145,12 @@ impl State { /// Execute a given transaction. /// This will change the state accordingly. pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &Transaction) -> ApplyResult { - // let old = self.to_pod(); let e = try!(Executive::new(self, env_info, engine).transact(t)); //println!("Executed: {:?}", e); + // TODO uncomment once to_pod() works correctly. // trace!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod())); self.commit(); let receipt = Receipt::new(self.root().clone(), e.cumulative_gas_used, e.logs); diff --git a/src/tests/chain.rs b/src/tests/chain.rs index aeb92d3fd..89199feed 100644 --- a/src/tests/chain.rs +++ b/src/tests/chain.rs @@ -47,7 +47,18 @@ fn do_json_test(json_data: &[u8]) -> Vec { failed } -// Fails. TODO: figure out why. -//declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"} - +declare_test!{ignore => BlockchainTests_bcBlockGasLimitTest, "BlockchainTests/bcBlockGasLimitTest"} // UNKNOWN declare_test!{BlockchainTests_bcForkBlockTest, "BlockchainTests/bcForkBlockTest"} +declare_test!{ignore => BlockchainTests_bcForkStressTest, "BlockchainTests/bcForkStressTest"} // UNKNOWN +declare_test!{ignore => BlockchainTests_bcForkUncle, "BlockchainTests/bcForkUncle"} // UNKNOWN +declare_test!{ignore => BlockchainTests_bcGasPricerTest, "BlockchainTests/bcGasPricerTest"} // UNKNOWN +declare_test!{ignore => BlockchainTests_bcInvalidHeaderTest, "BlockchainTests/bcInvalidHeaderTest"} // UNKNOWN +declare_test!{ignore => BlockchainTests_bcInvalidRLPTest, "BlockchainTests/bcInvalidRLPTest"} // UNKNOWN +declare_test!{ignore => BlockchainTests_bcMultiChainTest, "BlockchainTests/bcMultiChainTest"} // UNKNOWN +declare_test!{ignore => BlockchainTests_bcRPC_API_Test, "BlockchainTests/bcRPC_API_Test"} // UNKNOWN +declare_test!{ignore => BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"} // FAILS (Suicides, GasUsed) +declare_test!{ignore => BlockchainTests_bcTotalDifficultyTest, "BlockchainTests/bcTotalDifficultyTest"} // UNKNOWN +declare_test!{ignore => BlockchainTests_bcUncleHeaderValiditiy, "BlockchainTests/bcUncleHeaderValiditiy"}// UNKNOWN +declare_test!{ignore => BlockchainTests_bcUncleTest, "BlockchainTests/bcUncleTest"} // UNKNOWN +declare_test!{ignore => BlockchainTests_bcValidBlockTest, "BlockchainTests/bcValidBlockTest"} // UNKNOWN +declare_test!{ignore => BlockchainTests_bcWalletTest, "BlockchainTests/bcWalletTest"} // UNKNOWN From b6622e6efed4a68a70a28879261bdb7d475c640d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 25 Jan 2016 23:39:21 +0100 Subject: [PATCH 14/23] Remove flushln!s. --- src/block.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/block.rs b/src/block.rs index c63f49bd7..1ff326430 100644 --- a/src/block.rs +++ b/src/block.rs @@ -188,7 +188,6 @@ impl<'x, 'y> OpenBlock<'x, 'y> { // info!("env_info says gas_used={}", env_info.gas_used); match self.block.state.apply(&env_info, self.engine, &t) { Ok(receipt) => { - flushln!("Transaction executed {:?}", receipt); self.block.archive_set.insert(h.unwrap_or_else(||t.hash())); self.block.archive.push(Entry { transaction: t, receipt: receipt }); Ok(&self.block.archive.last().unwrap().receipt) From 16f2fa33ee9142ae8633b1a54998cf4a290bacc8 Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Mon, 25 Jan 2016 23:59:50 +0100 Subject: [PATCH 15/23] Merging CALL & DELEGATECALL branches --- src/evm/ext.rs | 2 +- src/evm/interpreter.rs | 69 ++++++++++++++---------------------------- src/evm/tests.rs | 2 +- src/externalities.rs | 4 +-- src/tests/executive.rs | 4 +-- 5 files changed, 29 insertions(+), 52 deletions(-) diff --git a/src/evm/ext.rs b/src/evm/ext.rs index 748bc89da..83f093bcf 100644 --- a/src/evm/ext.rs +++ b/src/evm/ext.rs @@ -57,7 +57,7 @@ pub trait Ext { gas: &U256, sender_address: &Address, receive_address: &Address, - value: Option<&U256>, + value: Option, data: &[u8], code_address: &Address, output: &mut [u8]) -> MessageCallResult; diff --git a/src/evm/interpreter.rs b/src/evm/interpreter.rs index 276f2873b..7657b1bbe 100644 --- a/src/evm/interpreter.rs +++ b/src/evm/interpreter.rs @@ -566,66 +566,43 @@ impl Interpreter { } }; }, - instructions::DELEGATECALL => { - let call_gas = stack.pop_back(); - let code_address = stack.pop_back(); - let code_address = u256_to_address(&code_address); - - let in_off = stack.pop_back(); - let in_size = stack.pop_back(); - let out_off = stack.pop_back(); - let out_size = stack.pop_back(); - - let can_call = ext.depth() < ext.schedule().max_depth; - if !can_call { - stack.push(U256::zero()); - return Ok(InstructionResult::UnusedGas(call_gas)); - } - - let call_result = { - // we need to write and read from memory in the same time - // and we don't want to copy - let input = unsafe { ::std::mem::transmute(mem.read_slice(in_off, in_size)) }; - let output = mem.writeable_slice(out_off, out_size); - ext.call(&call_gas, ¶ms.sender, ¶ms.address, None, input, &code_address, output) - }; - - return match call_result { - MessageCallResult::Success(gas_left) => { - stack.push(U256::one()); - Ok(InstructionResult::UnusedGas(gas_left)) - }, - MessageCallResult::Failed => { - stack.push(U256::zero()); - Ok(InstructionResult::Ok) - } - }; - }, - instructions::CALL | instructions::CALLCODE => { + instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL => { assert!(ext.schedule().call_value_transfer_gas > ext.schedule().call_stipend, "overflow possible"); let call_gas = stack.pop_back(); let code_address = stack.pop_back(); let code_address = u256_to_address(&code_address); - let value = stack.pop_back(); + let value = match instruction == instructions::DELEGATECALL { + true => None, + false => Some(stack.pop_back()) + }; let in_off = stack.pop_back(); let in_size = stack.pop_back(); let out_off = stack.pop_back(); let out_size = stack.pop_back(); - let call_gas = call_gas + match value > U256::zero() { + // Add stipend (only CALL|CALLCODE when value > 0) + let call_gas = call_gas + value.map_or_else(U256::zero, |val| match val > U256::zero() { true => U256::from(ext.schedule().call_stipend), false => U256::zero() + }); + + // Get sender & receive addresses, check if we have balance + let (sender_address, receive_address, has_balance) = match instruction { + instructions::CALL => { + let has_balance = ext.balance(¶ms.address) >= value.unwrap(); + (¶ms.address, &code_address, has_balance) + }, + instructions::CALLCODE => { + let has_balance = ext.balance(¶ms.address) >= value.unwrap(); + (¶ms.address, ¶ms.address, has_balance) + }, + instructions::DELEGATECALL => (¶ms.sender, ¶ms.address, true), + _ => panic!(format!("Unexpected instruction {} in CALL branch.", instruction)) }; - let (sender_address, receive_address) = match instruction == instructions::CALL { - true => (¶ms.address, &code_address), - false => (¶ms.address, ¶ms.address) - }; - - let can_call = ext.balance(¶ms.address) >= value && ext.depth() < ext.schedule().max_depth; - + let can_call = has_balance && ext.depth() < ext.schedule().max_depth; if !can_call { stack.push(U256::zero()); return Ok(InstructionResult::UnusedGas(call_gas)); @@ -636,7 +613,7 @@ impl Interpreter { // and we don't want to copy let input = unsafe { ::std::mem::transmute(mem.read_slice(in_off, in_size)) }; let output = mem.writeable_slice(out_off, out_size); - ext.call(&call_gas, sender_address, receive_address, Some(&value), input, &code_address, output) + ext.call(&call_gas, sender_address, receive_address, value, input, &code_address, output) }; return match call_result { diff --git a/src/evm/tests.rs b/src/evm/tests.rs index cf4262914..ad81cf877 100644 --- a/src/evm/tests.rs +++ b/src/evm/tests.rs @@ -63,7 +63,7 @@ impl Ext for FakeExt { _gas: &U256, _sender_address: &Address, _receive_address: &Address, - _value: Option<&U256>, + _value: Option, _data: &[u8], _code_address: &Address, _output: &mut [u8]) -> MessageCallResult { diff --git a/src/externalities.rs b/src/externalities.rs index d8b5d6110..f9a79c3c0 100644 --- a/src/externalities.rs +++ b/src/externalities.rs @@ -138,7 +138,7 @@ impl<'a> Ext for Externalities<'a> { gas: &U256, sender_address: &Address, receive_address: &Address, - value: Option<&U256>, + value: Option, data: &[u8], code_address: &Address, output: &mut [u8]) -> MessageCallResult { @@ -156,7 +156,7 @@ impl<'a> Ext for Externalities<'a> { }; if let Some(value) = value { - params.value = ActionValue::Transfer(value.clone()); + params.value = ActionValue::Transfer(value); } let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth); diff --git a/src/tests/executive.rs b/src/tests/executive.rs index 0604c9992..a94fd1605 100644 --- a/src/tests/executive.rs +++ b/src/tests/executive.rs @@ -103,7 +103,7 @@ impl<'a> Ext for TestExt<'a> { gas: &U256, _sender_address: &Address, receive_address: &Address, - value: Option<&U256>, + value: Option, data: &[u8], _code_address: &Address, _output: &mut [u8]) -> MessageCallResult { @@ -111,7 +111,7 @@ impl<'a> Ext for TestExt<'a> { data: data.to_vec(), destination: Some(receive_address.clone()), gas_limit: *gas, - value: *value.unwrap() + value: value.unwrap() }); MessageCallResult::Success(*gas) } From 746e2a57c9793da187d6df7dbb2b0a6948f0df27 Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Tue, 26 Jan 2016 00:03:01 +0100 Subject: [PATCH 16/23] Cleaning readme --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 48172bb60..216ac8091 100644 --- a/README.md +++ b/README.md @@ -1,5 +1 @@ # ethcore - - -# Running clippy - From 3fe0c3c7897b36fa9ed87ccca275d7c277093264 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 26 Jan 2016 00:26:36 +0100 Subject: [PATCH 17/23] Unignore passingn tests. --- src/tests/chain.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/tests/chain.rs b/src/tests/chain.rs index 89199feed..ba42ae935 100644 --- a/src/tests/chain.rs +++ b/src/tests/chain.rs @@ -47,18 +47,18 @@ fn do_json_test(json_data: &[u8]) -> Vec { failed } -declare_test!{ignore => BlockchainTests_bcBlockGasLimitTest, "BlockchainTests/bcBlockGasLimitTest"} // UNKNOWN +declare_test!{ignore => BlockchainTests_bcBlockGasLimitTest, "BlockchainTests/bcBlockGasLimitTest"} // FAILS declare_test!{BlockchainTests_bcForkBlockTest, "BlockchainTests/bcForkBlockTest"} -declare_test!{ignore => BlockchainTests_bcForkStressTest, "BlockchainTests/bcForkStressTest"} // UNKNOWN -declare_test!{ignore => BlockchainTests_bcForkUncle, "BlockchainTests/bcForkUncle"} // UNKNOWN -declare_test!{ignore => BlockchainTests_bcGasPricerTest, "BlockchainTests/bcGasPricerTest"} // UNKNOWN -declare_test!{ignore => BlockchainTests_bcInvalidHeaderTest, "BlockchainTests/bcInvalidHeaderTest"} // UNKNOWN -declare_test!{ignore => BlockchainTests_bcInvalidRLPTest, "BlockchainTests/bcInvalidRLPTest"} // UNKNOWN -declare_test!{ignore => BlockchainTests_bcMultiChainTest, "BlockchainTests/bcMultiChainTest"} // UNKNOWN -declare_test!{ignore => BlockchainTests_bcRPC_API_Test, "BlockchainTests/bcRPC_API_Test"} // UNKNOWN -declare_test!{ignore => BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"} // FAILS (Suicides, GasUsed) -declare_test!{ignore => BlockchainTests_bcTotalDifficultyTest, "BlockchainTests/bcTotalDifficultyTest"} // UNKNOWN -declare_test!{ignore => BlockchainTests_bcUncleHeaderValiditiy, "BlockchainTests/bcUncleHeaderValiditiy"}// UNKNOWN -declare_test!{ignore => BlockchainTests_bcUncleTest, "BlockchainTests/bcUncleTest"} // UNKNOWN -declare_test!{ignore => BlockchainTests_bcValidBlockTest, "BlockchainTests/bcValidBlockTest"} // UNKNOWN -declare_test!{ignore => BlockchainTests_bcWalletTest, "BlockchainTests/bcWalletTest"} // UNKNOWN +declare_test!{ignore => BlockchainTests_bcForkStressTest, "BlockchainTests/bcForkStressTest"} // FAILS +declare_test!{ignore => BlockchainTests_bcForkUncle, "BlockchainTests/bcForkUncle"} // FAILS +declare_test!{BlockchainTests_bcGasPricerTest, "BlockchainTests/bcGasPricerTest"} +declare_test!{BlockchainTests_bcInvalidHeaderTest, "BlockchainTests/bcInvalidHeaderTest"} +declare_test!{ignore => BlockchainTests_bcInvalidRLPTest, "BlockchainTests/bcInvalidRLPTest"} // FAILS +declare_test!{ignore => BlockchainTests_bcMultiChainTest, "BlockchainTests/bcMultiChainTest"} // FAILS +declare_test!{BlockchainTests_bcRPC_API_Test, "BlockchainTests/bcRPC_API_Test"} +declare_test!{ignore => BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"} // FAILS (Suicides, GasUsed) +declare_test!{BlockchainTests_bcTotalDifficultyTest, "BlockchainTests/bcTotalDifficultyTest"} +declare_test!{ignore => BlockchainTests_bcUncleHeaderValiditiy, "BlockchainTests/bcUncleHeaderValiditiy"} // FAILS +declare_test!{ignore => BlockchainTests_bcUncleTest, "BlockchainTests/bcUncleTest"} // FAILS +declare_test!{ignore => BlockchainTests_bcValidBlockTest, "BlockchainTests/bcValidBlockTest"} // FAILS +declare_test!{ignore => BlockchainTests_bcWalletTest, "BlockchainTests/bcWalletTest"} // FAILS From 2dcfb52b5692d37368e6d60e4d6eb2aad9f2fbbf Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 26 Jan 2016 00:46:24 +0100 Subject: [PATCH 18/23] Closes #213 --- src/tests/chain.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/chain.rs b/src/tests/chain.rs index ba42ae935..d3e978e05 100644 --- a/src/tests/chain.rs +++ b/src/tests/chain.rs @@ -47,6 +47,7 @@ fn do_json_test(json_data: &[u8]) -> Vec { failed } + declare_test!{ignore => BlockchainTests_bcBlockGasLimitTest, "BlockchainTests/bcBlockGasLimitTest"} // FAILS declare_test!{BlockchainTests_bcForkBlockTest, "BlockchainTests/bcForkBlockTest"} declare_test!{ignore => BlockchainTests_bcForkStressTest, "BlockchainTests/bcForkStressTest"} // FAILS From 7065c477a4ec5ac81b3cb24c4b45153f437e9287 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 26 Jan 2016 00:48:01 +0100 Subject: [PATCH 19/23] Closes #70 --- src/tests/chain.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tests/chain.rs b/src/tests/chain.rs index d3e978e05..ba42ae935 100644 --- a/src/tests/chain.rs +++ b/src/tests/chain.rs @@ -47,7 +47,6 @@ fn do_json_test(json_data: &[u8]) -> Vec { failed } - declare_test!{ignore => BlockchainTests_bcBlockGasLimitTest, "BlockchainTests/bcBlockGasLimitTest"} // FAILS declare_test!{BlockchainTests_bcForkBlockTest, "BlockchainTests/bcForkBlockTest"} declare_test!{ignore => BlockchainTests_bcForkStressTest, "BlockchainTests/bcForkStressTest"} // FAILS From 280749b34cfdce8c110cf93f52aaa677f57c3d72 Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Tue, 26 Jan 2016 09:13:44 +0100 Subject: [PATCH 20/23] Removing println --- src/executive.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/executive.rs b/src/executive.rs index f5952e530..af738b0f6 100644 --- a/src/executive.rs +++ b/src/executive.rs @@ -166,7 +166,6 @@ impl<'a> Executive<'a> { /// Modifies the substate and the output. /// Returns either gas_left or `evm::Error`. pub fn call(&mut self, params: ActionParams, substate: &mut Substate, mut output: BytesRef) -> evm::Result { - println!("Calling executive. Sender: {}", params.sender); // backup used in case of running out of gas let backup = self.state.clone(); From c66aa52166ab04f51ca90ded67574070e9357622 Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Tue, 26 Jan 2016 10:15:55 +0100 Subject: [PATCH 21/23] Spawning new thread when we are reaching stack limit --- Cargo.toml | 1 + src/evm/jit.rs | 19 ++++++++++++------- src/evm/tests.rs | 1 + src/executive.rs | 36 +++++++++++++++++++++++++++++------- src/lib.rs | 1 + src/tests/executive.rs | 4 ++-- src/tests/state.rs | 10 +++++----- 7 files changed, 51 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 54b1b406e..ce49d0dd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ num_cpus = "0.2" docopt = "0.6" docopt_macros = "0.6" ctrlc = "1.0" +crossbeam = "0.1.5" clippy = "0.0.37" [features] diff --git a/src/evm/jit.rs b/src/evm/jit.rs index 9f990155d..e073a380d 100644 --- a/src/evm/jit.rs +++ b/src/evm/jit.rs @@ -64,7 +64,7 @@ impl IntoJit for H256 { for i in 0..self.bytes().len() { let rev = self.bytes().len() - 1 - i; let pos = rev / 8; - ret[pos] += (self.bytes()[i] as u64) << (rev % 8) * 8; + ret[pos] += (self.bytes()[i] as u64) << ((rev % 8) * 8); } evmjit::I256 { words: ret } } @@ -218,9 +218,11 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> { } } - match self.ext.call(&call_gas, + match self.ext.call( + &call_gas, + &self.address, &receive_address, - &value, + Some(value), unsafe { slice::from_raw_parts(in_beg, in_size as usize) }, &code_address, unsafe { slice::from_raw_parts_mut(out_beg, out_size as usize) }) { @@ -262,7 +264,7 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> { } let bytes_ref: &[u8] = slice::from_raw_parts(beg, size as usize); - self.ext.log(topics, bytes_ref.to_vec()); + self.ext.log(topics, bytes_ref); } } @@ -287,8 +289,8 @@ impl evm::Evm for JitEvm { assert!(params.gas <= U256::from(i64::max_value() as u64), "evmjit max gas is 2 ^ 63"); assert!(params.gas_price <= U256::from(i64::max_value() as u64), "evmjit max gas is 2 ^ 63"); - let call_data = params.data.unwrap_or(vec![]); - let code = params.code.unwrap_or(vec![]); + let call_data = params.data.unwrap_or_else(Vec::new); + let code = params.code.unwrap_or_else(Vec::new); let mut data = evmjit::RuntimeDataHandle::new(); data.gas = params.gas.low_u64() as i64; @@ -303,7 +305,10 @@ impl evm::Evm for JitEvm { data.address = params.address.into_jit(); data.caller = params.sender.into_jit(); data.origin = params.origin.into_jit(); - data.call_value = params.value.into_jit(); + data.call_value = match params.value { + ActionValue::Transfer(val) => val.into_jit(), + ActionValue::Apparent(val) => val.into_jit() + }; data.author = ext.env_info().author.clone().into_jit(); data.difficulty = ext.env_info().difficulty.into_jit(); diff --git a/src/evm/tests.rs b/src/evm/tests.rs index ad81cf877..d448ccb3a 100644 --- a/src/evm/tests.rs +++ b/src/evm/tests.rs @@ -215,6 +215,7 @@ fn test_origin(factory: super::Factory) { assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681").unwrap()); } +// TODO [todr] Fails with Signal 11 on JIT evm_test!{test_sender: test_sender_jit, test_sender_int} fn test_sender(factory: super::Factory) { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); diff --git a/src/executive.rs b/src/executive.rs index f5952e530..d5446b0e9 100644 --- a/src/executive.rs +++ b/src/executive.rs @@ -5,6 +5,12 @@ use engine::*; use evm::{self, Ext}; use externalities::*; use substate::*; +use crossbeam; + +/// Max depth to avoid stack overflow (when it's reached we start a new thread with VM) +/// TODO [todr] We probably need some more sophisticated calculations here (limit on my machine 132) +/// Maybe something like here: https://github.com/ethereum/libethereum/blob/4db169b8504f2b87f7d5a481819cfb959fc65f6c/libethereum/ExtVM.cpp +const MAX_VM_DEPTH_FOR_THREAD: usize = 128; /// Returns new address created from address and given nonce. pub fn contract_address(address: &Address, nonce: &U256) -> Address { @@ -161,12 +167,32 @@ impl<'a> Executive<'a> { Ok(try!(self.finalize(t, substate, res))) } + fn exec_vm(&mut self, params: ActionParams, unconfirmed_substate: &mut Substate, output_policy: OutputPolicy) -> evm::Result { + // Ordinary execution - keep VM in same thread + if (self.depth + 1) % MAX_VM_DEPTH_FOR_THREAD != 0 { + let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy); + let vm_factory = self.engine.vm_factory(); + return vm_factory.create().exec(params, &mut ext); + } + + // Start in new thread to reset stack + // TODO [todr] No thread builder yet, so we need to reset once for a while + // https://github.com/aturon/crossbeam/issues/16 + crossbeam::scope(|scope| { + let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy); + let vm_factory = self.engine.vm_factory(); + + scope.spawn(move || { + vm_factory.create().exec(params, &mut ext) + }) + }).join() + } + /// Calls contract function with given contract params. /// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides). /// Modifies the substate and the output. /// Returns either gas_left or `evm::Error`. pub fn call(&mut self, params: ActionParams, substate: &mut Substate, mut output: BytesRef) -> evm::Result { - println!("Calling executive. Sender: {}", params.sender); // backup used in case of running out of gas let backup = self.state.clone(); @@ -201,8 +227,7 @@ impl<'a> Executive<'a> { let mut unconfirmed_substate = Substate::new(); let res = { - let mut ext = self.as_externalities(OriginInfo::from(¶ms), &mut unconfirmed_substate, OutputPolicy::Return(output)); - self.engine.vm_factory().create().exec(params, &mut ext) + self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output)) }; trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count); @@ -235,8 +260,7 @@ impl<'a> Executive<'a> { } let res = { - let mut ext = self.as_externalities(OriginInfo::from(¶ms), &mut unconfirmed_substate, OutputPolicy::InitContract); - self.engine.vm_factory().create().exec(params, &mut ext) + self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract) }; self.enact_result(&res, substate, unconfirmed_substate, backup); res @@ -277,7 +301,6 @@ impl<'a> Executive<'a> { match result { Err(evm::Error::Internal) => Err(ExecutionError::Internal), - // TODO [ToDr] BadJumpDestination @debris - how to handle that? Err(_) => { Ok(Executed { gas: t.gas, @@ -302,7 +325,6 @@ impl<'a> Executive<'a> { } fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate, backup: State) { - // TODO: handle other evm::Errors same as OutOfGas once they are implemented match *result { Err(evm::Error::OutOfGas) | Err(evm::Error::BadJumpDestination {..}) diff --git a/src/lib.rs b/src/lib.rs index 262f8682f..8dd02b3bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,6 +90,7 @@ extern crate num_cpus; extern crate evmjit; #[macro_use] extern crate ethcore_util as util; +extern crate crossbeam; // NOTE: Add doc parser exception for these pub declarations. diff --git a/src/tests/executive.rs b/src/tests/executive.rs index a94fd1605..1df1b7eec 100644 --- a/src/tests/executive.rs +++ b/src/tests/executive.rs @@ -271,8 +271,8 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec { declare_test!{ExecutiveTests_vmArithmeticTest, "VMTests/vmArithmeticTest"} declare_test!{ExecutiveTests_vmBitwiseLogicOperationTest, "VMTests/vmBitwiseLogicOperationTest"} -// this one crashes with some vm internal error. Separately they pass. -declare_test!{ignore => ExecutiveTests_vmBlockInfoTest, "VMTests/vmBlockInfoTest"} +declare_test!{ExecutiveTests_vmBlockInfoTest, "VMTests/vmBlockInfoTest"} + // TODO [todr] Fails with Signal 11 when using JIT declare_test!{ExecutiveTests_vmEnvironmentalInfoTest, "VMTests/vmEnvironmentalInfoTest"} declare_test!{ExecutiveTests_vmIOandFlowOperationsTest, "VMTests/vmIOandFlowOperationsTest"} declare_test!{heavy => ExecutiveTests_vmInputLimits, "VMTests/vmInputLimits"} diff --git a/src/tests/state.rs b/src/tests/state.rs index 75b9b2493..325a8b646 100644 --- a/src/tests/state.rs +++ b/src/tests/state.rs @@ -73,7 +73,7 @@ fn do_json_test(json_data: &[u8]) -> Vec { declare_test!{StateTests_stBlockHashTest, "StateTests/stBlockHashTest"} declare_test!{StateTests_stCallCodes, "StateTests/stCallCodes"} -declare_test!{ignore => StateTests_stCallCreateCallCodeTest, "StateTests/stCallCreateCallCodeTest"} //<< Out of stack +declare_test!{StateTests_stCallCreateCallCodeTest, "StateTests/stCallCreateCallCodeTest"} declare_test!{StateTests_stDelegatecallTest, "StateTests/stDelegatecallTest"} declare_test!{StateTests_stExample, "StateTests/stExample"} declare_test!{StateTests_stInitCodeTest, "StateTests/stInitCodeTest"} @@ -81,12 +81,12 @@ declare_test!{StateTests_stLogTests, "StateTests/stLogTests"} declare_test!{heavy => StateTests_stMemoryStressTest, "StateTests/stMemoryStressTest"} declare_test!{heavy => StateTests_stMemoryTest, "StateTests/stMemoryTest"} declare_test!{StateTests_stPreCompiledContracts, "StateTests/stPreCompiledContracts"} -declare_test!{heavy => StateTests_stQuadraticComplexityTest, "StateTests/stQuadraticComplexityTest"} //<< Too long -declare_test!{ignore => StateTests_stRecursiveCreate, "StateTests/stRecursiveCreate"} //<< Out of stack +declare_test!{heavy => StateTests_stQuadraticComplexityTest, "StateTests/stQuadraticComplexityTest"} +declare_test!{StateTests_stRecursiveCreate, "StateTests/stRecursiveCreate"} declare_test!{StateTests_stRefundTest, "StateTests/stRefundTest"} declare_test!{StateTests_stSolidityTest, "StateTests/stSolidityTest"} -declare_test!{ignore => StateTests_stSpecialTest, "StateTests/stSpecialTest"} //<< Out of Stack -declare_test!{ignore => StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"} //<< Out of stack +declare_test!{StateTests_stSpecialTest, "StateTests/stSpecialTest"} +declare_test!{StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"} declare_test!{StateTests_stTransactionTest, "StateTests/stTransactionTest"} declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"} declare_test!{StateTests_stWalletTest, "StateTests/stWalletTest"} From e9bd52b34a579a4ebefc9b4caaf492db970a521a Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 26 Jan 2016 10:26:18 +0100 Subject: [PATCH 22/23] fixed failing tests --- src/sync/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sync/mod.rs b/src/sync/mod.rs index 78a5d7613..34a1e429d 100644 --- a/src/sync/mod.rs +++ b/src/sync/mod.rs @@ -9,13 +9,13 @@ /// extern crate ethcore; /// use std::env; /// use std::sync::Arc; -/// use util::network::NetworkService; +/// use util::network::{NetworkService, NetworkConfiguration}; /// use ethcore::client::Client; /// use ethcore::sync::EthSync; /// use ethcore::ethereum; /// /// fn main() { -/// let mut service = NetworkService::start().unwrap(); +/// let mut service = NetworkService::start(NetworkConfiguration::new()).unwrap(); /// let dir = env::temp_dir(); /// let client = Client::new(ethereum::new_frontier(), &dir, service.io().channel()).unwrap(); /// EthSync::register(&mut service, client); From adbde5f3dac1abbdd7ba42d41a23038bc140c60c Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Tue, 26 Jan 2016 10:48:33 +0100 Subject: [PATCH 23/23] Schedule documentation --- src/evm/schedule.rs | 62 ++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/evm/schedule.rs b/src/evm/schedule.rs index 70edfceea..d46b7ff11 100644 --- a/src/evm/schedule.rs +++ b/src/evm/schedule.rs @@ -2,67 +2,67 @@ /// Definition of the cost schedule and other parameterisations for the EVM. pub struct Schedule { - /// TODO [Gav Wood] Please document me + /// Does it support exceptional failed code deposit pub exceptional_failed_code_deposit: bool, - /// TODO [Gav Wood] Please document me + /// Does it have a delegate cal pub have_delegate_call: bool, - /// TODO [Tomusdrw] Please document me + /// VM stack limit pub stack_limit: usize, - /// TODO [Gav Wood] Please document me + /// Max number of nested calls/creates pub max_depth: usize, - /// TODO [Gav Wood] Please document me + /// Gas prices for instructions in all tiers pub tier_step_gas: [usize; 8], - /// TODO [Gav Wood] Please document me + /// Gas price for `EXP` opcode pub exp_gas: usize, - /// TODO [Gav Wood] Please document me + /// Additional gas for `EXP` opcode for each byte of exponent pub exp_byte_gas: usize, - /// TODO [Gav Wood] Please document me + /// Gas price for `SHA3` opcode pub sha3_gas: usize, - /// TODO [Gav Wood] Please document me + /// Additional gas for `SHA3` opcode for each word of hashed memory pub sha3_word_gas: usize, - /// TODO [Gav Wood] Please document me + /// Gas price for loading from storage pub sload_gas: usize, - /// TODO [Gav Wood] Please document me + /// Gas price for setting new value to storage (`storage==0`, `new!=0`) pub sstore_set_gas: usize, - /// TODO [Gav Wood] Please document me + /// Gas price for altering value in storage pub sstore_reset_gas: usize, - /// TODO [Gav Wood] Please document me + /// Gas refund for `SSTORE` clearing (when `storage!=0`, `new==0`) pub sstore_refund_gas: usize, - /// TODO [Gav Wood] Please document me + /// Gas price for `JUMPDEST` opcode pub jumpdest_gas: usize, - /// TODO [Gav Wood] Please document me + /// Gas price for `LOG*` pub log_gas: usize, - /// TODO [Gav Wood] Please document me + /// Additional gas for data in `LOG*` pub log_data_gas: usize, - /// TODO [Gav Wood] Please document me + /// Additional gas for each topic in `LOG*` pub log_topic_gas: usize, - /// TODO [Gav Wood] Please document me + /// Gas price for `CREATE` opcode pub create_gas: usize, - /// TODO [Gav Wood] Please document me + /// Gas price for `*CALL*` opcodes pub call_gas: usize, - /// TODO [Gav Wood] Please document me + /// Stipend for transfer for `CALL|CALLCODE` opcode when `value>0` pub call_stipend: usize, - /// TODO [Gav Wood] Please document me + /// Additional gas required for value transfer (`CALL|CALLCODE`) pub call_value_transfer_gas: usize, - /// TODO [Gav Wood] Please document me + /// Additional gas for creating new account (`CALL|CALLCODE`) pub call_new_account_gas: usize, - /// TODO [Gav Wood] Please document me + /// Refund for SUICIDE pub suicide_refund_gas: usize, - /// TODO [Gav Wood] Please document me + /// Gas for used memory pub memory_gas: usize, - /// TODO [Gav Wood] Please document me + /// Coefficient used to convert memory size to gas price for memory pub quad_coeff_div: usize, - /// TODO [Gav Wood] Please document me + /// Cost for contract length when executing `CREATE` pub create_data_gas: usize, - /// TODO [Gav Wood] Please document me + /// Transaction cost pub tx_gas: usize, - /// TODO [Gav Wood] Please document me + /// `CREATE` transaction cost pub tx_create_gas: usize, - /// TODO [Gav Wood] Please document me + /// Additional cost for empty data transaction pub tx_data_zero_gas: usize, - /// TODO [Gav Wood] Please document me + /// Aditional cost for non-empty data transaction pub tx_data_non_zero_gas: usize, - /// TODO [Gav Wood] Please document me + /// Gas price for copying memory pub copy_gas: usize, }