Merge remote-tracking branch 'remotes/upstream/master' into transactions-permission-contract-fix

This commit is contained in:
Vlad Lupashevskyi
2017-12-28 12:56:21 +02:00
100 changed files with 385 additions and 441 deletions

View File

@@ -11,7 +11,6 @@ ansi_term = "0.9"
bloomchain = "0.1"
bn = { git = "https://github.com/paritytech/bn" }
byteorder = "1.0"
clippy = { version = "0.0.103", optional = true}
common-types = { path = "types" }
crossbeam = "0.2.9"
ethash = { path = "../ethash" }
@@ -83,6 +82,5 @@ evm-debug-tests = ["evm-debug"]
slow-blocks = [] # Use SLOW_TX_DURATION="50" (compile time!) to track transactions over 50ms
json-tests = []
test-heavy = []
dev = ["clippy"]
default = []
benches = []

View File

@@ -32,7 +32,6 @@ macro_rules! overflowing {
}}
}
#[cfg_attr(feature="dev", allow(enum_variant_names))]
enum Request<Cost: ::evm::CostType> {
Gas(Cost),
GasMem(Cost, Cost),
@@ -101,7 +100,6 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
}
}
#[cfg_attr(feature="dev", allow(cyclomatic_complexity))]
/// Determine how much gas is used by the given instruction, given the machine's state.
///
/// We guarantee that the final element of the returned tuple (`provided`) will be `Some`

View File

