-
Notifications
You must be signed in to change notification settings - Fork 76
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore(sequencer)!: change Deposit
byte length calculation
#1507
base: main
Are you sure you want to change the base?
Changes from 8 commits
3b6e795
df2f701
b1c855b
9c7090b
00da52a
10d1007
e06ad1a
c9e3cdf
c46fa8a
e7a9820
40d28dc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -34,6 +34,10 @@ use crate::{ | |||||
utils::create_deposit_event, | ||||||
}; | ||||||
|
||||||
// The base byte length of a deposit, as determined by the unit test | ||||||
// `get_base_deposit_byte_length()` below. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
const DEPOSIT_BASE_FEE: u128 = 16; | ||||||
|
||||||
#[async_trait::async_trait] | ||||||
impl ActionHandler for BridgeLockAction { | ||||||
async fn check_stateless(&self) -> Result<()> { | ||||||
|
@@ -99,7 +103,10 @@ impl ActionHandler for BridgeLockAction { | |||||
.await | ||||||
.wrap_err("failed to get byte cost multiplier")?; | ||||||
let fee = byte_cost_multiplier | ||||||
.saturating_mul(get_deposit_byte_len(&deposit)) | ||||||
.saturating_mul( | ||||||
calculate_base_deposit_fee(&deposit) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because we are doing saturating arithmetic here I would just keep doing that. Instead of returning early just replace it with with u128::MAX |
||||||
.expect("deposit fee calculation should not fail"), | ||||||
ethanoroshiba marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
) | ||||||
.saturating_add(transfer_fee); | ||||||
ensure!(from_balance >= fee, "insufficient funds for fee payment"); | ||||||
|
||||||
|
@@ -126,7 +133,9 @@ impl ActionHandler for BridgeLockAction { | |||||
.get_bridge_lock_byte_cost_multiplier() | ||||||
.await | ||||||
.wrap_err("failed to get byte cost multiplier")?; | ||||||
let fee = byte_cost_multiplier.saturating_mul(get_deposit_byte_len(&deposit)); | ||||||
let fee = byte_cost_multiplier.saturating_mul( | ||||||
calculate_base_deposit_fee(&deposit).expect("deposit fee calculation should not fail"), | ||||||
); | ||||||
state | ||||||
.get_and_increase_block_fees(&self.fee_asset, fee, Self::full_name()) | ||||||
.await | ||||||
|
@@ -145,19 +154,31 @@ impl ActionHandler for BridgeLockAction { | |||||
} | ||||||
} | ||||||
|
||||||
/// returns the length of a serialized `Deposit` message. | ||||||
pub(crate) fn get_deposit_byte_len(deposit: &Deposit) -> u128 { | ||||||
use prost::Message as _; | ||||||
let raw = deposit.clone().into_raw(); | ||||||
raw.encoded_len() as u128 | ||||||
/// Returns a modified byte length of the deposit event. Length is calculated with reasonable values | ||||||
/// for all fields except `asset` and `destination_chain_address`, ergo it may not be representative | ||||||
/// of on-wire length. | ||||||
pub(crate) fn calculate_base_deposit_fee(deposit: &Deposit) -> Option<u128> { | ||||||
let variable_length = deposit | ||||||
.asset | ||||||
.to_string() | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you extend We can avoid this allocation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in c46fa8a, let me know if this implementation works for you! |
||||||
.len() | ||||||
.checked_add(deposit.destination_chain_address.len()) | ||||||
.expect("deposit byte length overflowed usize") as u128; | ||||||
ethanoroshiba marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
DEPOSIT_BASE_FEE.checked_add(variable_length) | ||||||
} | ||||||
|
||||||
#[cfg(test)] | ||||||
mod tests { | ||||||
use astria_core::primitive::v1::{ | ||||||
asset, | ||||||
asset::{ | ||||||
self, | ||||||
}, | ||||||
Address, | ||||||
RollupId, | ||||||
TransactionId, | ||||||
ADDRESS_LEN, | ||||||
ROLLUP_ID_LEN, | ||||||
TRANSACTION_ID_LEN, | ||||||
}; | ||||||
use cnidarium::StateDelta; | ||||||
|
||||||
|
@@ -217,7 +238,7 @@ mod tests { | |||||
|
||||||
// not enough balance; should fail | ||||||
state | ||||||
.put_account_balance(from_address, &asset, 100 + transfer_fee) | ||||||
.put_account_balance(from_address, &asset, transfer_fee) | ||||||
.unwrap(); | ||||||
assert_eyre_error( | ||||||
&bridge_lock.check_and_execute(&mut state).await.unwrap_err(), | ||||||
|
@@ -226,18 +247,118 @@ mod tests { | |||||
|
||||||
// enough balance; should pass | ||||||
let expected_deposit_fee = transfer_fee | ||||||
+ get_deposit_byte_len(&Deposit { | ||||||
+ calculate_base_deposit_fee(&Deposit { | ||||||
bridge_address, | ||||||
rollup_id, | ||||||
amount: 100, | ||||||
asset: asset.clone(), | ||||||
destination_chain_address: "someaddress".to_string(), | ||||||
source_transaction_id: transaction_id, | ||||||
source_action_index: 0, | ||||||
}) * 2; | ||||||
}) | ||||||
.unwrap() | ||||||
* 2; | ||||||
state | ||||||
.put_account_balance(from_address, &asset, 100 + expected_deposit_fee) | ||||||
.unwrap(); | ||||||
bridge_lock.check_and_execute(&mut state).await.unwrap(); | ||||||
} | ||||||
|
||||||
#[test] | ||||||
fn test_calculate_base_deposit_fee() { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are in a test so don't call the test a test:
Suggested change
I'd also refactor the test to use |
||||||
// Test for length equality with drastically different int values | ||||||
let deposit = Deposit { | ||||||
bridge_address: astria_address(&[1; 20]), | ||||||
rollup_id: RollupId::from_unhashed_bytes(b"test_rollup_id"), | ||||||
amount: u128::MAX, | ||||||
asset: test_asset(), | ||||||
destination_chain_address: "someaddress".to_string(), | ||||||
source_transaction_id: TransactionId::new([0; 32]), | ||||||
source_action_index: u64::MAX, | ||||||
}; | ||||||
let calculated_len_0 = calculate_base_deposit_fee(&deposit).unwrap(); | ||||||
|
||||||
let deposit = Deposit { | ||||||
bridge_address: astria_address(&[1; 20]), | ||||||
rollup_id: RollupId::from_unhashed_bytes(b"test_rollup_id"), | ||||||
amount: 0, | ||||||
asset: test_asset(), | ||||||
destination_chain_address: "someaddress".to_string(), | ||||||
source_transaction_id: TransactionId::new([0; 32]), | ||||||
source_action_index: 0, | ||||||
}; | ||||||
let calculated_len_1 = calculate_base_deposit_fee(&deposit).unwrap(); | ||||||
assert_eq!(calculated_len_0, calculated_len_1); | ||||||
|
||||||
// Ensure longer asset name results in longer byte length. | ||||||
let deposit = Deposit { | ||||||
bridge_address: astria_address(&[1; 20]), | ||||||
rollup_id: RollupId::from_unhashed_bytes(b"test_rollup_id"), | ||||||
amount: 0, | ||||||
asset: "test_asset".parse().unwrap(), | ||||||
destination_chain_address: "someaddress".to_string(), | ||||||
source_transaction_id: TransactionId::new([0; 32]), | ||||||
source_action_index: 0, | ||||||
}; | ||||||
let calculated_len_2 = calculate_base_deposit_fee(&deposit).unwrap(); | ||||||
assert!(calculated_len_2 >= calculated_len_1); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Try to avoid |
||||||
|
||||||
// Ensure longer destination chain address results in longer byte length. | ||||||
let deposit = Deposit { | ||||||
bridge_address: astria_address(&[1; 20]), | ||||||
rollup_id: RollupId::from_unhashed_bytes(b"test_rollup_id"), | ||||||
amount: 0, | ||||||
asset: "test_asset".parse().unwrap(), | ||||||
destination_chain_address: "someaddresslonger".to_string(), | ||||||
source_transaction_id: TransactionId::new([0; 32]), | ||||||
source_action_index: 0, | ||||||
}; | ||||||
let calculated_len_3 = calculate_base_deposit_fee(&deposit).unwrap(); | ||||||
assert!(calculated_len_3 >= calculated_len_2); | ||||||
|
||||||
// Ensure calculated length is as expected with absurd string | ||||||
// lengths (have tested up to 99999999, but this makes testing very slow) | ||||||
let absurd_string: String = ['a'; u16::MAX as usize].iter().collect(); | ||||||
let deposit = Deposit { | ||||||
bridge_address: astria_address(&[1; 20]), | ||||||
rollup_id: RollupId::from_unhashed_bytes(b"test_rollup_id"), | ||||||
amount: 0, | ||||||
asset: absurd_string.parse().unwrap(), | ||||||
destination_chain_address: absurd_string.to_string(), | ||||||
source_transaction_id: TransactionId::new([0; 32]), | ||||||
source_action_index: 0, | ||||||
}; | ||||||
let calculated_len = calculate_base_deposit_fee(&deposit).unwrap(); | ||||||
let expected_len = 16 + u128::from(u16::MAX) * 2; | ||||||
assert_eq!(calculated_len, expected_len); | ||||||
} | ||||||
|
||||||
/// Used to determine the base deposit byte length for `get_deposit_byte_len()`. This is based | ||||||
/// on "reasonable" values for all fields except `asset` and `destination_chain_address`. These | ||||||
/// are empty strings, whose length will be added to the base cost at the time of | ||||||
/// calculation. | ||||||
/// | ||||||
/// This test determines 165 bytes for an average deposit with empty `asset` and | ||||||
/// `destination_chain_address`, which is divided by 10 to get our base byte length of 16. This | ||||||
/// is to allow for more flexibility in overall fees (we have more flexibility multiplying by a | ||||||
/// lower number, and if we want fees to be higher we can just raise the multiplier). | ||||||
#[test] | ||||||
fn get_base_deposit_fee() { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
use prost::Message as _; | ||||||
let bridge_address = Address::builder() | ||||||
.prefix("astria-bridge") | ||||||
.slice(&[0u8; ADDRESS_LEN][..]) | ||||||
.try_build() | ||||||
.unwrap(); | ||||||
let raw_deposit = astria_core::generated::sequencerblock::v1alpha1::Deposit { | ||||||
bridge_address: Some(bridge_address.to_raw()), | ||||||
rollup_id: Some(RollupId::from_unhashed_bytes([0; ROLLUP_ID_LEN]).to_raw()), | ||||||
amount: Some(1000.into()), | ||||||
asset: String::new(), | ||||||
destination_chain_address: String::new(), | ||||||
source_transaction_id: Some(TransactionId::new([0; TRANSACTION_ID_LEN]).to_raw()), | ||||||
source_action_index: 0, | ||||||
}; | ||||||
assert_eq!(DEPOSIT_BASE_FEE, raw_deposit.encoded_len() as u128 / 10); | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
source: crates/astria-sequencer/src/bridge/bridge_lock_action.rs | ||
expression: get_deposit_byte_len(&deposit) | ||
--- | ||
31 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make this a doc comment, i.e. start with
///