Skip to content

Commit 847a195

Browse files
segfault-magnetMujkicAhal3e
authored
feat: higher priority fee when late (#186)
Co-authored-by: MujkicA <32431923+MujkicA@users.noreply.github.com> Co-authored-by: hal3e <git@hal3e.io>
1 parent 54b09c6 commit 847a195

File tree

17 files changed

+511
-140
lines changed

17 files changed

+511
-140
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

+13-1
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,24 @@ The Fuel Block Committer is configured primarily through environment variables.
183183
- **Format:** Human-readable duration
184184
- **Example:** `300s`
185185

186-
- **`COMMITTER__APP__TX_MAX_FEE`**
186+
- **`COMMITTER__APP__TX_FEES__MAX`**
187187

188188
- **Description:** Maximum gas fee permitted for a transaction in wei.
189189
- **Type:** `u64`
190190
- **Example:** `4000000000000000`
191191

192+
- **`COMMITTER__APP__TX_FEES__MIN_REWARD_PERC`**
193+
194+
- **Description:** Lowest reward percentage to use when the system is up to date with L2 block posting.
195+
- **Type:** `f64`
196+
- **Example:** `20.0`
197+
198+
- **`COMMITTER__APP__TX_FEES__MAX_REWARD_PERC`**
199+
200+
- **Description:** Highest reward percentage to use when the system is very late with L2 block posting.
201+
- **Type:** `f64`
202+
- **Example:** `30.0`
203+
192204
- **`COMMITTER__APP__SEND_TX_REQUEST_TIMEOUT`**
193205

194206
- **Description:** Duration for timeout when sending transaction requests.

committer/src/config.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ pub struct App {
133133
/// Interval after which to bump a pending tx
134134
#[serde(deserialize_with = "human_readable_duration")]
135135
pub gas_bump_timeout: Duration,
136-
/// Max gas fee we permit a tx to have in wei
137-
pub tx_max_fee: u64,
136+
/// Tweak how we pay for a l1 transaction
137+
pub tx_fees: TxFeesConfig,
138138
///// Contains configs relating to block state posting to l1
139139
pub bundle: BundleConfig,
140140
//// Duration for timeout when sending tx requests
@@ -150,6 +150,16 @@ pub struct App {
150150
pub fee_algo: FeeAlgoConfig,
151151
}
152152

153+
#[derive(Debug, Clone, Deserialize, Copy)]
154+
pub struct TxFeesConfig {
155+
/// Max gas fee we permit a tx to have in wei
156+
pub max: u64,
157+
/// lowest reward percentage to use when we're up to date with l2 block posting (e.g. 20.)
158+
pub min_reward_perc: f64,
159+
/// highest reward percentage to use when we're very late with l2 block posting (e.g. 30.)
160+
pub max_reward_perc: f64,
161+
}
162+
153163
/// Configuration for the fee algorithm used by the StateCommitter
154164
#[derive(Debug, Clone, Deserialize)]
155165
pub struct FeeAlgoConfig {

committer/src/setup.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::time::Duration;
22

33
use clock::SystemClock;
4-
use eth::{BlobEncoder, Signers};
4+
use eth::{AcceptablePriorityFeePercentages, BlobEncoder, Signers};
55
use fuel_block_committer_encoding::bundle;
66
use metrics::{
77
prometheus::{IntGauge, Registry},
@@ -230,8 +230,12 @@ pub async fn l1_adapter(
230230
Signers::for_keys(config.eth.l1_keys.clone()).await?,
231231
internal_config.eth_errors_before_unhealthy,
232232
eth::TxConfig {
233-
tx_max_fee: config.app.tx_max_fee as u128,
233+
tx_max_fee: u128::from(config.app.tx_fees.max),
234234
send_tx_request_timeout: config.app.send_tx_request_timeout,
235+
acceptable_priority_fee_percentage: AcceptablePriorityFeePercentages::new(
236+
config.app.tx_fees.min_reward_perc,
237+
config.app.tx_fees.max_reward_perc,
238+
)?,
235239
},
236240
)
237241
.await?;

e2e/src/committer.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ impl Committer {
7676
.env("COMMITTER__APP__L1_FEE_CHECK_INTERVAL", "5s")
7777
.env("COMMITTER__APP__NUM_BLOCKS_TO_FINALIZE_TX", "3")
7878
.env("COMMITTER__APP__GAS_BUMP_TIMEOUT", "300s")
79-
.env("COMMITTER__APP__TX_MAX_FEE", "4000000000000000")
8079
.env("COMMITTER__APP__SEND_TX_REQUEST_TIMEOUT", "10s")
8180
.env(
8281
"COMMITTER__APP__BUNDLE__ACCUMULATION_TIMEOUT",
@@ -132,6 +131,9 @@ impl Committer {
132131
"COMMITTER__APP__FEE_ALGO__ALWAYS_ACCEPTABLE_FEE",
133132
u64::MAX.to_string(),
134133
)
134+
.env("COMMITTER__APP__TX_FEES__MAX", "4000000000000000")
135+
.env("COMMITTER__APP__TX_FEES__MIN_REWARD_PERC", "20")
136+
.env("COMMITTER__APP__TX_FEES__MAX_REWARD_PERC", "30")
135137
.current_dir(Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap())
136138
.kill_on_drop(true);
137139

e2e/src/eth_node/state_contract.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use alloy::{
77
providers::{Provider, ProviderBuilder, WsConnect},
88
rpc::types::TransactionRequest,
99
};
10-
use eth::{AwsClient, AwsConfig, Signer, Signers, WebsocketClient};
10+
use eth::{
11+
AcceptablePriorityFeePercentages, AwsClient, AwsConfig, Signer, Signers, WebsocketClient,
12+
};
1113
use fs_extra::dir::{copy, CopyOptions};
1214
use serde::Deserialize;
1315
use services::types::{fuel::FuelBlock, Address};
@@ -42,6 +44,7 @@ impl DeployedContract {
4244
eth::TxConfig {
4345
tx_max_fee,
4446
send_tx_request_timeout,
47+
acceptable_priority_fee_percentage: AcceptablePriorityFeePercentages::default(),
4548
},
4649
)
4750
.await?;

packages/adapters/eth/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ tracing = { workspace = true }
3838
url = { workspace = true }
3939

4040
[dev-dependencies]
41+
eth = { workspace = true, features = ["test-helpers"] }
4142
alloy = { workspace = true, features = [
4243
"signer-local",
4344
"node-bindings",

packages/adapters/eth/src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@ pub use alloy::primitives::Address;
1212
pub use aws::*;
1313
pub use blob_encoder::BlobEncoder;
1414
pub use http::Provider as HttpClient;
15-
pub use websocket::{L1Key, L1Keys, Signer, Signers, TxConfig, WebsocketClient};
15+
pub use websocket::{
16+
AcceptablePriorityFeePercentages, L1Key, L1Keys, Signer, Signers, TxConfig, WebsocketClient,
17+
};

packages/adapters/eth/src/websocket.rs

+94-9
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use alloy::{
1111
use delegate::delegate;
1212
use serde::Deserialize;
1313
use services::{
14+
state_committer::port::l1::Priority,
1415
types::{
1516
BlockSubmissionTx, Fragment, FragmentsSubmitted, L1Height, L1Tx, NonEmpty,
1617
TransactionResponse, U256,
@@ -110,6 +111,7 @@ impl services::state_committer::port::l1::Api for WebsocketClient {
110111
&self,
111112
fragments: NonEmpty<Fragment>,
112113
previous_tx: Option<services::types::L1Tx>,
114+
priority: Priority
113115
) -> Result<(L1Tx, FragmentsSubmitted)>;
114116
}
115117
}
@@ -158,6 +160,58 @@ impl L1Keys {
158160
pub struct TxConfig {
159161
pub tx_max_fee: u128,
160162
pub send_tx_request_timeout: Duration,
163+
pub acceptable_priority_fee_percentage: AcceptablePriorityFeePercentages,
164+
}
165+
166+
#[cfg(feature = "test-helpers")]
167+
impl Default for TxConfig {
168+
fn default() -> Self {
169+
Self {
170+
tx_max_fee: u128::MAX,
171+
send_tx_request_timeout: Duration::from_secs(10),
172+
acceptable_priority_fee_percentage: AcceptablePriorityFeePercentages::default(),
173+
}
174+
}
175+
}
176+
177+
#[derive(Debug, Clone, Copy)]
178+
pub struct AcceptablePriorityFeePercentages {
179+
min: f64,
180+
max: f64,
181+
}
182+
183+
#[cfg(feature = "test-helpers")]
184+
impl Default for AcceptablePriorityFeePercentages {
185+
fn default() -> Self {
186+
Self::new(20., 20.).expect("valid reward percentile range")
187+
}
188+
}
189+
190+
impl AcceptablePriorityFeePercentages {
191+
pub fn new(min: f64, max: f64) -> Result<Self> {
192+
if min > max {
193+
return Err(services::Error::Other(
194+
"min reward percentile must be less than or equal to max reward percentile"
195+
.to_string(),
196+
));
197+
}
198+
199+
if min <= 0.0 || max > 100.0 {
200+
return Err(services::Error::Other(
201+
"reward percentiles must be > 0 and <= 100".to_string(),
202+
));
203+
}
204+
205+
Ok(Self { min, max })
206+
}
207+
208+
pub fn apply(&self, priority: Priority) -> f64 {
209+
let min = self.min;
210+
211+
let increase = (self.max - min) * priority.get() / 100.;
212+
213+
(min + increase).min(self.max)
214+
}
161215
}
162216

163217
// This trait is needed because you cannot write `dyn TraitA + TraitB` except when TraitB is an
@@ -268,14 +322,7 @@ impl WebsocketClient {
268322
.map(|signer| TxSigner::address(&signer));
269323
let contract_caller_address = TxSigner::address(&signers.main);
270324

271-
let provider = WsConnection::connect(
272-
url,
273-
contract_address,
274-
signers,
275-
tx_config.tx_max_fee,
276-
tx_config.send_tx_request_timeout,
277-
)
278-
.await?;
325+
let provider = WsConnection::connect(url, contract_address, signers, tx_config).await?;
279326

280327
Ok(Self {
281328
inner: HealthTrackingMiddleware::new(provider, unhealthy_after_n_errors),
@@ -327,10 +374,11 @@ impl WebsocketClient {
327374
&self,
328375
fragments: NonEmpty<Fragment>,
329376
previous_tx: Option<services::types::L1Tx>,
377+
priority: Priority,
330378
) -> Result<(L1Tx, FragmentsSubmitted)> {
331379
Ok(self
332380
.inner
333-
.submit_state_fragments(fragments, previous_tx)
381+
.submit_state_fragments(fragments, previous_tx, priority)
334382
.await?)
335383
}
336384

@@ -366,6 +414,7 @@ impl RegistersMetrics for WebsocketClient {
366414
#[cfg(test)]
367415
mod tests {
368416
use pretty_assertions::assert_eq;
417+
use services::state_committer::port::l1::Priority;
369418

370419
use super::L1Key;
371420

@@ -392,4 +441,40 @@ mod tests {
392441
// then
393442
assert_eq!(key, L1Key::Kms("0x1234".to_owned()));
394443
}
444+
445+
#[test]
446+
fn lowest_priority_gives_min_priority_fee_perc() {
447+
// given
448+
let sut = super::AcceptablePriorityFeePercentages::new(20., 40.).unwrap();
449+
450+
// when
451+
let fee_perc = sut.apply(Priority::MIN);
452+
453+
// then
454+
assert_eq!(fee_perc, 20.);
455+
}
456+
457+
#[test]
458+
fn medium_priority_gives_middle_priority_fee_perc() {
459+
// given
460+
let sut = super::AcceptablePriorityFeePercentages::new(20., 40.).unwrap();
461+
462+
// when
463+
let fee_perc = sut.apply(Priority::new(50.).unwrap());
464+
465+
// then
466+
assert_eq!(fee_perc, 30.);
467+
}
468+
469+
#[test]
470+
fn highest_priority_gives_max_priority_fee_perc() {
471+
// given
472+
let sut = super::AcceptablePriorityFeePercentages::new(20., 40.).unwrap();
473+
474+
// when
475+
let fee_perc = sut.apply(Priority::MAX);
476+
477+
// then
478+
assert_eq!(fee_perc, 40.);
479+
}
395480
}

0 commit comments

Comments
 (0)