merge master

This commit is contained in:
Nikolay Volf 2016-01-26 14:43:11 +04:00
commit 1490412a34
28 changed files with 411 additions and 221 deletions

View File

@ -21,7 +21,9 @@ evmjit = { path = "rust-evmjit", optional = true }
ethash = { path = "ethash" } ethash = { path = "ethash" }
num_cpus = "0.2" num_cpus = "0.2"
docopt = "0.6" docopt = "0.6"
docopt_macros = "0.6"
ctrlc = "1.0" ctrlc = "1.0"
crossbeam = "0.1.5"
clippy = "0.0.37" clippy = "0.0.37"
[features] [features]

View File

@ -1,5 +1 @@
# ethcore # ethcore
# Running clippy

@ -1 +1 @@
Subproject commit e838fd90998fc5502d0b7c9427a4c231f9a6953d Subproject commit dc86e6359675440aea59ddb48648a01c799925d8

View File

@ -3,8 +3,16 @@ use util::hash::*;
use util::uint::*; use util::uint::*;
use util::bytes::*; 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. /// Action (call/create) input params. Everything else should be specified in Externalities.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ActionParams { pub struct ActionParams {
@ -22,16 +30,16 @@ pub struct ActionParams {
/// Gas price. /// Gas price.
pub gas_price: U256, pub gas_price: U256,
/// Transaction value. /// Transaction value.
pub value: U256, pub value: ActionValue,
/// Code being executed. /// Code being executed.
pub code: Option<Bytes>, pub code: Option<Bytes>,
/// Input data. /// Input data.
pub data: Option<Bytes> pub data: Option<Bytes>
} }
impl ActionParams { impl Default for ActionParams {
/// TODO [Gav Wood] Please document me /// Returns default ActionParams initialized with zeros
pub fn new() -> ActionParams { fn default() -> ActionParams {
ActionParams { ActionParams {
code_address: Address::new(), code_address: Address::new(),
address: Address::new(), address: Address::new(),
@ -39,7 +47,7 @@ impl ActionParams {
origin: Address::new(), origin: Address::new(),
gas: U256::zero(), gas: U256::zero(),
gas_price: U256::zero(), gas_price: U256::zero(),
value: U256::zero(), value: ActionValue::Transfer(U256::zero()),
code: None, code: None,
data: None data: None
} }

View File

@ -1,7 +1,5 @@
#![feature(plugin)] #![feature(plugin)]
// TODO: uncomment once this can be made to work. #![plugin(docopt_macros)]
//#![plugin(docopt_macros)]
extern crate docopt; extern crate docopt;
extern crate rustc_serialize; extern crate rustc_serialize;
extern crate ethcore_util as util; extern crate ethcore_util as util;
@ -20,9 +18,8 @@ use ethcore::service::{ClientService, NetSyncMessage};
use ethcore::ethereum; use ethcore::ethereum;
use ethcore::blockchain::CacheSize; use ethcore::blockchain::CacheSize;
use ethcore::sync::EthSync; use ethcore::sync::EthSync;
use docopt::Docopt;
const USAGE: &'static str = " docopt!(Args derive Debug, "
Parity. Ethereum Client. Parity. Ethereum Client.
Usage: Usage:
@ -32,15 +29,9 @@ Usage:
Options: Options:
-l --logging LOGGING Specify the logging level -l --logging LOGGING Specify the logging level
-h --help Show this screen. -h --help Show this screen.
"; ");
#[derive(Debug, RustcDecodable)] fn setup_log(init: &String) {
struct Args {
arg_enode: Option<Vec<String>>,
flag_logging: Option<String>,
}
fn setup_log(init: &Option<String>) {
let mut builder = LogBuilder::new(); let mut builder = LogBuilder::new();
builder.filter(None, LogLevelFilter::Info); builder.filter(None, LogLevelFilter::Info);
@ -48,22 +39,20 @@ fn setup_log(init: &Option<String>) {
builder.parse(&env::var("RUST_LOG").unwrap()); builder.parse(&env::var("RUST_LOG").unwrap());
} }
if let &Some(ref x) = init { builder.parse(init);
builder.parse(x);
}
builder.init().unwrap(); builder.init().unwrap();
} }
fn main() { 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); setup_log(&args.flag_logging);
let spec = ethereum::new_frontier(); let spec = ethereum::new_frontier();
let init_nodes = match &args.arg_enode { let init_nodes = match args.arg_enode.len() {
&None => spec.nodes().clone(), 0 => spec.nodes().clone(),
&Some(ref enodes) => enodes.clone(), _ => args.arg_enode.clone(),
}; };
let mut net_settings = NetworkConfiguration::new(); let mut net_settings = NetworkConfiguration::new();
net_settings.boot_nodes = init_nodes; net_settings.boot_nodes = init_nodes;

View File

@ -19,6 +19,16 @@ pub struct BlockQueueInfo {
pub unverified_queue_size: usize, pub unverified_queue_size: usize,
/// Number of verified queued blocks pending import /// Number of verified queued blocks pending import
pub verified_queue_size: usize, 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 + 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. /// A queue of blocks. Sits between network or other I/O and the BlockChain.
@ -30,6 +40,7 @@ pub struct BlockQueue {
verifiers: Vec<JoinHandle<()>>, verifiers: Vec<JoinHandle<()>>,
deleting: Arc<AtomicBool>, deleting: Arc<AtomicBool>,
ready_signal: Arc<QueueSignal>, ready_signal: Arc<QueueSignal>,
empty: Arc<Condvar>,
processing: HashSet<H256> processing: HashSet<H256>
} }
@ -74,6 +85,7 @@ impl BlockQueue {
let more_to_verify = Arc::new(Condvar::new()); let more_to_verify = Arc::new(Condvar::new());
let ready_signal = Arc::new(QueueSignal { signalled: AtomicBool::new(false), message_channel: message_channel }); let ready_signal = Arc::new(QueueSignal { signalled: AtomicBool::new(false), message_channel: message_channel });
let deleting = Arc::new(AtomicBool::new(false)); let deleting = Arc::new(AtomicBool::new(false));
let empty = Arc::new(Condvar::new());
let mut verifiers: Vec<JoinHandle<()>> = Vec::new(); let mut verifiers: Vec<JoinHandle<()>> = Vec::new();
let thread_count = max(::num_cpus::get(), 3) - 2; let thread_count = max(::num_cpus::get(), 3) - 2;
@ -82,8 +94,9 @@ impl BlockQueue {
let engine = engine.clone(); let engine = engine.clone();
let more_to_verify = more_to_verify.clone(); let more_to_verify = more_to_verify.clone();
let ready_signal = ready_signal.clone(); let ready_signal = ready_signal.clone();
let empty = empty.clone();
let deleting = deleting.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")); .expect("Error starting block verification thread"));
} }
BlockQueue { BlockQueue {
@ -94,13 +107,19 @@ impl BlockQueue {
verifiers: verifiers, verifiers: verifiers,
deleting: deleting.clone(), deleting: deleting.clone(),
processing: HashSet::new(), processing: HashSet::new(),
empty: empty.clone(),
} }
} }
fn verify(verification: Arc<Mutex<Verification>>, engine: Arc<Box<Engine>>, wait: Arc<Condvar>, ready: Arc<QueueSignal>, deleting: Arc<AtomicBool>) { fn verify(verification: Arc<Mutex<Verification>>, engine: Arc<Box<Engine>>, wait: Arc<Condvar>, ready: Arc<QueueSignal>, deleting: Arc<AtomicBool>, empty: Arc<Condvar>) {
while !deleting.load(AtomicOrdering::Relaxed) { while !deleting.load(AtomicOrdering::Relaxed) {
{ {
let mut lock = verification.lock().unwrap(); 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) { while lock.unverified.is_empty() && !deleting.load(AtomicOrdering::Relaxed) {
lock = wait.wait(lock).unwrap(); lock = wait.wait(lock).unwrap();
} }
@ -169,6 +188,14 @@ impl BlockQueue {
verification.verifying.clear(); verification.verifying.clear();
} }
/// Wait for queue to be empty
pub fn flush(&mut self) {
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. /// Add a block to the queue.
pub fn import_block(&mut self, bytes: Bytes) -> ImportResult { pub fn import_block(&mut self, bytes: Bytes) -> ImportResult {
let header = BlockView::new(&bytes).header(); let header = BlockView::new(&bytes).header();
@ -242,6 +269,7 @@ impl BlockQueue {
full: false, full: false,
verified_queue_size: verification.verified.len(), verified_queue_size: verification.verified.len(),
unverified_queue_size: verification.unverified.len(), unverified_queue_size: verification.unverified.len(),
verifying_queue_size: verification.verifying.len(),
} }
} }
} }

View File

@ -283,13 +283,6 @@ impl BlockChain {
bc 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: /// 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`. /// - 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. /// Inserts the block into backing cache database.
/// Expects the block to be valid and already verified. /// Expects the block to be valid and already verified.
/// If the block is already known, does nothing. /// If the block is already known, does nothing.

View File

@ -121,6 +121,7 @@ impl ClientReport {
} }
/// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue. /// 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 { pub struct Client {
chain: Arc<RwLock<BlockChain>>, chain: Arc<RwLock<BlockChain>>,
engine: Arc<Box<Engine>>, engine: Arc<Box<Engine>>,
@ -140,7 +141,8 @@ impl Client {
let mut opts = Options::new(); let mut opts = Options::new();
opts.set_max_open_files(256); opts.set_max_open_files(256);
opts.create_if_missing(true); opts.create_if_missing(true);
/*opts.set_use_fsync(false); opts.set_use_fsync(false);
/*
opts.set_bytes_per_sync(8388608); opts.set_bytes_per_sync(8388608);
opts.set_disable_data_sync(false); opts.set_disable_data_sync(false);
opts.set_block_cache_size_mb(1024); opts.set_block_cache_size_mb(1024);
@ -177,15 +179,16 @@ impl Client {
})) }))
} }
/// Flush the block import queue.
pub fn flush_queue(&self) {
self.block_queue.write().unwrap().flush();
}
/// This is triggered by a message coming from a block queue when the block is ready for insertion /// 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<NetSyncMessage>) { pub fn import_verified_blocks(&self, _io: &IoChannel<NetSyncMessage>) {
let mut bad = HashSet::new(); let mut bad = HashSet::new();
let _import_lock = self.import_lock.lock(); let _import_lock = self.import_lock.lock();
let blocks = self.block_queue.write().unwrap().drain(128); let blocks = self.block_queue.write().unwrap().drain(128);
if blocks.is_empty() {
return;
}
for block in blocks { for block in blocks {
if bad.contains(&block.header.parent_hash) { if bad.contains(&block.header.parent_hash) {
self.block_queue.write().unwrap().mark_as_bad(&block.header.hash()); self.block_queue.write().unwrap().mark_as_bad(&block.header.hash());
@ -233,6 +236,7 @@ impl Client {
} }
}; };
if let Err(e) = verify_block_final(&header, result.block().header()) { 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); 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()); self.block_queue.write().unwrap().mark_as_bad(&header.hash());
return; return;

View File

@ -26,7 +26,7 @@ pub enum MessageCallResult {
Failed Failed
} }
/// TODO [debris] Please document me /// Externalities interface for EVMs
pub trait Ext { pub trait Ext {
/// Returns a value for given key. /// Returns a value for given key.
fn storage_at(&self, key: &H256) -> H256; fn storage_at(&self, key: &H256) -> H256;
@ -55,8 +55,9 @@ pub trait Ext {
/// and true if subcall was successfull. /// and true if subcall was successfull.
fn call(&mut self, fn call(&mut self,
gas: &U256, gas: &U256,
address: &Address, sender_address: &Address,
value: &U256, receive_address: &Address,
value: Option<U256>,
data: &[u8], data: &[u8],
code_address: &Address, code_address: &Address,
output: &mut [u8]) -> MessageCallResult; output: &mut [u8]) -> MessageCallResult;

View File

@ -571,16 +571,10 @@ impl Interpreter {
let call_gas = stack.pop_back(); let call_gas = stack.pop_back();
let code_address = stack.pop_back(); let code_address = stack.pop_back();
let code_address = u256_to_address(&code_address); let code_address = u256_to_address(&code_address);
let is_delegatecall = instruction == instructions::DELEGATECALL;
let value = match is_delegatecall { let value = match instruction == instructions::DELEGATECALL {
true => params.value, true => None,
false => stack.pop_back() false => Some(stack.pop_back())
};
let address = match instruction == instructions::CALL {
true => &code_address,
false => &params.address
}; };
let in_off = stack.pop_back(); let in_off = stack.pop_back();
@ -588,13 +582,27 @@ impl Interpreter {
let out_off = stack.pop_back(); let out_off = stack.pop_back();
let out_size = stack.pop_back(); let out_size = stack.pop_back();
let call_gas = call_gas + match !is_delegatecall && 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), true => U256::from(ext.schedule().call_stipend),
false => U256::zero() 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(&params.address) >= value.unwrap();
(&params.address, &code_address, has_balance)
},
instructions::CALLCODE => {
let has_balance = ext.balance(&params.address) >= value.unwrap();
(&params.address, &params.address, has_balance)
},
instructions::DELEGATECALL => (&params.sender, &params.address, true),
_ => panic!(format!("Unexpected instruction {} in CALL branch.", instruction))
}; };
let can_call = (is_delegatecall || ext.balance(&params.address) >= value) && ext.depth() < ext.schedule().max_depth; let can_call = has_balance && ext.depth() < ext.schedule().max_depth;
if !can_call { if !can_call {
stack.push(U256::zero()); stack.push(U256::zero());
return Ok(InstructionResult::UnusedGas(call_gas)); return Ok(InstructionResult::UnusedGas(call_gas));
@ -605,7 +613,7 @@ impl Interpreter {
// and we don't want to copy // and we don't want to copy
let input = unsafe { ::std::mem::transmute(mem.read_slice(in_off, in_size)) }; let input = unsafe { ::std::mem::transmute(mem.read_slice(in_off, in_size)) };
let output = mem.writeable_slice(out_off, out_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, value, input, &code_address, output)
}; };
return match call_result { return match call_result {
@ -712,7 +720,10 @@ impl Interpreter {
stack.push(address_to_u256(params.sender.clone())); stack.push(address_to_u256(params.sender.clone()));
}, },
instructions::CALLVALUE => { instructions::CALLVALUE => {
stack.push(params.value.clone()); stack.push(match params.value {
ActionValue::Transfer(val) => val,
ActionValue::Apparent(val) => val,
});
}, },
instructions::CALLDATALOAD => { instructions::CALLDATALOAD => {
let big_id = stack.pop_back(); let big_id = stack.pop_back();

View File

@ -64,7 +64,7 @@ impl IntoJit<evmjit::I256> for H256 {
for i in 0..self.bytes().len() { for i in 0..self.bytes().len() {
let rev = self.bytes().len() - 1 - i; let rev = self.bytes().len() - 1 - i;
let pos = rev / 8; 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 } 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, &receive_address,
&value, Some(value),
unsafe { slice::from_raw_parts(in_beg, in_size as usize) }, unsafe { slice::from_raw_parts(in_beg, in_size as usize) },
&code_address, &code_address,
unsafe { slice::from_raw_parts_mut(out_beg, out_size as usize) }) { 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); 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 <= 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"); 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 call_data = params.data.unwrap_or_else(Vec::new);
let code = params.code.unwrap_or(vec![]); let code = params.code.unwrap_or_else(Vec::new);
let mut data = evmjit::RuntimeDataHandle::new(); let mut data = evmjit::RuntimeDataHandle::new();
data.gas = params.gas.low_u64() as i64; data.gas = params.gas.low_u64() as i64;
@ -303,7 +305,10 @@ impl evm::Evm for JitEvm {
data.address = params.address.into_jit(); data.address = params.address.into_jit();
data.caller = params.sender.into_jit(); data.caller = params.sender.into_jit();
data.origin = params.origin.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.author = ext.env_info().author.clone().into_jit();
data.difficulty = ext.env_info().difficulty.into_jit(); data.difficulty = ext.env_info().difficulty.into_jit();

View File

@ -2,67 +2,67 @@
/// Definition of the cost schedule and other parameterisations for the EVM. /// Definition of the cost schedule and other parameterisations for the EVM.
pub struct Schedule { pub struct Schedule {
/// TODO [Gav Wood] Please document me /// Does it support exceptional failed code deposit
pub exceptional_failed_code_deposit: bool, pub exceptional_failed_code_deposit: bool,
/// TODO [Gav Wood] Please document me /// Does it have a delegate cal
pub have_delegate_call: bool, pub have_delegate_call: bool,
/// TODO [Tomusdrw] Please document me /// VM stack limit
pub stack_limit: usize, pub stack_limit: usize,
/// TODO [Gav Wood] Please document me /// Max number of nested calls/creates
pub max_depth: usize, pub max_depth: usize,
/// TODO [Gav Wood] Please document me /// Gas prices for instructions in all tiers
pub tier_step_gas: [usize; 8], pub tier_step_gas: [usize; 8],
/// TODO [Gav Wood] Please document me /// Gas price for `EXP` opcode
pub exp_gas: usize, 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, pub exp_byte_gas: usize,
/// TODO [Gav Wood] Please document me /// Gas price for `SHA3` opcode
pub sha3_gas: usize, 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, pub sha3_word_gas: usize,
/// TODO [Gav Wood] Please document me /// Gas price for loading from storage
pub sload_gas: usize, 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, pub sstore_set_gas: usize,
/// TODO [Gav Wood] Please document me /// Gas price for altering value in storage
pub sstore_reset_gas: usize, 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, pub sstore_refund_gas: usize,
/// TODO [Gav Wood] Please document me /// Gas price for `JUMPDEST` opcode
pub jumpdest_gas: usize, pub jumpdest_gas: usize,
/// TODO [Gav Wood] Please document me /// Gas price for `LOG*`
pub log_gas: usize, pub log_gas: usize,
/// TODO [Gav Wood] Please document me /// Additional gas for data in `LOG*`
pub log_data_gas: usize, pub log_data_gas: usize,
/// TODO [Gav Wood] Please document me /// Additional gas for each topic in `LOG*`
pub log_topic_gas: usize, pub log_topic_gas: usize,
/// TODO [Gav Wood] Please document me /// Gas price for `CREATE` opcode
pub create_gas: usize, pub create_gas: usize,
/// TODO [Gav Wood] Please document me /// Gas price for `*CALL*` opcodes
pub call_gas: usize, pub call_gas: usize,
/// TODO [Gav Wood] Please document me /// Stipend for transfer for `CALL|CALLCODE` opcode when `value>0`
pub call_stipend: usize, pub call_stipend: usize,
/// TODO [Gav Wood] Please document me /// Additional gas required for value transfer (`CALL|CALLCODE`)
pub call_value_transfer_gas: usize, 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, pub call_new_account_gas: usize,
/// TODO [Gav Wood] Please document me /// Refund for SUICIDE
pub suicide_refund_gas: usize, pub suicide_refund_gas: usize,
/// TODO [Gav Wood] Please document me /// Gas for used memory
pub memory_gas: usize, 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, pub quad_coeff_div: usize,
/// TODO [Gav Wood] Please document me /// Cost for contract length when executing `CREATE`
pub create_data_gas: usize, pub create_data_gas: usize,
/// TODO [Gav Wood] Please document me /// Transaction cost
pub tx_gas: usize, pub tx_gas: usize,
/// TODO [Gav Wood] Please document me /// `CREATE` transaction cost
pub tx_create_gas: usize, pub tx_create_gas: usize,
/// TODO [Gav Wood] Please document me /// Additional cost for empty data transaction
pub tx_data_zero_gas: usize, 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, pub tx_data_non_zero_gas: usize,
/// TODO [Gav Wood] Please document me /// Gas price for copying memory
pub copy_gas: usize, pub copy_gas: usize,
} }

View File

@ -61,8 +61,9 @@ impl Ext for FakeExt {
fn call(&mut self, fn call(&mut self,
_gas: &U256, _gas: &U256,
_address: &Address, _sender_address: &Address,
_value: &U256, _receive_address: &Address,
_value: Option<U256>,
_data: &[u8], _data: &[u8],
_code_address: &Address, _code_address: &Address,
_output: &mut [u8]) -> MessageCallResult { _output: &mut [u8]) -> MessageCallResult {
@ -110,7 +111,7 @@ fn test_stack_underflow() {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let code = "01600055".from_hex().unwrap(); let code = "01600055".from_hex().unwrap();
let mut params = ActionParams::new(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(code);
@ -137,7 +138,7 @@ fn test_add(factory: super::Factory) {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let code = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01600055".from_hex().unwrap(); let code = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01600055".from_hex().unwrap();
let mut params = ActionParams::new(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(code);
@ -157,7 +158,7 @@ fn test_sha3(factory: super::Factory) {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let code = "6000600020600055".from_hex().unwrap(); let code = "6000600020600055".from_hex().unwrap();
let mut params = ActionParams::new(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(code);
@ -177,7 +178,7 @@ fn test_address(factory: super::Factory) {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let code = "30600055".from_hex().unwrap(); let code = "30600055".from_hex().unwrap();
let mut params = ActionParams::new(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(code);
@ -198,7 +199,7 @@ fn test_origin(factory: super::Factory) {
let origin = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").unwrap(); let origin = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").unwrap();
let code = "32600055".from_hex().unwrap(); let code = "32600055".from_hex().unwrap();
let mut params = ActionParams::new(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.origin = origin.clone(); params.origin = origin.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
@ -214,13 +215,14 @@ fn test_origin(factory: super::Factory) {
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681").unwrap()); 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} evm_test!{test_sender: test_sender_jit, test_sender_int}
fn test_sender(factory: super::Factory) { fn test_sender(factory: super::Factory) {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let sender = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").unwrap(); let sender = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").unwrap();
let code = "33600055".from_hex().unwrap(); let code = "33600055".from_hex().unwrap();
let mut params = ActionParams::new(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.sender = sender.clone(); params.sender = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
@ -254,7 +256,7 @@ fn test_extcodecopy(factory: super::Factory) {
let code = "333b60006000333c600051600055".from_hex().unwrap(); let code = "333b60006000333c600051600055".from_hex().unwrap();
let sender_code = "6005600055".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.address = address.clone();
params.sender = sender.clone(); params.sender = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
@ -276,7 +278,7 @@ fn test_log_empty(factory: super::Factory) {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let code = "60006000a0".from_hex().unwrap(); let code = "60006000a0".from_hex().unwrap();
let mut params = ActionParams::new(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(code);
@ -307,7 +309,7 @@ fn test_log_sender(factory: super::Factory) {
let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap();
let code = "60ff6000533360206000a1".from_hex().unwrap(); let code = "60ff6000533360206000a1".from_hex().unwrap();
let mut params = ActionParams::new(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.sender = sender.clone(); params.sender = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
@ -332,7 +334,7 @@ fn test_blockhash(factory: super::Factory) {
let code = "600040600055".from_hex().unwrap(); let code = "600040600055".from_hex().unwrap();
let blockhash = H256::from_str("123400000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681").unwrap(); let blockhash = H256::from_str("123400000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681").unwrap();
let mut params = ActionParams::new(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(code);
@ -354,7 +356,7 @@ fn test_calldataload(factory: super::Factory) {
let code = "600135600055".from_hex().unwrap(); let code = "600135600055".from_hex().unwrap();
let data = "0123ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff23".from_hex().unwrap(); let data = "0123ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff23".from_hex().unwrap();
let mut params = ActionParams::new(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(code);
@ -376,7 +378,7 @@ fn test_author(factory: super::Factory) {
let author = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let author = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let code = "41600055".from_hex().unwrap(); let code = "41600055".from_hex().unwrap();
let mut params = ActionParams::new(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(code);
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
@ -396,7 +398,7 @@ fn test_timestamp(factory: super::Factory) {
let timestamp = 0x1234; let timestamp = 0x1234;
let code = "42600055".from_hex().unwrap(); let code = "42600055".from_hex().unwrap();
let mut params = ActionParams::new(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(code);
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
@ -416,7 +418,7 @@ fn test_number(factory: super::Factory) {
let number = 0x1234; let number = 0x1234;
let code = "43600055".from_hex().unwrap(); let code = "43600055".from_hex().unwrap();
let mut params = ActionParams::new(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(code);
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
@ -436,7 +438,7 @@ fn test_difficulty(factory: super::Factory) {
let difficulty = U256::from(0x1234); let difficulty = U256::from(0x1234);
let code = "44600055".from_hex().unwrap(); let code = "44600055".from_hex().unwrap();
let mut params = ActionParams::new(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(code);
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();
@ -456,7 +458,7 @@ fn test_gas_limit(factory: super::Factory) {
let gas_limit = U256::from(0x1234); let gas_limit = U256::from(0x1234);
let code = "45600055".from_hex().unwrap(); let code = "45600055".from_hex().unwrap();
let mut params = ActionParams::new(); let mut params = ActionParams::default();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code); params.code = Some(code);
let mut ext = FakeExt::new(); let mut ext = FakeExt::new();

View File

@ -5,6 +5,12 @@ use engine::*;
use evm::{self, Ext}; use evm::{self, Ext};
use externalities::*; use externalities::*;
use substate::*; 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. /// Returns new address created from address and given nonce.
pub fn contract_address(address: &Address, nonce: &U256) -> Address { pub fn contract_address(address: &Address, nonce: &U256) -> Address {
@ -133,7 +139,7 @@ impl<'a> Executive<'a> {
origin: sender.clone(), origin: sender.clone(),
gas: init_gas, gas: init_gas,
gas_price: t.gas_price, gas_price: t.gas_price,
value: t.value, value: ActionValue::Transfer(t.value),
code: Some(t.data.clone()), code: Some(t.data.clone()),
data: None, data: None,
}; };
@ -147,7 +153,7 @@ impl<'a> Executive<'a> {
origin: sender.clone(), origin: sender.clone(),
gas: init_gas, gas: init_gas,
gas_price: t.gas_price, gas_price: t.gas_price,
value: t.value, value: ActionValue::Transfer(t.value),
code: self.state.code(address), code: self.state.code(address),
data: Some(t.data.clone()), data: Some(t.data.clone()),
}; };
@ -161,6 +167,27 @@ impl<'a> Executive<'a> {
Ok(try!(self.finalize(t, substate, res))) 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(&params), 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(&params), 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. /// Calls contract function with given contract params.
/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides). /// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
/// Modifies the substate and the output. /// Modifies the substate and the output.
@ -170,7 +197,9 @@ impl<'a> Executive<'a> {
let backup = self.state.clone(); let backup = self.state.clone();
// at first, transfer value to destination // at first, transfer value to destination
self.state.transfer_balance(&params.sender, &params.address, &params.value); if let ActionValue::Transfer(val) = params.value {
self.state.transfer_balance(&params.sender, &params.address, &val);
}
trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info); trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);
if self.engine.is_builtin(&params.code_address) { if self.engine.is_builtin(&params.code_address) {
@ -198,8 +227,7 @@ impl<'a> Executive<'a> {
let mut unconfirmed_substate = Substate::new(); let mut unconfirmed_substate = Substate::new();
let res = { let res = {
let mut ext = self.as_externalities(OriginInfo::from(&params), &mut unconfirmed_substate, OutputPolicy::Return(output)); self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output))
self.engine.vm_factory().create().exec(params, &mut ext)
}; };
trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count); trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count);
@ -227,11 +255,12 @@ impl<'a> Executive<'a> {
self.state.new_contract(&params.address); self.state.new_contract(&params.address);
// then transfer value to it // then transfer value to it
self.state.transfer_balance(&params.sender, &params.address, &params.value); if let ActionValue::Transfer(val) = params.value {
self.state.transfer_balance(&params.sender, &params.address, &val);
}
let res = { let res = {
let mut ext = self.as_externalities(OriginInfo::from(&params), &mut unconfirmed_substate, OutputPolicy::InitContract); self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract)
self.engine.vm_factory().create().exec(params, &mut ext)
}; };
self.enact_result(&res, substate, unconfirmed_substate, backup); self.enact_result(&res, substate, unconfirmed_substate, backup);
res res
@ -272,7 +301,6 @@ impl<'a> Executive<'a> {
match result { match result {
Err(evm::Error::Internal) => Err(ExecutionError::Internal), Err(evm::Error::Internal) => Err(ExecutionError::Internal),
// TODO [ToDr] BadJumpDestination @debris - how to handle that?
Err(_) => { Err(_) => {
Ok(Executed { Ok(Executed {
gas: t.gas, gas: t.gas,
@ -297,7 +325,6 @@ impl<'a> Executive<'a> {
} }
fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate, backup: State) { 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 { match *result {
Err(evm::Error::OutOfGas) Err(evm::Error::OutOfGas)
| Err(evm::Error::BadJumpDestination {..}) | Err(evm::Error::BadJumpDestination {..})
@ -363,12 +390,12 @@ mod tests {
fn test_sender_balance(factory: Factory) { fn test_sender_balance(factory: Factory) {
let sender = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let sender = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
let address = contract_address(&sender, &U256::zero()); let address = contract_address(&sender, &U256::zero());
let mut params = ActionParams::new(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.sender = sender.clone(); params.sender = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some("3331600055".from_hex().unwrap()); 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(); let mut state = State::new_temp();
state.add_balance(&sender, &U256::from(0x100u64)); state.add_balance(&sender, &U256::from(0x100u64));
let info = EnvInfo::new(); let info = EnvInfo::new();
@ -420,13 +447,13 @@ mod tests {
let address = contract_address(&sender, &U256::zero()); let address = contract_address(&sender, &U256::zero());
// TODO: add tests for 'callcreate' // TODO: add tests for 'callcreate'
//let next_address = contract_address(&address, &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.address = address.clone();
params.sender = sender.clone(); params.sender = sender.clone();
params.origin = sender.clone(); params.origin = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code.clone()); params.code = Some(code.clone());
params.value = U256::from(100); params.value = ActionValue::Transfer(U256::from(100));
let mut state = State::new_temp(); let mut state = State::new_temp();
state.add_balance(&sender, &U256::from(100)); state.add_balance(&sender, &U256::from(100));
let info = EnvInfo::new(); let info = EnvInfo::new();
@ -473,13 +500,13 @@ mod tests {
let address = contract_address(&sender, &U256::zero()); let address = contract_address(&sender, &U256::zero());
// TODO: add tests for 'callcreate' // TODO: add tests for 'callcreate'
//let next_address = contract_address(&address, &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.address = address.clone();
params.sender = sender.clone(); params.sender = sender.clone();
params.origin = sender.clone(); params.origin = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code.clone()); params.code = Some(code.clone());
params.value = U256::from(100); params.value = ActionValue::Transfer(U256::from(100));
let mut state = State::new_temp(); let mut state = State::new_temp();
state.add_balance(&sender, &U256::from(100)); state.add_balance(&sender, &U256::from(100));
let info = EnvInfo::new(); let info = EnvInfo::new();
@ -524,13 +551,13 @@ mod tests {
let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap();
let address = contract_address(&sender, &U256::zero()); let address = contract_address(&sender, &U256::zero());
let next_address = contract_address(&address, &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.address = address.clone();
params.sender = sender.clone(); params.sender = sender.clone();
params.origin = sender.clone(); params.origin = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code.clone()); params.code = Some(code.clone());
params.value = U256::from(100); params.value = ActionValue::Transfer(U256::from(100));
let mut state = State::new_temp(); let mut state = State::new_temp();
state.add_balance(&sender, &U256::from(100)); state.add_balance(&sender, &U256::from(100));
let info = EnvInfo::new(); let info = EnvInfo::new();
@ -580,12 +607,12 @@ mod tests {
let address_b = Address::from_str("945304eb96065b2a98b57a48a06ae28d285a71b5" ).unwrap(); let address_b = Address::from_str("945304eb96065b2a98b57a48a06ae28d285a71b5" ).unwrap();
let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap();
let mut params = ActionParams::new(); let mut params = ActionParams::default();
params.address = address_a.clone(); params.address = address_a.clone();
params.sender = sender.clone(); params.sender = sender.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code_a.clone()); 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(); let mut state = State::new_temp();
state.init_code(&address_a, code_a.clone()); state.init_code(&address_a, code_a.clone());
@ -629,7 +656,7 @@ mod tests {
let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap();
let code = "600160005401600055600060006000600060003060e05a03f1600155".from_hex().unwrap(); let code = "600160005401600055600060006000600060003060e05a03f1600155".from_hex().unwrap();
let address = contract_address(&sender, &U256::zero()); let address = contract_address(&sender, &U256::zero());
let mut params = ActionParams::new(); let mut params = ActionParams::default();
params.address = address.clone(); params.address = address.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(code.clone()); params.code = Some(code.clone());
@ -785,13 +812,13 @@ mod tests {
let address = contract_address(&sender, &U256::zero()); let address = contract_address(&sender, &U256::zero());
// TODO: add tests for 'callcreate' // TODO: add tests for 'callcreate'
//let next_address = contract_address(&address, &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.address = address.clone();
params.sender = sender.clone(); params.sender = sender.clone();
params.origin = sender.clone(); params.origin = sender.clone();
params.gas = U256::from(0x0186a0); params.gas = U256::from(0x0186a0);
params.code = Some(code.clone()); 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(); let mut state = State::new_temp();
state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap()); state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap());
let info = EnvInfo::new(); let info = EnvInfo::new();

View File

@ -19,7 +19,8 @@ pub enum OutputPolicy<'a> {
pub struct OriginInfo { pub struct OriginInfo {
address: Address, address: Address,
origin: Address, origin: Address,
gas_price: U256 gas_price: U256,
value: U256
} }
impl OriginInfo { impl OriginInfo {
@ -28,7 +29,11 @@ impl OriginInfo {
OriginInfo { OriginInfo {
address: params.address.clone(), address: params.address.clone(),
origin: params.origin.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,
}
} }
} }
} }
@ -111,7 +116,7 @@ impl<'a> Ext for Externalities<'a> {
origin: self.origin_info.origin.clone(), origin: self.origin_info.origin.clone(),
gas: *gas, gas: *gas,
gas_price: self.origin_info.gas_price.clone(), gas_price: self.origin_info.gas_price.clone(),
value: value.clone(), value: ActionValue::Transfer(value.clone()),
code: Some(code.to_vec()), code: Some(code.to_vec()),
data: None, data: None,
}; };
@ -131,24 +136,29 @@ impl<'a> Ext for Externalities<'a> {
fn call(&mut self, fn call(&mut self,
gas: &U256, gas: &U256,
address: &Address, sender_address: &Address,
value: &U256, receive_address: &Address,
value: Option<U256>,
data: &[u8], data: &[u8],
code_address: &Address, code_address: &Address,
output: &mut [u8]) -> MessageCallResult { 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(), code_address: code_address.clone(),
address: address.clone(),
sender: self.origin_info.address.clone(),
origin: self.origin_info.origin.clone(), origin: self.origin_info.origin.clone(),
gas: *gas, gas: *gas,
gas_price: self.origin_info.gas_price.clone(), gas_price: self.origin_info.gas_price.clone(),
value: value.clone(),
code: self.state.code(code_address), code: self.state.code(code_address),
data: Some(data.to_vec()), data: Some(data.to_vec()),
}; };
if let Some(value) = value {
params.value = ActionValue::Transfer(value);
}
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth); let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth);
match ex.call(params, self.substate, BytesRef::Fixed(output)) { match ex.call(params, self.substate, BytesRef::Fixed(output)) {

View File

@ -90,6 +90,7 @@ extern crate num_cpus;
extern crate evmjit; extern crate evmjit;
#[macro_use] #[macro_use]
extern crate ethcore_util as util; extern crate ethcore_util as util;
extern crate crossbeam;
// NOTE: Add doc parser exception for these pub declarations. // NOTE: Add doc parser exception for these pub declarations.

View File

@ -1,17 +1,25 @@
use util::*; use util::*;
use pod_account::*; use pod_account::*;
#[derive(Debug,Clone,PartialEq,Eq)] #[derive(Debug,Clone,PartialEq,Eq,Default)]
/// TODO [Gav Wood] Please document me /// TODO [Gav Wood] Please document me
pub struct PodState (BTreeMap<Address, PodAccount>); pub struct PodState (BTreeMap<Address, PodAccount>);
impl PodState { impl PodState {
/// Contruct a new object from the `m`. /// Contruct a new object from the `m`.
pub fn new(m: BTreeMap<Address, PodAccount>) -> PodState { PodState(m) } pub fn new() -> PodState { Default::default() }
/// Contruct a new object from the `m`.
pub fn from(m: BTreeMap<Address, PodAccount>) -> PodState { PodState(m) }
/// Get the underlying map. /// Get the underlying map.
pub fn get(&self) -> &BTreeMap<Address, PodAccount> { &self.0 } pub fn get(&self) -> &BTreeMap<Address, PodAccount> { &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. /// Drain object to get the underlying map.
pub fn drain(self) -> BTreeMap<Address, PodAccount> { self.0 } pub fn drain(self) -> BTreeMap<Address, PodAccount> { self.0 }
} }

View File

@ -1,6 +1,7 @@
use common::*; use common::*;
use flate2::read::GzDecoder; use flate2::read::GzDecoder;
use engine::*; use engine::*;
use pod_state::*;
use null_engine::*; use null_engine::*;
/// Converts file from base64 gzipped bytes to json /// Converts file from base64 gzipped bytes to json
@ -40,28 +41,6 @@ fn json_to_rlp_map(json: &Json) -> HashMap<String, Bytes> {
}) })
} }
//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 /// 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. /// chain and those to be interpreted by the active chain engine.
#[derive(Debug)] #[derive(Debug)]
@ -83,7 +62,7 @@ pub struct Spec {
// Builtin-contracts are here for now but would like to abstract into Engine API eventually. // Builtin-contracts are here for now but would like to abstract into Engine API eventually.
/// TODO [Gav Wood] Please document me /// TODO [Gav Wood] Please document me
pub builtins: HashMap<Address, Builtin>, pub builtins: BTreeMap<Address, Builtin>,
// Genesis params. // Genesis params.
/// TODO [Gav Wood] Please document me /// TODO [Gav Wood] Please document me
@ -101,7 +80,7 @@ pub struct Spec {
/// TODO [arkpar] Please document me /// TODO [arkpar] Please document me
pub extra_data: Bytes, pub extra_data: Bytes,
/// TODO [Gav Wood] Please document me /// TODO [Gav Wood] Please document me
pub genesis_state: HashMap<Address, GenesisAccount>, genesis_state: PodState,
/// TODO [Gav Wood] Please document me /// TODO [Gav Wood] Please document me
pub seal_fields: usize, pub seal_fields: usize,
/// TODO [Gav Wood] Please document me /// TODO [Gav Wood] Please document me
@ -126,7 +105,7 @@ impl Spec {
/// Return the state root for the genesis state, memoising accordingly. /// Return the state root for the genesis state, memoising accordingly.
pub fn state_root(&self) -> H256 { pub fn state_root(&self) -> H256 {
if self.state_root_memo.read().unwrap().is_none() { 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() self.state_root_memo.read().unwrap().as_ref().unwrap().clone()
} }
@ -174,6 +153,46 @@ impl Spec {
ret.append_raw(&empty_list, 1); ret.append_raw(&empty_list, 1);
ret.out() 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"]))));
}
/// 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 { impl FromJson for Spec {
@ -181,8 +200,8 @@ impl FromJson for Spec {
fn from_json(json: &Json) -> Spec { fn from_json(json: &Json) -> Spec {
// once we commit ourselves to some json parsing library (serde?) // once we commit ourselves to some json parsing library (serde?)
// move it to proper data structure // move it to proper data structure
let mut state = HashMap::new(); let mut builtins = BTreeMap::new();
let mut builtins = HashMap::new(); let mut state = PodState::new();
if let Some(&Json::Object(ref accounts)) = json.find("accounts") { if let Some(&Json::Object(ref accounts)) = json.find("accounts") {
for (address, acc) in accounts.iter() { for (address, acc) in accounts.iter() {
@ -192,15 +211,8 @@ impl FromJson for Spec {
builtins.insert(addr.clone(), builtin); 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") { let nodes = if let Some(&Json::Array(ref ns)) = json.find("nodes") {
@ -253,7 +265,7 @@ impl Spec {
let mut root = H256::new(); let mut root = H256::new();
{ {
let mut t = SecTrieDBMut::new(db, &mut root); 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()); t.insert(address.as_slice(), &account.rlp());
} }
} }

View File

@ -3,7 +3,7 @@ use engine::Engine;
use executive::Executive; use executive::Executive;
use pod_account::*; use pod_account::*;
use pod_state::*; use pod_state::*;
use state_diff::*; //use state_diff::*; // TODO: uncomment once to_pod() works correctly.
/// TODO [Gav Wood] Please document me /// TODO [Gav Wood] Please document me
pub type ApplyResult = Result<Receipt, Error>; pub type ApplyResult = Result<Receipt, Error>;
@ -145,16 +145,16 @@ impl State {
/// Execute a given transaction. /// Execute a given transaction.
/// This will change the state accordingly. /// This will change the state accordingly.
pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &Transaction) -> ApplyResult { 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)); let e = try!(Executive::new(self, env_info, engine).transact(t));
//println!("Executed: {:?}", e); //println!("Executed: {:?}", e);
trace!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod())); // TODO uncomment once to_pod() works correctly.
// trace!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod()));
self.commit(); self.commit();
let receipt = Receipt::new(self.root().clone(), e.cumulative_gas_used, e.logs); let receipt = Receipt::new(self.root().clone(), e.cumulative_gas_used, e.logs);
trace!("Transaction receipt: {:?}", receipt); // trace!("Transaction receipt: {:?}", receipt);
Ok(receipt) Ok(receipt)
} }
@ -221,7 +221,7 @@ impl State {
/// Populate a PodAccount map from this state. /// Populate a PodAccount map from this state.
pub fn to_pod(&self) -> PodState { pub fn to_pod(&self) -> PodState {
// TODO: handle database rather than just the cache. // 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 { if let Some(ref acc) = *opt {
m.insert(add.clone(), PodAccount::from_account(acc)); m.insert(add.clone(), PodAccount::from_account(acc));
} }

View File

@ -32,8 +32,8 @@ mod test {
#[test] #[test]
fn create_delete() { fn create_delete() {
let a = PodState::new(map![ x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]) ]); let a = PodState::from(map![ x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]) ]);
assert_eq!(StateDiff::diff_pod(&a, &PodState::new(map![])), StateDiff(map![ assert_eq!(StateDiff::diff_pod(&a, &PodState::new()), StateDiff(map![
x!(1) => AccountDiff{ x!(1) => AccountDiff{
balance: Diff::Died(x!(69)), balance: Diff::Died(x!(69)),
nonce: Diff::Died(x!(0)), nonce: Diff::Died(x!(0)),
@ -41,7 +41,7 @@ mod test {
storage: map![], 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{ x!(1) => AccountDiff{
balance: Diff::Born(x!(69)), balance: Diff::Born(x!(69)),
nonce: Diff::Born(x!(0)), nonce: Diff::Born(x!(0)),
@ -53,8 +53,8 @@ mod test {
#[test] #[test]
fn create_delete_with_unchanged() { fn create_delete_with_unchanged() {
let a = PodState::new(map![ x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]) ]); let a = PodState::from(map![ x!(1) => 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!(0), vec![], map![]), x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]),
x!(2) => 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] #[test]
fn change_with_unchanged() { 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!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]),
x!(2) => 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!(1) => PodAccount::new(x!(69), x!(1), vec![], map![]),
x!(2) => PodAccount::new(x!(69), x!(0), vec![], map![]) x!(2) => PodAccount::new(x!(69), x!(0), vec![], map![])
]); ]);

View File

@ -9,13 +9,13 @@
/// extern crate ethcore; /// extern crate ethcore;
/// use std::env; /// use std::env;
/// use std::sync::Arc; /// use std::sync::Arc;
/// use util::network::NetworkService; /// use util::network::{NetworkService, NetworkConfiguration};
/// use ethcore::client::Client; /// use ethcore::client::Client;
/// use ethcore::sync::EthSync; /// use ethcore::sync::EthSync;
/// use ethcore::ethereum; /// use ethcore::ethereum;
/// ///
/// fn main() { /// fn main() {
/// let mut service = NetworkService::start().unwrap(); /// let mut service = NetworkService::start(NetworkConfiguration::new()).unwrap();
/// let dir = env::temp_dir(); /// let dir = env::temp_dir();
/// let client = Client::new(ethereum::new_frontier(), &dir, service.io().channel()).unwrap(); /// let client = Client::new(ethereum::new_frontier(), &dir, service.io().channel()).unwrap();
/// EthSync::register(&mut service, client); /// EthSync::register(&mut service, client);

View File

@ -158,6 +158,7 @@ impl BlockChainClient for TestBlockChainClient {
full: false, full: false,
verified_queue_size: 0, verified_queue_size: 0,
unverified_queue_size: 0, unverified_queue_size: 0,
verifying_queue_size: 0,
} }
} }

64
src/tests/chain.rs Normal file
View File

@ -0,0 +1,64 @@
use std::env;
use super::test_common::*;
use client::{BlockChainClient,Client};
use pod_state::*;
use ethereum;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
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<Bytes> = 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());
assert!(spec.is_state_root_valid());
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());
fail_unless(client.chain_info().best_block_hash == H256::from_json(&test["lastblockhash"]));
}
fs::remove_dir_all(&dir).unwrap();
}
if !fail {
flush(format!("ok\n"));
}
}
println!("!!! {:?} tests from failed.", failed.len());
failed
}
declare_test!{ignore => BlockchainTests_bcBlockGasLimitTest, "BlockchainTests/bcBlockGasLimitTest"} // FAILS
declare_test!{BlockchainTests_bcForkBlockTest, "BlockchainTests/bcForkBlockTest"}
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

View File

@ -101,8 +101,9 @@ impl<'a> Ext for TestExt<'a> {
fn call(&mut self, fn call(&mut self,
gas: &U256, gas: &U256,
_sender_address: &Address,
receive_address: &Address, receive_address: &Address,
value: &U256, value: Option<U256>,
data: &[u8], data: &[u8],
_code_address: &Address, _code_address: &Address,
_output: &mut [u8]) -> MessageCallResult { _output: &mut [u8]) -> MessageCallResult {
@ -110,7 +111,7 @@ impl<'a> Ext for TestExt<'a> {
data: data.to_vec(), data: data.to_vec(),
destination: Some(receive_address.clone()), destination: Some(receive_address.clone()),
gas_limit: *gas, gas_limit: *gas,
value: *value value: value.unwrap()
}); });
MessageCallResult::Success(*gas) MessageCallResult::Success(*gas)
} }
@ -194,7 +195,7 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec<String> {
let engine = TestEngine::new(1, vm.clone()); let engine = TestEngine::new(1, vm.clone());
// params // params
let mut params = ActionParams::new(); let mut params = ActionParams::default();
test.find("exec").map(|exec| { test.find("exec").map(|exec| {
params.address = xjson!(&exec["address"]); params.address = xjson!(&exec["address"]);
params.sender = xjson!(&exec["caller"]); params.sender = xjson!(&exec["caller"]);
@ -203,7 +204,7 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec<String> {
params.data = xjson!(&exec["data"]); params.data = xjson!(&exec["data"]);
params.gas = xjson!(&exec["gas"]); params.gas = xjson!(&exec["gas"]);
params.gas_price = xjson!(&exec["gasPrice"]); 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| { let out_of_gas = test.find("callcreates").map(|_calls| {
@ -270,8 +271,8 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec<String> {
declare_test!{ExecutiveTests_vmArithmeticTest, "VMTests/vmArithmeticTest"} declare_test!{ExecutiveTests_vmArithmeticTest, "VMTests/vmArithmeticTest"}
declare_test!{ExecutiveTests_vmBitwiseLogicOperationTest, "VMTests/vmBitwiseLogicOperationTest"} declare_test!{ExecutiveTests_vmBitwiseLogicOperationTest, "VMTests/vmBitwiseLogicOperationTest"}
// this one crashes with some vm internal error. Separately they pass. declare_test!{ExecutiveTests_vmBlockInfoTest, "VMTests/vmBlockInfoTest"}
declare_test!{ignore => ExecutiveTests_vmBlockInfoTest, "VMTests/vmBlockInfoTest"} // TODO [todr] Fails with Signal 11 when using JIT
declare_test!{ExecutiveTests_vmEnvironmentalInfoTest, "VMTests/vmEnvironmentalInfoTest"} declare_test!{ExecutiveTests_vmEnvironmentalInfoTest, "VMTests/vmEnvironmentalInfoTest"}
declare_test!{ExecutiveTests_vmIOandFlowOperationsTest, "VMTests/vmIOandFlowOperationsTest"} declare_test!{ExecutiveTests_vmIOandFlowOperationsTest, "VMTests/vmIOandFlowOperationsTest"}
declare_test!{heavy => ExecutiveTests_vmInputLimits, "VMTests/vmInputLimits"} declare_test!{heavy => ExecutiveTests_vmInputLimits, "VMTests/vmInputLimits"}

View File

@ -4,4 +4,5 @@ mod test_common;
mod transaction; mod transaction;
mod executive; mod executive;
mod state; mod state;
mod client; mod client;
mod chain;

View File

@ -73,7 +73,7 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
declare_test!{StateTests_stBlockHashTest, "StateTests/stBlockHashTest"} declare_test!{StateTests_stBlockHashTest, "StateTests/stBlockHashTest"}
declare_test!{StateTests_stCallCodes, "StateTests/stCallCodes"} 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_stDelegatecallTest, "StateTests/stDelegatecallTest"}
declare_test!{StateTests_stExample, "StateTests/stExample"} declare_test!{StateTests_stExample, "StateTests/stExample"}
declare_test!{StateTests_stInitCodeTest, "StateTests/stInitCodeTest"} 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_stMemoryStressTest, "StateTests/stMemoryStressTest"}
declare_test!{heavy => StateTests_stMemoryTest, "StateTests/stMemoryTest"} declare_test!{heavy => StateTests_stMemoryTest, "StateTests/stMemoryTest"}
declare_test!{StateTests_stPreCompiledContracts, "StateTests/stPreCompiledContracts"} declare_test!{StateTests_stPreCompiledContracts, "StateTests/stPreCompiledContracts"}
declare_test!{heavy => StateTests_stQuadraticComplexityTest, "StateTests/stQuadraticComplexityTest"} //<< Too long declare_test!{heavy => StateTests_stQuadraticComplexityTest, "StateTests/stQuadraticComplexityTest"}
declare_test!{ignore => StateTests_stRecursiveCreate, "StateTests/stRecursiveCreate"} //<< Out of stack declare_test!{StateTests_stRecursiveCreate, "StateTests/stRecursiveCreate"}
declare_test!{StateTests_stRefundTest, "StateTests/stRefundTest"} declare_test!{StateTests_stRefundTest, "StateTests/stRefundTest"}
declare_test!{StateTests_stSolidityTest, "StateTests/stSolidityTest"} declare_test!{StateTests_stSolidityTest, "StateTests/stSolidityTest"}
declare_test!{ignore => StateTests_stSpecialTest, "StateTests/stSpecialTest"} //<< Out of Stack declare_test!{StateTests_stSpecialTest, "StateTests/stSpecialTest"}
declare_test!{ignore => StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"} //<< Out of stack declare_test!{StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"}
declare_test!{StateTests_stTransactionTest, "StateTests/stTransactionTest"} declare_test!{StateTests_stTransactionTest, "StateTests/stTransactionTest"}
declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"} declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"}
declare_test!{StateTests_stWalletTest, "StateTests/stWalletTest"} declare_test!{StateTests_stWalletTest, "StateTests/stWalletTest"}

View File

@ -469,6 +469,18 @@ impl<'_> From<&'_ U256> for H256 {
} }
} }
impl From<H256> 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<H256> for Address { impl From<H256> for Address {
fn from(value: H256) -> Address { fn from(value: H256) -> Address {
unsafe { unsafe {
@ -562,6 +574,7 @@ pub static ZERO_H256: H256 = H256([0x00; 32]);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use hash::*; use hash::*;
use uint::*;
use std::str::FromStr; use std::str::FromStr;
#[test] #[test]
@ -635,5 +648,18 @@ mod tests {
// too short. // too short.
assert_eq!(H64::from(0), H64::from("0x34567890abcdef")); 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);
}
} }

View File

@ -1,13 +1,14 @@
pub use std::io; pub use std::io;
pub use std::fs;
pub use std::str; pub use std::str;
pub use std::fmt; pub use std::fmt;
pub use std::slice;
pub use std::cmp; pub use std::cmp;
pub use std::ptr; pub use std::ptr;
pub use std::result;
pub use std::option;
pub use std::mem; pub use std::mem;
pub use std::ops; pub use std::ops;
pub use std::slice;
pub use std::result;
pub use std::option;
pub use std::path::Path; pub use std::path::Path;
pub use std::str::{FromStr}; pub use std::str::{FromStr};
@ -15,9 +16,9 @@ pub use std::io::{Read,Write};
pub use std::hash::{Hash, Hasher}; pub use std::hash::{Hash, Hasher};
pub use std::error::Error as StdError; pub use std::error::Error as StdError;
pub use std::sync::*;
pub use std::ops::*; pub use std::ops::*;
pub use std::cmp::*; pub use std::cmp::*;
pub use std::sync::*;
pub use std::cell::*; pub use std::cell::*;
pub use std::collections::*; pub use std::collections::*;