Skip to content

Commit 67640a3

Browse files
committed
perf: parallelize commit data collection and widen event scan range
- Increase event scan width from 5 to 1000 blocks per RPC call - Split Step 2 into 3 phases: scan events, parallel fetch tx/receipt (20 workers), then sequential blob parsing - Add L1 gas price distribution stats to comparison analysis
1 parent 5157b34 commit 67640a3

1 file changed

Lines changed: 89 additions & 41 deletions

File tree

scripts/derive_galileo_gas_parameter/derive_galileo_gas_parameter.py

Lines changed: 89 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ def kzg_to_versioned_hash(kzg_commitment):
198198
return "0x01"+sha256(bytes.fromhex(kzg_commitment[2:])).hexdigest()[2:]
199199

200200

201-
def latest_finalized_event_block(width=5):
201+
def latest_finalized_event_block(width=1000):
202202
"""Find the latest L1 block with a FinalizeBatch event"""
203203
finalized_l1_head = -1
204204

@@ -520,7 +520,7 @@ def parse_batch(blob_hash, block_number, mainnet_beacon_url, cur_slot, cur_block
520520
# DATA COLLECTION FUNCTIONS
521521
# ============================================================================
522522

523-
def collect_batch_data(n_batches=30, width=5, start_time=None):
523+
def collect_batch_data(n_batches=30, width=1000, start_time=None):
524524
"""
525525
Collect batch data from L1 (commits and finalizations)
526526
@@ -686,19 +686,17 @@ def collect_batch_data(n_batches=30, width=5, start_time=None):
686686

687687
# Step 2: Now collect commit data for these specific batches
688688
print(f"\nStep 2: Collecting commit data for finalized batches...")
689-
batch_data_dict = {} # batch_index -> [versioned_hash, initial_L2_block_number, num_blocks, commit_cost, blob_cost]
690-
to_block = l1_head
691-
from_block = to_block - width
692-
cur_slot = beacon_head_slot
693-
cur_block = l1_head
694-
prev_batch_count = 0
695689

696-
# We need to find commits for all batches in finalized_batch_indices
690+
# Phase 1: Scan all CommitBatch events and record metadata
691+
print(f" Phase 1: Scanning CommitBatch events...")
697692
target_batches = set(finalized_batch_indices)
693+
batch_events = {} # batch_index -> {tx_hash, blob_index}
698694
last_tx_hash = None
699695
blob_index = 0
696+
to_block = l1_head
697+
from_block = to_block - width
700698

701-
while len(batch_data_dict) < n_batches:
699+
while len(batch_events) < n_batches:
702700
event_filter = rollup_contract.events.CommitBatch.create_filter(fromBlock=from_block, toBlock=to_block)
703701
events = event_filter.get_all_entries()
704702

@@ -707,53 +705,77 @@ def collect_batch_data(n_batches=30, width=5, start_time=None):
707705
tx_hash = event.transactionHash
708706

709707
# Track blob index for multiple batches in same transaction
710-
# This must be done BEFORE filtering, so we count all batches in the tx
711708
if last_tx_hash == tx_hash:
712709
blob_index += 1
713710
else:
714711
last_tx_hash = tx_hash
715712
blob_index = 0
716713

717-
# Only process if this batch is in our finalized list
718-
if batch_index not in target_batches:
719-
continue
714+
if batch_index in target_batches and batch_index not in batch_events:
715+
batch_events[batch_index] = {'tx_hash': tx_hash, 'blob_index': blob_index}
720716

721-
# Skip if we already have this batch
722-
if batch_index in batch_data_dict:
723-
continue
717+
to_block = from_block - 1
718+
from_block = from_block - width - 1
719+
if from_block < 0:
720+
break
724721

725-
tx = w3.eth.get_transaction(event.transactionHash)
726-
receipt = w3.eth.get_transaction_receipt(event.transactionHash)
722+
print(f" Found {len(batch_events)} CommitBatch events")
727723

728-
block_number = tx.blockNumber
729-
num_batches_in_tx = len(tx.blobVersionedHashes)
730-
blob_hash = tx.blobVersionedHashes[blob_index].hex()
724+
# Phase 2: Parallel fetch tx + receipt for unique tx hashes
725+
print(f" Phase 2: Fetching transactions and receipts in parallel...")
726+
unique_tx_hashes = list(set(e['tx_hash'] for e in batch_events.values()))
727+
print(f" Unique transactions to fetch: {len(unique_tx_hashes)}")
731728

732-
# Calculate commit cost (execution gas only, amortized across all batches in this tx)
733-
commit_cost = (receipt['gasUsed'] * receipt['effectiveGasPrice']) / num_batches_in_tx
729+
tx_cache = {} # tx_hash -> (tx, receipt)
734730

735-
# Parse batch to get L2 block range
736-
initial_L2_block_number, num_blocks, cur_slot, cur_block = parse_batch(
737-
blob_hash, block_number, mainnet_beacon_url, cur_slot, cur_block
738-
)
731+
def fetch_tx_and_receipt(tx_hash):
732+
tx = w3.eth.get_transaction(tx_hash)
733+
receipt = w3.eth.get_transaction_receipt(tx_hash)
734+
return tx_hash, tx, receipt
739735

740-
# Calculate blob cost (amortized across all batches in this tx)
741-
blob_cost = (receipt['blobGasPrice'] * receipt['blobGasUsed']) / num_batches_in_tx
736+
max_workers = 20
737+
with ThreadPoolExecutor(max_workers=max_workers) as executor:
738+
futures = {executor.submit(fetch_tx_and_receipt, h): h for h in unique_tx_hashes}
739+
completed = 0
740+
for future in as_completed(futures):
741+
tx_hash, tx, receipt = future.result()
742+
tx_cache[tx_hash] = (tx, receipt)
743+
completed += 1
744+
if completed % 50 == 0 or completed == len(unique_tx_hashes):
745+
print(f" Fetched {completed}/{len(unique_tx_hashes)} transactions")
742746

743-
batch_data_dict[batch_index] = [blob_hash, initial_L2_block_number, num_blocks,
744-
commit_cost, blob_cost]
747+
print(f" Done fetching transactions")
745748

746-
# Only print when count changes
747-
if len(batch_data_dict) > prev_batch_count:
748-
print(f" Collected commit data for {len(batch_data_dict)}/{n_batches} batches")
749-
prev_batch_count = len(batch_data_dict)
749+
# Phase 3: Parse blob data for each batch (sequential, needs slot state)
750+
print(f" Phase 3: Parsing blob data...")
751+
batch_data_dict = {}
752+
cur_slot = beacon_head_slot
753+
cur_block = l1_head
750754

751-
to_block = from_block - 1
752-
from_block = from_block - width - 1
755+
# Process in block_number descending order for slot tracking
756+
sorted_batches = sorted(batch_events.items(), key=lambda x: tx_cache[x[1]['tx_hash']][0].blockNumber, reverse=True)
753757

754-
# Stop if we've searched far enough
755-
if from_block < 0:
756-
break
758+
for i, (batch_index, event_info) in enumerate(sorted_batches):
759+
tx, receipt = tx_cache[event_info['tx_hash']]
760+
blob_idx = event_info['blob_index']
761+
762+
block_number = tx.blockNumber
763+
num_batches_in_tx = len(tx.blobVersionedHashes)
764+
blob_hash = tx.blobVersionedHashes[blob_idx].hex()
765+
766+
commit_cost = (receipt['gasUsed'] * receipt['effectiveGasPrice']) / num_batches_in_tx
767+
768+
initial_L2_block_number, num_blocks, cur_slot, cur_block = parse_batch(
769+
blob_hash, block_number, mainnet_beacon_url, cur_slot, cur_block
770+
)
771+
772+
blob_cost = (receipt['blobGasPrice'] * receipt['blobGasUsed']) / num_batches_in_tx
773+
774+
batch_data_dict[batch_index] = [blob_hash, initial_L2_block_number, num_blocks,
775+
commit_cost, blob_cost]
776+
777+
if (i + 1) % 50 == 0 or (i + 1) == len(sorted_batches):
778+
print(f" Parsed {i + 1}/{len(sorted_batches)} batches")
757779

758780
# Step 3: Combine commit and finalize data
759781
print(f"\nStep 3: Combining commit and finalize data...")
@@ -1398,6 +1420,32 @@ def compare_parameters(current_params, commit_scalar, blob_scalar, penalty_multi
13981420
print("PARAMETER COMPARISON ANALYSIS")
13991421
print("=" * 60)
14001422

1423+
# L1 Gas Price Distribution
1424+
print("\n" + "-" * 60)
1425+
print("L1 Gas Price Distribution (as seen by L2 fee oracle)")
1426+
print("-" * 60)
1427+
1428+
l1_base = tx_df['l1_base_fee']
1429+
l1_blob = tx_df['l1_blob_base_fee']
1430+
1431+
print(f"\n l1_base_fee (wei):")
1432+
print(f" Min: {l1_base.min():>15,} ({l1_base.min()/1e9:.4f} gwei)")
1433+
print(f" P5: {l1_base.quantile(0.05):>15,.0f} ({l1_base.quantile(0.05)/1e9:.4f} gwei)")
1434+
print(f" Median: {l1_base.median():>15,.0f} ({l1_base.median()/1e9:.4f} gwei)")
1435+
print(f" Mean: {l1_base.mean():>15,.0f} ({l1_base.mean()/1e9:.4f} gwei)")
1436+
print(f" P95: {l1_base.quantile(0.95):>15,.0f} ({l1_base.quantile(0.95)/1e9:.4f} gwei)")
1437+
print(f" Max: {l1_base.max():>15,} ({l1_base.max()/1e9:.4f} gwei)")
1438+
print(f" Max/Min ratio: {l1_base.max()/l1_base.min():.1f}x")
1439+
1440+
print(f"\n l1_blob_base_fee (wei):")
1441+
print(f" Min: {l1_blob.min():>15,} ({l1_blob.min()/1e9:.4f} gwei)")
1442+
print(f" P5: {l1_blob.quantile(0.05):>15,.0f} ({l1_blob.quantile(0.05)/1e9:.4f} gwei)")
1443+
print(f" Median: {l1_blob.median():>15,.0f} ({l1_blob.median()/1e9:.4f} gwei)")
1444+
print(f" Mean: {l1_blob.mean():>15,.0f} ({l1_blob.mean()/1e9:.4f} gwei)")
1445+
print(f" P95: {l1_blob.quantile(0.95):>15,.0f} ({l1_blob.quantile(0.95)/1e9:.4f} gwei)")
1446+
print(f" Max: {l1_blob.max():>15,} ({l1_blob.max()/1e9:.4f} gwei)")
1447+
print(f" Max/Min ratio: {l1_blob.max()/l1_blob.min():.1f}x")
1448+
14011449
# Extract current (old) parameters
14021450
old_commit_scalar = current_params['commit_scalar']
14031451
old_blob_scalar = current_params['blob_scalar']

0 commit comments

Comments
 (0)