Skip to content

Commit 5157b34

Browse files
committed
feat: add parameter comparison analysis against current on-chain values
Compare derived gas parameters with current on-chain parameters to evaluate impact on historical transactions before deploying. Includes four analyses: per-tx fee changes, fee change by size group, cost recovery by batch, and penalty proportion breakdown.
1 parent 0484c36 commit 5157b34

1 file changed

Lines changed: 215 additions & 0 deletions

File tree

scripts/derive_galileo_gas_parameter/derive_galileo_gas_parameter.py

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,6 +1374,218 @@ def analyze_etherfi_penalties(tx_df, penalty_multiplier):
13741374
return results
13751375

13761376

1377+
# ============================================================================
1378+
# PARAMETER COMPARISON ANALYSIS
1379+
# ============================================================================
1380+
1381+
def compare_parameters(current_params, commit_scalar, blob_scalar, penalty_multiplier, tx_df, batch_df):
1382+
"""
1383+
Compare derived parameters against current on-chain parameters.
1384+
1385+
Computes per-tx L1 fees under both old and new parameter sets using:
1386+
effective_size = compressed_tx_size + compressed_tx_size² / penalty_factor
1387+
L1_fee = (commit_scalar * l1_base_fee + blob_scalar * l1_blob_base_fee) * effective_size
1388+
1389+
Args:
1390+
current_params: Dict with current on-chain parameters from read_current_gas_parameters()
1391+
commit_scalar: Newly derived commit scalar
1392+
blob_scalar: Newly derived blob scalar
1393+
penalty_multiplier: Newly derived penalty multiplier
1394+
tx_df: Transaction DataFrame
1395+
batch_df: Batch DataFrame with L1 costs
1396+
"""
1397+
print("\n" + "=" * 60)
1398+
print("PARAMETER COMPARISON ANALYSIS")
1399+
print("=" * 60)
1400+
1401+
# Extract current (old) parameters
1402+
old_commit_scalar = current_params['commit_scalar']
1403+
old_blob_scalar = current_params['blob_scalar']
1404+
old_penalty_factor = current_params['penalty_factor']
1405+
1406+
new_commit_scalar = commit_scalar
1407+
new_blob_scalar = blob_scalar
1408+
new_penalty_factor = penalty_multiplier
1409+
1410+
# --- Analysis 1: Fee Comparison (Old vs New) ---
1411+
print("\n" + "-" * 60)
1412+
print("Analysis 1: Fee Comparison (Old vs New)")
1413+
print("-" * 60)
1414+
1415+
print(f"\n Parameter Comparison:")
1416+
print(f" {'Parameter':<25} {'Current':>15} {'New':>15} {'Change':>15}")
1417+
print(f" {'-'*25} {'-'*15} {'-'*15} {'-'*15}")
1418+
print(f" {'commit_scalar':<25} {old_commit_scalar:>15.4f} {new_commit_scalar:>15.4f} {new_commit_scalar - old_commit_scalar:>+15.4f}")
1419+
print(f" {'blob_scalar':<25} {old_blob_scalar:>15.4f} {new_blob_scalar:>15.4f} {new_blob_scalar - old_blob_scalar:>+15.4f}")
1420+
print(f" {'penalty_factor':<25} {old_penalty_factor:>15.0f} {new_penalty_factor:>15.0f} {new_penalty_factor - old_penalty_factor:>+15.0f}")
1421+
1422+
# Calculate effective_size and fees under both parameter sets
1423+
df = tx_df.copy()
1424+
1425+
df['old_effective_size'] = df['compressed_tx_size'] + df['compressed_tx_size']**2 / old_penalty_factor
1426+
df['new_effective_size'] = df['compressed_tx_size'] + df['compressed_tx_size']**2 / new_penalty_factor
1427+
1428+
df['old_fee'] = (old_commit_scalar * df['l1_base_fee'] + old_blob_scalar * df['l1_blob_base_fee']) * df['old_effective_size']
1429+
df['new_fee'] = (new_commit_scalar * df['l1_base_fee'] + new_blob_scalar * df['l1_blob_base_fee']) * df['new_effective_size']
1430+
1431+
df['fee_change'] = df['new_fee'] - df['old_fee']
1432+
df['fee_change_pct'] = df['fee_change'] / df['old_fee'] * 100
1433+
1434+
print(f"\n Per-Transaction Fee Change Statistics:")
1435+
print(f" {'Metric':<20} {'Absolute (wei)':>20} {'Percentage':>15}")
1436+
print(f" {'-'*20} {'-'*20} {'-'*15}")
1437+
print(f" {'Mean':<20} {df['fee_change'].mean():>+20,.0f} {df['fee_change_pct'].mean():>+14.2f}%")
1438+
print(f" {'Median':<20} {df['fee_change'].median():>+20,.0f} {df['fee_change_pct'].median():>+14.2f}%")
1439+
print(f" {'P95':<20} {df['fee_change'].quantile(0.95):>+20,.0f} {df['fee_change_pct'].quantile(0.95):>+14.2f}%")
1440+
print(f" {'P99':<20} {df['fee_change'].quantile(0.99):>+20,.0f} {df['fee_change_pct'].quantile(0.99):>+14.2f}%")
1441+
1442+
paying_more = (df['fee_change'] > 0).sum()
1443+
paying_less = (df['fee_change'] < 0).sum()
1444+
paying_same = (df['fee_change'] == 0).sum()
1445+
total_txs = len(df)
1446+
1447+
print(f"\n Fee Direction:")
1448+
print(f" Paying more: {paying_more:>8,} ({paying_more/total_txs*100:>6.2f}%)")
1449+
print(f" Paying less: {paying_less:>8,} ({paying_less/total_txs*100:>6.2f}%)")
1450+
print(f" No change: {paying_same:>8,} ({paying_same/total_txs*100:>6.2f}%)")
1451+
1452+
total_old_fee = df['old_fee'].sum()
1453+
total_new_fee = df['new_fee'].sum()
1454+
total_change = total_new_fee - total_old_fee
1455+
1456+
print(f"\n Aggregate Total Fee:")
1457+
print(f" Old total: {total_old_fee:>25,.0f} wei ({total_old_fee/1e18:.6f} ETH)")
1458+
print(f" New total: {total_new_fee:>25,.0f} wei ({total_new_fee/1e18:.6f} ETH)")
1459+
print(f" Change: {total_change:>+25,.0f} wei ({total_change/total_old_fee*100:>+.2f}%)")
1460+
1461+
# --- Analysis 2: Fee Change by Transaction Size Group ---
1462+
print("\n" + "-" * 60)
1463+
print("Analysis 2: Fee Change by Transaction Size Group")
1464+
print("-" * 60)
1465+
1466+
p50_size = df['compressed_tx_size'].quantile(0.50)
1467+
p95_size = df['compressed_tx_size'].quantile(0.95)
1468+
1469+
def size_group(size):
1470+
if size < p50_size:
1471+
return 'Small (< P50)'
1472+
elif size <= p95_size:
1473+
return 'Medium (P50-P95)'
1474+
else:
1475+
return 'Large (> P95)'
1476+
1477+
df['size_group'] = df['compressed_tx_size'].apply(size_group)
1478+
1479+
# Calculate penalty terms for both parameter sets
1480+
df['old_penalty_term'] = df['compressed_tx_size']**2 / old_penalty_factor
1481+
df['new_penalty_term'] = df['compressed_tx_size']**2 / new_penalty_factor
1482+
1483+
group_order = ['Small (< P50)', 'Medium (P50-P95)', 'Large (> P95)']
1484+
print(f"\n Size thresholds: P50 = {p50_size:.0f} bytes, P95 = {p95_size:.0f} bytes\n")
1485+
1486+
for group_name in group_order:
1487+
g = df[df['size_group'] == group_name]
1488+
if len(g) == 0:
1489+
continue
1490+
1491+
print(f" {group_name}:")
1492+
print(f" Count: {len(g):,}")
1493+
print(f" Size range: {g['compressed_tx_size'].min():.0f} - {g['compressed_tx_size'].max():.0f} bytes")
1494+
print(f" Old fee: mean={g['old_fee'].mean():,.0f} median={g['old_fee'].median():,.0f} wei")
1495+
print(f" New fee: mean={g['new_fee'].mean():,.0f} median={g['new_fee'].median():,.0f} wei")
1496+
print(f" Fee change: mean={g['fee_change'].mean():+,.0f} median={g['fee_change'].median():+,.0f} wei")
1497+
print(f" Fee change %%: mean={g['fee_change_pct'].mean():+.2f}%% median={g['fee_change_pct'].median():+.2f}%%")
1498+
print(f" Old penalty/eff: mean={((g['old_penalty_term'] / g['old_effective_size']) * 100).mean():.2f}%%")
1499+
print(f" New penalty/eff: mean={((g['new_penalty_term'] / g['new_effective_size']) * 100).mean():.2f}%%")
1500+
print()
1501+
1502+
# --- Analysis 3: Cost Recovery by Batch ---
1503+
print("-" * 60)
1504+
print("Analysis 3: Cost Recovery by Batch")
1505+
print("-" * 60)
1506+
1507+
batch_old_fees = df.groupby('batch_index')['old_fee'].sum()
1508+
batch_new_fees = df.groupby('batch_index')['new_fee'].sum()
1509+
1510+
batch_actual_cost = batch_df['commit_cost'] + batch_df['finalize_cost'] + batch_df['blob_cost']
1511+
1512+
# Align indices
1513+
common_idx = batch_old_fees.index.intersection(batch_actual_cost.index)
1514+
batch_old_fees = batch_old_fees.loc[common_idx]
1515+
batch_new_fees = batch_new_fees.loc[common_idx]
1516+
batch_actual_cost = batch_actual_cost.loc[common_idx]
1517+
1518+
old_recovery_rate = batch_old_fees / batch_actual_cost
1519+
new_recovery_rate = batch_new_fees / batch_actual_cost
1520+
1521+
print(f"\n Recovery Rate Statistics:")
1522+
print(f" {'Metric':<15} {'Old Params':>15} {'New Params':>15}")
1523+
print(f" {'-'*15} {'-'*15} {'-'*15}")
1524+
print(f" {'Mean':<15} {old_recovery_rate.mean():>14.4f}x {new_recovery_rate.mean():>14.4f}x")
1525+
print(f" {'Median':<15} {old_recovery_rate.median():>14.4f}x {new_recovery_rate.median():>14.4f}x")
1526+
print(f" {'Min':<15} {old_recovery_rate.min():>14.4f}x {new_recovery_rate.min():>14.4f}x")
1527+
print(f" {'Max':<15} {old_recovery_rate.max():>14.4f}x {new_recovery_rate.max():>14.4f}x")
1528+
1529+
old_over = (old_recovery_rate > 1).sum()
1530+
old_under = (old_recovery_rate < 1).sum()
1531+
new_over = (new_recovery_rate > 1).sum()
1532+
new_under = (new_recovery_rate < 1).sum()
1533+
1534+
print(f"\n Over/Under Recovery:")
1535+
print(f" Old params: {old_over} over, {old_under} under (of {len(common_idx)} batches)")
1536+
print(f" New params: {new_over} over, {new_under} under (of {len(common_idx)} batches)")
1537+
1538+
# Per-batch table (show all if <= 30 batches)
1539+
if len(common_idx) <= 30:
1540+
print(f"\n Per-Batch Detail:")
1541+
print(f" {'Batch':>8} {'Actual Cost':>18} {'Old Fees':>18} {'Old Rate':>10} {'New Fees':>18} {'New Rate':>10}")
1542+
print(f" {'-'*8} {'-'*18} {'-'*18} {'-'*10} {'-'*18} {'-'*10}")
1543+
for idx in sorted(common_idx):
1544+
print(f" {idx:>8} {batch_actual_cost.loc[idx]:>18,.0f} {batch_old_fees.loc[idx]:>18,.0f} {old_recovery_rate.loc[idx]:>9.4f}x {batch_new_fees.loc[idx]:>18,.0f} {new_recovery_rate.loc[idx]:>9.4f}x")
1545+
1546+
# Aggregate totals
1547+
total_actual = batch_actual_cost.sum()
1548+
total_old = batch_old_fees.sum()
1549+
total_new = batch_new_fees.sum()
1550+
1551+
print(f"\n Aggregate Totals:")
1552+
print(f" Actual L1 cost: {total_actual:>25,.0f} wei ({total_actual/1e18:.6f} ETH)")
1553+
print(f" Old fee total: {total_old:>25,.0f} wei ({total_old/1e18:.6f} ETH) ({total_old/total_actual:.4f}x)")
1554+
print(f" New fee total: {total_new:>25,.0f} wei ({total_new/1e18:.6f} ETH) ({total_new/total_actual:.4f}x)")
1555+
1556+
# --- Analysis 4: Penalty Proportion ---
1557+
print("\n" + "-" * 60)
1558+
print("Analysis 4: Penalty Proportion")
1559+
print("-" * 60)
1560+
1561+
df['old_penalty_pct'] = df['old_penalty_term'] / df['old_effective_size'] * 100
1562+
df['new_penalty_pct'] = df['new_penalty_term'] / df['new_effective_size'] * 100
1563+
1564+
print(f"\n Overall Penalty Proportion (penalty_term / effective_size × 100):")
1565+
print(f" {'Metric':<15} {'Old Params':>15} {'New Params':>15}")
1566+
print(f" {'-'*15} {'-'*15} {'-'*15}")
1567+
print(f" {'Mean':<15} {df['old_penalty_pct'].mean():>14.2f}% {df['new_penalty_pct'].mean():>14.2f}%")
1568+
print(f" {'Median':<15} {df['old_penalty_pct'].median():>14.2f}% {df['new_penalty_pct'].median():>14.2f}%")
1569+
print(f" {'P95':<15} {df['old_penalty_pct'].quantile(0.95):>14.2f}% {df['new_penalty_pct'].quantile(0.95):>14.2f}%")
1570+
print(f" {'P99':<15} {df['old_penalty_pct'].quantile(0.99):>14.2f}% {df['new_penalty_pct'].quantile(0.99):>14.2f}%")
1571+
1572+
print(f"\n Per Size Group:")
1573+
for group_name in group_order:
1574+
g = df[df['size_group'] == group_name]
1575+
if len(g) == 0:
1576+
continue
1577+
1578+
print(f"\n {group_name} (n={len(g):,}):")
1579+
print(f" {'Metric':<15} {'Old Params':>15} {'New Params':>15}")
1580+
print(f" {'-'*15} {'-'*15} {'-'*15}")
1581+
print(f" {'Mean':<15} {g['old_penalty_pct'].mean():>14.2f}% {g['new_penalty_pct'].mean():>14.2f}%")
1582+
print(f" {'Median':<15} {g['old_penalty_pct'].median():>14.2f}% {g['new_penalty_pct'].median():>14.2f}%")
1583+
print(f" {'P95':<15} {g['old_penalty_pct'].quantile(0.95):>14.2f}% {g['new_penalty_pct'].quantile(0.95):>14.2f}%")
1584+
print(f" {'P99':<15} {g['old_penalty_pct'].quantile(0.99):>14.2f}% {g['new_penalty_pct'].quantile(0.99):>14.2f}%")
1585+
1586+
print("\n" + "=" * 60)
1587+
1588+
13771589
# ============================================================================
13781590
# MAIN
13791591
# ============================================================================
@@ -1455,6 +1667,9 @@ def main():
14551667
# Step 6: Analyze EtherFi penalties
14561668
etherfi_results = analyze_etherfi_penalties(tx_df, penalty_multiplier)
14571669

1670+
# Step 7: Compare with current on-chain parameters
1671+
compare_parameters(current_params, commit_scalar, blob_scalar, penalty_multiplier, tx_df, batch_df)
1672+
14581673
# Final summary
14591674
print("\n" + "=" * 60)
14601675
print("FINAL RESULTS")

0 commit comments

Comments
 (0)