Additional error for invalid gas (#10327)

* Tag sensible place (ECHECH)

* Additional overflows checks.
This commit is contained in:
cheme 2019-02-11 23:20:51 +01:00 committed by Kirill Pimenov
parent 8e866ee551
commit d89b8d904f
8 changed files with 37 additions and 16 deletions

View File

@ -571,10 +571,10 @@ impl<Cost: CostType> Interpreter<Cost> {
let out_size = self.stack.pop_back(); let out_size = self.stack.pop_back();
// Add stipend (only CALL|CALLCODE when value > 0) // Add stipend (only CALL|CALLCODE when value > 0)
let call_gas = call_gas + value.map_or_else(|| Cost::from(0), |val| match val.is_zero() { let call_gas = call_gas.overflow_add(value.map_or_else(|| Cost::from(0), |val| match val.is_zero() {
false => Cost::from(ext.schedule().call_stipend), false => Cost::from(ext.schedule().call_stipend),
true => Cost::from(0), true => Cost::from(0),
}); })).0;
// Get sender & receive addresses, check if we have balance // Get sender & receive addresses, check if we have balance
let (sender_address, receive_address, has_balance, call_type) = match instruction { let (sender_address, receive_address, has_balance, call_type) = match instruction {

View File

@ -95,7 +95,7 @@ impl AccountTransactions {
} }
fn next_nonce(&self) -> U256 { fn next_nonce(&self) -> U256 {
self.current.last().map(|last| last.nonce + 1) self.current.last().map(|last| last.nonce.saturating_add(1.into()))
.unwrap_or_else(|| *self.cur_nonce.value()) .unwrap_or_else(|| *self.cur_nonce.value())
} }
@ -107,7 +107,7 @@ impl AccountTransactions {
while let Some(tx) = self.future.remove(&next_nonce) { while let Some(tx) = self.future.remove(&next_nonce) {
promoted.push(tx.hash); promoted.push(tx.hash);
self.current.push(tx); self.current.push(tx);
next_nonce = next_nonce + 1; next_nonce = next_nonce.saturating_add(1.into());
} }
promoted promoted

View File

@ -312,7 +312,7 @@ impl<'a> CallCreateExecutive<'a> {
let prev_bal = state.balance(&params.address)?; let prev_bal = state.balance(&params.address)?;
if let ActionValue::Transfer(val) = params.value { if let ActionValue::Transfer(val) = params.value {
state.sub_balance(&params.sender, &val, &mut substate.to_cleanup_mode(&schedule))?; state.sub_balance(&params.sender, &val, &mut substate.to_cleanup_mode(&schedule))?;
state.new_contract(&params.address, val + prev_bal, nonce_offset)?; state.new_contract(&params.address, val.saturating_add(prev_bal), nonce_offset)?;
} else { } else {
state.new_contract(&params.address, prev_bal, nonce_offset)?; state.new_contract(&params.address, prev_bal, nonce_offset)?;
} }
@ -1103,9 +1103,13 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
let refunded = cmp::min(refunds_bound, (t.gas - gas_left_prerefund) >> 1); let refunded = cmp::min(refunds_bound, (t.gas - gas_left_prerefund) >> 1);
let gas_left = gas_left_prerefund + refunded; let gas_left = gas_left_prerefund + refunded;
let gas_used = t.gas - gas_left; let gas_used = t.gas.saturating_sub(gas_left);
let refund_value = gas_left * t.gas_price; let (refund_value, overflow_1) = gas_left.overflowing_mul(t.gas_price);
let fees_value = gas_used * t.gas_price; let (fees_value, overflow_2) = gas_used.overflowing_mul(t.gas_price);
if overflow_1 || overflow_2 {
return Err(ExecutionError::TransactionMalformed("U256 Overflow".to_string()));
}
trace!("exec::finalize: t.gas={}, sstore_refunds={}, suicide_refunds={}, refunds_bound={}, gas_left_prerefund={}, refunded={}, gas_left={}, gas_used={}, refund_value={}, fees_value={}\n", trace!("exec::finalize: t.gas={}, sstore_refunds={}, suicide_refunds={}, refunds_bound={}, gas_left_prerefund={}, refunded={}, gas_left={}, gas_used={}, refund_value={}, fees_value={}\n",
t.gas, sstore_refunds, suicide_refunds, refunds_bound, gas_left_prerefund, refunded, gas_left, gas_used, refund_value, fees_value); t.gas, sstore_refunds, suicide_refunds, refunds_bound, gas_left_prerefund, refunded, gas_left, gas_used, refund_value, fees_value);
@ -1123,7 +1127,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
} }
// perform garbage-collection // perform garbage-collection
let min_balance = if schedule.kill_dust != CleanDustMode::Off { Some(U256::from(schedule.tx_gas) * t.gas_price) } else { None }; let min_balance = if schedule.kill_dust != CleanDustMode::Off { Some(U256::from(schedule.tx_gas).overflowing_mul(t.gas_price).0) } else { None };
self.state.kill_garbage(&substate.touched, schedule.kill_empty, &min_balance, schedule.kill_dust == CleanDustMode::WithCodeAndStorage)?; self.state.kill_garbage(&substate.touched, schedule.kill_empty, &min_balance, schedule.kill_dust == CleanDustMode::WithCodeAndStorage)?;
match result { match result {

View File

@ -466,12 +466,12 @@ impl Account {
/// Increment the nonce of the account by one. /// Increment the nonce of the account by one.
pub fn inc_nonce(&mut self) { pub fn inc_nonce(&mut self) {
self.nonce = self.nonce + U256::from(1u8); self.nonce = self.nonce.saturating_add(U256::from(1u8));
} }
/// Increase account balance. /// Increase account balance.
pub fn add_balance(&mut self, x: &U256) { pub fn add_balance(&mut self, x: &U256) {
self.balance = self.balance + *x; self.balance = self.balance.saturating_add(*x);
} }
/// Decrease account balance. /// Decrease account balance.

View File

@ -500,7 +500,12 @@ impl<B: Backend> State<B> {
/// it will have its code reset, ready for `init_code()`. /// it will have its code reset, ready for `init_code()`.
pub fn new_contract(&mut self, contract: &Address, balance: U256, nonce_offset: U256) -> TrieResult<()> { pub fn new_contract(&mut self, contract: &Address, balance: U256, nonce_offset: U256) -> TrieResult<()> {
let original_storage_root = self.original_storage_root(contract)?; let original_storage_root = self.original_storage_root(contract)?;
self.insert_cache(contract, AccountEntry::new_dirty(Some(Account::new_contract(balance, self.account_start_nonce + nonce_offset, original_storage_root)))); let (nonce, overflow) = self.account_start_nonce.overflowing_add(nonce_offset);
if overflow {
return Err(Box::new(TrieError::DecoderError(H256::from(contract),
rlp::DecoderError::Custom("Nonce overflow".into()))));
}
self.insert_cache(contract, AccountEntry::new_dirty(Some(Account::new_contract(balance, nonce, original_storage_root))));
Ok(()) Ok(())
} }

View File

@ -474,7 +474,7 @@ impl TransactionQueue {
self.pool.read().pending_from_sender(state_readiness, address) self.pool.read().pending_from_sender(state_readiness, address)
.last() .last()
.map(|tx| tx.signed().nonce + 1) .map(|tx| tx.signed().nonce.saturating_add(U256::from(1)))
} }
/// Retrieve a transaction from the pool. /// Retrieve a transaction from the pool.

View File

@ -95,7 +95,7 @@ impl<C: NonceClient> txpool::Ready<VerifiedTransaction> for State<C> {
}, },
cmp::Ordering::Less => txpool::Readiness::Stale, cmp::Ordering::Less => txpool::Readiness::Stale,
cmp::Ordering::Equal => { cmp::Ordering::Equal => {
*nonce = *nonce + 1; *nonce = nonce.saturating_add(U256::from(1));
txpool::Readiness::Ready txpool::Readiness::Ready
}, },
} }
@ -159,7 +159,7 @@ impl<C: Fn(&Address) -> Option<U256>> txpool::Ready<VerifiedTransaction> for Opt
cmp::Ordering::Greater => txpool::Readiness::Future, cmp::Ordering::Greater => txpool::Readiness::Future,
cmp::Ordering::Less => txpool::Readiness::Stale, cmp::Ordering::Less => txpool::Readiness::Stale,
cmp::Ordering::Equal => { cmp::Ordering::Equal => {
*nonce = *nonce + 1; *nonce = nonce.saturating_add(U256::from(1));
txpool::Readiness::Ready txpool::Readiness::Ready
}, },
} }

View File

@ -283,7 +283,19 @@ impl<C: Client> txpool::Verifier<Transaction> for Verifier<C, ::pool::scoring::N
} }
} }
let cost = transaction.value + transaction.gas_price * transaction.gas; let (full_gas_price, overflow_1) = transaction.gas_price.overflowing_mul(transaction.gas);
let (cost, overflow_2) = transaction.value.overflowing_add(full_gas_price);
if overflow_1 || overflow_2 {
trace!(
target: "txqueue",
"[{:?}] Rejected tx, price overflow",
hash
);
bail!(transaction::Error::InsufficientBalance {
cost: U256::max_value(),
balance: account_details.balance,
});
}
if account_details.balance < cost { if account_details.balance < cost {
debug!( debug!(
target: "txqueue", target: "txqueue",