Skip to content

Commit

Permalink
Remove redundant gas checks in precompiles (paritytech#745)
Browse files Browse the repository at this point in the history
* remove redundant gas checks

* fmt

* fix borrowing issue
  • Loading branch information
nanocryk authored Jul 4, 2022
1 parent c52d5e8 commit da3f879
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 40 deletions.
10 changes: 1 addition & 9 deletions frame/evm/precompile/blake2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ impl Precompile for Blake2F {
const BLAKE2_F_ARG_LEN: usize = 213;

let input = handle.input();
let target_gas = handle.gas_limit();

if input.len() != BLAKE2_F_ARG_LEN {
return Err(PrecompileFailure::Error {
Expand All @@ -54,15 +53,8 @@ impl Precompile for Blake2F {
let rounds: u32 = u32::from_be_bytes(rounds_buf);

let gas_cost: u64 = (rounds as u64) * Blake2F::GAS_COST_PER_ROUND;
if let Some(gas_left) = target_gas {
if gas_left < gas_cost {
return Err(PrecompileFailure::Error {
exit_status: ExitError::OutOfGas,
});
}
}

handle.record_cost(gas_cost)?;

let input = handle.input();

// we use from_le_bytes below to effectively swap byte order to LE if architecture is BE
Expand Down
27 changes: 10 additions & 17 deletions frame/evm/precompile/bn128/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,24 +169,19 @@ impl Precompile for Bn128Pairing {
fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult {
use bn::{pairing_batch, AffineG1, AffineG2, Fq, Fq2, Group, Gt, G1, G2};

let input = handle.input();
let target_gas = handle.gas_limit();

let (ret_val, gas_cost) = if input.is_empty() {
(U256::one(), Bn128Pairing::BASE_GAS_COST)
let ret_val = if handle.input().is_empty() {
handle.record_cost(Bn128Pairing::BASE_GAS_COST)?;
U256::one()
} else {
// (a, b_a, b_b - each 64-byte affine coordinates)
let elements = input.len() / 192;
let elements = handle.input().len() / 192;

let gas_cost: u64 = Bn128Pairing::BASE_GAS_COST
+ (elements as u64 * Bn128Pairing::GAS_COST_PER_PAIRING);
if let Some(gas_left) = target_gas {
if gas_left < gas_cost {
return Err(PrecompileFailure::Error {
exit_status: ExitError::OutOfGas,
});
}
}

handle.record_cost(gas_cost)?;

let input = handle.input();

let mut vals = Vec::new();
for idx in 0..elements {
Expand Down Expand Up @@ -268,14 +263,12 @@ impl Precompile for Bn128Pairing {
let mul = pairing_batch(&vals);

if mul == Gt::one() {
(U256::one(), gas_cost)
U256::one()
} else {
(U256::zero(), gas_cost)
U256::zero()
}
};

handle.record_cost(gas_cost)?;

let mut buf = [0u8; 32];
ret_val.to_big_endian(&mut buf);

Expand Down
22 changes: 8 additions & 14 deletions frame/evm/precompile/modexp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ fn calculate_gas_cost(
impl Precompile for Modexp {
fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult {
let input = handle.input();
let target_gas = handle.gas_limit();

if input.len() < 96 {
return Err(PrecompileFailure::Error {
Expand Down Expand Up @@ -161,8 +160,9 @@ impl Precompile for Modexp {
}

// Gas formula allows arbitrary large exp_len when base and modulus are empty, so we need to handle empty base first.
let (r, gas_cost) = if base_len == 0 && mod_len == 0 {
(BigUint::zero(), MIN_GAS_COST)
let r = if base_len == 0 && mod_len == 0 {
handle.record_cost(MIN_GAS_COST)?;
BigUint::zero()
} else {
// read the numbers themselves.
let base_start = 96; // previous 3 32-byte fields
Expand All @@ -174,26 +174,20 @@ impl Precompile for Modexp {
// do our gas accounting
let gas_cost =
calculate_gas_cost(base_len as u64, exp_len as u64, mod_len as u64, &exponent);
if let Some(gas_left) = target_gas {
if gas_left < gas_cost {
return Err(PrecompileFailure::Error {
exit_status: ExitError::OutOfGas,
});
}
};

handle.record_cost(gas_cost)?;
let input = handle.input();

let mod_start = exp_start + exp_len;
let modulus = BigUint::from_bytes_be(&input[mod_start..mod_start + mod_len]);

if modulus.is_zero() || modulus.is_one() {
(BigUint::zero(), gas_cost)
BigUint::zero()
} else {
(base.modpow(&exponent, &modulus), gas_cost)
base.modpow(&exponent, &modulus)
}
};

handle.record_cost(gas_cost)?;

// write output to given memory, left padded and same length as the modulus.
let bytes = r.to_bytes_be();

Expand Down

0 comments on commit da3f879

Please sign in to comment.