Skip to content

Commit 6ec7f88

Browse files
committed
fix: ensure DA transaction throttling uses params that are set
1 parent 12a09e2 commit 6ec7f88

File tree

6 files changed

+244
-21
lines changed

6 files changed

+244
-21
lines changed

Cargo.lock

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

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ op-alloy-rpc-types-engine = { version = "0.14.1", default-features = false }
128128
op-alloy-rpc-jsonrpsee = { version = "0.14.1", default-features = false }
129129
op-alloy-network = { version = "0.14.1", default-features = false }
130130
op-alloy-consensus = { version = "0.14.1", default-features = false }
131+
op-alloy-flz = { version = "0.13.0", default-features = false }
131132

132133
async-trait = { version = "0.1.83" }
133134
clap = { version = "4.4.3", features = ["derive", "env"] }

crates/op-rbuilder/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ alloy-op-evm.workspace = true
5959
op-alloy-consensus.workspace = true
6060
op-alloy-rpc-types-engine.workspace = true
6161
op-alloy-network.workspace = true
62+
op-alloy-flz.workspace = true
6263

6364
revm.workspace = true
6465
op-revm.workspace = true

crates/op-rbuilder/src/payload_builder.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1097,9 +1097,7 @@ where
10971097
}
10981098
};
10991099

1100-
// add gas used by the transaction to cumulative gas used, before creating the receipt
1101-
let gas_used = result.gas_used();
1102-
info.cumulative_gas_used += gas_used;
1100+
info.track_transaction_resource_usage(sequencer_tx.inner(), &result);
11031101

11041102
let ctx = ReceiptBuilderCtx {
11051103
tx: sequencer_tx.inner(),
@@ -1164,7 +1162,7 @@ where
11641162

11651163
// A sequencer's block should never contain blob or deposit transactions from the pool.
11661164
if tx.is_eip4844() || tx.is_deposit() {
1167-
println!("B");
1165+
warn!(target: "payload_builder", ?tx, "Unexpected transaction type.");
11681166
best_txs.mark_invalid(tx.signer(), tx.nonce());
11691167
continue;
11701168
}
@@ -1209,9 +1207,8 @@ where
12091207
trace!(target: "payload_builder", ?tx, "reverted transaction");
12101208
}
12111209

1212-
// add gas used by the transaction to cumulative gas used, before creating the receipt
1210+
info.track_transaction_resource_usage(tx.inner(), &result);
12131211
let gas_used = result.gas_used();
1214-
info.cumulative_gas_used += gas_used;
12151212

12161213
let ctx = ReceiptBuilderCtx {
12171214
tx: tx.inner(),

crates/op-rbuilder/src/payload_builder_vanilla.rs

+3-9
Original file line numberDiff line numberDiff line change
@@ -993,9 +993,7 @@ where
993993
}
994994
};
995995

996-
// add gas used by the transaction to cumulative gas used, before creating the receipt
997-
let gas_used = result.gas_used();
998-
info.cumulative_gas_used += gas_used;
996+
info.track_transaction_resource_usage(sequencer_tx.inner(), &result);
999997

1000998
let ctx = ReceiptBuilderCtx {
1001999
tx: sequencer_tx.inner(),
@@ -1102,10 +1100,8 @@ where
11021100
continue;
11031101
}
11041102

1105-
// add gas used by the transaction to cumulative gas used, before creating the
1106-
// receipt
1103+
info.track_transaction_resource_usage(tx.inner(), &result);
11071104
let gas_used = result.gas_used();
1108-
info.cumulative_gas_used += gas_used;
11091105