@@ -66,7 +66,6 @@ struct CodeReader<'a> {
code: &'a [u8]
}
#[cfg_attr(feature="dev", allow(len_without_is_empty))]
impl<'a> CodeReader<'a> {
/// Create new code reader - starting at position 0.
@@ -287,7 +286,6 @@ impl<Cost: CostType> Interpreter<Cost> {
}
}
#[cfg_attr(feature="dev", allow(too_many_arguments))]
fn exec_instruction(
&mut self,
gas: Cost,

View File

@@ -22,7 +22,6 @@ pub type LogBloom = ::log_entry::LogBloom;
/// Constant 2048-bit datum for 0. Often used as a default.
pub static ZERO_LOGBLOOM: LogBloom = ::bigint::hash::H2048([0x00; 256]);
#[cfg_attr(feature="dev", allow(enum_variant_names))]
/// Semantic boolean for when a seal/signature is included.
pub enum Seal {
/// The seal/signature is included.

View File

@@ -301,7 +301,6 @@ pub struct SealedBlock {
}
impl<'x> OpenBlock<'x> {
#[cfg_attr(feature="dev", allow(too_many_arguments))]
/// Create a new `OpenBlock` ready for transaction pushing.
pub fn new(
engine: &'x EthEngine,
@@ -614,7 +613,6 @@ impl IsBlock for SealedBlock {
}
/// Enact the block given by block header, transactions and uncles
#[cfg_attr(feature="dev", allow(too_many_arguments))]
pub fn enact(
header: &Header,
transactions: &[SignedTransaction],
@@ -688,7 +686,6 @@ fn push_transactions(block: &mut OpenBlock, transactions: &[SignedTransaction])
// TODO [ToDr] Pass `PreverifiedBlock` by move, this will avoid unecessary allocation
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
#[cfg_attr(feature="dev", allow(too_many_arguments))]
pub fn enact_verified(
block: &PreverifiedBlock,
engine: &EthEngine,
@@ -731,7 +728,6 @@ mod tests {
use transaction::SignedTransaction;
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
#[cfg_attr(feature="dev", allow(too_many_arguments))]
fn enact_bytes(
block_bytes: &[u8],
engine: &EthEngine,
@@ -778,7 +774,6 @@ mod tests {
}
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards
#[cfg_attr(feature="dev", allow(too_many_arguments))]
fn enact_and_seal(
block_bytes: &[u8],
engine: &EthEngine,

View File

@@ -970,7 +970,6 @@ impl BlockChain {
self.cache_man.lock().note_used(CacheId::BlockDetails(block_hash));
}
#[cfg_attr(feature="dev", allow(similar_names))]
/// Inserts the block into backing cache database.
/// Expects the block to be valid and already verified.
/// If the block is already known, does nothing.
@@ -1475,7 +1474,6 @@ impl BlockChain {
#[cfg(test)]
mod tests {
#![cfg_attr(feature="dev", allow(similar_names))]
use std::sync::Arc;
use rustc_hex::FromHex;
use hash::keccak;
@@ -1583,7 +1581,6 @@ mod tests {
}
#[test]
#[cfg_attr(feature="dev", allow(cyclomatic_complexity))]
fn test_find_uncles() {
let mut canon_chain = ChainGenerator::default();
let mut finalizer = BlockFinalizer::default();
@@ -1793,7 +1790,6 @@ mod tests {
}
#[test]
#[cfg_attr(feature="dev", allow(cyclomatic_complexity))]
fn test_small_fork() {
let mut canon_chain = ChainGenerator::default();
let mut finalizer = BlockFinalizer::default();

View File

@@ -1857,7 +1857,7 @@ impl MiningBlockChainClient for Client {
let mut open_block = OpenBlock::new(
engine,
self.factories.clone(),
false, // TODO: this will need to be parameterised once we want to do immediate mining insertion.
self.tracedb.read().tracing_enabled(),
self.state_db.lock().boxed_clone_canon(&h),
best_header,
self.build_last_hashes(h.clone()),

View File

@@ -51,8 +51,12 @@ mod finality;
/// `AuthorityRound` params.
pub struct AuthorityRoundParams {
/// Time to wait before next block or authority switching.
pub step_duration: Duration,
/// Time to wait before next block or authority switching,
/// in seconds.
///
/// Deliberately typed as u16 as too high of a value leads
/// to slow block issuance.
pub step_duration: u16,
/// Starting step,
pub start_step: Option<u64>,
/// Valid validators.
@@ -71,10 +75,17 @@ pub struct AuthorityRoundParams {
pub maximum_uncle_count: usize,
}
const U16_MAX: usize = ::std::u16::MAX as usize;
impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
fn from(p: ethjson::spec::AuthorityRoundParams) -> Self {
let mut step_duration_usize: usize = p.step_duration.into();
if step_duration_usize > U16_MAX {
step_duration_usize = U16_MAX;
warn!(target: "engine", "step_duration is too high ({}), setting it to {}", step_duration_usize, U16_MAX);
}
AuthorityRoundParams {
step_duration: Duration::from_secs(p.step_duration.into()),
step_duration: step_duration_usize as u16,
validators: new_validator_set(p.validators),
start_step: p.start_step.map(Into::into),
validate_score_transition: p.validate_score_transition.map_or(0, Into::into),
@@ -92,26 +103,47 @@ impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
struct Step {
calibrate: bool, // whether calibration is enabled.
inner: AtomicUsize,
duration: Duration,
duration: u16,
}
impl Step {
fn load(&self) -> usize { self.inner.load(AtomicOrdering::SeqCst) }
fn duration_remaining(&self) -> Duration {
let now = unix_now();
let step_end = self.duration * (self.load() as u32 + 1);
if step_end > now {
step_end - now
} else {
Duration::from_secs(0)
let expected_seconds = (self.load() as u64)
.checked_add(1)
.and_then(|ctr| ctr.checked_mul(self.duration as u64));
match expected_seconds {
Some(secs) => {
let step_end = Duration::from_secs(secs);
if step_end > now {
step_end - now
} else {
Duration::from_secs(0)
}
},
None => {
let ctr = self.load();
error!(target: "engine", "Step counter is too high: {}, aborting", ctr);
panic!("step counter is too high: {}", ctr)
},
}
}
fn increment(&self) {
self.inner.fetch_add(1, AtomicOrdering::SeqCst);
use std::usize;
// fetch_add won't panic on overflow but will rather wrap
// around, leading to zero as the step counter, which might
// lead to unexpected situations, so it's better to shut down.
if self.inner.fetch_add(1, AtomicOrdering::SeqCst) == usize::MAX {
error!(target: "engine", "Step counter is too high: {}, aborting", usize::MAX);
panic!("step counter is too high: {}", usize::MAX);
}
}
fn calibrate(&self) {
if self.calibrate {
let new_step = unix_now().as_secs() / self.duration.as_secs();
let new_step = unix_now().as_secs() / (self.duration as u64);
self.inner.store(new_step as usize, AtomicOrdering::SeqCst);
}
}
@@ -359,8 +391,12 @@ impl AsMillis for Duration {
impl AuthorityRound {
/// Create a new instance of AuthorityRound engine.
pub fn new(our_params: AuthorityRoundParams, machine: EthereumMachine) -> Result<Arc<Self>, Error> {
if our_params.step_duration == 0 {
error!(target: "engine", "Authority Round step duration can't be zero, aborting");
panic!("authority_round: step duration can't be zero")
}
let should_timeout = our_params.start_step.is_none();
let initial_step = our_params.start_step.unwrap_or_else(|| (unix_now().as_secs() / our_params.step_duration.as_secs())) as usize;
let initial_step = our_params.start_step.unwrap_or_else(|| (unix_now().as_secs() / (our_params.step_duration as u64))) as usize;
let engine = Arc::new(
AuthorityRound {
transition_service: IoService::<()>::start()?,
@@ -1019,7 +1055,7 @@ mod tests {
fn reports_skipped() {
let last_benign = Arc::new(AtomicUsize::new(0));
let params = AuthorityRoundParams {
step_duration: Default::default(),
step_duration: 1,
start_step: Some(1),
validators: Box::new(TestSet::new(Default::default(), last_benign.clone())),
validate_score_transition: 0,
@@ -1059,7 +1095,7 @@ mod tests {
fn test_uncles_transition() {
let last_benign = Arc::new(AtomicUsize::new(0));
let params = AuthorityRoundParams {
step_duration: Default::default(),
step_duration: 1,
start_step: Some(1),
validators: Box::new(TestSet::new(Default::default(), last_benign.clone())),
validate_score_transition: 0,
@@ -1081,4 +1117,50 @@ mod tests {
assert_eq!(aura.maximum_uncle_count(1), 0);
assert_eq!(aura.maximum_uncle_count(100), 0);
}
#[test]
#[should_panic(expected="counter is too high")]
fn test_counter_increment_too_high() {
use super::Step;
let step = Step {
calibrate: false,
inner: AtomicUsize::new(::std::usize::MAX),
duration: 1,
};
step.increment();
}
#[test]
#[should_panic(expected="counter is too high")]
fn test_counter_duration_remaining_too_high() {
use super::Step;
let step = Step {
calibrate: false,
inner: AtomicUsize::new(::std::usize::MAX),
duration: 1,
};
step.duration_remaining();
}
#[test]
#[should_panic(expected="authority_round: step duration can't be zero")]
fn test_step_duration_zero() {
let last_benign = Arc::new(AtomicUsize::new(0));
let params = AuthorityRoundParams {
step_duration: 0,
start_step: Some(1),
validators: Box::new(TestSet::new(Default::default(), last_benign.clone())),
validate_score_transition: 0,
validate_step_transition: 0,
immediate_transitions: true,
maximum_uncle_count_transition: 0,
maximum_uncle_count: 0,
block_reward: Default::default(),
};
let mut c_params = ::spec::CommonParams::default();
c_params.gas_limit_bound_divisor = 5.into();
let machine = ::machine::EthereumMachine::regular(c_params, Default::default());
AuthorityRound::new(params, machine).unwrap();
}
}

View File

@@ -58,7 +58,7 @@ impl ValidatorContract {
let client = self.client.read().clone();
Box::new(move |a, d| client.as_ref()
.and_then(Weak::upgrade)
.ok_or("No client!".into())
.ok_or_else(|| "No client!".into())
.and_then(|c| {
match c.as_full_client() {
Some(c) => c.transact_contract(a, d)

View File

@@ -138,7 +138,7 @@ impl ValidatorSet for Multi {
}
*self.block_number.write() = Box::new(move |id| client
.upgrade()
.ok_or("No client!".into())
.ok_or_else(|| "No client!".into())
.and_then(|c| c.block_number(id).ok_or("Unknown block".into())));
}
}

View File

@@ -311,7 +311,7 @@ impl ValidatorSet for ValidatorSafeContract {
let client = self.client.read().clone();
Box::new(move |addr, data| client.as_ref()
.and_then(Weak::upgrade)
.ok_or("No client!".into())
.ok_or_else(|| "No client!".into())
.and_then(|c| {
match c.as_full_client() {
Some(c) => c.call_contract(id, addr, data),

View File

@@ -336,7 +336,6 @@ impl Engine<EthereumMachine> for Arc<Ethash> {
}
}
#[cfg_attr(feature="dev", allow(wrong_self_convention))]
impl Ethash {
fn calculate_difficulty(&self, header: &Header, parent: &Header) -> U256 {
const EXP_DIFF_PERIOD: u64 = 100_000;

View File

@@ -85,7 +85,6 @@ impl<'a, T: 'a, V: 'a, B: 'a> Externalities<'a, T, V, B>
where T: Tracer, V: VMTracer, B: StateBackend
{
/// Basic `Externalities` constructor.
#[cfg_attr(feature="dev", allow(too_many_arguments))]
pub fn new(state: &'a mut State<B>,
env_info: &'a EnvInfo,
machine: &'a Machine,
@@ -302,7 +301,6 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
Ok(self.state.code_size(address)?.unwrap_or(0))
}
#[cfg_attr(feature="dev", allow(match_ref_pats))]
fn ret(mut self, gas: &U256, data: &ReturnData, apply_state: bool) -> vm::Result<U256>
where Self: Sized {
let handle_copy = |to: &mut Option<&mut Bytes>| {

View File

@@ -16,23 +16,6 @@
#![warn(missing_docs)]
#![cfg_attr(feature="benches", feature(test))]
#![cfg_attr(feature="dev", feature(plugin))]
#![cfg_attr(feature="dev", plugin(clippy))]
// Clippy settings
// Most of the time much more readable
#![cfg_attr(feature="dev", allow(needless_range_loop))]
// Shorter than if-else
#![cfg_attr(feature="dev", allow(match_bool))]
// Keeps consistency (all lines with `.clone()`).
#![cfg_attr(feature="dev", allow(clone_on_copy))]
// Complains on Box<E> when implementing From<Box<E>>
#![cfg_attr(feature="dev", allow(boxed_local))]
// Complains about nested modules with same name as parent
#![cfg_attr(feature="dev", allow(module_inception))]
// TODO [todr] a lot of warnings to be fixed
#![cfg_attr(feature="dev", allow(assign_op_pattern))]
//! Ethcore library
//!

View File

@@ -366,7 +366,6 @@ impl Miner {
)
}
#[cfg_attr(feature="dev", allow(match_same_arms))]
/// Prepares new block for sealing including top transactions from queue.
fn prepare_block(&self, chain: &MiningBlockChainClient) -> (ClosedBlock, Option<H256>) {
let _timer = PerfTimer::new("prepare_block");
@@ -729,8 +728,6 @@ impl Miner {
/// Are we allowed to do a non-mandatory reseal?
fn tx_reseal_allowed(&self) -> bool { Instant::now() > *self.next_allowed_reseal.lock() }
#[cfg_attr(feature="dev", allow(wrong_self_convention))]
#[cfg_attr(feature="dev", allow(redundant_closure))]
fn from_pending_block<H, F, G>(&self, latest_block_number: BlockNumber, from_chain: F, map_block: G) -> H
where F: Fn() -> H, G: FnOnce(&ClosedBlock) -> H {
let sealing_work = self.sealing_work.lock();
@@ -890,7 +887,6 @@ impl MinerService for Miner {
results
}
#[cfg_attr(feature="dev", allow(collapsible_if))]
fn import_own_transaction(
&self,
chain: &MiningBlockChainClient,

View File

@@ -15,8 +15,6 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
#![warn(missing_docs)]
#![cfg_attr(all(nightly, feature="dev"), feature(plugin))]
#![cfg_attr(all(nightly, feature="dev"), plugin(clippy))]
//! Miner module
//! Keeps track of transactions and mined block.

View File

@@ -136,7 +136,6 @@ impl PartialOrd for TransactionOrigin {
}
impl Ord for TransactionOrigin {
#[cfg_attr(feature="dev", allow(match_same_arms))]
fn cmp(&self, other: &TransactionOrigin) -> Ordering {
if *other == *self {
return Ordering::Equal;
@@ -516,7 +515,6 @@ pub struct AccountDetails {
const GAS_PRICE_BUMP_SHIFT: usize = 3; // 2 = 25%, 3 = 12.5%, 4 = 6.25%
/// Describes the strategy used to prioritize transactions in the queue.
#[cfg_attr(feature="dev", allow(enum_variant_names))]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum PrioritizationStrategy {
/// Use only gas price. Disregards the actual computation cost of the transaction.

View File

@@ -186,7 +186,6 @@ impl IoHandler<ClientIoMessage> for ClientIoHandler {
}
}
#[cfg_attr(feature="dev", allow(single_match))]
fn message(&self, _io: &IoContext<ClientIoMessage>, net_message: &ClientIoMessage) {
use std::thread;

View File

@@ -57,7 +57,6 @@ impl StateProducer {
}
}
#[cfg_attr(feature="dev", allow(let_and_return))]
/// Tick the state producer. This alters the state, writing new data into
/// the database.
pub fn tick<R: Rng>(&mut self, rng: &mut R, db: &mut HashDB) {

View File

@@ -35,6 +35,15 @@ use std::cell::{RefCell, Cell};
const STORAGE_CACHE_ITEMS: usize = 8192;
/// Boolean type for clean/dirty status.
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum Filth {
/// Data has not been changed.
Clean,
/// Data has been changed.
Dirty,
}
/// Single account in the system.
/// Keeps track of changes to the code and storage.
/// The changes are applied in `commit_storage` and `commit_code`

View File

@@ -604,7 +604,6 @@ impl<B: Backend> State<B> {
}
/// Add `incr` to the balance of account `a`.
#[cfg_attr(feature="dev", allow(single_match))]
pub fn add_balance(&mut self, a: &Address, incr: &U256, cleanup_mode: CleanupMode) -> trie::Result<()> {
trace!(target: "state", "add_balance({}, {}): {}", a, incr, self.balance(a)?);
let is_value_transfer = !incr.is_zero();
@@ -744,8 +743,6 @@ impl<B: Backend> State<B> {
}
/// Commits our cached account changes into the trie.
#[cfg_attr(feature="dev", allow(match_ref_pats))]
#[cfg_attr(feature="dev", allow(needless_borrow))]
pub fn commit(&mut self) -> Result<(), Error> {
// first, commit the sub trees.
let mut accounts = self.cache.borrow_mut();

View File

@@ -58,7 +58,6 @@ impl Substate {
}
/// Get the cleanup mode object from this.
#[cfg_attr(feature="dev", allow(wrong_self_convention))]
pub fn to_cleanup_mode(&mut self, schedule: &Schedule) -> CleanupMode {
match (schedule.kill_dust != CleanDustMode::Off, schedule.no_empty, schedule.kill_empty) {
(false, false, _) => CleanupMode::ForceCreate,

View File

@@ -427,7 +427,6 @@ impl state::Backend for StateDB {
cache.accounts.get_mut(addr).map(|a| a.as_ref().map(|a| a.clone_basic()))
}
#[cfg_attr(feature="dev", allow(map_clone))]
fn get_cached_code(&self, hash: &H256) -> Option<Arc<Vec<u8>>> {
let mut cache = self.code_cache.lock();

View File

@@ -34,7 +34,6 @@ use cache_manager::CacheManager;
const TRACE_DB_VER: &'static [u8] = b"1.0";
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature="dev", allow(enum_variant_names))]
enum TraceDBIndex {
/// Block traces index.
BlockTraces = 0,

View File

@@ -164,7 +164,6 @@ struct QueueSignal {
}
impl QueueSignal {
#[cfg_attr(feature="dev", allow(bool_comparison))]
fn set_sync(&self) {
// Do not signal when we are about to close
if self.deleting.load(AtomicOrdering::Relaxed) {
@@ -179,7 +178,6 @@ impl QueueSignal {
}
}
#[cfg_attr(feature="dev", allow(bool_comparison))]
fn set_async(&self) {
// Do not signal when we are about to close
if self.deleting.load(AtomicOrdering::Relaxed) {

View File

@@ -498,7 +498,6 @@ mod tests {
}
#[test]
#[cfg_attr(feature="dev", allow(similar_names))]
fn test_verify_block() {
use rlp::RlpStream;

View File

@@ -96,7 +96,6 @@ pub trait Ext {
/// Returns Err, if we run out of gas.
/// Otherwise returns call_result which contains gas left
/// and true if subcall was successfull.
#[cfg_attr(feature="dev", allow(too_many_arguments))]
fn call(&mut self,
gas: &U256,
sender_address: &Address,

View File

@@ -69,17 +69,17 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
),
Static(
"_ccall",
&[I32; 6],
&[I64, I32, I32, I32, I32, I32, I32],
Some(I32),
),
Static(
"_dcall",
&[I32; 5],
&[I64, I32, I32, I32, I32, I32],
Some(I32),
),
Static(
"_scall",
&[I32; 5],
&[I64, I32, I32, I32, I32, I32],
Some(I32),
),
Static(

View File

@@ -111,6 +111,7 @@ impl vm::Vm for WasmInterpreter {
address: params.address,
sender: params.sender,
origin: params.origin,
code_address: params.code_address,
value: params.value.value(),
},
&self.program,

View File

@@ -104,6 +104,7 @@ pub struct RuntimeContext {
pub address: Address,
pub sender: Address,
pub origin: Address,
pub code_address: Address,
pub value: U256,
}
@@ -305,6 +306,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
//
// method signature:
// fn (
// gas: i64,
// address: *const u8,
// val_ptr: *const u8,
// input_ptr: *const u8,
@@ -323,6 +325,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
//
// signature (same as static call):
// fn (
// gas: i64,
// address: *const u8,
// input_ptr: *const u8,
// input_len: u32,
@@ -330,7 +333,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
// result_len: u32,
// ) -> i32
self.do_call(false, CallType::CallCode, context)
self.do_call(false, CallType::DelegateCall, context)
}
fn do_call(
@@ -363,6 +366,9 @@ impl<'a, 'b> Runtime<'a, 'b> {
let address = self.pop_address(&mut context)?;
trace!(target: "wasm", " address: {:?}", address);
let gas = context.value_stack.pop_as::<i64>()? as u64;
trace!(target: "wasm", " gas: {:?}", gas);
if let Some(ref val) = val {
let address_balance = self.ext.balance(&self.context.address)
.map_err(|_| UserTrap::BalanceQueryError)?;
@@ -377,16 +383,16 @@ impl<'a, 'b> Runtime<'a, 'b> {
let mut result = Vec::with_capacity(result_alloc_len as usize);
result.resize(result_alloc_len as usize, 0);
let gas = self.gas_left()
.map_err(|_| UserTrap::InvalidGasState)?
.into();
// todo: optimize to use memory views once it's in
let payload = self.memory.get(input_ptr, input_len as usize)?;
self.charge(|_| gas.into())?;
let call_result = self.ext.call(
&gas,
&self.context.sender,
&self.context.address,
&gas.into(),
match call_type { CallType::DelegateCall => &self.context.sender, _ => &self.context.address },
match call_type { CallType::Call | CallType::StaticCall => &address, _ => &self.context.address },
val,
&payload,
&address,
@@ -396,12 +402,16 @@ impl<'a, 'b> Runtime<'a, 'b> {
match call_result {
vm::MessageCallResult::Success(gas_left, _) => {
self.gas_counter = self.gas_limit - gas_left.low_u64();
// cannot overflow, before making call gas_counter was incremented with gas, and gas_left < gas
self.gas_counter = self.gas_counter - gas_left.low_u64();
self.memory.set(result_ptr, &result)?;
Ok(Some(0i32.into()))
},
vm::MessageCallResult::Reverted(gas_left, _) => {
self.gas_counter = self.gas_limit - gas_left.low_u64();
// cannot overflow, before making call gas_counter was incremented with gas, and gas_left < gas
self.gas_counter = self.gas_counter - gas_left.low_u64();
self.memory.set(result_ptr, &result)?;
Ok(Some((-1i32).into()))
},
@@ -416,6 +426,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
{
// signature (same as code call):
// fn (
// gas: i64,
// address: *const u8,
// input_ptr: *const u8,
// input_len: u32,

View File

@@ -60,7 +60,7 @@ fn empty() {
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
};
assert_eq!(gas_left, U256::from(99_982));
assert_eq!(gas_left, U256::from(96_678));
}
// This test checks if the contract deserializes payload header properly.
@@ -112,7 +112,7 @@ fn logger() {
U256::from(1_000_000_000),
"Logger sets 0x04 key to the trasferred value"
);
assert_eq!(gas_left, U256::from(19_147));
assert_eq!(gas_left, U256::from(15_860));
}
// This test checks if the contract can allocate memory and pass pointer to the result stream properly.
@@ -147,7 +147,7 @@ fn identity() {
sender,
"Idenity test contract does not return the sender passed"
);
assert_eq!(gas_left, U256::from(99_844));
assert_eq!(gas_left, U256::from(96_540));
}
// Dispersion test sends byte array and expect the contract to 'disperse' the original elements with
@@ -180,7 +180,7 @@ fn dispersion() {
result,
vec![0u8, 0, 125, 11, 197, 7, 255, 8, 19, 0]
);
assert_eq!(gas_left, U256::from(96_393));
assert_eq!(gas_left, U256::from(96_116));
}
#[test]
@@ -208,7 +208,7 @@ fn suicide_not() {
result,
vec![0u8]
);
assert_eq!(gas_left, U256::from(96_725));
assert_eq!(gas_left, U256::from(96_461));
}
#[test]
@@ -240,7 +240,7 @@ fn suicide() {
};
assert!(ext.suicides.contains(&refund));
assert_eq!(gas_left, U256::from(96_687));
assert_eq!(gas_left, U256::from(96_429));
}
#[test]
@@ -270,7 +270,7 @@ fn create() {
assert!(ext.calls.contains(
&FakeCall {
call_type: FakeCallType::Create,
gas: U256::from(65_899),
gas: U256::from(62_545),
sender_address: None,
receive_address: None,
value: Some(1_000_000_000.into()),
@@ -278,9 +278,52 @@ fn create() {
code_address: None,
}
));
assert_eq!(gas_left, U256::from(65_892));
assert_eq!(gas_left, U256::from(62_538));
}
#[test]
fn call_msg() {
::ethcore_logger::init_log();
let sender: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
let receiver: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
let contract_address: Address = "0d461d4174b4ae35775c4a342f1e5e1e4e6c4db5".parse().unwrap();
let mut params = ActionParams::default();
params.sender = sender.clone();
params.address = receiver.clone();
params.code_address = contract_address.clone();
params.gas = U256::from(100_000);
params.code = Some(Arc::new(load_sample!("call.wasm")));
params.data = Some(Vec::new());
let mut ext = FakeExt::new();
ext.balances.insert(receiver.clone(), U256::from(10000000000u64));
let gas_left = {
let mut interpreter = wasm_interpreter();
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
match result {
GasLeft::Known(gas_left) => gas_left,
GasLeft::NeedsReturn { .. } => { panic!("Call test should not return payload"); },
}
};
trace!(target: "wasm", "fake_calls: {:?}", &ext.calls);
assert!(ext.calls.contains(
&FakeCall {
call_type: FakeCallType::Call,
gas: U256::from(33_000),
sender_address: Some(receiver),
receive_address: Some(Address::from([99, 88, 77, 66, 55, 44, 33, 22, 11, 0, 11, 22, 33, 44, 55, 66, 77, 88, 99, 0])),
value: Some(1000000000.into()),
data: vec![129u8, 123, 113, 107, 101, 97],
code_address: Some(Address::from([99, 88, 77, 66, 55, 44, 33, 22, 11, 0, 11, 22, 33, 44, 55, 66, 77, 88, 99, 0])),
}
));
assert_eq!(gas_left, U256::from(95_699));
}
#[test]
fn call_code() {
@@ -312,7 +355,7 @@ fn call_code() {
assert!(ext.calls.contains(
&FakeCall {
call_type: FakeCallType::Call,
gas: U256::from(98_713),
gas: U256::from(20_000),
sender_address: Some(sender),
receive_address: Some(receiver),
value: None,
@@ -324,7 +367,7 @@ fn call_code() {
// siphash result
let res = LittleEndian::read_u32(&result[..]);
assert_eq!(res, 4198595614);
assert_eq!(gas_left, U256::from(93_855));
assert_eq!(gas_left, U256::from(90_550));
}
#[test]
@@ -333,6 +376,7 @@ fn call_static() {
let sender: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
let receiver: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
let contract_address: Address = "0d461d4174b4ae35775c4a342f1e5e1e4e6c4db5".parse().unwrap();
let mut params = ActionParams::default();
params.sender = sender.clone();
@@ -341,6 +385,7 @@ fn call_static() {
params.code = Some(Arc::new(load_sample!("call_static.wasm")));
params.data = Some(Vec::new());
params.value = ActionValue::transfer(1_000_000_000);
params.code_address = contract_address.clone();
let mut ext = FakeExt::new();
@@ -357,9 +402,9 @@ fn call_static() {
assert!(ext.calls.contains(
&FakeCall {
call_type: FakeCallType::Call,
gas: U256::from(98_713),
sender_address: Some(sender),
receive_address: Some(receiver),
gas: U256::from(20_000),
sender_address: Some(receiver),
receive_address: Some("13077bfb00000000000000000000000000000000".parse().unwrap()),
value: None,
data: vec![1u8, 2, 3, 5, 7, 11],
code_address: Some("13077bfb00000000000000000000000000000000".parse().unwrap()),
@@ -370,7 +415,7 @@ fn call_static() {
let res = LittleEndian::read_u32(&result[..]);
assert_eq!(res, 317632590);
assert_eq!(gas_left, U256::from(93_855));
assert_eq!(gas_left, U256::from(90_550));
}
// Realloc test
@@ -393,7 +438,7 @@ fn realloc() {
}
};
assert_eq!(result, vec![0u8; 2]);
assert_eq!(gas_left, U256::from(96_723));
assert_eq!(gas_left, U256::from(96_445));
}
// Tests that contract's ability to read from a storage
@@ -419,7 +464,7 @@ fn storage_read() {
};
assert_eq!(Address::from(&result[12..32]), address);
assert_eq!(gas_left, U256::from(99_767));
assert_eq!(gas_left, U256::from(96_463));
}
// Tests keccak calculation
@@ -445,7 +490,7 @@ fn keccak() {
};
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
assert_eq!(gas_left, U256::from(81_446));
assert_eq!(gas_left, U256::from(81_067));
}
// memcpy test.
@@ -477,7 +522,7 @@ fn memcpy() {
};
assert_eq!(result, test_payload);
assert_eq!(gas_left, U256::from(72_216));
assert_eq!(gas_left, U256::from(71_940));
}
// memmove test.
@@ -509,7 +554,7 @@ fn memmove() {
};
assert_eq!(result, test_payload);
assert_eq!(gas_left, U256::from(72_216));
assert_eq!(gas_left, U256::from(71_940));
}
// memset test
@@ -534,7 +579,7 @@ fn memset() {
};
assert_eq!(result, vec![228u8; 8192]);
assert_eq!(gas_left, U256::from(72_196));
assert_eq!(gas_left, U256::from(71_921));
}
macro_rules! reqrep_test {
@@ -591,7 +636,7 @@ fn math_add() {
U256::from_dec_str("1888888888888888888888888888887").unwrap(),
(&result[..]).into()
);
assert_eq!(gas_left, U256::from(95_524));
assert_eq!(gas_left, U256::from(95_384));
}
// multiplication
@@ -613,7 +658,7 @@ fn math_mul() {
U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(),
(&result[..]).into()
);
assert_eq!(gas_left, U256::from(94_674));
assert_eq!(gas_left, U256::from(94_374));
}
// subtraction
@@ -635,7 +680,7 @@ fn math_sub() {
U256::from_dec_str("111111111111111111111111111111").unwrap(),
(&result[..]).into()
);
assert_eq!(gas_left, U256::from(95_516));
assert_eq!(gas_left, U256::from(95_372));
}
// subtraction with overflow
@@ -677,7 +722,7 @@ fn math_div() {
U256::from_dec_str("1125000").unwrap(),
(&result[..]).into()
);
assert_eq!(gas_left, U256::from(88_514));
assert_eq!(gas_left, U256::from(88_356));
}
// This test checks the ability of wasm contract to invoke
@@ -765,7 +810,7 @@ fn externs() {
"Gas limit requested and returned does not match"
);
assert_eq!(gas_left, U256::from(94_858));
assert_eq!(gas_left, U256::from(95_321));
}
#[test]
@@ -791,7 +836,7 @@ fn embedded_keccak() {
};
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
assert_eq!(gas_left, U256::from(81_446));
assert_eq!(gas_left, U256::from(81_067));
}
/// This test checks the correctness of log extern
@@ -826,5 +871,5 @@ fn events() {
assert_eq!(&log_entry.data, b"gnihtemos");
assert_eq!(&result, b"gnihtemos");
assert_eq!(gas_left, U256::from(79_637));
assert_eq!(gas_left, U256::from(79_206));
}