mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-09 20:59:23 +00:00
Clarified usage of CREATE
CREATE was originally intended for gas savings. While one sketch did move to CREATE2, the security concerns around address collisions (requiring all init codes not be malleable to achieve security) continue to justify this. To resolve the gas estimation concerns raised in the prior commit, the createAddress function has been made constant-gas.
This commit is contained in:
@@ -23,8 +23,9 @@ const CHAIN_ID: U256 = U256::from_be_slice(&[1]);
|
||||
pub(crate) type GasEstimator = Evm<'static, (), InMemoryDB>;
|
||||
|
||||
impl Router {
|
||||
const NONCE_STORAGE_SLOT: U256 = U256::from_be_slice(&[0]);
|
||||
const SERAI_KEY_STORAGE_SLOT: U256 = U256::from_be_slice(&[2]);
|
||||
const SMART_CONTRACT_NONCE_STORAGE_SLOT: U256 = U256::from_be_slice(&[0]);
|
||||
const NONCE_STORAGE_SLOT: U256 = U256::from_be_slice(&[1]);
|
||||
const SERAI_KEY_STORAGE_SLOT: U256 = U256::from_be_slice(&[3]);
|
||||
|
||||
// Gas allocated for ERC20 calls
|
||||
#[cfg(test)]
|
||||
@@ -46,11 +47,11 @@ impl Router {
|
||||
the correct set of prices for the network they're operating on.
|
||||
*/
|
||||
/// The gas used by `confirmSeraiKey`.
|
||||
pub const CONFIRM_NEXT_SERAI_KEY_GAS: u64 = 57_764;
|
||||
pub const CONFIRM_NEXT_SERAI_KEY_GAS: u64 = 57_736;
|
||||
/// The gas used by `updateSeraiKey`.
|
||||
pub const UPDATE_SERAI_KEY_GAS: u64 = 60_073;
|
||||
pub const UPDATE_SERAI_KEY_GAS: u64 = 60_045;
|
||||
/// The gas used by `escapeHatch`.
|
||||
pub const ESCAPE_HATCH_GAS: u64 = 44_037;
|
||||
pub const ESCAPE_HATCH_GAS: u64 = 61_094;
|
||||
|
||||
/// The key to use when performing gas estimations.
|
||||
///
|
||||
@@ -89,6 +90,15 @@ impl Router {
|
||||
},
|
||||
);
|
||||
|
||||
// Insert the value for _smartContractNonce set in the constructor
|
||||
// All operations w.r.t. execute in constant-time, making the actual value irrelevant
|
||||
db.insert_account_storage(
|
||||
self.address,
|
||||
Self::SMART_CONTRACT_NONCE_STORAGE_SLOT,
|
||||
U256::from(1),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Insert a non-zero nonce, as the zero nonce will update to the initial key and never be
|
||||
// used for any gas estimations of `execute`, the only function estimated
|
||||
db.insert_account_storage(self.address, Self::NONCE_STORAGE_SLOT, U256::from(1)).unwrap();
|
||||
|
||||
@@ -56,42 +56,30 @@ async fn test_create_address() {
|
||||
// The only meaningful patterns are < 0x80, == 0x80, and then each length greater > 0x80
|
||||
// The following covers all three
|
||||
let mut nonce = 1u64;
|
||||
let mut gas = None;
|
||||
while nonce.checked_add(nonce).is_some() {
|
||||
let input =
|
||||
(abi::CreateAddress::createAddressForSelfCall { nonce: U256::from(nonce) }).abi_encode();
|
||||
|
||||
// Make sure the function works as expected
|
||||
let call =
|
||||
TransactionRequest::default().to(address).input(TransactionInput::new(input.clone().into()));
|
||||
assert_eq!(
|
||||
&test
|
||||
.provider
|
||||
.call(
|
||||
&TransactionRequest::default().to(address).input(TransactionInput::new(
|
||||
(abi::CreateAddress::createAddressForSelfCall { nonce: U256::from(nonce) })
|
||||
.abi_encode()
|
||||
.into()
|
||||
))
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.as_ref()[12 ..],
|
||||
&test.provider.call(&call).await.unwrap().as_ref()[12 ..],
|
||||
address.create(nonce).as_slice(),
|
||||
);
|
||||
|
||||
// Check the function is constant-gas
|
||||
let gas_used = test.provider.estimate_gas(&call).await.unwrap();
|
||||
let initial_gas = calculate_initial_tx_gas(SpecId::CANCUN, &input, false, &[], 0).initial_gas;
|
||||
let this_call = gas_used - initial_gas;
|
||||
if gas.is_none() {
|
||||
gas = Some(this_call);
|
||||
}
|
||||
assert_eq!(gas, Some(this_call));
|
||||
|
||||
nonce <<= 1;
|
||||
}
|
||||
|
||||
let input =
|
||||
(abi::CreateAddress::createAddressForSelfCall { nonce: U256::from(u64::MAX) }).abi_encode();
|
||||
let gas = test
|
||||
.provider
|
||||
.estimate_gas(
|
||||
&TransactionRequest::default().to(address).input(TransactionInput::new(input.clone().into())),
|
||||
)
|
||||
.await
|
||||
.unwrap() -
|
||||
calculate_initial_tx_gas(SpecId::CANCUN, &input, false, &[], 0).initial_gas;
|
||||
|
||||
let keccak256_gas_estimate = |len: u64| 30 + (6 * len.div_ceil(32));
|
||||
let mut bytecode_len = 0;
|
||||
while (keccak256_gas_estimate(bytecode_len) + keccak256_gas_estimate(85)) < gas {
|
||||
bytecode_len += 32;
|
||||
}
|
||||
println!(
|
||||
"Worst-case createAddress gas: {gas}, CREATE2 break-even is bytecode of length {bytecode_len}",
|
||||
);
|
||||
println!("createAddress gas: {}", gas.unwrap());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user