11101106
// Push transaction changeset and calculate header bloom filter for receipt.
11111107
let ctx = ReceiptBuilderCtx {
@@ -1174,9 +1170,7 @@ where
11741170
.transact(&builder_tx)
11751171
.map_err(|err| PayloadBuilderError::EvmExecutionError(Box::new(err)))?;
11761172

1177-
// Add gas used by the transaction to cumulative gas used, before creating the receipt
1178-
let gas_used = result.gas_used();
1179-
info.cumulative_gas_used += gas_used;
1173+
info.track_transaction_resource_usage(builder_tx.inner(), &result);
11801174

11811175
let ctx = ReceiptBuilderCtx {
11821176
tx: builder_tx.inner(),

crates/op-rbuilder/src/primitives/reth/execution.rs

+235-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
//! Heavily influenced by [reth](https://github.com/paradigmxyz/reth/blob/1e965caf5fa176f244a31c0d2662ba1b590938db/crates/optimism/payload/src/builder.rs#L570)
22
use alloy_consensus::Transaction;
3-
use alloy_primitives::{private::alloy_rlp::Encodable, Address, TxHash, U256};
3+
use alloy_eips::Encodable2718;
4+
use alloy_primitives::{Address, TxHash, U256};
5+
use op_revm::OpHaltReason;
46
use reth_node_api::NodePrimitives;
57
use reth_optimism_primitives::OpReceipt;
8+
use revm::context::result::ExecutionResult;
69
use std::collections::HashSet;
710

811
/// Holds the state after execution
@@ -62,16 +65,242 @@ impl<N: NodePrimitives> ExecutionInfo<N> {
6265
tx_data_limit: Option<u64>,
6366
block_data_limit: Option<u64>,
6467
) -> bool {
65-
if tx_data_limit.is_some_and(|da_limit| tx.length() as u64 > da_limit) {
68+
if self.cumulative_gas_used + tx.gas_limit() > block_gas_limit {
6669
return true;
6770
}
6871

69-
if block_data_limit
70-
.is_some_and(|da_limit| self.cumulative_da_bytes_used + (tx.length() as u64) > da_limit)
71-
{
72+
if tx_data_limit.is_none() && block_data_limit.is_none() {
73+
return false;
74+
}
75+
76+
let tx_compressed_size = op_alloy_flz::flz_compress_len(tx.encoded_2718().as_slice());
77+
if tx_data_limit.is_some_and(|da_limit| tx_compressed_size as u64 > da_limit) {
7278
return true;
7379
}
7480

75-
self.cumulative_gas_used + tx.gas_limit() > block_gas_limit
81+
if block_data_limit.is_some_and(|da_limit| {
82+
self.cumulative_da_bytes_used + (tx_compressed_size as u64) > da_limit
83+
}) {
84+
return true;
85+
}
86+
87+
false
88+
}
89+
90+
/// Increments the current usage trackers (gas, DA) for a transaction that has been included.
91+
pub fn track_transaction_resource_usage(
92+
&mut self,
93+
tx: &N::SignedTx,
94+
result: &ExecutionResult<OpHaltReason>,
95+
) {
96+
self.cumulative_gas_used += result.gas_used();
97+
self.cumulative_da_bytes_used +=
98+
op_alloy_flz::flz_compress_len(tx.encoded_2718().as_slice()) as u64;
99+
}
100+
}
101+
102+
#[cfg(test)]
103+
mod tests {
104+
use super::*;
105+
use alloy_consensus::{SignableTransaction, TxEip1559};
106+
use alloy_eips::Encodable2718;
107+
use alloy_primitives::private::alloy_rlp::Encodable;
108+
use alloy_primitives::{Bytes, Signature};
109+
use rand::RngCore;
110+
use reth::revm::context::result::SuccessReason;
111+
use reth_optimism_primitives::{OpPrimitives, OpTransactionSigned};
112+
use revm::context::result::Output;
113+
114+
#[test]
115+
fn test_block_gas_limit() {
116+
let gas_limit = 100;
117+
let info = ExecutionInfo::<OpPrimitives>::with_capacity(10);
118+
119+
let allowable_transaction: OpTransactionSigned = TxEip1559 {
120+
gas_limit: gas_limit - 10,
121+
..TxEip1559::default()
122+
}
123+
.into_signed(Signature::test_signature())
124+
.into();
125+
126+
assert_eq!(
127+
false,
128+
info.is_tx_over_limits(&allowable_transaction, gas_limit, None, None)
129+
);
130+
131+
let too_much_gas: OpTransactionSigned = TxEip1559 {
132+
gas_limit: gas_limit + 10,
133+
..TxEip1559::default()
134+
}
135+
.into_signed(Signature::test_signature())
136+
.into();
137+
138+
assert_eq!(
139+
true,
140+
info.is_tx_over_limits(&too_much_gas, gas_limit, None, None)
141+
);
142+
}
143+
144+
fn gen_random_bytes(size: usize) -> alloy_primitives::bytes::Bytes {
145+
let mut rng = rand::thread_rng();
146+
let mut vec = vec![0u8; size];
147+
rng.fill_bytes(&mut vec);
148+
vec.into()
149+
}
150+
151+
#[test]
152+
fn test_tx_da_size() {
153+
let allowable_transaction: OpTransactionSigned = TxEip1559 {
154+
..TxEip1559::default()
155+
}
156+
.into_signed(Signature::test_signature())
157+
.into();
158+
159+
let over_tx_da_limits: OpTransactionSigned = TxEip1559 {
160+
input: gen_random_bytes(2000).into(),
161+
..TxEip1559::default()
162+
}
163+
.into_signed(Signature::test_signature())
164+
.into();
165+
166+
let large_but_compressable: OpTransactionSigned = TxEip1559 {
167+
input: vec![0u8; 2000].into(),
168+
..TxEip1559::default()
169+
}
170+
.into_signed(Signature::test_signature())
171+
.into();
172+
173+
let max_tx_size: u64 = 1000;
174+
175+
// Sanity check compressed and uncompressed transaction sizes
176+
// Uncompressed, the large transactions are the same size, but the all zero one compresses
177+
// 90+% and should be included when DA throttling is active
178+
assert_eq!(
179+
78,
180+
op_alloy_flz::flz_compress_len(allowable_transaction.encoded_2718().as_slice())
181+
);
182+
assert_eq!(81, allowable_transaction.length());
183+
assert_eq!(
184+
108,
185+
op_alloy_flz::flz_compress_len(large_but_compressable.encoded_2718().as_slice())
186+
);
187+
assert_eq!(2085, large_but_compressable.length());
188+
// Relative check as the randomness of the data may change the compressed size
189+
assert_eq!(
190+
true,
191+
max_tx_size
192+
< op_alloy_flz::flz_compress_len(over_tx_da_limits.encoded_2718().as_slice())
193+
as u64
194+
);
195+
assert_eq!(2085, over_tx_da_limits.length());
196+
197+
let info = ExecutionInfo::<OpPrimitives>::with_capacity(10);
198+
199+
assert_eq!(
200+
false,
201+
info.is_tx_over_limits(&allowable_transaction, 10000, Some(max_tx_size), None)
202+
);
203+
assert_eq!(
204+
false,
205+
info.is_tx_over_limits(&large_but_compressable, 10000, Some(max_tx_size), None)
206+
);
207+
assert_eq!(
208+
true,
209+
info.is_tx_over_limits(&over_tx_da_limits, 10000, Some(max_tx_size), None)
210+
);
211+
212+
// When no DA specific limits are set, large transactions are allowable
213+
assert_eq!(
214+
false,
215+
info.is_tx_over_limits(&over_tx_da_limits, 10000, None, None)
216+
);
217+
}
218+
219+
#[test]
220+
fn test_block_da_limit() {
221+
let block_data_limit = 1000;
222+
let mut info = ExecutionInfo::<OpPrimitives>::with_capacity(10);
223+
224+
let large_transaction: OpTransactionSigned = TxEip1559 {
225+
input: gen_random_bytes(2000).into(),
226+
..TxEip1559::default()
227+
}
228+
.into_signed(Signature::test_signature())
229+
.into();
230+
231+
let large_but_compressable: OpTransactionSigned = TxEip1559 {
232+
input: vec![0u8; 2000].into(),
233+
..TxEip1559::default()
234+
}
235+
.into_signed(Signature::test_signature())
236+
.into();
237+
238+
// Sanity check compressed and uncompressed transaction sizes
239+
assert_eq!(
240+
108,
241+
op_alloy_flz::flz_compress_len(large_but_compressable.encoded_2718().as_slice())
242+
);
243+
assert_eq!(2085, large_but_compressable.length());
244+
// Relative check as the randomness of the data may change the compressed size
245+
assert_eq!(
246+
true,
247+
block_data_limit
248+
< op_alloy_flz::flz_compress_len(large_transaction.encoded_2718().as_slice())
249+
as u64
250+
);
251+
assert_eq!(2085, large_transaction.length());
252+
253+
assert_eq!(
254+
true,
255+
info.is_tx_over_limits(&large_transaction, 1000, None, Some(block_data_limit))
256+
);
257+
assert_eq!(
258+
false,
259+
info.is_tx_over_limits(&large_but_compressable, 1000, None, Some(block_data_limit))
260+
);
261+
262+
// Block level DA inclusion should take into account the current amount of DA bytes used in the block
263+
info.cumulative_da_bytes_used += 990;
264+
assert_eq!(
265+
true,
266+
info.is_tx_over_limits(&large_but_compressable, 1000, None, Some(block_data_limit))
267+
);
268+
}
269+
270+
#[test]
271+
pub fn test_track_resource_usage() {
272+
let txn_gas_limit = 250;
273+
274+
let txn: OpTransactionSigned = TxEip1559 {
275+
input: vec![0u8; 2000].into(),
276+
gas_limit: txn_gas_limit,
277+
..TxEip1559::default()
278+
}
279+
.into_signed(Signature::test_signature())
280+
.into();
281+
282+
let expected_compressed_size: u64 = 112;
283+
assert_eq!(
284+
expected_compressed_size,
285+
op_alloy_flz::flz_compress_len(txn.encoded_2718().as_slice()) as u64
286+
);
287+
288+
let mut info = ExecutionInfo::<OpPrimitives>::with_capacity(10);
289+
290+
let result = &ExecutionResult::<OpHaltReason>::Success {
291+
reason: SuccessReason::Return,
292+
gas_used: 100,
293+
gas_refunded: 0,
294+
logs: vec![],
295+
output: Output::Call(Bytes(vec![].into())),
296+
};
297+
298+
assert_eq!(0, info.cumulative_gas_used);
299+
assert_eq!(0, info.cumulative_da_bytes_used);
300+
301+
info.track_transaction_resource_usage(&txn, &result);
302+
303+
assert_eq!(100, info.cumulative_gas_used);
304+
assert_eq!(expected_compressed_size, info.cumulative_da_bytes_used);
76305
}
77306
}

0 commit comments

Comments
 (0)