Skip to content

Commit df07f77

Browse files
committed
fix: use fastlz sizes for tracking da usage
1 parent d0d4882 commit df07f77

File tree

6 files changed

+243
-20
lines changed

6 files changed

+243
-20
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-5
Original file line numberDiff line numberDiff line change
@@ -1107,9 +1107,7 @@ where
11071107
}
11081108
};
11091109

1110-
// add gas used by the transaction to cumulative gas used, before creating the receipt
1111-
let gas_used = result.gas_used();
1112-
info.cumulative_gas_used += gas_used;
1110+
info.track_transaction_resource_usage(sequencer_tx.inner(), &result);
11131111

11141112
let ctx = ReceiptBuilderCtx {
11151113
tx: sequencer_tx.inner(),
@@ -1174,6 +1172,7 @@ where
11741172

11751173
// A sequencer's block should never contain blob or deposit transactions from the pool.
11761174
if tx.is_eip4844() || tx.is_deposit() {
1175+
warn!(target: "payload_builder", ?tx, "Unexpected transaction type.");
11771176
best_txs.mark_invalid(tx.signer(), tx.nonce());
11781177
continue;
11791178
}
@@ -1218,9 +1217,8 @@ where
12181217
trace!(target: "payload_builder", ?tx, "reverted transaction");
12191218
}
12201219

1221-
// add gas used by the transaction to cumulative gas used, before creating the receipt
1220+
info.track_transaction_resource_usage(tx.inner(), &result);
12221221
let gas_used = result.gas_used();
1223-
info.cumulative_gas_used += gas_used;
12241222

12251223
let ctx = ReceiptBuilderCtx {
12261224
tx: tx.inner(),

crates/op-rbuilder/src/payload_builder_vanilla.rs

+3-9
Original file line numberDiff line numberDiff line change
@@ -1009,9 +1009,7 @@ where
10091009
}
10101010
};
10111011

1012-
// add gas used by the transaction to cumulative gas used, before creating the receipt
1013-
let gas_used = result.gas_used();
1014-
info.cumulative_gas_used += gas_used;
1012+
info.track_transaction_resource_usage(sequencer_tx.inner(), &result);
10151013

10161014
let ctx = ReceiptBuilderCtx {
10171015
tx: sequencer_tx.inner(),
@@ -1120,10 +1118,8 @@ where
11201118
}
11211119
}
11221120

1123-
// add gas used by the transaction to cumulative gas used, before creating the
1124-
// receipt
1121+
info.track_transaction_resource_usage(tx.inner(), &result);
11251122
let gas_used = result.gas_used();
1126-
info.cumulative_gas_used += gas_used;
11271123

11281124
// Push transaction changeset and calculate header bloom filter for receipt.
11291125
let ctx = ReceiptBuilderCtx {
@@ -1192,9 +1188,7 @@ where
11921188
.transact(&builder_tx)
11931189
.map_err(|err| PayloadBuilderError::EvmExecutionError(Box::new(err)))?;
11941190

1195-
// Add gas used by the transaction to cumulative gas used, before creating the receipt
1196-
let gas_used = result.gas_used();
1197-
info.cumulative_gas_used += gas_used;
1191+
info.track_transaction_resource_usage(builder_tx.inner(), &result);
11981192

11991193
let ctx = ReceiptBuilderCtx {
12001194
tx: builder_tx.inner(),

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

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

0 commit comments

Comments
 (0)