Ensure a non-zero fee in the Router OutInstruction gas fuzz test

This commit is contained in:
Luke Parker 2025-01-27 15:39:55 -05:00
parent fa0dadc9bd
commit 19422de231
No known key found for this signature in database
4 changed files with 13 additions and 2 deletions
processor/ethereum
erc20/src
router
contracts
src

View file

@ -11,3 +11,5 @@ fn selector_collisions() {
crate::abi::SeraiIERC20::transferFromWithInInstruction00081948E0Call::SELECTOR
);
}
// This is primarily tested via serai-processor-ethereum-router

View file

@ -441,6 +441,8 @@ contract Router is IRouterWithoutCollisions {
unchecked {
// The amount of bytes needed to represent the nonce
uint256 bitsNeeded = 0;
// This only iterates up to 64-bits as this will never exceed 2**64 as a matter of
// practicality
for (uint256 bits = 0; bits <= 64; bits += 8) {
bool valueFits = nonce < (uint256(1) << bits);
bool notPriorSet = bitsNeeded == 0;

View file

@ -225,6 +225,8 @@ impl Router {
}
/// The worst-case gas cost for a legacy transaction which executes this batch.
///
/// This assumes the fee will be non-zero.
pub fn execute_gas(&self, coin: Coin, fee_per_gas: U256, outs: &OutInstructions) -> u64 {
// Unfortunately, we can't cache this in self, despite the following code being written such
// that a common EVM instance could be used, as revm's types aren't Send/Sync and we expect the

View file

@ -836,6 +836,7 @@ async fn fuzz_test_out_instructions_gas() {
out_instructions.push((SeraiEthereumAddress::Address(address), amount_out));
}
}
let out_instructions_original = out_instructions.clone();
let out_instructions = OutInstructions::from(out_instructions.as_slice());
// Randomly decide the coin
@ -852,13 +853,17 @@ async fn fuzz_test_out_instructions_gas() {
Coin::Erc20(erc20.address())
};
let fee_per_gas = U256::from(OsRng.next_u64() % 10);
let fee_per_gas = U256::from(1) + U256::from(OsRng.next_u64() % 10);
let gas = test.router.execute_gas(coin, fee_per_gas, &out_instructions);
let fee = U256::from(gas) * fee_per_gas;
// All of these should have succeeded
let (tx, gas_used) =
test.execute(coin, fee, out_instructions.clone(), vec![true; out_instructions.0.len()]).await;
let unused_gas = test.gas_unused_by_calls(&tx).await;
assert_eq!(gas_used + unused_gas, gas);
assert_eq!(
gas_used + unused_gas,
gas,
"{coin:?} {fee_per_gas:?} {out_instructions_original:?}"
);
}
}