diff --git a/config.yaml b/config.yaml index 2e63ea8d..a3407a85 100644 --- a/config.yaml +++ b/config.yaml @@ -4,7 +4,7 @@ data: notebooks: xatu-public-contributors: enabled: true - schedule_hours: 3 + schedule_hours: 1 description: "Analyzes public Xatu contributor data and client versions" networks: - mainnet @@ -27,15 +27,34 @@ notebooks: step: "5m" label: "Last 6h" range: "-6h" - # - file: "next_week" - # step: "1d" - # label: "+7d" - # range: "+7d" - # - file: "2024_q1" - # step: "1d" - # label: "Q1 2024" - # range: "2024-01-01/2024-03-31" - # - file: "last_2_weeks" - # step: "6h" - # label: "2w" - # range: "-2w" \ No newline at end of file + # mev-relays: + # enabled: false + # schedule_hours: 1 + # description: "Analyzes MEV relays" + # networks: + # - mainnet + beacon-chain-timings: + enabled: true + schedule_hours: 1 + description: "Analyzes beacon chain timings" + networks: + - mainnet + - sepolia + - holesky + time_windows: + - file: "last_30_days" + step: "6h" + label: "Last 30d" + range: "-30d" + - file: "last_90_days" + step: "1d" + label: "Last 90d" + range: "-90d" + # - file: "last_1_day" + # step: "5m" + # label: "Last 1d" + # range: "-1d" + # - file: "last_year" + # step: "1d" + # label: "Last 1y" + # range: "-365d" \ No newline at end of file diff --git a/data/beacon-chain-timings/block_timings/holesky/last_30_days.json b/data/beacon-chain-timings/block_timings/holesky/last_30_days.json new file mode 100644 index 00000000..5dfb4d24 --- /dev/null +++ b/data/beacon-chain-timings/block_timings/holesky/last_30_days.json @@ -0,0 +1 @@ +{"updated_at": 1736496265, "timestamps": [1733860800, 1733882400, 1733904000, 1733925600, 1733947200, 1733968800, 1733990400, 1734012000, 1734033600, 1734055200, 1734076800, 1734098400, 1734120000, 1734141600, 1734163200, 1734184800, 1734206400, 1734228000, 1734249600, 1734271200, 1734292800, 1734314400, 1734336000, 1734357600, 1734379200, 1734400800, 1734422400, 1734444000, 1734465600, 1734487200, 1734508800, 1734530400, 1734552000, 1734573600, 1734595200, 1734616800, 1734638400, 1734660000, 1734681600, 1734703200, 1734724800, 1734746400, 1734768000, 1734789600, 1734811200, 1734832800, 1734854400, 1734876000, 1734897600, 1734919200, 1734940800, 1734962400, 1734984000, 1735005600, 1735027200, 1735048800, 1735070400, 1735092000, 1735113600, 1735135200, 1735156800, 1735178400, 1735200000, 1735221600, 1735243200, 1735264800, 1735286400, 1735308000, 1735329600, 1735351200, 1735372800, 1735394400, 1735416000, 1735437600, 1735459200, 1735480800, 1735502400, 1735524000, 1735545600, 1735567200, 1735588800, 1735610400, 1735632000, 1735653600, 1735675200, 1735696800, 1735718400, 1735740000, 1735761600, 1735783200, 1735804800, 1735826400, 1735848000, 1735869600, 1735891200, 1735912800, 1735934400, 1735956000, 1735977600, 1735999200, 1736020800, 1736042400, 1736064000, 1736085600, 1736107200, 1736128800, 1736150400, 1736172000, 1736193600, 1736215200, 1736236800, 1736258400, 1736280000, 1736301600, 1736323200, 1736344800, 1736366400, 1736388000, 1736409600, 1736431200, 1736452800], "mins": [643, 659, 606, 613, 515, 665, 682, 493, 559, 490, 598, 621, 569, 573, 569, 540, 580, 619, 625, 580, 528, 551, 573, 555, 631, 629, 609, 627, 654, 567, 598, 541, 591, 598, 467, 513, 571, 655, 565, 646, 631, 574, 617, 646, 636, 535, 567, 531, 627, 458, 635, 577, 574, 607, 655, 572, 581, 620, 579, 563, 574, 613, 610, 584, 563, 646, 606, 556, 596, 595, 565, 497, 707, 661, 548, 563, 549, 606, 579, 635, 603, 576, 544, 606, 667, 699, 590, 613, 548, 662, 603, 562, 602, 547, 571, 642, 562, 582, 576, 536, 646, 614, 639, 583, 628, 640, 744, 691, 626, 448, 469, 466, 461, 456, 427, 508, 435, 478, 385, 422, 468], "maxs": [5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5998, 5999, 5999, 5999, 5999, 5998, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5998, 5999, 5999, 5999, 5999, 5998, 5999, 5999, 5999, 5999, 5998, 5999, 5999, 5999, 5999, 5998, 5999, 5999, 5999, 5998, 5999, 5999, 5999, 5998, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5998, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5998, 5999, 5998, 5999, 5998, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5998, 5999, 5998, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5998, 5998], "avgs": [2846.358, 2879.334, 2895.473, 2886.213, 2922.478, 2928.624, 2936.806, 2898.432, 2920.124, 2944.655, 2932.698, 2925.555, 2957.1, 2938.549, 2915.175, 2909.733, 2942.961, 2905.812, 2883.948, 2944.094, 3009.957, 3014.057, 2998.64, 2991.308, 2996.971, 2918.771, 2916.701, 2916.339, 2937.557, 2966.487, 2951.835, 2948.247, 2955.824, 3005.729, 2981.845, 2969.66, 3006.529, 2974.055, 2991.976, 3007.792, 2975.825, 3005.524, 2999.086, 2991.741, 2962.101, 2978.193, 2998.092, 2997.366, 3003.744, 3015.719, 2967.106, 2980.847, 2993.181, 2931.51, 2973.798, 2966.547, 3003.675, 2995.381, 3001.65, 2995.937, 3032.019, 3003.206, 3011.253, 3025.018, 2999.977, 2989.3, 3026.468, 3024.144, 3014.174, 3007.673, 2998.595, 2967.84, 2985.006, 2976.874, 2950.744, 3000.655, 3013.129, 2992.217, 3041.96, 3011.031, 2927.234, 2903.833, 2910.795, 2912.061, 2965.656, 2941.021, 2918.565, 2957.214, 2929.64, 2963.808, 2939.067, 2946.42, 2924.55, 2909.555, 2950.504, 2955.472, 2953.984, 2934.61, 2936.086, 2959.118, 2900.388, 2937.339, 2894.241, 2927.115, 2924.773, 2961.272, 2974.325, 2992.223, 2957.944, 2827.972, 2915.588, 2887.504, 2878.017, 2897.041, 2882.146, 2887.454, 2898.065, 2933.341, 2900.274, 2901.187, 2940.722], "p05s": [1041.55, 1067.0, 1063.55, 1040.0, 1053.0, 1063.0, 1057.0, 1029.55, 1042.55, 1074.55, 1070.0, 1064.0, 1095.55, 1073.0, 1059.0, 1049.0, 1069.0, 1063.55, 1069.0, 1082.0, 1110.55, 1091.0, 1107.55, 1070.0, 1076.0, 1081.55, 1076.0, 1070.55, 1076.0, 1078.0, 1067.0, 1057.0, 1086.0, 1113.0, 1137.0, 1072.0, 1107.0, 1097.55, 1098.0, 1095.0, 1055.0, 1090.0, 1071.0, 1066.55, 1080.0, 1091.0, 1086.55, 1087.55, 1076.0, 1104.0, 1044.0, 1064.55, 1080.0, 1044.55, 1057.55, 1072.0, 1083.0, 1083.0, 1076.55, 1081.55, 1092.55, 1089.0, 1094.0, 1092.55, 1069.0, 1074.55, 1071.0, 1083.55, 1114.0, 1070.0, 1056.0, 1061.0, 1081.0, 1085.0, 1055.55, 1129.0, 1076.55, 1109.1, 1111.55, 1135.0, 1086.0, 1069.55, 1085.1, 1073.0, 1146.55, 1108.55, 1062.55, 1104.55, 1090.0, 1133.0, 1123.0, 1128.0, 1099.0, 1106.0, 1114.55, 1103.0, 1105.0, 1119.55, 1093.0, 1120.0, 1097.0, 1096.0, 1066.0, 1083.0, 1096.55, 1137.0, 1108.0, 1113.0, 1105.55, 1063.0, 1058.55, 1051.55, 1057.55, 1058.0, 1053.0, 1041.55, 1092.0, 1080.0, 1032.0, 1020.0, 1083.55], "p50s": [2545.0, 2531.5, 2609.5, 2553.0, 2613.0, 2711.0, 2675.0, 2622.0, 2761.0, 2667.0, 2629.5, 2621.0, 2653.5, 2705.5, 2654.5, 2607.0, 2640.0, 2612.0, 2599.5, 2681.5, 2787.5, 2799.5, 2818.5, 2776.0, 2732.0, 2662.0, 2694.0, 2626.5, 2691.0, 2764.0, 2809.0, 2679.0, 2782.5, 2822.0, 2699.5, 2719.0, 2806.0, 2748.5, 2807.0, 2830.0, 2826.0, 2854.0, 2819.0, 2790.0, 2785.0, 2800.0, 2809.0, 2784.5, 2779.5, 2797.0, 2755.5, 2744.5, 2738.5, 2694.0, 2760.0, 2803.0, 2779.5, 2833.0, 2837.5, 2833.0, 2853.0, 2813.0, 2889.0, 2879.0, 2884.5, 2867.5, 2855.0, 2809.0, 2820.0, 2846.5, 2836.5, 2787.0, 2783.5, 2818.5, 2720.5, 2809.0, 2832.5, 2798.0, 2867.0, 2836.0, 2735.0, 2613.0, 2674.0, 2713.0, 2785.5, 2750.0, 2741.0, 2788.0, 2746.5, 2771.0, 2762.5, 2764.0, 2772.0, 2695.0, 2742.5, 2738.0, 2802.5, 2773.0, 2772.5, 2740.0, 2585.0, 2740.0, 2717.0, 2701.0, 2694.5, 2773.5, 2837.0, 2908.5, 2827.5, 2570.0, 2792.5, 2748.0, 2653.0, 2788.5, 2756.5, 2705.0, 2812.5, 2840.0, 2790.0, 2833.0, 2826.5], "p95s": [5405.0, 5406.45, 5395.0, 5395.0, 5456.45, 5422.45, 5437.45, 5459.45, 5478.0, 5453.0, 5425.45, 5466.0, 5471.45, 5513.0, 5397.45, 5497.35, 5484.25, 5441.0, 5419.0, 5483.0, 5515.45, 5494.0, 5464.0, 5516.0, 5509.45, 5456.8, 5464.0, 5475.9, 5533.45, 5559.8, 5447.0, 5482.45, 5531.45, 5518.0, 5445.45, 5537.45, 5499.9, 5496.45, 5497.45, 5456.45, 5507.0, 5507.0, 5480.0, 5501.0, 5565.9, 5490.45, 5509.0, 5510.0, 5526.9, 5544.0, 5478.45, 5492.45, 5495.8, 5428.9, 5466.0, 5491.9, 5477.0, 5506.45, 5494.0, 5504.9, 5522.0, 5492.0, 5481.45, 5491.45, 5521.45, 5460.9, 5515.0, 5483.35, 5476.0, 5520.0, 5508.45, 5461.9, 5462.9, 5490.45, 5480.0, 5507.9, 5508.45, 5526.45, 5540.45, 5556.9, 5523.45, 5447.35, 5431.0, 5462.0, 5448.45, 5435.45, 5470.9, 5436.45, 5380.35, 5349.45, 5327.0, 5389.0, 5369.0, 5365.0, 5436.0, 5432.45, 5451.35, 5408.05, 5440.0, 5351.0, 5293.0, 5391.0, 5364.15, 5419.0, 5439.9, 5469.45, 5442.0, 5442.0, 5445.45, 5236.45, 5345.0, 5365.0, 5285.45, 5273.35, 5291.0, 5317.8, 5300.0, 5311.0, 5352.35, 5327.0, 5316.25], "blocks": [17260, 26047, 25631, 26107, 26002, 25876, 25241, 25702, 26216, 26188, 26279, 25802, 26051, 26523, 26645, 26662, 27174, 28271, 28973, 28124, 26880, 26236, 26615, 26397, 25876, 26917, 27320, 27412, 26491, 26038, 26129, 26801, 27397, 26733, 27018, 27194, 26937, 27062, 27062, 27189, 27134, 26984, 26780, 26980, 26975, 26810, 26592, 27051, 27054, 26606, 26997, 26500, 26522, 26963, 27206, 26906, 26738, 26917, 26987, 26684, 26349, 27108, 26772, 26919, 27265, 26913, 26832, 26687, 26937, 26767, 26402, 26878, 27173, 26645, 26844, 26209, 26473, 26354, 26267, 25824, 26855, 26406, 26933, 26768, 26126, 26417, 25915, 25910, 25888, 26028, 26214, 26320, 25826, 26489, 26305, 26113, 26222, 26124, 26669, 26397, 26106, 26279, 26435, 26500, 26529, 25635, 26263, 26211, 26064, 24588, 25921, 25974, 26064, 25842, 26009, 25433, 26104, 24782, 25096, 24824, 8433]} \ No newline at end of file diff --git a/data/beacon-chain-timings/block_timings/holesky/last_90_days.json b/data/beacon-chain-timings/block_timings/holesky/last_90_days.json new file mode 100644 index 00000000..80ba9ca0 --- /dev/null +++ b/data/beacon-chain-timings/block_timings/holesky/last_90_days.json @@ -0,0 +1 @@ +{"updated_at": 1736496266, "timestamps": [1728655200, 1728741600, 1728828000, 1728914400, 1729000800, 1729087200, 1729173600, 1729260000, 1729346400, 1729432800, 1729519200, 1729605600, 1729692000, 1729778400, 1729864800, 1729951200, 1730037600, 1730124000, 1730210400, 1730296800, 1730383200, 1730469600, 1730556000, 1730642400, 1730728800, 1730815200, 1730901600, 1730988000, 1731074400, 1731160800, 1731247200, 1731333600, 1731420000, 1731506400, 1731592800, 1731679200, 1731765600, 1731852000, 1731938400, 1732024800, 1732111200, 1732197600, 1732284000, 1732370400, 1732456800, 1732543200, 1732629600, 1732716000, 1732802400, 1732888800, 1732975200, 1733061600, 1733148000, 1733234400, 1733320800, 1733407200, 1733493600, 1733580000, 1733666400, 1733752800, 1733839200, 1733925600, 1734012000, 1734098400, 1734184800, 1734271200, 1734357600, 1734444000, 1734530400, 1734616800, 1734703200, 1734789600, 1734876000, 1734962400, 1735048800, 1735135200, 1735221600, 1735308000, 1735394400, 1735480800, 1735567200, 1735653600, 1735740000, 1735826400, 1735912800, 1735999200, 1736085600, 1736172000, 1736258400, 1736344800, 1736431200], "mins": [518, 520, 541, 535, 543, 390, 581, 537, 503, 501, 526, 604, 484, 556, 493, 471, 541, 476, 533, 533, 595, 544, 548, 534, 430, 490, 537, 517, 499, 492, 546, 487, 547, 534, 518, 505, 540, 449, 564, 518, 524, 523, 520, 516, 458, 177, 572, 423, 527, 512, 484, 572, 591, 591, 501, 467, 554, 46, 459, 505, 544, 515, 490, 569, 540, 528, 555, 567, 467, 513, 574, 535, 458, 574, 572, 563, 563, 556, 497, 549, 544, 590, 548, 547, 562, 536, 583, 448, 427, 385, 422], "maxs": [5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5998], "avgs": [3046.802, 3064.796, 3083.353, 3126.329, 3083.416, 3102.33, 3143.225, 3086.131, 3054.003, 3086.12, 3097.524, 3114.253, 3088.212, 3139.467, 3121.988, 3146.649, 3138.586, 3087.244, 3124.526, 3102.057, 3179.309, 3295.03, 3199.592, 3103.737, 3104.474, 3102.891, 3087.016, 3114.323, 3115.265, 3122.08, 3104.316, 3065.816, 3073.721, 3097.671, 3087.195, 3072.706, 3092.486, 3177.959, 3182.957, 3186.442, 3130.643, 3172.206, 3175.599, 3144.471, 3086.02, 3071.904, 3025.167, 3313.388, 3316.705, 3327.556, 3277.07, 3107.391, 2955.419, 2975.473, 3006.593, 2915.271, 2942.978, 2906.013, 2902.394, 2906.353, 2880.17, 2918.351, 2924.103, 2934.028, 2910.138, 2990.987, 2955.215, 2942.692, 2972.814, 2985.512, 2997.044, 2982.483, 2995.917, 2969.699, 2991.803, 3010.508, 3010.146, 3011.185, 2970.148, 3011.982, 2937.641, 2934.24, 2947.43, 2932.756, 2944.999, 2922.807, 2946.684, 2924.912, 2886.155, 2904.571, 2911.212], "p05s": [1250.55, 1257.55, 1263.0, 1292.55, 1255.0, 1202.0, 1181.0, 1191.55, 1156.55, 1181.0, 1160.0, 1126.55, 1160.55, 1150.0, 1181.0, 1181.1, 1197.55, 1169.0, 1205.0, 1167.0, 1202.55, 1296.55, 1199.55, 1150.55, 1158.0, 1173.0, 1157.0, 1183.0, 1142.55, 1151.55, 1129.0, 1146.0, 1141.55, 1157.0, 1154.0, 1158.1, 1147.0, 1204.0, 1149.55, 1144.0, 1159.55, 1134.55, 1154.0, 1118.55, 1107.55, 1097.0, 1123.0, 1146.55, 1110.55, 1115.0, 1071.1, 1094.0, 1103.55, 1074.0, 1076.0, 1069.55, 1055.0, 1051.0, 1054.0, 1067.0, 1056.0, 1054.0, 1044.0, 1064.0, 1058.55, 1108.0, 1068.55, 1053.0, 1090.55, 1082.0, 1078.0, 1077.55, 1075.0, 1076.0, 1085.0, 1090.0, 1085.55, 1090.0, 1072.0, 1113.0, 1091.0, 1096.0, 1109.0, 1115.0, 1104.0, 1088.0, 1104.55, 1089.0, 1053.0, 1049.0, 1030.0], "p50s": [2796.5, 2757.5, 2827.5, 2904.5, 2889.0, 2836.5, 3017.0, 2967.5, 2860.5, 2953.0, 2927.5, 2951.5, 2965.5, 3116.0, 3072.0, 3093.0, 3037.0, 2958.5, 2927.5, 2908.0, 3022.5, 3178.0, 3092.5, 2977.5, 3015.5, 3063.0, 3032.0, 3023.0, 2986.0, 3025.0, 3022.0, 3009.0, 3004.5, 2986.5, 2990.5, 2972.0, 3058.5, 3103.0, 3146.5, 3073.5, 3068.0, 3086.5, 3103.5, 3088.0, 2920.0, 2921.5, 2883.0, 3469.0, 3494.5, 3480.0, 3435.5, 3109.5, 2806.0, 2748.5, 2958.0, 2723.0, 2799.5, 2762.5, 2665.0, 2705.0, 2531.5, 2584.0, 2648.0, 2654.5, 2591.5, 2711.0, 2703.0, 2723.0, 2762.5, 2750.0, 2817.0, 2836.0, 2746.0, 2811.0, 2804.5, 2800.5, 2880.5, 2792.0, 2795.0, 2831.0, 2747.5, 2725.5, 2750.5, 2758.5, 2740.0, 2739.5, 2787.5, 2721.5, 2666.0, 2743.5, 2805.5], "p95s": [5488.45, 5466.45, 5541.45, 5546.9, 5514.45, 5559.45, 5582.45, 5570.45, 5494.45, 5538.45, 5519.45, 5577.45, 5519.45, 5560.0, 5529.9, 5504.0, 5504.45, 5461.0, 5454.0, 5452.0, 5473.9, 5528.0, 5478.45, 5522.45, 5536.9, 5511.45, 5497.45, 5552.0, 5554.0, 5575.45, 5521.9, 5472.0, 5523.9, 5463.0, 5483.45, 5473.45, 5483.45, 5493.45, 5581.35, 5582.0, 5533.0, 5605.45, 5588.0, 5570.0, 5558.0, 5463.9, 5435.45, 5637.0, 5588.45, 5582.9, 5566.9, 5485.0, 5428.45, 5502.45, 5536.45, 5502.45, 5461.35, 5481.45, 5504.0, 5456.0, 5353.45, 5425.0, 5425.45, 5441.45, 5409.0, 5444.45, 5453.45, 5502.8, 5518.45, 5498.0, 5519.0, 5489.45, 5497.9, 5498.9, 5485.45, 5519.0, 5492.8, 5471.35, 5461.8, 5547.45, 5475.8, 5446.0, 5365.0, 5379.9, 5442.45, 5432.0, 5434.9, 5346.45, 5267.0, 5303.9, 5303.35], "blocks": [69084, 103911, 108018, 109171, 110962, 106951, 99322, 100678, 100240, 97846, 97851, 95855, 96372, 91312, 98695, 99614, 97079, 98538, 100800, 100786, 95074, 91768, 91482, 90135, 92358, 91538, 90631, 91328, 92083, 91647, 90417, 89045, 92366, 95251, 94456, 92064, 86132, 83043, 81820, 82657, 83490, 83229, 84156, 84677, 87694, 87100, 90365, 73000, 74281, 70036, 69976, 84402, 97355, 99360, 97930, 103372, 92225, 93861, 100995, 105418, 104515, 103226, 104385, 105021, 111080, 107855, 106510, 106070, 107949, 108255, 108087, 107357, 107708, 107191, 107548, 106913, 107929, 106793, 107540, 105303, 106018, 105226, 104040, 104940, 105128, 105217, 104927, 102784, 103889, 101415, 33257]} \ No newline at end of file diff --git a/data/beacon-chain-timings/block_timings/mainnet/last_30_days.json b/data/beacon-chain-timings/block_timings/mainnet/last_30_days.json new file mode 100644 index 00000000..ab5cd94a --- /dev/null +++ b/data/beacon-chain-timings/block_timings/mainnet/last_30_days.json @@ -0,0 +1 @@ +{"updated_at": 1736496265, "timestamps": [1733860800, 1733882400, 1733904000, 1733925600, 1733947200, 1733968800, 1733990400, 1734012000, 1734033600, 1734055200, 1734076800, 1734098400, 1734120000, 1734141600, 1734163200, 1734184800, 1734206400, 1734228000, 1734249600, 1734271200, 1734292800, 1734314400, 1734336000, 1734357600, 1734379200, 1734400800, 1734422400, 1734444000, 1734465600, 1734487200, 1734508800, 1734530400, 1734552000, 1734573600, 1734595200, 1734616800, 1734638400, 1734660000, 1734681600, 1734703200, 1734724800, 1734746400, 1734768000, 1734789600, 1734811200, 1734832800, 1734854400, 1734876000, 1734897600, 1734919200, 1734940800, 1734962400, 1734984000, 1735005600, 1735027200, 1735048800, 1735070400, 1735092000, 1735113600, 1735135200, 1735156800, 1735178400, 1735200000, 1735221600, 1735243200, 1735264800, 1735286400, 1735308000, 1735329600, 1735351200, 1735372800, 1735394400, 1735416000, 1735437600, 1735459200, 1735480800, 1735502400, 1735524000, 1735545600, 1735567200, 1735588800, 1735610400, 1735632000, 1735653600, 1735675200, 1735696800, 1735718400, 1735740000, 1735761600, 1735783200, 1735804800, 1735826400, 1735848000, 1735869600, 1735891200, 1735912800, 1735934400, 1735956000, 1735977600, 1735999200, 1736020800, 1736042400, 1736064000, 1736085600, 1736107200, 1736128800, 1736150400, 1736172000, 1736193600, 1736215200, 1736236800, 1736258400, 1736280000, 1736301600, 1736323200, 1736344800, 1736366400, 1736388000, 1736409600, 1736431200, 1736452800], "mins": [387, 441, 327, 489, 460, 607, 608, 443, 454, 440, 423, 504, 516, 428, 421, 437, 294, 517, 399, 152, 497, 422, 507, 457, 460, 392, 441, 553, 460, 485, 478, 451, 434, 386, 426, 403, 484, 484, 0, 579, 452, 440, 446, 402, 498, 441, 437, 383, 108, 438, 501, 458, 364, 451, 435, 489, 518, 477, 354, 427, 387, 483, 419, 443, 324, 400, 346, 447, 444, 469, 292, 374, 473, 264, 461, 323, 417, 423, 454, 244, 201, 448, 426, 319, 436, 365, 505, 340, 148, 378, 238, 296, 463, 350, 488, 304, 379, 503, 446, 423, 484, 443, 160, 466, 433, 386, 419, 391, 396, 413, 397, 397, 440, 296, 359, 518, 340, 431, 437, 399, 565], "maxs": [5999, 5986, 5999, 5998, 5996, 5997, 5990, 5999, 5998, 5991, 5995, 5999, 5997, 5996, 5993, 5998, 5992, 5995, 5995, 5994, 5993, 5999, 5998, 5997, 5996, 5998, 5999, 5999, 5998, 5999, 5997, 5999, 5997, 5996, 5998, 5995, 5996, 5999, 5999, 5999, 5996, 5995, 5999, 5994, 5999, 5999, 5998, 5996, 5998, 5997, 5996, 5996, 5999, 5999, 5997, 5999, 5999, 5995, 5991, 5999, 5996, 5993, 5999, 5998, 5997, 5998, 5999, 5999, 5991, 5992, 5998, 5998, 5998, 5998, 5995, 5997, 5999, 5991, 5999, 5995, 5999, 5998, 5995, 5992, 5999, 5998, 5999, 5991, 5998, 5997, 5999, 5991, 5999, 5995, 5999, 5998, 5998, 5998, 5998, 5995, 5999, 5999, 5999, 5999, 5994, 5999, 5999, 5999, 5995, 5998, 5999, 5998, 5999, 5999, 5998, 5990, 5999, 5995, 5998, 5999, 5995], "avgs": [2532.582, 2563.943, 2514.783, 2567.409, 2560.628, 2587.628, 2565.917, 2563.45, 2577.895, 2597.293, 2571.744, 2581.862, 2582.127, 2557.756, 2559.54, 2597.892, 2577.542, 2559.518, 2562.895, 2555.514, 2588.784, 2579.809, 2582.865, 2605.521, 2609.431, 2610.546, 2591.435, 2589.619, 2580.894, 2586.56, 2619.99, 2591.195, 2609.42, 2642.15, 2587.702, 2645.71, 2609.368, 2620.574, 2590.432, 2715.294, 2615.39, 2610.126, 2585.121, 2634.283, 2580.129, 2619.292, 2597.262, 2614.593, 2623.369, 2633.811, 2576.901, 2646.025, 2667.292, 2631.712, 2622.096, 2621.827, 2600.227, 2572.856, 2571.835, 2640.796, 2578.168, 2616.995, 2591.016, 2615.26, 2618.584, 2602.034, 2590.401, 2577.222, 2554.198, 2552.375, 2550.361, 2562.756, 2571.255, 2604.433, 2521.159, 2540.131, 2558.245, 2570.41, 2610.732, 2597.805, 2528.593, 2606.535, 2556.308, 2558.763, 2503.442, 2494.705, 2468.863, 2418.265, 2555.278, 2600.313, 2542.416, 2562.166, 2581.866, 2570.145, 2561.376, 2577.657, 2542.198, 2524.918, 2528.784, 2556.918, 2540.002, 2512.157, 2522.255, 2560.574, 2542.122, 2573.239, 2506.36, 2533.887, 2558.316, 2612.286, 2600.015, 2549.325, 2524.205, 2523.231, 2572.83, 2566.316, 2567.227, 2538.645, 2545.692, 2571.086, 2560.469], "p05s": [1681.0, 1701.0, 1678.55, 1693.0, 1688.0, 1747.0, 1748.55, 1727.55, 1712.55, 1745.0, 1737.0, 1721.0, 1697.0, 1729.55, 1688.55, 1717.55, 1701.0, 1692.0, 1719.0, 1714.0, 1711.55, 1740.0, 1706.55, 1728.0, 1675.55, 1669.0, 1691.0, 1699.0, 1687.0, 1716.0, 1704.55, 1673.0, 1694.0, 1730.55, 1708.0, 1725.1, 1701.0, 1695.0, 1691.55, 1789.0, 1688.55, 1724.55, 1685.0, 1703.55, 1721.0, 1708.1, 1709.0, 1707.0, 1724.55, 1708.0, 1648.55, 1724.55, 1705.0, 1700.55, 1713.0, 1680.1, 1706.55, 1668.55, 1709.0, 1710.0, 1672.55, 1716.0, 1659.55, 1673.55, 1716.55, 1689.55, 1675.55, 1681.0, 1649.55, 1690.55, 1670.0, 1640.0, 1656.0, 1648.55, 1639.55, 1652.0, 1649.55, 1685.55, 1717.55, 1717.0, 1710.0, 1698.0, 1681.0, 1706.0, 1664.0, 1649.0, 1616.0, 1617.1, 1690.0, 1714.0, 1659.0, 1658.0, 1696.0, 1689.55, 1679.55, 1689.0, 1643.55, 1691.55, 1655.0, 1670.0, 1646.0, 1655.55, 1645.55, 1665.0, 1677.0, 1696.0, 1681.55, 1683.55, 1670.55, 1676.55, 1689.0, 1665.55, 1676.55, 1674.0, 1656.55, 1679.0, 1681.55, 1661.0, 1669.0, 1685.55, 1679.0], "p50s": [2354.0, 2360.0, 2336.0, 2382.0, 2376.0, 2393.5, 2363.0, 2384.0, 2399.0, 2426.0, 2377.0, 2406.0, 2398.0, 2379.5, 2375.0, 2414.0, 2374.0, 2386.0, 2367.0, 2371.0, 2390.0, 2401.0, 2388.0, 2423.0, 2411.0, 2397.5, 2411.0, 2371.0, 2378.0, 2379.0, 2411.0, 2389.0, 2412.5, 2452.0, 2380.0, 2452.0, 2404.0, 2405.0, 2397.5, 2539.0, 2418.0, 2434.0, 2388.0, 2453.5, 2372.0, 2428.0, 2410.0, 2436.5, 2435.0, 2454.0, 2399.5, 2447.0, 2487.0, 2444.0, 2398.0, 2444.0, 2394.0, 2396.0, 2376.0, 2425.0, 2411.0, 2403.5, 2405.0, 2406.0, 2426.0, 2408.0, 2409.0, 2378.0, 2357.0, 2355.0, 2342.0, 2373.0, 2355.0, 2426.0, 2344.0, 2375.0, 2382.0, 2396.0, 2440.0, 2402.0, 2346.0, 2403.0, 2382.0, 2375.0, 2316.0, 2307.0, 2285.0, 2264.0, 2387.5, 2434.0, 2367.0, 2387.0, 2383.5, 2376.0, 2375.0, 2372.0, 2361.0, 2344.5, 2334.0, 2372.0, 2356.0, 2332.5, 2342.0, 2383.0, 2372.5, 2408.0, 2338.5, 2364.0, 2387.0, 2460.0, 2444.0, 2382.5, 2359.5, 2363.0, 2404.0, 2383.0, 2402.0, 2361.0, 2367.0, 2388.5, 2376.0], "p95s": [3890.45, 3992.45, 3892.0, 4012.0, 3933.45, 3952.45, 3947.0, 3963.0, 3946.45, 4003.0, 4000.0, 3964.0, 3994.9, 3984.45, 3978.0, 3985.0, 4018.45, 3949.45, 3981.0, 4036.45, 4019.0, 3925.0, 4063.9, 4039.0, 4140.9, 4172.45, 4038.9, 4082.8, 4104.45, 4076.25, 4134.35, 4128.9, 4131.0, 4119.45, 4013.9, 4179.8, 4119.0, 4112.0, 4121.45, 4256.45, 4047.25, 4109.9, 4142.45, 4188.35, 3989.45, 4056.45, 4062.45, 3967.45, 4117.45, 4023.45, 4047.9, 4225.45, 4154.45, 4162.9, 4212.45, 4171.8, 4099.45, 4066.9, 4023.25, 4267.9, 4133.45, 4105.9, 4094.9, 4211.5, 4148.45, 4079.35, 4111.9, 4079.35, 4090.45, 4012.9, 4050.45, 4095.9, 4073.0, 4144.15, 3897.45, 3933.35, 3984.45, 3994.9, 3994.0, 4029.0, 3926.45, 4172.45, 4014.9, 3992.9, 3949.9, 3854.45, 3809.9, 3766.45, 4004.45, 4039.0, 3983.45, 4012.9, 4024.35, 4034.45, 4013.6, 4016.0, 4094.0, 3932.45, 3955.35, 4023.9, 4028.45, 3899.35, 3940.0, 3996.45, 3941.0, 3968.45, 3834.0, 3966.35, 4006.0, 3975.35, 4019.45, 3976.35, 3867.8, 3920.9, 3986.25, 4051.0, 4036.45, 3955.7, 3999.9, 4030.35, 4043.45], "blocks": [33320, 51344, 51230, 51193, 51321, 49813, 49709, 49807, 49005, 49192, 49220, 48938, 49476, 49458, 49649, 51069, 50689, 51145, 51242, 50820, 48861, 50626, 50826, 53291, 56094, 56320, 56029, 56335, 56145, 54276, 54452, 54495, 55721, 55946, 57031, 58141, 58349, 58269, 58502, 57173, 57766, 57744, 57671, 58128, 58460, 58517, 58351, 58374, 58386, 58363, 58470, 58276, 59131, 60249, 60259, 60143, 58452, 58502, 58534, 58029, 58247, 58307, 58167, 60108, 59850, 60317, 60124, 60359, 60242, 60489, 60179, 60574, 61682, 61948, 62310, 63012, 63810, 63678, 63832, 63117, 62199, 61481, 62039, 62165, 61847, 62245, 61908, 60584, 60878, 62365, 62254, 62100, 61581, 61485, 62027, 61993, 62002, 62170, 62078, 62856, 63649, 63823, 63624, 63522, 63271, 63501, 64015, 64034, 63721, 62220, 63946, 63764, 64104, 64130, 64022, 63958, 63556, 63777, 63501, 63373, 21898]} \ No newline at end of file diff --git a/data/beacon-chain-timings/block_timings/mainnet/last_90_days.json b/data/beacon-chain-timings/block_timings/mainnet/last_90_days.json new file mode 100644 index 00000000..56e3d8af --- /dev/null +++ b/data/beacon-chain-timings/block_timings/mainnet/last_90_days.json @@ -0,0 +1 @@ +{"updated_at": 1736496266, "timestamps": [1728655200, 1728741600, 1728828000, 1728914400, 1729000800, 1729087200, 1729173600, 1729260000, 1729346400, 1729432800, 1729519200, 1729605600, 1729692000, 1729778400, 1729864800, 1729951200, 1730037600, 1730124000, 1730210400, 1730296800, 1730383200, 1730469600, 1730556000, 1730642400, 1730728800, 1730815200, 1730901600, 1730988000, 1731074400, 1731160800, 1731247200, 1731333600, 1731420000, 1731506400, 1731592800, 1731679200, 1731765600, 1731852000, 1731938400, 1732024800, 1732111200, 1732197600, 1732284000, 1732370400, 1732456800, 1732543200, 1732629600, 1732716000, 1732802400, 1732888800, 1732975200, 1733061600, 1733148000, 1733234400, 1733320800, 1733407200, 1733493600, 1733580000, 1733666400, 1733752800, 1733839200, 1733925600, 1734012000, 1734098400, 1734184800, 1734271200, 1734357600, 1734444000, 1734530400, 1734616800, 1734703200, 1734789600, 1734876000, 1734962400, 1735048800, 1735135200, 1735221600, 1735308000, 1735394400, 1735480800, 1735567200, 1735653600, 1735740000, 1735826400, 1735912800, 1735999200, 1736085600, 1736172000, 1736258400, 1736344800, 1736431200], "mins": [364, 408, 49, 259, 473, 267, 318, 346, 347, 366, 132, 289, 368, 184, 377, 193, 150, 145, 175, 7, 311, 5, 83, 158, 88, 138, 366, 58, 373, 8, 435, 445, 379, 136, 425, 474, 212, 416, 322, 129, 402, 386, 399, 391, 408, 144, 144, 431, 378, 444, 382, 363, 421, 361, 379, 450, 367, 456, 350, 352, 327, 460, 423, 421, 294, 152, 392, 460, 386, 0, 440, 402, 108, 364, 354, 387, 324, 292, 264, 323, 201, 319, 148, 296, 304, 160, 386, 391, 296, 340, 399], "maxs": [5999, 5999, 5999, 5999, 5997, 5999, 5999, 5998, 5999, 5999, 5999, 5998, 5999, 5999, 5999, 5998, 5999, 5997, 5999, 5999, 5999, 5999, 5998, 5998, 5998, 5998, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5997, 5996, 5999, 5999, 5998, 5998, 5999, 5999, 5997, 5999, 5996, 5999, 5997, 5999, 5999, 5996, 5998, 5999, 5999, 5998, 5999, 5999, 5998, 5999, 5998, 5999, 5999, 5999, 5998, 5999, 5999, 5998, 5999, 5999, 5999, 5999, 5999, 5999, 5999, 5998, 5999, 5999, 5999, 5999, 5999, 5998, 5999, 5999, 5999, 5999, 5999, 5998, 5999, 5999, 5999, 5999, 5999, 5999], "avgs": [2394.961, 2395.309, 2410.251, 2451.207, 2454.531, 2459.369, 2448.431, 2456.826, 2434.467, 2467.207, 2480.528, 2464.693, 2472.006, 2479.813, 2473.162, 2451.894, 2509.705, 2539.306, 2530.9, 2473.557, 2479.246, 2465.093, 2480.82, 2473.405, 2438.847, 2458.535, 2485.958, 2470.197, 2461.857, 2473.451, 2540.638, 2538.935, 2506.108, 2498.242, 2525.527, 2554.497, 2570.188, 2492.292, 2487.144, 2493.1, 2536.752, 2528.173, 2539.293, 2517.387, 2515.718, 2489.657, 2527.757, 2516.098, 2425.006, 2438.081, 2475.951, 2494.928, 2509.455, 2561.068, 2552.808, 2640.808, 2561.052, 2568.411, 2558.197, 2621.503, 2546.258, 2570.304, 2577.55, 2570.282, 2574.441, 2576.623, 2604.227, 2594.13, 2607.625, 2616.476, 2631.288, 2607.712, 2612.153, 2641.625, 2591.892, 2606.72, 2606.552, 2558.544, 2564.842, 2569.976, 2572.316, 2506.482, 2529.706, 2568.86, 2543.371, 2532.745, 2545.499, 2575.881, 2542.377, 2554.477, 2568.361], "p05s": [1607.55, 1600.0, 1627.55, 1636.55, 1650.55, 1659.55, 1627.55, 1634.55, 1606.55, 1640.0, 1644.0, 1656.55, 1650.0, 1637.0, 1643.55, 1618.55, 1670.0, 1664.65, 1657.55, 1643.55, 1655.55, 1626.1, 1631.0, 1631.0, 1649.0, 1666.0, 1676.0, 1659.55, 1662.0, 1658.55, 1685.55, 1701.55, 1695.55, 1691.55, 1685.55, 1679.0, 1675.0, 1669.55, 1685.55, 1686.0, 1695.55, 1708.0, 1712.0, 1685.0, 1679.55, 1654.0, 1658.0, 1700.0, 1660.0, 1669.55, 1674.0, 1675.55, 1693.0, 1717.55, 1704.55, 1770.0, 1695.0, 1713.55, 1716.0, 1744.55, 1709.0, 1733.0, 1716.0, 1716.0, 1719.55, 1707.0, 1692.55, 1703.0, 1704.0, 1697.0, 1723.55, 1708.55, 1684.0, 1700.0, 1680.55, 1677.55, 1696.0, 1683.1, 1636.0, 1682.0, 1680.55, 1655.55, 1657.0, 1680.55, 1673.0, 1657.0, 1694.0, 1678.0, 1680.0, 1669.55, 1669.55], "p50s": [2220.0, 2231.0, 2251.0, 2285.5, 2314.0, 2304.5, 2306.0, 2304.0, 2269.5, 2319.0, 2333.0, 2301.5, 2334.0, 2330.0, 2326.0, 2311.5, 2366.0, 2376.5, 2376.0, 2324.0, 2330.0, 2311.0, 2322.0, 2309.5, 2300.0, 2309.0, 2348.0, 2312.0, 2311.0, 2324.0, 2349.0, 2372.0, 2355.5, 2344.0, 2364.0, 2378.0, 2368.5, 2342.0, 2330.0, 2333.0, 2363.5, 2389.0, 2406.0, 2364.0, 2353.5, 2331.5, 2321.0, 2345.0, 2272.0, 2275.0, 2318.0, 2334.0, 2349.0, 2379.0, 2373.0, 2481.0, 2400.0, 2396.5, 2400.0, 2462.0, 2365.0, 2386.0, 2397.0, 2370.5, 2380.0, 2373.0, 2396.5, 2392.0, 2407.5, 2411.5, 2419.5, 2409.0, 2417.5, 2455.0, 2393.0, 2406.0, 2426.0, 2367.0, 2384.5, 2394.0, 2388.0, 2313.5, 2370.0, 2384.0, 2365.0, 2351.0, 2371.0, 2406.0, 2369.0, 2391.0, 2382.0], "p95s": [3747.9, 3719.45, 3796.9, 3795.25, 3810.45, 3864.9, 3784.35, 3884.9, 3788.0, 3819.0, 3833.45, 3820.0, 3793.35, 3839.45, 3823.0, 3794.45, 3793.0, 3874.9, 3884.45, 3785.45, 3789.9, 3818.0, 3842.35, 3849.9, 3749.9, 3745.0, 3837.9, 3827.35, 3810.9, 3898.45, 4049.45, 3929.0, 3858.45, 3837.6, 3883.35, 4052.45, 4150.45, 3909.45, 3889.35, 3832.8, 3911.45, 3876.45, 3911.0, 3940.9, 3913.35, 3905.45, 4083.0, 3938.45, 3719.45, 3771.45, 3850.0, 3857.9, 3862.35, 4006.45, 3952.0, 4050.9, 3989.45, 4001.45, 3934.45, 4073.9, 3967.9, 3981.8, 3983.9, 4031.0, 3960.0, 4069.45, 4087.45, 4096.45, 4076.35, 4125.45, 4142.45, 4055.0, 4044.0, 4241.8, 4105.25, 4141.45, 4100.9, 4077.45, 4047.45, 3990.0, 4026.9, 3884.0, 3923.45, 4091.9, 4031.45, 3960.0, 3968.9, 3981.0, 3938.45, 4070.25, 4037.35], "blocks": [112367, 168657, 168923, 169020, 168258, 167744, 162288, 163098, 162983, 167994, 169835, 163420, 167755, 167896, 173099, 177159, 174986, 175304, 176756, 180741, 170709, 171458, 171372, 171072, 174337, 181862, 178402, 175407, 175858, 178077, 177839, 177832, 183980, 184515, 183050, 183343, 179973, 181477, 175718, 175855, 171050, 166616, 169060, 169637, 167382, 169856, 163593, 148249, 184625, 201534, 202297, 204789, 209376, 211791, 211791, 212208, 211394, 211717, 205425, 204776, 204609, 202036, 197224, 197521, 204145, 201133, 221734, 221208, 223193, 233261, 230354, 233456, 233593, 237915, 235631, 232750, 240399, 241269, 246514, 254332, 248836, 248165, 246081, 247193, 248243, 253952, 254309, 253921, 256020, 254792, 85273]} \ No newline at end of file diff --git a/data/beacon-chain-timings/block_timings/sepolia/last_30_days.json b/data/beacon-chain-timings/block_timings/sepolia/last_30_days.json new file mode 100644 index 00000000..68f86e4f --- /dev/null +++ b/data/beacon-chain-timings/block_timings/sepolia/last_30_days.json @@ -0,0 +1 @@ +{"updated_at": 1736496265, "timestamps": [1733860800, 1733882400, 1733904000, 1733925600, 1733947200, 1733968800, 1733990400, 1734012000, 1734033600, 1734055200, 1734076800, 1734098400, 1734120000, 1734141600, 1734163200, 1734184800, 1734206400, 1734228000, 1734249600, 1734271200, 1734292800, 1734314400, 1734336000, 1734357600, 1734379200, 1734400800, 1734422400, 1734444000, 1734465600, 1734487200, 1734508800, 1734530400, 1734552000, 1734573600, 1734595200, 1734616800, 1734638400, 1734660000, 1734681600, 1734703200, 1734724800, 1734746400, 1734768000, 1734789600, 1734811200, 1734832800, 1734854400, 1734876000, 1734897600, 1734919200, 1734940800, 1734962400, 1734984000, 1735005600, 1735027200, 1735048800, 1735070400, 1735092000, 1735113600, 1735135200, 1735156800, 1735178400, 1735200000, 1735221600, 1735243200, 1735264800, 1735286400, 1735308000, 1735329600, 1735351200, 1735372800, 1735394400, 1735416000, 1735437600, 1735459200, 1735480800, 1735502400, 1735524000, 1735545600, 1735567200, 1735588800, 1735610400, 1735632000, 1735653600, 1735675200, 1735696800, 1735718400, 1735740000, 1735761600, 1735783200, 1735804800, 1735826400, 1735848000, 1735869600, 1735891200, 1735912800, 1735934400, 1735956000, 1735977600, 1735999200, 1736020800, 1736042400, 1736064000, 1736085600, 1736107200, 1736128800, 1736150400, 1736172000, 1736193600, 1736215200, 1736236800, 1736258400, 1736280000, 1736301600, 1736323200, 1736344800, 1736366400, 1736388000, 1736409600, 1736431200, 1736452800], "mins": [143, 180, 161, 137, 149, 145, 122, 148, 148, 155, 135, 146, 147, 147, 153, 118, 125, 151, 119, 142, 81, 146, 150, 138, 129, 123, 121, 111, 143, 137, 137, 136, 151, 164, 158, 138, 144, 140, 129, 147, 141, 141, 146, 155, 139, 137, 155, 175, 123, 200, 171, 164, 135, 150, 116, 147, 129, 136, 154, 143, 163, 151, 170, 150, 156, 146, 126, 123, 143, 127, 129, 120, 123, 160, 113, 128, 157, 138, 124, 122, 146, 146, 152, 143, 137, 136, 127, 143, 160, 171, 144, 149, 135, 148, 133, 138, 142, 150, 143, 154, 104, 169, 144, 95, 158, 154, 151, 131, 133, 97, 142, 157, 103, 70, 87, 86, 86, 78, 73, 91, 83], "maxs": [5941, 5964, 5950, 5964, 5990, 5980, 5990, 5969, 5985, 5990, 5977, 5988, 5999, 5997, 5964, 5999, 5981, 5997, 5974, 5998, 5979, 5955, 5993, 5971, 5947, 5954, 5989, 5982, 5999, 5997, 5998, 5992, 5998, 5999, 5955, 5991, 5999, 5995, 5991, 5965, 5987, 5992, 5993, 5982, 5968, 5986, 5992, 5995, 5993, 5971, 5990, 5958, 5995, 5976, 5999, 5976, 5997, 5977, 5992, 5995, 5986, 5996, 5992, 5998, 5985, 5991, 5993, 5996, 5983, 5998, 5987, 5986, 5998, 5943, 5990, 5977, 5996, 5980, 5999, 5997, 5998, 5995, 5936, 5996, 5996, 5975, 5999, 5995, 5980, 5981, 5999, 5974, 5988, 5998, 5991, 5993, 5984, 5968, 5997, 5994, 5973, 5976, 5989, 5994, 5997, 5989, 5983, 5994, 5989, 5984, 5968, 5953, 5997, 5992, 5998, 5996, 5989, 5991, 5995, 5998, 5970], "avgs": [2128.257, 2158.364, 2137.217, 2156.615, 2194.515, 2159.03, 2107.543, 2138.972, 2147.549, 2152.856, 2098.089, 2061.575, 2014.655, 2014.81, 2037.313, 2036.214, 2011.582, 2012.853, 2002.26, 2004.033, 2047.885, 2069.698, 2022.379, 1996.978, 2040.145, 2037.147, 2041.021, 2062.618, 2138.319, 2224.155, 2203.857, 2210.653, 2199.081, 2197.266, 2173.746, 2087.595, 2109.138, 2112.927, 2084.39, 2043.415, 2054.907, 2128.405, 2109.972, 2022.108, 2057.842, 2084.199, 2111.915, 2080.922, 2111.964, 2120.522, 2105.719, 2094.387, 2084.625, 2075.705, 2054.577, 2066.179, 2090.793, 2128.91, 2145.347, 2095.367, 2118.653, 2138.058, 2112.537, 2047.354, 2084.027, 2065.376, 2079.014, 2041.081, 2086.846, 2088.963, 2111.17, 2131.958, 2108.782, 2180.755, 2023.375, 2039.642, 2084.201, 2144.616, 2101.971, 2095.461, 2070.523, 2086.234, 2026.936, 2097.318, 2054.604, 2031.019, 2008.003, 2061.092, 2052.181, 2138.6, 2128.324, 2106.81, 2124.336, 2114.499, 2093.556, 2082.278, 2106.718, 2115.181, 2081.965, 2117.298, 2115.283, 2109.819, 2071.9, 2081.623, 2160.411, 2098.501, 2106.443, 2072.8, 2109.984, 2072.637, 2141.744, 2144.352, 2157.691, 2083.418, 2108.831, 2136.46, 2128.937, 2148.233, 2140.262, 2119.044, 2098.58], "p05s": [360.0, 373.55, 378.0, 385.0, 383.55, 368.0, 344.0, 349.0, 360.0, 365.0, 364.0, 374.55, 354.55, 348.0, 340.0, 353.55, 326.55, 327.55, 330.0, 321.55, 328.0, 349.0, 334.55, 325.55, 335.55, 333.0, 342.0, 346.0, 355.0, 357.0, 368.0, 362.0, 347.55, 369.0, 358.55, 354.55, 365.55, 351.0, 350.0, 349.0, 346.0, 356.55, 351.0, 346.55, 375.0, 376.0, 396.55, 389.0, 385.0, 392.0, 392.0, 378.0, 372.0, 373.0, 359.55, 377.55, 363.0, 384.55, 401.0, 361.0, 378.0, 382.0, 363.0, 353.0, 370.0, 360.55, 344.0, 349.0, 355.0, 344.0, 334.55, 349.0, 353.0, 372.0, 344.0, 353.55, 364.0, 352.55, 327.55, 334.0, 349.0, 348.0, 313.0, 330.0, 367.0, 357.0, 337.0, 356.0, 353.0, 361.0, 355.0, 378.0, 363.55, 368.0, 353.0, 371.0, 362.0, 370.0, 345.55, 357.55, 348.0, 364.0, 330.0, 354.0, 373.0, 371.0, 360.0, 356.0, 370.0, 359.0, 357.0, 352.55, 365.55, 360.0, 368.0, 365.0, 371.0, 362.0, 366.0, 346.0, 358.0], "p50s": [2449.0, 2471.0, 2476.0, 2469.0, 2499.5, 2477.0, 2439.0, 2460.0, 2451.0, 2461.0, 2429.0, 2381.5, 2371.0, 2373.5, 2381.0, 2361.5, 2365.0, 2347.0, 2365.0, 2351.0, 2371.0, 2391.0, 2379.5, 2358.0, 2375.0, 2372.0, 2369.5, 2384.0, 2419.0, 2459.0, 2474.5, 2482.0, 2447.0, 2454.0, 2429.5, 2394.0, 2395.0, 2400.5, 2390.0, 2361.0, 2381.0, 2414.0, 2405.5, 2353.0, 2365.5, 2380.0, 2415.0, 2405.0, 2448.5, 2416.5, 2438.0, 2386.0, 2382.0, 2382.0, 2369.5, 2390.0, 2379.0, 2406.0, 2430.5, 2387.0, 2403.0, 2440.0, 2405.0, 2364.0, 2401.5, 2385.5, 2372.0, 2354.0, 2385.0, 2374.0, 2384.0, 2405.0, 2409.5, 2458.0, 2373.0, 2368.0, 2400.5, 2428.0, 2394.5, 2380.5, 2390.0, 2390.0, 2349.5, 2403.0, 2366.0, 2370.5, 2354.0, 2352.0, 2380.0, 2450.0, 2451.0, 2418.0, 2436.5, 2419.0, 2387.5, 2386.5, 2404.5, 2417.0, 2397.0, 2434.0, 2423.0, 2413.0, 2387.5, 2393.0, 2451.0, 2410.0, 2398.0, 2403.0, 2420.0, 2392.0, 2433.0, 2470.0, 2445.0, 2387.0, 2423.0, 2438.0, 2432.0, 2444.0, 2430.0, 2431.0, 2415.0], "p95s": [4071.45, 4106.45, 4088.0, 4086.45, 4138.0, 4156.9, 4059.0, 4125.0, 4144.45, 4148.45, 4037.45, 4040.25, 3993.0, 4000.9, 4022.45, 3996.35, 4020.45, 4000.45, 3974.45, 3986.45, 4061.0, 4094.9, 4007.9, 4025.45, 4067.0, 4036.0, 3964.9, 4005.45, 4080.8, 4269.45, 4217.45, 4278.0, 4244.9, 4275.9, 4138.9, 4004.85, 4043.25, 4013.0, 4009.9, 3946.45, 3972.9, 4049.0, 4054.8, 3986.45, 3995.9, 4112.9, 4087.0, 4052.45, 4085.9, 4062.9, 4039.9, 4067.0, 4012.45, 4000.35, 3941.0, 4007.0, 4054.35, 4137.8, 4123.35, 4025.45, 4079.35, 4056.35, 3982.9, 4000.45, 4010.45, 4012.9, 4025.0, 4005.45, 4028.15, 3992.9, 4070.35, 4095.45, 4066.9, 4181.0, 3984.45, 3957.45, 3962.9, 4095.35, 4069.0, 4040.45, 3992.35, 3987.45, 3978.45, 4019.45, 3989.45, 3939.0, 3941.0, 4018.0, 4015.0, 4119.9, 4079.45, 4036.45, 4036.7, 4024.0, 4022.45, 3991.9, 4031.0, 4056.0, 4030.0, 4054.45, 4027.0, 4068.35, 4002.25, 4004.45, 4209.45, 3999.0, 4088.45, 4006.45, 4006.6, 3988.9, 4067.45, 4027.45, 4189.8, 3978.0, 3984.9, 4070.9, 4032.0, 4029.9, 4080.0, 4103.0, 4030.45], "blocks": [15585, 23553, 23620, 23792, 23562, 23322, 23028, 22944, 22877, 23654, 24411, 25278, 25438, 25409, 25290, 25588, 25740, 25501, 25113, 25386, 25341, 25571, 25632, 25498, 25455, 25523, 25566, 25390, 25417, 25237, 25417, 25017, 25383, 24942, 25506, 25408, 25409, 25620, 25352, 25601, 25338, 25192, 25245, 25355, 25535, 25417, 25060, 25483, 25410, 25475, 25338, 25580, 25399, 25702, 25315, 25465, 25280, 25255, 24649, 23401, 25255, 25298, 25285, 25582, 25281, 25604, 25677, 25431, 25230, 25664, 25635, 25294, 25461, 25209, 25375, 25500, 25495, 25405, 25609, 25623, 25277, 25261, 25606, 25006, 25573, 25196, 25359, 25197, 25422, 25249, 25201, 25510, 25445, 25501, 25169, 25281, 25303, 25321, 25377, 25459, 25070, 25413, 25078, 25273, 25241, 25295, 25583, 25402, 25562, 23757, 24373, 25405, 25266, 26550, 26873, 26889, 26906, 26794, 26738, 26614, 9307]} \ No newline at end of file diff --git a/data/beacon-chain-timings/block_timings/sepolia/last_90_days.json b/data/beacon-chain-timings/block_timings/sepolia/last_90_days.json new file mode 100644 index 00000000..a5db52cf --- /dev/null +++ b/data/beacon-chain-timings/block_timings/sepolia/last_90_days.json @@ -0,0 +1 @@ +{"updated_at": 1736496266, "timestamps": [1728655200, 1728741600, 1728828000, 1728914400, 1729000800, 1729087200, 1729173600, 1729260000, 1729346400, 1729432800, 1729519200, 1729605600, 1729692000, 1729778400, 1729864800, 1729951200, 1730037600, 1730124000, 1730210400, 1730296800, 1730383200, 1730469600, 1730556000, 1730642400, 1730728800, 1730815200, 1730901600, 1730988000, 1731074400, 1731160800, 1731247200, 1731333600, 1731420000, 1731506400, 1731592800, 1731679200, 1731765600, 1731852000, 1731938400, 1732024800, 1732111200, 1732197600, 1732284000, 1732370400, 1732456800, 1732543200, 1732629600, 1732716000, 1732802400, 1732888800, 1732975200, 1733061600, 1733148000, 1733234400, 1733320800, 1733407200, 1733493600, 1733580000, 1733666400, 1733752800, 1733839200, 1733925600, 1734012000, 1734098400, 1734184800, 1734271200, 1734357600, 1734444000, 1734530400, 1734616800, 1734703200, 1734789600, 1734876000, 1734962400, 1735048800, 1735135200, 1735221600, 1735308000, 1735394400, 1735480800, 1735567200, 1735653600, 1735740000, 1735826400, 1735912800, 1735999200, 1736085600, 1736172000, 1736258400, 1736344800, 1736431200], "mins": [72, 51, 93, 89, 111, 98, 62, 88, 57, 58, 84, 29, 69, 70, 35, 65, 66, 74, 57, 70, 58, 87, 86, 90, 87, 70, 47, 50, 84, 105, 110, 49, 117, 59, 64, 115, 95, 120, 147, 144, 172, 132, 135, 124, 152, 93, 108, 94, 147, 175, 188, 241, 132, 143, 146, 148, 120, 123, 70, 73, 143, 122, 135, 146, 118, 81, 121, 111, 136, 129, 141, 137, 123, 116, 129, 143, 126, 123, 113, 124, 122, 127, 143, 133, 138, 104, 95, 97, 70, 73, 83], "maxs": [5998, 5999, 5999, 5997, 5996, 5992, 5998, 5997, 5988, 5991, 5997, 5999, 5991, 5997, 5995, 5998, 5999, 5993, 5996, 5996, 5995, 5993, 5995, 5995, 5996, 5985, 5995, 5999, 5990, 5989, 5999, 5995, 5998, 5998, 5998, 5999, 5997, 5994, 5986, 5995, 5997, 5998, 5997, 5995, 5982, 5999, 5998, 5999, 5983, 5999, 5987, 5994, 5994, 5998, 5998, 5999, 5992, 5998, 5988, 5989, 5998, 5990, 5990, 5999, 5999, 5998, 5989, 5999, 5999, 5999, 5993, 5992, 5995, 5999, 5997, 5996, 5998, 5998, 5998, 5999, 5998, 5999, 5999, 5998, 5997, 5994, 5997, 5994, 5998, 5996, 5998], "avgs": [1956.144, 1962.982, 2068.176, 2072.97, 2081.595, 2072.223, 2053.986, 2049.999, 2047.066, 2068.913, 2098.673, 2103.27, 2087.403, 2090.154, 2079.632, 2053.322, 2073.282, 2104.926, 2081.437, 2102.364, 2091.095, 2110.791, 2121.224, 2106.327, 2054.846, 2041.518, 2038.711, 2046.459, 2042.228, 2036.401, 2031.192, 2040.479, 2075.02, 2124.021, 2134.228, 2087.413, 2085.231, 2111.836, 2174.639, 2250.384, 2209.033, 2188.082, 2188.778, 2310.102, 2304.084, 2320.88, 2304.404, 2601.053, 2698.734, 2605.465, 2589.647, 2846.733, 2281.014, 2179.129, 2135.625, 2127.515, 2079.313, 2084.193, 2105.013, 2141.992, 2138.559, 2154.686, 2133.93, 2032.039, 2015.786, 2036.022, 2028.828, 2157.144, 2195.095, 2098.551, 2083.982, 2068.881, 2104.774, 2077.368, 2107.49, 2116.551, 2068.907, 2082.08, 2111.085, 2092.57, 2069.735, 2047.605, 2094.977, 2109.845, 2096.531, 2103.646, 2111.71, 2099.311, 2122.878, 2138.46, 2113.742], "p05s": [294.0, 281.0, 307.0, 302.0, 313.0, 317.0, 311.0, 298.55, 306.0, 311.55, 333.55, 355.0, 328.0, 318.0, 304.0, 298.55, 316.0, 345.0, 324.0, 328.0, 340.55, 348.55, 347.55, 348.55, 340.0, 331.0, 321.0, 320.0, 328.0, 317.0, 309.55, 322.0, 331.55, 375.0, 379.0, 334.0, 338.0, 361.0, 406.55, 457.55, 445.0, 423.55, 394.0, 482.55, 469.0, 473.55, 436.0, 502.0, 574.0, 550.0, 530.55, 907.55, 411.55, 392.0, 372.0, 359.0, 340.0, 341.55, 343.0, 352.0, 372.0, 363.0, 352.0, 348.0, 339.0, 337.0, 330.0, 357.0, 366.55, 366.0, 354.0, 373.0, 391.55, 369.0, 378.0, 378.0, 361.55, 343.55, 352.0, 354.55, 339.0, 339.0, 353.0, 367.0, 368.55, 350.0, 369.0, 363.55, 356.0, 370.0, 350.0], "p50s": [2329.0, 2321.0, 2402.0, 2381.0, 2387.0, 2388.5, 2373.0, 2371.0, 2379.0, 2384.0, 2404.0, 2438.0, 2416.0, 2384.0, 2373.0, 2378.5, 2380.0, 2406.0, 2396.0, 2418.5, 2417.5, 2428.0, 2425.0, 2398.0, 2403.0, 2402.0, 2376.0, 2391.5, 2402.0, 2384.0, 2378.0, 2399.0, 2416.5, 2453.5, 2453.5, 2406.0, 2428.5, 2415.0, 2497.0, 2564.0, 2547.0, 2520.0, 2502.0, 2599.0, 2586.0, 2598.0, 2590.0, 2688.0, 2729.0, 2685.0, 2680.0, 2764.0, 2550.5, 2482.0, 2482.0, 2449.0, 2402.0, 2407.0, 2420.5, 2436.0, 2451.0, 2454.0, 2447.0, 2396.0, 2383.0, 2372.0, 2370.0, 2426.0, 2465.0, 2417.5, 2387.5, 2365.0, 2430.0, 2388.5, 2393.5, 2417.0, 2385.0, 2394.5, 2392.0, 2402.0, 2396.0, 2372.0, 2395.0, 2422.5, 2410.0, 2424.0, 2426.0, 2425.5, 2429.0, 2452.0, 2419.0], "p95s": [3968.9, 4000.9, 4064.0, 3994.35, 4048.25, 4101.45, 4054.9, 4104.45, 4060.45, 4135.9, 4177.35, 4088.9, 4142.45, 4133.0, 4152.9, 4054.45, 4022.9, 4091.8, 4053.0, 4164.45, 4078.9, 4075.45, 4130.0, 4083.0, 4014.35, 4047.9, 3992.0, 4056.45, 4026.0, 4037.0, 3991.35, 4029.9, 4166.45, 4177.45, 4110.45, 4084.25, 4124.35, 4094.45, 4205.0, 4238.9, 4164.0, 4161.45, 4090.9, 4159.45, 4218.0, 4180.8, 4190.0, 4233.9, 4239.45, 3876.45, 3895.9, 4262.0, 4153.0, 4118.45, 4060.45, 4123.0, 4074.45, 4139.0, 4066.7, 4140.45, 4035.45, 4115.45, 4111.45, 4032.9, 3989.45, 4020.45, 3995.35, 4135.0, 4250.9, 4052.9, 4006.45, 4028.8, 4069.45, 4016.0, 4076.0, 4043.7, 3981.0, 4026.45, 4049.45, 4024.35, 4002.0, 3960.45, 4053.45, 4038.0, 4021.45, 4048.0, 4059.0, 4047.45, 4041.45, 4072.45, 4069.25], "blocks": [59231, 88602, 82945, 82378, 82661, 82044, 82635, 83681, 83605, 86772, 89150, 91832, 93382, 93492, 94596, 94805, 94030, 95057, 93900, 93401, 93903, 91413, 88353, 89259, 92555, 91320, 89810, 83567, 86786, 88657, 87685, 88189, 94982, 94809, 94085, 94215, 93487, 93297, 93577, 92888, 93543, 92445, 89521, 87574, 85895, 85854, 79803, 67576, 66437, 63740, 63042, 59406, 84176, 91731, 95028, 94587, 95181, 94768, 94384, 94706, 94720, 93704, 93886, 101415, 101942, 101930, 102042, 101461, 100848, 101789, 101376, 101367, 101706, 101996, 100649, 99239, 102144, 101960, 101339, 102009, 101767, 101134, 101069, 101625, 101282, 101020, 101392, 99094, 104094, 107327, 35921]} \ No newline at end of file diff --git a/data/beacon-chain-timings/size_cdf/holesky/last_30_days.json b/data/beacon-chain-timings/size_cdf/holesky/last_30_days.json new file mode 100644 index 00000000..9362ebed --- /dev/null +++ b/data/beacon-chain-timings/size_cdf/holesky/last_30_days.json @@ -0,0 +1 @@ +{"updated_at": 1736496295, "sizes_kb": [32.0, 64.0, 96.0, 128.0, 160.0, 192.0, 224.0, 256.0, 288.0, 320.0, 352.0, 384.0, 416.0, 448.0, 480.0, 512.0, 544.0, 576.0, 608.0, 640.0, 672.0, 704.0, 736.0, 768.0, 800.0, 832.0, 864.0, 896.0, 928.0, 960.0], "arrival_times_ms": {"all": [1869.0, 1949.0, 1876.0, 2099.0, 1757.0, 1841.0, 1924.0, 1962.0, 1831.0, 1891.0, 2030.0, 2067.0, 1862.0, 1946.0, 1973.0, 2039.0, 1882.0, 1977.0, 1884.0, 1836.0, 1838.0, 1793.0, 2028.0, 1763.0, 2352.0, 2231.0, 2165.0, 2074.0, 2254.0, 2539.0], "mev": [2246.0, 2360.0, 2291.0, 2374.0, 2253.0, 2361.0, 2423.0, 2532.0, 2309.0, 2399.0, 2546.0, 2855.0, 2372.0, 2499.0, 2569.0, 2868.0, 2442.0, 2593.0, 1860.0, 2418.0, 2416.0, 1814.0, 2488.0, 2453.0, 2497.0, 2581.0, 2409.0, 2420.0, 2539.0], "non_mev": [1733.0, 1694.0, 1649.0, 1439.0, 1649.0, 1754.0, 1857.0, 1724.0, 1717.0, 1819.0, 1963.0, 1985.0, 1743.0, 1866.0, 1894.0, 1873.0, 1765.0, 1904.0, 1885.0, 1836.0, 1737.0, 1740.0, 2041.0, 1522.0, 1596.0, 1816.0, 1623.0, 1570.0, 1466.0], "solo_mev": [2209.0, 2308.0, 2251.0, 2201.0, 2226.0, 2650.0, 2231.0, 2278.0, 2370.0, 2276.0, 2296.0, 2432.0, 1827.0, 2375.0, 2320.0, 2365.0, 2328.0, 2458.0, 2412.0, 2586.0, 2817.0], "solo_non_mev": [1814.0, 1530.0, 1890.0, 1627.0, 1767.0, 2114.0, 1592.0, 1691.0, 1843.0, 4699.0, 1221.0, 1702.0, 1950.0, 1637.0, 1689.0, 1984.0, 2100.0, 1726.0, 1558.0, 1873.0, 1577.0, 1610.0, 1237.0]}} \ No newline at end of file diff --git a/data/beacon-chain-timings/size_cdf/holesky/last_90_days.json b/data/beacon-chain-timings/size_cdf/holesky/last_90_days.json new file mode 100644 index 00000000..97fd992d --- /dev/null +++ b/data/beacon-chain-timings/size_cdf/holesky/last_90_days.json @@ -0,0 +1 @@ +{"updated_at": 1736496355, "sizes_kb": [32.0, 64.0, 96.0, 128.0, 160.0, 192.0, 224.0, 256.0, 288.0, 320.0, 352.0, 384.0, 416.0, 448.0, 480.0, 512.0, 544.0, 576.0, 608.0, 640.0, 672.0, 704.0, 736.0, 768.0, 800.0, 832.0, 864.0, 896.0, 928.0, 960.0], "arrival_times_ms": {"all": [1853.0, 2076.0, 1996.0, 2081.0, 1801.0, 1930.0, 1983.0, 1988.0, 1852.0, 1958.0, 2027.0, 2018.0, 1889.0, 1989.0, 2027.0, 2037.0, 1899.0, 2004.0, 2112.0, 1980.0, 1869.0, 2015.0, 2137.0, 1938.0, 2345.0, 2121.0, 2257.0, 2590.0, 2208.0, 2306.0], "mev": [2256.0, 2397.0, 2344.0, 2444.0, 2291.0, 2383.0, 2430.0, 2624.0, 2323.0, 2428.0, 2573.0, 2747.0, 2369.0, 2491.0, 2689.0, 2762.0, 2420.0, 2499.0, 2393.0, 2604.0, 2427.0, 2533.0, 2562.0, 2488.0, 2457.0, 2503.0, 2628.0, 2568.0, 2420.0, 2539.0], "non_mev": [1673.0, 1844.0, 1830.0, 1754.0, 1720.0, 1885.0, 1946.0, 1862.0, 1775.0, 1917.0, 1990.0, 1973.0, 1825.0, 1950.0, 1974.0, 1974.0, 1827.0, 1954.0, 2106.0, 1902.0, 1790.0, 1944.0, 2066.0, 1828.0, 1752.0, 1926.0, 1770.0, 2606.0, 1854.0, 2190.0], "solo_mev": [2261.0, 2411.0, 2393.0, 2317.0, 2309.0, 2412.0, 2591.0, 2523.0, 2330.0, 2418.0, 2204.0, 2377.0, 2416.0, 2277.0, 2408.0, 2324.0, 2436.0, 2879.0, 2313.0, 2581.0, 2141.0, 2448.0, 2451.0, 2586.0, 3284.0, 2412.0], "solo_non_mev": [1655.0, 1766.0, 1634.0, 1689.0, 1840.0, 2056.0, 1556.0, 1770.0, 1913.0, 2607.0, 1584.0, 1831.0, 1894.0, 1769.0, 2335.0, 1791.0, 1896.0, 1956.0, 2478.0, 1827.0, 1730.0, 1873.0, 1729.0, 2089.0, 2744.0, 2355.0, 1614.0]}} \ No newline at end of file diff --git a/data/beacon-chain-timings/size_cdf/mainnet/last_30_days.json b/data/beacon-chain-timings/size_cdf/mainnet/last_30_days.json new file mode 100644 index 00000000..f4f46916 --- /dev/null +++ b/data/beacon-chain-timings/size_cdf/mainnet/last_30_days.json @@ -0,0 +1 @@ +{"updated_at": 1736496291, "sizes_kb": [32.0, 64.0, 96.0, 128.0, 160.0, 192.0, 224.0, 256.0, 288.0, 320.0, 352.0, 384.0, 416.0, 448.0, 480.0, 512.0, 544.0, 576.0, 608.0, 640.0, 672.0, 704.0, 736.0, 768.0, 800.0, 832.0, 864.0, 896.0, 928.0, 960.0, 992.0, 1024.0, 1056.0, 1088.0, 1152.0, 1184.0, 1216.0, 1248.0, 1312.0, 1408.0, 1792.0], "arrival_times_ms": {"all": [1899.0, 2085.0, 2194.0, 2139.0, 1907.0, 2114.0, 2195.0, 2235.0, 1923.0, 2147.0, 2255.0, 2191.0, 1941.0, 2175.0, 2277.0, 2105.0, 1994.0, 2190.0, 2265.0, 2115.0, 1975.0, 2213.0, 2313.0, 2245.0, 2010.0, 2241.0, 2341.0, 2371.0, 2338.0, 2248.0, 2499.0, 2679.0, 2545.0, 2044.0, 3444.0, 2601.0, 3478.0, 3987.0, 2510.0, 2644.0, 1860.0], "mev": [1956.0, 2088.0, 2198.0, 2168.0, 1993.0, 2116.0, 2207.0, 2301.0, 2010.0, 2150.0, 2259.0, 2331.0, 2041.0, 2177.0, 2284.0, 2217.0, 2059.0, 2192.0, 2268.0, 2214.0, 2075.0, 2217.0, 2313.0, 2339.0, 2101.0, 2244.0, 2343.0, 2387.0, 2344.0, 2274.0, 2514.0, 2679.0, 2545.0, 2044.0, 3444.0, 2777.0, 3478.0, 3987.0, 2510.0, 2644.0], "non_mev": [1566.0, 1826.0, 1780.0, 1612.0, 1659.0, 1986.0, 1612.0, 1595.0, 1663.0, 1975.0, 2042.0, 1705.0, 1684.0, 2056.0, 1952.0, 1530.0, 1744.0, 1975.0, 2014.0, 1554.0, 1755.0, 2027.0, 2318.0, 1559.0, 1774.0, 2056.0, 2239.0, 2118.0, 1158.0, 2047.0, 2384.0, 2074.0, 1860.0], "solo_mev": [1780.0, 1896.0, 1982.0, 1923.0, 1870.0, 1976.0, 1980.0, 2052.0, 1830.0, 2002.0, 2011.0, 1708.0, 1902.0, 2000.0, 2090.0, 1936.0, 1940.0, 2014.0, 2159.0, 1857.0, 1975.0, 2061.0, 2165.0, 1874.0, 1963.0, 2078.0, 2156.0, 2388.0, 2236.0, 1701.0, 2095.0, 2489.0, 2733.0], "solo_non_mev": [1111.0, 1217.0, 866.0, 1250.0, 1172.0, 1165.0, 1124.0, 754.0, 1183.0, 1911.0, 1271.0, 1334.0, 1143.0, 1465.0, 1387.0, 1099.0, 1259.0, 1195.0, 1542.0, 1373.0, 1283.0, 1423.0, 1124.0, 1785.0, 1234.0, 1361.0, 1224.0, 1359.0]}} \ No newline at end of file diff --git a/data/beacon-chain-timings/size_cdf/mainnet/last_90_days.json b/data/beacon-chain-timings/size_cdf/mainnet/last_90_days.json new file mode 100644 index 00000000..a3547a89 --- /dev/null +++ b/data/beacon-chain-timings/size_cdf/mainnet/last_90_days.json @@ -0,0 +1 @@ +{"updated_at": 1736496344, "sizes_kb": [32.0, 64.0, 96.0, 128.0, 160.0, 192.0, 224.0, 256.0, 288.0, 320.0, 352.0, 384.0, 416.0, 448.0, 480.0, 512.0, 544.0, 576.0, 608.0, 640.0, 672.0, 704.0, 736.0, 768.0, 800.0, 832.0, 864.0, 896.0, 928.0, 960.0, 992.0, 1024.0, 1056.0, 1088.0, 1152.0, 1184.0, 1216.0, 1248.0, 1312.0, 1344.0, 1408.0, 1792.0], "arrival_times_ms": {"all": [1897.0, 2061.0, 2149.0, 2123.0, 1889.0, 2070.0, 2177.0, 2220.0, 1916.0, 2098.0, 2190.0, 2190.0, 1941.0, 2129.0, 2239.0, 2132.0, 1973.0, 2148.0, 2235.0, 2124.0, 1967.0, 2164.0, 2266.0, 2255.0, 2003.0, 2187.0, 2286.0, 2324.0, 2309.0, 2274.0, 2435.0, 2553.0, 2433.0, 2044.0, 3223.0, 2601.0, 2814.0, 3987.0, 2719.0, 2487.0, 2644.0, 1860.0], "mev": [1939.0, 2063.0, 2150.0, 2144.0, 1963.0, 2072.0, 2187.0, 2270.0, 1981.0, 2099.0, 2200.0, 2223.0, 2011.0, 2132.0, 2245.0, 2203.0, 2027.0, 2150.0, 2240.0, 2232.0, 2044.0, 2167.0, 2265.0, 2339.0, 2066.0, 2189.0, 2290.0, 2328.0, 2311.0, 2287.0, 2409.0, 2553.0, 2433.0, 2044.0, 3223.0, 2777.0, 3478.0, 3987.0, 2719.0, 2487.0, 2644.0], "non_mev": [1543.0, 1799.0, 2010.0, 1653.0, 1645.0, 1942.0, 1796.0, 1772.0, 1663.0, 2044.0, 1849.0, 1999.0, 1730.0, 1985.0, 1999.0, 1584.0, 1763.0, 1980.0, 1988.0, 1548.0, 1775.0, 2018.0, 2286.0, 1651.0, 1828.0, 2003.0, 2148.0, 2257.0, 2242.0, 2116.0, 2603.0, 2074.0, 2151.0, 1860.0], "solo_mev": [1771.0, 1864.0, 1941.0, 1904.0, 1837.0, 1920.0, 1986.0, 2049.0, 1834.0, 1930.0, 2034.0, 1950.0, 1872.0, 1966.0, 2128.0, 1977.0, 1925.0, 2006.0, 2041.0, 2011.0, 1940.0, 2020.0, 2090.0, 1972.0, 1940.0, 2045.0, 2131.0, 2279.0, 2234.0, 1724.0, 2095.0, 2489.0, 2733.0], "solo_non_mev": [1078.0, 1145.0, 1427.0, 1293.0, 1110.0, 1341.0, 1424.0, 1638.0, 1140.0, 1879.0, 1622.0, 1308.0, 1242.0, 1349.0, 1052.0, 1399.0, 1269.0, 1297.0, 1368.0, 1375.0, 1276.0, 1476.0, 1239.0, 1735.0, 1307.0, 1401.0, 1468.0, 2154.0, 1382.0, 2822.0]}} \ No newline at end of file diff --git a/data/beacon-chain-timings/size_cdf/sepolia/last_30_days.json b/data/beacon-chain-timings/size_cdf/sepolia/last_30_days.json new file mode 100644 index 00000000..c13cc0c7 --- /dev/null +++ b/data/beacon-chain-timings/size_cdf/sepolia/last_30_days.json @@ -0,0 +1 @@ +{"updated_at": 1736496293, "sizes_kb": [32.0, 64.0, 96.0, 128.0, 160.0, 192.0, 224.0, 256.0, 288.0, 320.0, 352.0, 384.0, 416.0, 448.0, 480.0, 512.0, 544.0, 576.0, 608.0, 640.0, 672.0, 704.0, 736.0, 768.0, 800.0, 832.0, 864.0, 896.0, 928.0, 960.0, 992.0, 1024.0, 1056.0, 1088.0, 1120.0, 1152.0, 1184.0, 1216.0, 1248.0, 1280.0, 1312.0, 1344.0, 1376.0, 1408.0, 1440.0, 1472.0, 1504.0, 1536.0, 1568.0, 1600.0, 1632.0, 1664.0, 1696.0, 1728.0, 1760.0, 1792.0, 1824.0, 1856.0, 1888.0, 1984.0, 2048.0, 2080.0, 2112.0, 2144.0, 2240.0], "arrival_times_ms": {"all": [556.0, 579.0, 631.0, 660.0, 603.0, 608.0, 660.0, 700.0, 625.0, 637.0, 685.0, 697.0, 648.0, 652.0, 688.0, 721.0, 674.0, 682.0, 729.0, 766.0, 723.0, 720.0, 781.0, 855.0, 734.0, 757.0, 800.0, 821.0, 825.0, 875.0, 883.0, 934.0, 947.0, 1034.0, 936.0, 856.0, 1078.0, 973.0, 1240.0, 1234.0, 969.0, 1292.0, 1168.0, 1426.0, 1071.0, 1321.0, 1007.0, 1476.0, 1022.0, 1152.0, 1157.0, 1127.0, 1322.0, 894.0, 1041.0, 900.0, 1757.0, 1721.0, 1075.0, 1495.0, 1180.0, 1187.0, 2372.0, 1144.0, 1272.0], "mev": [1152.0, 1354.0, 1416.0, 1078.0, 1221.0, 1357.0, 1410.0, 1200.0, 1274.0, 1443.0, 1468.0, 1201.0, 1360.0, 1497.0, 1636.0, 1318.0, 1455.0, 1518.0, 1793.0, 1391.0, 1545.0, 1641.0, 1608.0, 1399.0, 1582.0, 1718.0, 1801.0, 1893.0, 2021.0, 2041.0, 2014.0, 2647.0], "non_mev": [444.0, 536.0, 587.0, 467.0, 484.0, 568.0, 611.0, 544.0, 510.0, 598.0, 649.0, 602.0, 533.0, 616.0, 652.0, 606.0, 564.0, 650.0, 692.0, 652.0, 610.0, 694.0, 764.0, 692.0, 637.0, 731.0, 775.0, 784.0, 781.0, 862.0, 883.0, 909.0, 947.0, 1034.0, 936.0, 856.0, 1078.0, 973.0, 1240.0, 1125.0, 969.0, 1292.0, 1168.0, 1426.0, 1071.0, 1321.0, 1007.0, 1476.0, 1022.0, 1152.0, 1157.0, 1127.0, 1322.0, 894.0, 1041.0, 900.0, 1757.0, 1721.0, 1075.0, 1495.0, 1180.0, 1187.0, 2372.0, 1144.0, 1272.0], "solo_mev": [1230.0, 1465.0, 1433.0, 1147.0, 1310.0, 1498.0, 1425.0, 1338.0, 1377.0, 1558.0, 1669.0, 1319.0, 1487.0, 1616.0, 1669.0, 1408.0, 1567.0, 1647.0, 1956.0, 1541.0, 1647.0, 1698.0, 1796.0, 1513.0, 1726.0, 1800.0, 2009.0, 2013.0, 2218.0, 2024.0, 2788.0, 2647.0], "solo_non_mev": [468.0, 542.0, 581.0, 520.0, 502.0, 581.0, 598.0, 573.0, 525.0, 609.0, 634.0, 614.0, 549.0, 624.0, 660.0, 638.0, 585.0, 664.0, 713.0, 671.0, 627.0, 689.0, 769.0, 704.0, 655.0, 744.0, 792.0, 787.0, 794.0, 840.0, 875.0, 915.0, 1022.0, 1010.0, 806.0, 900.0, 1054.0, 914.0, 1182.0, 1000.0, 1072.0, 1438.0, 1255.0, 1606.0, 1289.0, 1496.0, 1094.0, 1576.0, 817.0, 944.0, 1152.0, 855.0, 1046.0, 894.0, 950.0, 900.0, 1757.0, 1532.0, 1466.0, 1180.0, 1187.0, 2372.0, 1144.0, 1399.0]}} \ No newline at end of file diff --git a/data/beacon-chain-timings/size_cdf/sepolia/last_90_days.json b/data/beacon-chain-timings/size_cdf/sepolia/last_90_days.json new file mode 100644 index 00000000..33e768a9 --- /dev/null +++ b/data/beacon-chain-timings/size_cdf/sepolia/last_90_days.json @@ -0,0 +1 @@ +{"updated_at": 1736496349, "sizes_kb": [32.0, 64.0, 96.0, 128.0, 160.0, 192.0, 224.0, 256.0, 288.0, 320.0, 352.0, 384.0, 416.0, 448.0, 480.0, 512.0, 544.0, 576.0, 608.0, 640.0, 672.0, 704.0, 736.0, 768.0, 800.0, 832.0, 864.0, 896.0, 928.0, 960.0, 992.0, 1024.0, 1056.0, 1088.0, 1120.0, 1152.0, 1184.0, 1216.0, 1248.0, 1280.0, 1312.0, 1344.0, 1376.0, 1408.0, 1440.0, 1472.0, 1504.0, 1536.0, 1568.0, 1600.0, 1632.0, 1664.0, 1696.0, 1728.0, 1760.0, 1792.0, 1824.0, 1856.0, 1888.0, 1984.0, 2048.0, 2080.0, 2112.0, 2144.0, 2240.0], "arrival_times_ms": {"all": [546.0, 603.0, 653.0, 686.0, 599.0, 634.0, 699.0, 735.0, 632.0, 663.0, 727.0, 762.0, 663.0, 687.0, 752.0, 783.0, 693.0, 719.0, 792.0, 804.0, 743.0, 749.0, 852.0, 893.0, 768.0, 794.0, 859.0, 863.0, 852.0, 915.0, 939.0, 932.0, 934.0, 1031.0, 933.0, 934.0, 1105.0, 962.0, 1300.0, 1191.0, 944.0, 1292.0, 1326.0, 1355.0, 1071.0, 1321.0, 1007.0, 1476.0, 1053.0, 1152.0, 1157.0, 1127.0, 1322.0, 894.0, 1041.0, 1084.0, 1757.0, 1676.0, 1075.0, 1495.0, 1180.0, 1187.0, 2372.0, 1144.0, 1272.0], "mev": [1247.0, 1457.0, 1526.0, 1168.0, 1325.0, 1512.0, 1491.0, 1235.0, 1386.0, 1597.0, 1644.0, 1326.0, 1461.0, 1661.0, 1758.0, 1410.0, 1539.0, 1685.0, 1800.0, 1457.0, 1635.0, 1770.0, 1835.0, 1546.0, 1700.0, 1865.0, 1971.0, 1984.0, 2067.0, 2248.0, 2746.0, 1796.0, 1629.0, 3058.0, 2647.0], "non_mev": [432.0, 563.0, 611.0, 467.0, 481.0, 594.0, 661.0, 553.0, 513.0, 627.0, 692.0, 611.0, 545.0, 655.0, 715.0, 648.0, 581.0, 689.0, 759.0, 684.0, 629.0, 720.0, 829.0, 698.0, 667.0, 766.0, 828.0, 803.0, 802.0, 898.0, 909.0, 895.0, 919.0, 1031.0, 933.0, 832.0, 1105.0, 962.0, 1300.0, 1094.0, 944.0, 1292.0, 1326.0, 1355.0, 1071.0, 1321.0, 1007.0, 1476.0, 1053.0, 1152.0, 1157.0, 1127.0, 1322.0, 894.0, 1041.0, 1084.0, 1757.0, 1676.0, 1075.0, 1495.0, 1180.0, 1187.0, 2372.0, 1144.0, 1272.0], "solo_mev": [1360.0, 1575.0, 1681.0, 1261.0, 1439.0, 1629.0, 1616.0, 1344.0, 1501.0, 1761.0, 1793.0, 1453.0, 1594.0, 1787.0, 1840.0, 1537.0, 1664.0, 1835.0, 1923.0, 1626.0, 1766.0, 1905.0, 1969.0, 1658.0, 1839.0, 1982.0, 2085.0, 2164.0, 2229.0, 2148.0, 2746.0, 2246.0, 1560.0, 3058.0, 2647.0], "solo_non_mev": [438.0, 547.0, 591.0, 487.0, 477.0, 586.0, 629.0, 552.0, 511.0, 622.0, 679.0, 608.0, 548.0, 653.0, 721.0, 665.0, 589.0, 693.0, 768.0, 711.0, 629.0, 710.0, 823.0, 696.0, 670.0, 767.0, 825.0, 807.0, 803.0, 870.0, 881.0, 874.0, 955.0, 1002.0, 865.0, 900.0, 1087.0, 892.0, 1182.0, 992.0, 1072.0, 1438.0, 1466.0, 1606.0, 1289.0, 1496.0, 1094.0, 1576.0, 1044.0, 944.0, 1152.0, 855.0, 1046.0, 894.0, 950.0, 900.0, 1757.0, 1532.0, 1466.0, 1180.0, 1187.0, 2372.0, 1144.0, 1399.0]}} \ No newline at end of file diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json index b5cdc146..126e03ba 100644 --- a/frontend/.eslintrc.json +++ b/frontend/.eslintrc.json @@ -8,17 +8,7 @@ "parser": "@typescript-eslint/parser", "plugins": ["react-prefer-function-component"], "extends": [ - "eslint:all", - "plugin:@typescript-eslint/all", - "plugin:import/recommended", - "plugin:import/typescript", - "plugin:react/all", - "plugin:jsx-a11y/recommended", - "airbnb", - "airbnb-typescript", - "airbnb/hooks", - "plugin:react/jsx-runtime", - "plugin:unicorn/all" + ], "rules": { "no-dupe-else-if": "error", diff --git a/frontend/public/ethereum.png b/frontend/public/ethereum.png new file mode 100644 index 00000000..a77b0aa9 Binary files /dev/null and b/frontend/public/ethereum.png differ diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 48bac756..d1f6cd92 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -7,6 +7,8 @@ import Networks from './pages/xatu/networks'; import ContributorsList from './pages/xatu/ContributorsList'; import ContributorDetail from './pages/xatu/ContributorDetail'; import Layout from './components/layout/Layout'; +import { BeaconChainTimings } from './pages/beacon-chain-timings'; +import { BlockTimings } from './pages/beacon-chain-timings/blocks'; function App(): JSX.Element { return ( @@ -20,6 +22,9 @@ function App(): JSX.Element { } /> } /> + }> + } /> + } /> diff --git a/frontend/src/components/layout/Breadcrumbs.tsx b/frontend/src/components/layout/Breadcrumbs.tsx index fd8ad10e..cf1b4f72 100644 --- a/frontend/src/components/layout/Breadcrumbs.tsx +++ b/frontend/src/components/layout/Breadcrumbs.tsx @@ -23,6 +23,13 @@ export const breadcrumbs = [ } ], }, + { + name: 'Beacon Chain', + path: '/beacon-chain-timings', + children: [ + { name: 'Blocks', path: '/beacon-chain-timings/blocks' }, + ], + }, ]; function findActivePath(pathname: string, items: NavItem[]): NavItem[] { diff --git a/frontend/src/components/layout/Layout.tsx b/frontend/src/components/layout/Layout.tsx index 69f87053..84d32dfd 100644 --- a/frontend/src/components/layout/Layout.tsx +++ b/frontend/src/components/layout/Layout.tsx @@ -4,32 +4,7 @@ import { Breadcrumbs } from './Breadcrumbs' function Layout(): JSX.Element { return ( -
- {/* Animated Background */} -
-
- {/* Main gradient */} -
- - {/* Noise texture */} -
- - {/* Grid */} -
-
-
-
- - {/* Glow effects */} -
-
-
-
- - {/* Neon Lines */} -
-
- +
{/* Content */}
@@ -41,16 +16,10 @@ function Layout(): JSX.Element { {/* Content Area */}
- {/* Subtle top highlight */} -
- {/* Main content */} -
+
- - {/* Subtle bottom highlight */} -
diff --git a/frontend/src/components/layout/Navigation.tsx b/frontend/src/components/layout/Navigation.tsx index b6dfdaff..b5596b7b 100644 --- a/frontend/src/components/layout/Navigation.tsx +++ b/frontend/src/components/layout/Navigation.tsx @@ -18,6 +18,13 @@ export const navigation = [ { name: 'Contributors', path: '/xatu/contributors' }, ], }, + { + name: 'Beacon Chain', + path: '/beacon-chain-timings', + children: [ + { name: 'Block Timings', path: '/beacon-chain-timings/blocks' }, + ], + }, ] export function Navigation(): JSX.Element { diff --git a/frontend/src/index.css b/frontend/src/index.css index aae20442..8e350521 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -26,4 +26,44 @@ font-display: swap; src: url('/fonts/Inter-Bold.woff2') format('woff2'); } + + body { + background: linear-gradient(135deg, #080810 0%, #0f0f23 40%, #151530 100%); + background-attachment: fixed; + min-height: 100vh; + position: relative; + } + + body::before { + content: ''; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: + linear-gradient(rgba(15, 15, 35, 0.3) 1px, transparent 1px), + linear-gradient(90deg, rgba(15, 15, 35, 0.3) 1px, transparent 1px), + radial-gradient(circle at 20% 30%, rgba(45, 212, 191, 0.05) 0%, transparent 50%), + radial-gradient(circle at 80% 70%, rgba(124, 58, 237, 0.05) 0%, transparent 50%); + background-size: 30px 30px, 30px 30px, 100% 100%, 100% 100%; + mask-image: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.7) 0%, rgba(0, 0, 0, 0.2) 100%); + pointer-events: none; + z-index: -1; + opacity: 0.3; + } + + /* Add a subtle noise texture */ + body::after { + content: ''; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%' height='100%' filter='url(%23noise)'/%3E%3C/svg%3E"); + opacity: 0.015; + pointer-events: none; + z-index: -1; + } } diff --git a/frontend/src/pages/Home.tsx b/frontend/src/pages/Home.tsx index ad2210ae..1722431d 100644 --- a/frontend/src/pages/Home.tsx +++ b/frontend/src/pages/Home.tsx @@ -45,6 +45,24 @@ const experimentGroups: ExperimentGroup[] = [ }, ], }, + { + id: 'beacon-chain', + title: 'Beacon Chain', + subtitle: 'Analyze Ethereum beacon chain metrics and performance', + logo: '/ethereum.png', + overview: { + title: 'Overview', + description: 'Explore beacon chain metrics and performance data', + href: '/beacon-chain-timings', + }, + links: [ + { + title: 'Blocks', + description: 'Analyze block arrival times and network performance', + href: '/beacon-chain-timings/blocks', + }, + ], + }, ]; function Home(): JSX.Element { diff --git a/frontend/src/pages/beacon-chain-timings/blocks/index.tsx b/frontend/src/pages/beacon-chain-timings/blocks/index.tsx new file mode 100644 index 00000000..79311998 --- /dev/null +++ b/frontend/src/pages/beacon-chain-timings/blocks/index.tsx @@ -0,0 +1,659 @@ +import { useDataFetch } from '../../../utils/data' +import { LoadingState } from '../../../components/common/LoadingState' +import { ErrorState } from '../../../components/common/ErrorState' +import { NetworkSelector } from '../../../components/common/NetworkSelector' +import { useState, useEffect, useMemo } from 'react' +import { LineChart, Line, XAxis, YAxis, Tooltip, ResponsiveContainer, Legend, ReferenceLine, ScatterChart, Scatter, ZAxis } from 'recharts' +import { getConfig } from '../../../utils/config' +import type { Config } from '../../../types' +import { useSearchParams } from 'react-router-dom' +import { formatDistanceToNow } from 'date-fns' + +interface TimingData { + timestamps: number[] + mins: number[] + maxs: number[] + p05s: number[] + p50s: number[] + p95s: number[] + blocks: number[] + updated_at: number +} + +interface CDFData { + sizes_kb: number[] + arrival_times_ms: { + all: number[] + mev: number[] + non_mev: number[] + solo_mev: number[] + solo_non_mev: number[] + } + updated_at: number +} + +interface TimeWindowConfig { + file: string + step: string + label: string + range: string +} + +const DEFAULT_TIME_WINDOWS: TimeWindowConfig[] = [ + { file: 'last_30_days', step: '1d', label: '30d', range: '-30d' }, + { file: 'last_1_day', step: '15m', label: '1d', range: '-1d' } +] + +const TIMESTAMP_MULTIPLIER = 1000 +const DECIMAL_PLACES = 3 + +export const BlockTimings: React.FC = () => { + const [searchParams, setSearchParams] = useSearchParams() + const [config, setConfig] = useState() + const [configLoading, setConfigLoading] = useState(true) + const [configError, setConfigError] = useState() + const [isTimeWindowOpen, setIsTimeWindowOpen] = useState(false) + const [hiddenLines, setHiddenLines] = useState>(new Set()) + + const timeWindows = useMemo(() => { + const notebookConfig = config?.notebooks?.['beacon-chain-timings'] + return notebookConfig?.time_windows || DEFAULT_TIME_WINDOWS + }, [config]) + + const defaultTimeWindow = useMemo(() => timeWindows[0]?.file || 'last_30_days', [timeWindows]) + const defaultNetwork = useMemo(() => { + const notebookConfig = config?.notebooks?.['beacon-chain-timings'] + return notebookConfig?.networks?.[0] || 'mainnet' + }, [config]) + + const [timeWindow, setTimeWindow] = useState(() => + searchParams.get('timeWindow') || defaultTimeWindow + ) + const [network, setNetwork] = useState(() => + searchParams.get('network') || defaultNetwork + ) + + useEffect(() => { + setConfigLoading(true) + getConfig() + .then(setConfig) + .catch(setConfigError) + .finally(() => setConfigLoading(false)) + }, []) + + // Update URL when network/timeWindow changes + useEffect(() => { + const params = new URLSearchParams(searchParams) + params.set('network', network) + params.set('timeWindow', timeWindow) + setSearchParams(params) + }, [network, timeWindow, setSearchParams, searchParams]) + + const { data: timingData, loading, error } = useDataFetch( + `beacon-chain-timings/block_timings/${network}/${timeWindow}.json` + ) + + const { data: cdfData, loading: cdfLoading, error: cdfError } = useDataFetch( + `beacon-chain-timings/size_cdf/${network}/${timeWindow}.json` + ) + + const currentWindow = useMemo(() => + timeWindows.find((w: TimeWindowConfig) => w.file === timeWindow), + [timeWindows, timeWindow] + ) + + const formatTime = useMemo(() => (time: number) => { + const date = new Date(time * TIMESTAMP_MULTIPLIER) + return currentWindow?.step === '15m' + ? date.toLocaleTimeString() + : date.toLocaleDateString() + }, [currentWindow]) + + const chartData = useMemo(() => { + if (!timingData?.timestamps) return [] + + return timingData.timestamps.map((time, index) => ({ + time: time, + min: timingData.mins[index] / 1000, // Convert to seconds + p05: timingData.p05s[index] / 1000, + p50: timingData.p50s[index] / 1000, + p95: timingData.p95s[index] / 1000, + blocks: timingData.blocks[index] + })) + }, [timingData]) + + const xAxisTicks = useMemo(() => { + if (!timingData?.timestamps.length) return [] + const timestamps = timingData.timestamps + const count = 6 // Show 6 ticks + const step = Math.floor(timestamps.length / (count - 1)) + return Array.from({ length: count }, (_, i) => + i === count - 1 ? timestamps[timestamps.length - 1] : timestamps[i * step] + ) + }, [timingData]) + + const scatterData = useMemo(() => { + if (!cdfData?.arrival_times_ms || !cdfData?.sizes_kb) return [] + + // Create separate datasets for each type + const allData = cdfData.arrival_times_ms.all.map((time, index) => ({ + arrival_time: time / 1000, + size: cdfData.sizes_kb[index], + type: 'all' + })).filter(d => d.size <= 1536) + + const mevData = cdfData.arrival_times_ms.mev.map((time, index) => ({ + arrival_time: time / 1000, + size: cdfData.sizes_kb[index], + type: 'mev' + })).filter(d => d.size <= 1536) + + const nonMevData = cdfData.arrival_times_ms.non_mev.map((time, index) => ({ + arrival_time: time / 1000, + size: cdfData.sizes_kb[index], + type: 'non_mev' + })).filter(d => d.size <= 1536) + + const soloMevData = cdfData.arrival_times_ms.solo_mev.map((time, index) => ({ + arrival_time: time / 1000, + size: cdfData.sizes_kb[index], + type: 'solo_mev' + })).filter(d => d.size <= 1536) + + const soloNonMevData = cdfData.arrival_times_ms.solo_non_mev.map((time, index) => ({ + arrival_time: time / 1000, + size: cdfData.sizes_kb[index], + type: 'solo_non_mev' + })).filter(d => d.size <= 1536) + + return [...allData, ...mevData, ...nonMevData, ...soloMevData, ...soloNonMevData].sort((a, b) => a.size - b.size) + }, [cdfData]) + + if (configLoading || loading) { + return + } + + if (configError) { + return + } + + if (error) { + return + } + + if (!timingData) { + return + } + + return ( +
+
+

About This Data

+

+ This data shows timing data for blocks on the beacon chain. The data is updated hourly and aggregated in {timeWindows.map((w, i) => ( + + {w.step} intervals for the {w.label} view{i < timeWindows.length - 1 ? ', and ' : ''} + + ))}. +

+
+ +
+ +
+ + + {isTimeWindowOpen && ( +
+ {timeWindows.map((window) => ( + + ))} +
+ )} +
+
+ +
+ {/* Block Arrival Timing Chart */} +
+
+
+

Block Arrival Time

+
+ Last updated: {timingData?.updated_at ? formatDistanceToNow(new Date(timingData.updated_at * TIMESTAMP_MULTIPLIER), { addSuffix: true }) : 'No data available'} +
+
+
+ + + + + new Date(time * TIMESTAMP_MULTIPLIER).toLocaleString()} + formatter={(value: number) => [`${value.toFixed(DECIMAL_PLACES)}s`, '']} + /> + ( +
+ {/* Attestation Deadline */} +
+
+ Attestation Deadline (4s) +
+ {/* Regular legend items */} + {payload?.map((entry) => ( + + ))} +
+ )} + /> + {/* Attestation Deadline Reference Line */} + + {!hiddenLines.has('95th Percentile') && ( + + )} + {!hiddenLines.has('Median') && ( + + )} + {!hiddenLines.has('5th Percentile') && ( + + )} + {!hiddenLines.has('Minimum') && ( + + )} + + +
+
+
+ + {/* Block Size vs Arrival Time */} +
+
+
+

Block Size vs Arrival Time

+
+ Last updated: {cdfData?.updated_at ? formatDistanceToNow(new Date(cdfData.updated_at * TIMESTAMP_MULTIPLIER), { addSuffix: true }) : 'No data available'} +
+
+
+ + + ( +
+ {/* Attestation Deadline */} +
+
+ Attestation Deadline (4s) +
+ {/* Block Types */} +
+ + + + + +
+
+ )} + /> + value.toFixed(0)} + /> + + [ + key === 'arrival_time' ? `${value.toFixed(DECIMAL_PLACES)}s` : `${value.toFixed(1)} KB (Block+Blob)`, + key === 'arrival_time' ? 'Arrival Time' : 'Combined Size' + ]} + /> + {/* Attestation Deadline Reference Line */} + + {!hiddenLines.has('all') && ( + d.type === 'all')} + dataKey="arrival_time" + name="All Blocks" + stroke="#22d3ee" + strokeWidth={2} + dot={false} + /> + )} + {!hiddenLines.has('mev') && ( + d.type === 'mev')} + dataKey="arrival_time" + name="MEV Blocks" + stroke="#ef4444" + strokeWidth={2} + dot={false} + /> + )} + {!hiddenLines.has('non_mev') && ( + d.type === 'non_mev')} + dataKey="arrival_time" + name="Non-MEV Blocks" + stroke="#22c55e" + strokeWidth={2} + dot={false} + /> + )} + {!hiddenLines.has('solo_mev') && ( + d.type === 'solo_mev')} + dataKey="arrival_time" + name="Solo MEV Blocks" + stroke="#f472b6" + strokeWidth={2} + dot={false} + /> + )} + {!hiddenLines.has('solo_non_mev') && ( + d.type === 'solo_non_mev')} + dataKey="arrival_time" + name="Solo Non-MEV Blocks" + stroke="#fbbf24" + strokeWidth={2} + dot={false} + /> + )} + + +
+
+

Notes

+
    +
  • All Blocks: Shows the average arrival time for all blocks, regardless of their source.
  • +
  • MEV Blocks: Blocks that were built by MEV-Boost relays, which may have different arrival characteristics due to their specialized construction.
  • +
  • Non-MEV Blocks: Regular blocks built by validators without using MEV-Boost relays.
  • +
  • Solo MEV: Blocks built by solo stakers using MEV-Boost relays.
  • +
  • Solo Non-MEV: Blocks built by solo stakers without using MEV-Boost relays.
  • +
+
+
+
+
+
+ ) +} \ No newline at end of file diff --git a/frontend/src/pages/beacon-chain-timings/index.tsx b/frontend/src/pages/beacon-chain-timings/index.tsx new file mode 100644 index 00000000..57a095df --- /dev/null +++ b/frontend/src/pages/beacon-chain-timings/index.tsx @@ -0,0 +1,48 @@ +import { Link, Outlet, useLocation } from 'react-router-dom' +import { ArrowRight } from 'lucide-react' + +export function BeaconChainTimings(): JSX.Element { + const location = useLocation() + + // If we're on a nested route, render the child route + if (location.pathname !== '/beacon-chain-timings') { + return ( +
+
+ +
+
+ ) + } + + return ( +
+ {/* Overview Section */} +
+
+

Beacon Chain Timings

+

+ This section provides insights into Ethereum beacon chain block timing metrics, including arrival times and block sizes. +

+
+ + {/* Navigation Cards */} +
+ +
+
+
+

Block Arrival Times

+

Analyze block arrival times and their distribution across the network

+
+
+ + +
+
+
+ ) +} \ No newline at end of file diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 71d90db3..3c25aaef 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -12,6 +12,18 @@ export interface Config { range: string }[] } + 'beacon-chain-timings': { + enabled: boolean + schedule_hours: number + description: string + networks: string[] + time_windows: { + file: string + step: string + label: string + range: string + }[] + } } data: { type: string diff --git a/notebooks/beacon-chain-timings.ipynb b/notebooks/beacon-chain-timings.ipynb new file mode 100644 index 00000000..44c0d484 --- /dev/null +++ b/notebooks/beacon-chain-timings.ipynb @@ -0,0 +1,416 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-01-10 16:31:53,437 - beacon-chain-timings - INFO - Good to go!\n" + ] + } + ], + "source": [ + "import os\n", + "from datetime import datetime, timedelta\n", + "import pandas as pd\n", + "from pathlib import Path\n", + "from lib import Lab\n", + "\n", + "# Initialize lab\n", + "lab = Lab('beacon-chain-timings', '../config.yaml')\n", + "lab.setup()\n", + "lab.setup_pandaops_clickhouse()\n", + "log = lab.log\n", + "\n", + "# Get notebook specific config\n", + "notebook_config = lab.get_notebook_config()\n", + "\n", + "writer = lab.get_data_writer()\n", + "\n", + "pandaops_clickhouse_client = lab.get_pandaops_clickhouse_client()\n", + "\n", + "## Clear the data directory\n", + "lab.delete_directory('')\n", + "\n", + "log.info(\"Good to go!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "BeaconChainTimings(time_windows=[TimeWindow(file='last_30_days', step='6h', label='Last 30d', range='-30d'), TimeWindow(file='last_90_days', step='1d', label='Last 90d', range='-90d')], networks=['mainnet', 'sepolia', 'holesky'], data_dir='../data/beacon-chain-timings')" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "beacon_chain_timings_config = lab.get_notebook_config().as_beacon_chain_timings()\n", + "beacon_chain_timings_config\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-01-10 16:56:54,199 - beacon-chain-timings - INFO - Fetching data for last_30_days\n", + "2025-01-10 16:56:55,844 - beacon-chain-timings - INFO - Found 363 entries for time window last_30_days\n", + "2025-01-10 16:56:55,848 - beacon-chain-timings - INFO - Fetching data for last_90_days\n", + "2025-01-10 16:56:56,731 - beacon-chain-timings - INFO - Found 273 entries for time window last_90_days\n" + ] + } + ], + "source": [ + "from sqlalchemy import text\n", + "from datetime import datetime, timezone\n", + "query = text(\"\"\"\n", + " WITH time_slots AS (\n", + " SELECT \n", + " toStartOfInterval(slot_start_date_time, INTERVAL :step_seconds second) as time_slot,\n", + " meta_network_name,\n", + " min(propagation_slot_start_diff) as min_arrival,\n", + " max(propagation_slot_start_diff) as max_arrival,\n", + " avg(propagation_slot_start_diff) as avg_arrival,\n", + " quantile(0.05)(propagation_slot_start_diff) as p05_arrival,\n", + " quantile(0.50)(propagation_slot_start_diff) as p50_arrival,\n", + " quantile(0.95)(propagation_slot_start_diff) as p95_arrival,\n", + " count(*) as total_blocks\n", + " FROM beacon_api_eth_v1_events_block FINAL\n", + " WHERE\n", + " slot_start_date_time BETWEEN toDateTime(:start_date) AND toDateTime(:end_date)\n", + " AND meta_network_name IN (:networks)\n", + " AND propagation_slot_start_diff < 6000\n", + " GROUP BY time_slot, meta_network_name\n", + " )\n", + " SELECT\n", + " time_slot as time,\n", + " meta_network_name,\n", + " min_arrival,\n", + " max_arrival,\n", + " avg_arrival,\n", + " p05_arrival,\n", + " p50_arrival,\n", + " p95_arrival,\n", + " total_blocks\n", + " FROM time_slots\n", + " ORDER BY time_slot ASC\n", + "\"\"\")\n", + "\n", + "for window in beacon_chain_timings_config.time_windows:\n", + " start_date, end_date = window.get_time_range(datetime.now(timezone.utc))\n", + " step_seconds = window.get_step_seconds()\n", + " \n", + " start_str = start_date.strftime('%Y-%m-%d %H:%M:%S')\n", + " end_str = end_date.strftime('%Y-%m-%d %H:%M:%S')\n", + "\n", + " log.info(f\"Fetching data for {window.file}\")\n", + " \n", + " result = pandaops_clickhouse_client.execute(\n", + " query,\n", + " {\n", + " \"start_date\": start_str,\n", + " \"end_date\": end_str,\n", + " \"networks\": beacon_chain_timings_config.networks,\n", + " \"step_seconds\": step_seconds\n", + " }\n", + " )\n", + " timings = result.fetchall()\n", + "\n", + " if len(timings) == 0:\n", + " log.warning(f\"No data found for time window {window.file}\")\n", + " continue\n", + "\n", + " log.info(f\"Found {len(timings)} entries for time window {window.file}\")\n", + " \n", + " # Process each network separately\n", + " for network in beacon_chain_timings_config.networks:\n", + " network_timings = [t for t in timings if t[1] == network]\n", + " if not network_timings:\n", + " continue\n", + " \n", + " # Structure data as arrays to save space\n", + " times = []\n", + " mins = []\n", + " maxs = []\n", + " avgs = []\n", + " p05s = []\n", + " p50s = []\n", + " p95s = []\n", + " blocks = []\n", + " \n", + " for t in network_timings:\n", + " times.append(int(t[0].timestamp()))\n", + " mins.append(round(t[2], 3))\n", + " maxs.append(round(t[3], 3))\n", + " avgs.append(round(t[4], 3))\n", + " p05s.append(round(t[5], 3))\n", + " p50s.append(round(t[6], 3))\n", + " p95s.append(round(t[7], 3))\n", + " blocks.append(t[8])\n", + " \n", + " # Write compact array format\n", + " formatted_data = {\n", + " \"timestamps\": times,\n", + " \"mins\": mins,\n", + " \"maxs\": maxs,\n", + " \"avgs\": avgs,\n", + " \"p05s\": p05s,\n", + " \"p50s\": p50s,\n", + " \"p95s\": p95s,\n", + " \"blocks\": blocks\n", + " }\n", + " \n", + " # Write to file per time window and network\n", + " lab.write_json(f\"block_timings/{network}/{window.file}.json\", formatted_data)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-01-10 17:38:04,941 - beacon-chain-timings - INFO - Fetching block and blob data for last_30_days (2024-12-11 07:38:04 to 2025-01-10 07:38:04)\n", + "2025-01-10 17:38:04,942 - beacon-chain-timings - INFO - Querying blob data...\n", + "2025-01-10 17:38:09,475 - beacon-chain-timings - INFO - Found blob data for 503400 slots\n", + "2025-01-10 17:38:09,476 - beacon-chain-timings - INFO - Querying MEV relay data...\n", + "2025-01-10 17:38:11,216 - beacon-chain-timings - INFO - Found 264044 MEV relay slots\n", + "2025-01-10 17:38:11,216 - beacon-chain-timings - INFO - Querying block arrival data...\n", + "2025-01-10 17:38:11,217 - beacon-chain-timings - INFO - Querying block size data...\n", + "2025-01-10 17:38:17,907 - beacon-chain-timings - INFO - Found arrival data for 621757 blocks\n", + "2025-01-10 17:38:22,072 - beacon-chain-timings - INFO - Found size data for 619833 blocks\n", + "2025-01-10 17:38:22,073 - beacon-chain-timings - INFO - Getting proposer entities...\n", + "2025-01-10 17:38:31,121 - beacon-chain-timings - INFO - Merged data contains 619833 blocks\n", + "2025-01-10 17:38:31,121 - beacon-chain-timings - INFO - Processing network mainnet...\n" + ] + }, + { + "ename": "KeyError", + "evalue": "'solo_stakers'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn [19], line 143\u001b[0m\n\u001b[1;32m 141\u001b[0m network_df[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mis_mev\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m network_df\u001b[38;5;241m.\u001b[39mslot\u001b[38;5;241m.\u001b[39misin(mev_slots)\n\u001b[1;32m 142\u001b[0m network_df \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mmerge(network_df, proposer_entities, on\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mproposer_index\u001b[39m\u001b[38;5;124m'\u001b[39m, how\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mleft\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m--> 143\u001b[0m network_df[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mis_solo\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m network_df\u001b[38;5;241m.\u001b[39mentity[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msolo_stakers\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[1;32m 145\u001b[0m \u001b[38;5;66;03m# Bucket sizes into 32KB chunks and get average arrival time per bucket\u001b[39;00m\n\u001b[1;32m 146\u001b[0m network_df[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msize_bucket\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m (network_df\u001b[38;5;241m.\u001b[39mtotal_size \u001b[38;5;241m/\u001b[39m (\u001b[38;5;241m32\u001b[39m \u001b[38;5;241m*\u001b[39m \u001b[38;5;241m1024\u001b[39m))\u001b[38;5;241m.\u001b[39mround() \u001b[38;5;241m*\u001b[39m \u001b[38;5;241m32\u001b[39m\n", + "File \u001b[0;32m~/.pyenv/versions/anaconda3-2022.05/envs/ldm/lib/python3.10/site-packages/pandas/core/series.py:1121\u001b[0m, in \u001b[0;36mSeries.__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 1118\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_values[key]\n\u001b[1;32m 1120\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m key_is_scalar:\n\u001b[0;32m-> 1121\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_get_value\u001b[49m\u001b[43m(\u001b[49m\u001b[43mkey\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1123\u001b[0m \u001b[38;5;66;03m# Convert generator to list before going through hashable part\u001b[39;00m\n\u001b[1;32m 1124\u001b[0m \u001b[38;5;66;03m# (We will iterate through the generator there to check for slices)\u001b[39;00m\n\u001b[1;32m 1125\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m is_iterator(key):\n", + "File \u001b[0;32m~/.pyenv/versions/anaconda3-2022.05/envs/ldm/lib/python3.10/site-packages/pandas/core/series.py:1237\u001b[0m, in \u001b[0;36mSeries._get_value\u001b[0;34m(self, label, takeable)\u001b[0m\n\u001b[1;32m 1234\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_values[label]\n\u001b[1;32m 1236\u001b[0m \u001b[38;5;66;03m# Similar to Index.get_value, but we do not fall back to positional\u001b[39;00m\n\u001b[0;32m-> 1237\u001b[0m loc \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mindex\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlabel\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1239\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m is_integer(loc):\n\u001b[1;32m 1240\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_values[loc]\n", + "File \u001b[0;32m~/.pyenv/versions/anaconda3-2022.05/envs/ldm/lib/python3.10/site-packages/pandas/core/indexes/range.py:417\u001b[0m, in \u001b[0;36mRangeIndex.get_loc\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 415\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(key) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01merr\u001b[39;00m\n\u001b[1;32m 416\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(key, Hashable):\n\u001b[0;32m--> 417\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(key)\n\u001b[1;32m 418\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_check_indexing_error(key)\n\u001b[1;32m 419\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(key)\n", + "\u001b[0;31mKeyError\u001b[0m: 'solo_stakers'" + ] + } + ], + "source": [ + "import numpy as np\n", + "\n", + "# Fetch block sizes, blob data and build CDF for each time window\n", + "for window in beacon_chain_timings_config.time_windows:\n", + " start_date, end_date = window.get_time_range(datetime.now(timezone.utc))\n", + " start_str = start_date.strftime('%Y-%m-%d %H:%M:%S')\n", + " end_str = end_date.strftime('%Y-%m-%d %H:%M:%S')\n", + "\n", + " log.info(f\"Fetching block and blob data for {window.file} ({start_str} to {end_str})\")\n", + "\n", + " # Get blob data\n", + " log.info(\"Querying blob data...\")\n", + " blob_query = text(\"\"\"\n", + " SELECT\n", + " slot,\n", + " COUNT(*) * 131072 as total_blob_bytes -- 128KB per blob\n", + " FROM canonical_beacon_blob_sidecar FINAL\n", + " WHERE\n", + " slot_start_date_time BETWEEN toDateTime(:start_date) AND toDateTime(:end_date)\n", + " AND meta_network_name IN (:networks)\n", + " GROUP BY slot\n", + " \"\"\")\n", + "\n", + " blob_result = pandaops_clickhouse_client.execute(\n", + " blob_query,\n", + " {\n", + " \"start_date\": start_str,\n", + " \"end_date\": end_str,\n", + " \"networks\": beacon_chain_timings_config.networks\n", + " }\n", + " )\n", + " blob_data = {r[0]: r[1] for r in blob_result.fetchall()}\n", + " log.info(f\"Found blob data for {len(blob_data)} slots\")\n", + "\n", + " # Get MEV relay data\n", + " log.info(\"Querying MEV relay data...\")\n", + " mev_query = text(\"\"\"\n", + " SELECT DISTINCT\n", + " slot\n", + " FROM mev_relay_proposer_payload_delivered FINAL\n", + " WHERE\n", + " slot_start_date_time BETWEEN toDateTime(:start_date) AND toDateTime(:end_date)\n", + " AND meta_network_name IN (:networks)\n", + " \"\"\")\n", + " \n", + " mev_result = pandaops_clickhouse_client.execute(\n", + " mev_query,\n", + " {\n", + " \"start_date\": start_str,\n", + " \"end_date\": end_str,\n", + " \"networks\": beacon_chain_timings_config.networks\n", + " }\n", + " )\n", + " mev_slots = set(r[0] for r in mev_result.fetchall())\n", + " log.info(f\"Found {len(mev_slots)} MEV relay slots\")\n", + "\n", + " # Get block arrival data\n", + " log.info(\"Querying block arrival data...\")\n", + " block_arrival_query = text(\"\"\"\n", + " SELECT \n", + " slot,\n", + " meta_network_name,\n", + " min(propagation_slot_start_diff) as arrival_time\n", + " FROM beacon_api_eth_v1_events_block FINAL\n", + " WHERE\n", + " slot_start_date_time BETWEEN toDateTime(:start_date) AND toDateTime(:end_date)\n", + " AND meta_network_name IN (:networks)\n", + " GROUP BY slot, meta_network_name\n", + " \"\"\")\n", + "\n", + " # Get block size data\n", + " log.info(\"Querying block size data...\")\n", + " block_size_query = text(\"\"\"\n", + " SELECT \n", + " slot,\n", + " meta_network_name,\n", + " proposer_index,\n", + " block_total_bytes_compressed\n", + " FROM canonical_beacon_block FINAL\n", + " WHERE\n", + " slot_start_date_time BETWEEN toDateTime(:start_date) AND toDateTime(:end_date)\n", + " AND meta_network_name IN (:networks)\n", + " \"\"\")\n", + "\n", + " params = {\n", + " \"start_date\": start_str,\n", + " \"end_date\": end_str,\n", + " \"networks\": beacon_chain_timings_config.networks\n", + " }\n", + "\n", + " # Execute queries and convert to dataframes\n", + " arrival_df = pd.DataFrame(\n", + " pandaops_clickhouse_client.execute(block_arrival_query, params).fetchall(),\n", + " columns=['slot', 'meta_network_name', 'arrival_time']\n", + " )\n", + " log.info(f\"Found arrival data for {len(arrival_df)} blocks\")\n", + " \n", + " size_df = pd.DataFrame(\n", + " pandaops_clickhouse_client.execute(block_size_query, params).fetchall(),\n", + " columns=['slot', 'meta_network_name', 'proposer_index', 'block_size']\n", + " )\n", + " log.info(f\"Found size data for {len(size_df)} blocks\")\n", + "\n", + " # Get proposer entities\n", + " log.info(\"Getting proposer entities...\")\n", + " proposer_query = text(\"\"\"\n", + " SELECT \n", + " `index` as proposer_index,\n", + " entity\n", + " FROM ethseer_validator_entity\n", + " WHERE \n", + " meta_network_name IN (:networks)\n", + " \"\"\")\n", + " proposer_entities = pd.DataFrame(\n", + " pandaops_clickhouse_client.execute(proposer_query, params).fetchall(),\n", + " columns=['proposer_index', 'entity']\n", + " )\n", + "\n", + " # Merge dataframes and only keep slots that exist in size_df (canonical blocks)\n", + " block_data = pd.merge(\n", + " arrival_df, \n", + " size_df,\n", + " on=['slot', 'meta_network_name'],\n", + " how='right'\n", + " ).dropna()\n", + " log.info(f\"Merged data contains {len(block_data)} blocks\")\n", + "\n", + " # Process each network\n", + " for network in beacon_chain_timings_config.networks:\n", + " log.info(f\"Processing network {network}...\")\n", + " network_df = block_data[block_data.meta_network_name == network].copy()\n", + " if network_df.empty:\n", + " log.warning(f\"No data found for network {network}\")\n", + " continue\n", + " \n", + " # Add blob sizes, MEV flag and entity info\n", + " network_df['total_size'] = network_df.apply(\n", + " lambda row: max(row.block_size + blob_data.get(row.slot, 0), 1), # Ensure minimum size of 1 byte\n", + " axis=1\n", + " )\n", + " network_df['is_mev'] = network_df.slot.isin(mev_slots)\n", + " network_df = pd.merge(network_df, proposer_entities, on='proposer_index', how='left')\n", + " network_df['is_solo'] = network_df.entity == 'solo_stakers'\n", + "\n", + " # Bucket sizes into 32KB chunks and get average arrival time per bucket\n", + " network_df['size_bucket'] = (network_df.total_size / (32 * 1024)).round() * 32\n", + " network_df['size_bucket'] = network_df['size_bucket'].apply(lambda x: max(x, 32)) # Minimum bucket of 32KB\n", + " \n", + " # Calculate averages for all blocks, MEV blocks, non-MEV blocks, and solo staker blocks\n", + " avg_all = network_df.groupby('size_bucket')['arrival_time'].mean().round().reset_index()\n", + " avg_mev = network_df[network_df.is_mev].groupby('size_bucket')['arrival_time'].mean().round().reset_index()\n", + " avg_non_mev = network_df[~network_df.is_mev].groupby('size_bucket')['arrival_time'].mean().round().reset_index()\n", + " avg_solo_mev = network_df[network_df.is_solo & network_df.is_mev].groupby('size_bucket')['arrival_time'].mean().round().reset_index()\n", + " avg_solo_non_mev = network_df[network_df.is_solo & ~network_df.is_mev].groupby('size_bucket')['arrival_time'].mean().round().reset_index()\n", + "\n", + " # Write data\n", + " formatted_data = {\n", + " \"sizes_kb\": avg_all.size_bucket.tolist(),\n", + " \"arrival_times_ms\": {\n", + " \"all\": avg_all.arrival_time.tolist(),\n", + " \"mev\": avg_mev.arrival_time.tolist() if not avg_mev.empty else [],\n", + " \"non_mev\": avg_non_mev.arrival_time.tolist() if not avg_non_mev.empty else [],\n", + " \"solo_mev\": avg_solo_mev.arrival_time.tolist() if not avg_solo_mev.empty else [],\n", + " \"solo_non_mev\": avg_solo_non_mev.arrival_time.tolist() if not avg_solo_non_mev.empty else []\n", + " }\n", + " }\n", + "\n", + " output_path = f\"size_cdf/{network}/{window.file}.json\"\n", + " log.info(f\"Writing data to {output_path}\")\n", + " lab.write_json(output_path, formatted_data)\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.5" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/notebooks/lib/config.py b/notebooks/lib/config.py index 928f5505..841dd0ea 100644 --- a/notebooks/lib/config.py +++ b/notebooks/lib/config.py @@ -89,7 +89,26 @@ def from_dict(cls, data: Dict[str, Any], data_config: DataConfig) -> "XatuPublic data_dir=str(Path(data_config.path) / "xatu-public-contributors"), networks=data.get("networks", []) ) - +@dataclass +class MevRelays: + networks: List[str] + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> "MevRelays": + return cls( + networks=data.get("networks", []) + ) +@dataclass +class BeaconChainTimings: + time_windows: List[TimeWindow] + networks: List[str] + data_dir: str + @classmethod + def from_dict(cls, data: Dict[str, Any], data_config: DataConfig) -> "BeaconChainTimings": + return cls( + time_windows=[TimeWindow(**w) for w in data.get("time_windows", [])], + networks=data.get("networks", []), + data_dir=str(Path(data_config.path) / "beacon-chain-timings") + ) @dataclass class NotebookConfig: enabled: bool @@ -106,6 +125,20 @@ def as_xatu_public_contributors(self) -> Optional[XatuPublicContributors]: except Exception as e: print(f"Failed to parse XatuPublicContributors config: {e}") return None + def as_mev_relays(self) -> Optional[MevRelays]: + """Convert config to MevRelays if valid""" + try: + return MevRelays.from_dict(self.config) + except Exception as e: + print(f"Failed to parse MevRelays config: {e}") + return None + def as_beacon_chain_timings(self) -> Optional[BeaconChainTimings]: + """Convert config to BeaconChainTimings if valid""" + try: + return BeaconChainTimings.from_dict(self.config, self.data_config) + except Exception as e: + print(f"Failed to parse BeaconChainTimings config: {e}") + return None @dataclass class Config: diff --git a/notebooks/mev-relays.disabled-ipynb b/notebooks/mev-relays.disabled-ipynb new file mode 100644 index 00000000..c6851e9a --- /dev/null +++ b/notebooks/mev-relays.disabled-ipynb @@ -0,0 +1,1503 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-01-10 15:00:18,874 - mev-relays - INFO - Good to go!\n" + ] + }, + { + "ename": "", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31mThe Kernel crashed while executing code in the current cell or a previous cell. \n", + "\u001b[1;31mPlease review the code in the cell(s) to identify a possible cause of the failure. \n", + "\u001b[1;31mClick here for more info. \n", + "\u001b[1;31mView Jupyter log for further details." + ] + } + ], + "source": [ + "import os\n", + "from datetime import datetime, timedelta\n", + "import pandas as pd\n", + "from pathlib import Path\n", + "from lib import Lab\n", + "\n", + "# Initialize lab\n", + "lab = Lab('mev-relays', '../config.yaml')\n", + "lab.setup()\n", + "lab.setup_pandaops_clickhouse()\n", + "log = lab.log\n", + "\n", + "# Get notebook specific config\n", + "notebook_config = lab.get_notebook_config()\n", + "\n", + "writer = lab.get_data_writer()\n", + "\n", + "pandaops_clickhouse_client = lab.get_pandaops_clickhouse_client()\n", + "\n", + "log.info(\"Good to go!\")\n", + "\n", + "# EARLY EXIT. We Don't use this notebook yet.\n", + "return\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "MevRelays(time_windows=[TimeWindow(file='last_30_days', step='1d', label='Last 30d', range='-30d'), TimeWindow(file='last_1_day', step='1h', label='Last 1d', range='-1d'), TimeWindow(file='last_6h', step='5m', label='Last 6h', range='-6h')], networks=['mainnet'])" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mev_relays_config = lab.get_notebook_config().as_mev_relays()\n", + "mev_relays_config" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
validator_indexentity
088035whale_0x3230
1985037whale_0x9f1d
2985038whale_0x9f1d
3985039whale_0x9f1d
4985040whale_0x9f1d
.........
1535620983558rocketpool
1535621983572solo_stakers
1535622983573solo_stakers
1535623983671solo_stakers
1535624983746stakefish
\n", + "

1535625 rows × 2 columns

\n", + "
" + ], + "text/plain": [ + " validator_index entity\n", + "0 88035 whale_0x3230\n", + "1 985037 whale_0x9f1d\n", + "2 985038 whale_0x9f1d\n", + "3 985039 whale_0x9f1d\n", + "4 985040 whale_0x9f1d\n", + "... ... ...\n", + "1535620 983558 rocketpool\n", + "1535621 983572 solo_stakers\n", + "1535622 983573 solo_stakers\n", + "1535623 983671 solo_stakers\n", + "1535624 983746 stakefish\n", + "\n", + "[1535625 rows x 2 columns]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "validator_query = text(\"\"\"\n", + " SELECT \n", + " `index` as validator_index,\n", + " entity\n", + " FROM ethseer_validator_entity\n", + " WHERE \n", + " meta_network_name = :network\n", + "\"\"\")\n", + "validator_entities = pd.DataFrame(\n", + " pandaops_clickhouse_client.execute(validator_query, {\"network\": mev_relays_config.networks[0]}).fetchall(),\n", + " columns=['validator_index', 'entity']\n", + ")\n", + "validator_entities" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-01-10 14:09:45,607 - mev-relays - INFO - Fetching relay registrations for last 2.5 weeks\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
validator_indexslotgas_limittimestamprelay_nameentity
04944810300000001606824023Aestussolo_stakers
14944810300000001606824023Agnostic Gnosissolo_stakers
24944810300000001606824023Titan Relaysolo_stakers
34944810300000001606824023Ultra Soundsolo_stakers
45565450300000001606824023Aestussolo_stakers
.....................
1192997078143310804781360000001736481404Titan Relaycoinbase
1192997178162810804781360000001736481404BloXroute Max Profitcoinbase
1192997278162810804781360000001736481404Titan Relaycoinbase
1192997378260210804781360000001736481404BloXroute Max Profitcoinbase
1192997478260210804781360000001736481404Titan Relaycoinbase
\n", + "

11929975 rows × 6 columns

\n", + "
" + ], + "text/plain": [ + " validator_index slot gas_limit timestamp \\\n", + "0 494481 0 30000000 1606824023 \n", + "1 494481 0 30000000 1606824023 \n", + "2 494481 0 30000000 1606824023 \n", + "3 494481 0 30000000 1606824023 \n", + "4 556545 0 30000000 1606824023 \n", + "... ... ... ... ... \n", + "11929970 781433 10804781 36000000 1736481404 \n", + "11929971 781628 10804781 36000000 1736481404 \n", + "11929972 781628 10804781 36000000 1736481404 \n", + "11929973 782602 10804781 36000000 1736481404 \n", + "11929974 782602 10804781 36000000 1736481404 \n", + "\n", + " relay_name entity \n", + "0 Aestus solo_stakers \n", + "1 Agnostic Gnosis solo_stakers \n", + "2 Titan Relay solo_stakers \n", + "3 Ultra Sound solo_stakers \n", + "4 Aestus solo_stakers \n", + "... ... ... \n", + "11929970 Titan Relay coinbase \n", + "11929971 BloXroute Max Profit coinbase \n", + "11929972 Titan Relay coinbase \n", + "11929973 BloXroute Max Profit coinbase \n", + "11929974 Titan Relay coinbase \n", + "\n", + "[11929975 rows x 6 columns]" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from sqlalchemy import text\n", + "from datetime import datetime, timezone\n", + "\n", + "query = text(\"\"\"\n", + " SELECT\n", + " validator_index,\n", + " slot,\n", + " gas_limit,\n", + " timestamp,\n", + " relay_name\n", + " FROM\n", + " mev_relay_validator_registration\n", + " WHERE\n", + " event_date_time >= :start_date\n", + " AND event_date_time < :end_date\n", + " AND meta_network_name = :network\n", + " GROUP BY\n", + " validator_index,\n", + " slot,\n", + " gas_limit,\n", + " timestamp,\n", + " relay_name\n", + " ORDER BY\n", + " slot,\n", + " validator_index,\n", + " relay_name\n", + "\"\"\")\n", + "\n", + "# Get last 2.5 weeks window\n", + "end_date = datetime.now(timezone.utc)\n", + "start_date = end_date - timedelta(days=16)\n", + "\n", + "# Format dates without microseconds for Clickhouse\n", + "start_str = start_date.strftime('%Y-%m-%d %H:%M:%S')\n", + "end_str = end_date.strftime('%Y-%m-%d %H:%M:%S')\n", + "\n", + "log.info(\"Fetching relay registrations for last 16 days\")\n", + "\n", + "registrations = pd.read_sql(\n", + " query, \n", + " pandaops_clickhouse_client, \n", + " params={\n", + " \"start_date\": start_str,\n", + " \"end_date\": end_str,\n", + " \"network\": mev_relays_config.networks[0]\n", + " }\n", + ")\n", + "\n", + "# Add proposer entity to registrations\n", + "registrations = registrations.merge(validator_entities, on='validator_index', how='left')\n", + "registrations\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
indexstatus
02active_ongoing
13active_ongoing
24active_ongoing
38active_ongoing
411active_ongoing
.........
1759949893333active_ongoing
1759950893335active_ongoing
1759951893343active_ongoing
1759952893344active_ongoing
1759953893352active_ongoing
\n", + "

1759954 rows × 2 columns

\n", + "
" + ], + "text/plain": [ + " index status\n", + "0 2 active_ongoing\n", + "1 3 active_ongoing\n", + "2 4 active_ongoing\n", + "3 8 active_ongoing\n", + "4 11 active_ongoing\n", + "... ... ...\n", + "1759949 893333 active_ongoing\n", + "1759950 893335 active_ongoing\n", + "1759951 893343 active_ongoing\n", + "1759952 893344 active_ongoing\n", + "1759953 893352 active_ongoing\n", + "\n", + "[1759954 rows x 2 columns]" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Get latest epoch's validators\n", + "query = text(\"\"\"\n", + " SELECT \n", + " index,\n", + " status\n", + " FROM canonical_beacon_validators\n", + " WHERE \n", + " epoch = (\n", + " SELECT MAX(epoch) \n", + " FROM canonical_beacon_validators \n", + " WHERE meta_network_name = :network\n", + " AND epoch_start_date_time >= NOW() - INTERVAL 14 DAY\n", + " )\n", + " AND meta_network_name = :network\n", + " AND epoch_start_date_time >= NOW() - INTERVAL 14 DAY\n", + "\"\"\")\n", + "\n", + "validators = pd.read_sql(\n", + " query,\n", + " pandaops_clickhouse_client,\n", + " params={\"network\": mev_relays_config.networks[0]}\n", + ")\n", + "validators\n" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
indexstatus
02active_ongoing
13active_ongoing
24active_ongoing
38active_ongoing
411active_ongoing
.........
1759949893333active_ongoing
1759950893335active_ongoing
1759951893343active_ongoing
1759952893344active_ongoing
1759953893352active_ongoing
\n", + "

1070507 rows × 2 columns

\n", + "
" + ], + "text/plain": [ + " index status\n", + "0 2 active_ongoing\n", + "1 3 active_ongoing\n", + "2 4 active_ongoing\n", + "3 8 active_ongoing\n", + "4 11 active_ongoing\n", + "... ... ...\n", + "1759949 893333 active_ongoing\n", + "1759950 893335 active_ongoing\n", + "1759951 893343 active_ongoing\n", + "1759952 893344 active_ongoing\n", + "1759953 893352 active_ongoing\n", + "\n", + "[1070507 rows x 2 columns]" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "non_active_validators = validators[validators['status'] != 'active_ongoing']\n", + "non_active_validators\n", + "\n", + "active_validators = validators[validators['status'] == 'active_ongoing']\n", + "active_validators" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/fq/bp58gxy12nd2b32pw1y8wy040000gn/T/ipykernel_28284/3333959086.py:2: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " active_registrations['date'] = pd.to_datetime(active_registrations['timestamp'], unit='s').dt.date\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
validator_indexslotgas_limittimestamprelay_nameentitydate
04944810300000001606824023Aestussolo_stakers2020-12-01
14944810300000001606824023Agnostic Gnosissolo_stakers2020-12-01
24944810300000001606824023Titan Relaysolo_stakers2020-12-01
34944810300000001606824023Ultra Soundsolo_stakers2020-12-01
45565450300000001606824023Aestussolo_stakers2020-12-01
........................
1192997078143310804781360000001736481404Titan Relaycoinbase2025-01-10
1192997178162810804781360000001736481404BloXroute Max Profitcoinbase2025-01-10
1192997278162810804781360000001736481404Titan Relaycoinbase2025-01-10
1192997378260210804781360000001736481404BloXroute Max Profitcoinbase2025-01-10
1192997478260210804781360000001736481404Titan Relaycoinbase2025-01-10
\n", + "

11748058 rows × 7 columns

\n", + "
" + ], + "text/plain": [ + " validator_index slot gas_limit timestamp \\\n", + "0 494481 0 30000000 1606824023 \n", + "1 494481 0 30000000 1606824023 \n", + "2 494481 0 30000000 1606824023 \n", + "3 494481 0 30000000 1606824023 \n", + "4 556545 0 30000000 1606824023 \n", + "... ... ... ... ... \n", + "11929970 781433 10804781 36000000 1736481404 \n", + "11929971 781628 10804781 36000000 1736481404 \n", + "11929972 781628 10804781 36000000 1736481404 \n", + "11929973 782602 10804781 36000000 1736481404 \n", + "11929974 782602 10804781 36000000 1736481404 \n", + "\n", + " relay_name entity date \n", + "0 Aestus solo_stakers 2020-12-01 \n", + "1 Agnostic Gnosis solo_stakers 2020-12-01 \n", + "2 Titan Relay solo_stakers 2020-12-01 \n", + "3 Ultra Sound solo_stakers 2020-12-01 \n", + "4 Aestus solo_stakers 2020-12-01 \n", + "... ... ... ... \n", + "11929970 Titan Relay coinbase 2025-01-10 \n", + "11929971 BloXroute Max Profit coinbase 2025-01-10 \n", + "11929972 Titan Relay coinbase 2025-01-10 \n", + "11929973 BloXroute Max Profit coinbase 2025-01-10 \n", + "11929974 Titan Relay coinbase 2025-01-10 \n", + "\n", + "[11748058 rows x 7 columns]" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "active_registrations = registrations[~registrations['validator_index'].isin(non_active_validators['index'])]\n", + "active_registrations['date'] = pd.to_datetime(active_registrations['timestamp'], unit='s').dt.date\n", + "active_registrations\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
validator_indexrelay_nameslotgas_limittimestampentity
00Aestus8708041300000001711320515solo_stakers
10Agnostic Gnosis8708041300000001711320515solo_stakers
20BloXroute Max Profit10681573300000001735002899solo_stakers
30Eden Network10681573300000001735002899solo_stakers
40Flashbots8708041300000001711320515solo_stakers
.....................
67089791734312BloXroute Regulated10799168300000001736414039None
67089801734312Flashbots10796057300000001736376707None
67089811734312Manifold10796057300000001736376707None
67089821734312Titan Relay10799168300000001736414039None
67089831734312Ultra Sound10796057300000001736376707None
\n", + "

6708984 rows × 6 columns

\n", + "
" + ], + "text/plain": [ + " validator_index relay_name slot gas_limit \\\n", + "0 0 Aestus 8708041 30000000 \n", + "1 0 Agnostic Gnosis 8708041 30000000 \n", + "2 0 BloXroute Max Profit 10681573 30000000 \n", + "3 0 Eden Network 10681573 30000000 \n", + "4 0 Flashbots 8708041 30000000 \n", + "... ... ... ... ... \n", + "6708979 1734312 BloXroute Regulated 10799168 30000000 \n", + "6708980 1734312 Flashbots 10796057 30000000 \n", + "6708981 1734312 Manifold 10796057 30000000 \n", + "6708982 1734312 Titan Relay 10799168 30000000 \n", + "6708983 1734312 Ultra Sound 10796057 30000000 \n", + "\n", + " timestamp entity \n", + "0 1711320515 solo_stakers \n", + "1 1711320515 solo_stakers \n", + "2 1735002899 solo_stakers \n", + "3 1735002899 solo_stakers \n", + "4 1711320515 solo_stakers \n", + "... ... ... \n", + "6708979 1736414039 None \n", + "6708980 1736376707 None \n", + "6708981 1736376707 None \n", + "6708982 1736414039 None \n", + "6708983 1736376707 None \n", + "\n", + "[6708984 rows x 6 columns]" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Ensure we've got the most recent registrations with a unique key of validator index and relay name\n", + "most_recent_registrations_per_relay = active_registrations.groupby(['validator_index', 'relay_name']).last().reset_index()\n", + "most_recent_registrations_per_relay\n" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
validator_indexslotgas_limittimestamprelay_nameentitydate
0010681573300000001735002899Titan Relaysolo_stakers2024-12-24
1110681573300000001735002899Titan Relaysolo_stakers2024-12-24
2210681573300000001735002899Titan Relaysolo_stakers2024-12-24
3310681573300000001735002899Titan Relaysolo_stakers2024-12-24
4410681573300000001735002899Titan Relaysolo_stakers2024-12-24
........................
1036498173430810799168300000001736414039Titan RelayNone2025-01-09
1036499173430910799168300000001736414039Titan RelayNone2025-01-09
1036500173431010799168300000001736414039Titan RelayNone2025-01-09
1036501173431110799168300000001736414039Titan RelayNone2025-01-09
1036502173431210799168300000001736414039Titan RelayNone2025-01-09
\n", + "

1036503 rows × 7 columns

\n", + "
" + ], + "text/plain": [ + " validator_index slot gas_limit timestamp relay_name \\\n", + "0 0 10681573 30000000 1735002899 Titan Relay \n", + "1 1 10681573 30000000 1735002899 Titan Relay \n", + "2 2 10681573 30000000 1735002899 Titan Relay \n", + "3 3 10681573 30000000 1735002899 Titan Relay \n", + "4 4 10681573 30000000 1735002899 Titan Relay \n", + "... ... ... ... ... ... \n", + "1036498 1734308 10799168 30000000 1736414039 Titan Relay \n", + "1036499 1734309 10799168 30000000 1736414039 Titan Relay \n", + "1036500 1734310 10799168 30000000 1736414039 Titan Relay \n", + "1036501 1734311 10799168 30000000 1736414039 Titan Relay \n", + "1036502 1734312 10799168 30000000 1736414039 Titan Relay \n", + "\n", + " entity date \n", + "0 solo_stakers 2024-12-24 \n", + "1 solo_stakers 2024-12-24 \n", + "2 solo_stakers 2024-12-24 \n", + "3 solo_stakers 2024-12-24 \n", + "4 solo_stakers 2024-12-24 \n", + "... ... ... \n", + "1036498 None 2025-01-09 \n", + "1036499 None 2025-01-09 \n", + "1036500 None 2025-01-09 \n", + "1036501 None 2025-01-09 \n", + "1036502 None 2025-01-09 \n", + "\n", + "[1036503 rows x 7 columns]" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Ensure we've got the most recent registrations with a unique key of validator index ordered by timestamp\n", + "# Filter for active validators only\n", + "most_recent_registrations = active_registrations[active_registrations['validator_index'].isin(active_validators['index'])] \\\n", + " .groupby(['validator_index']).last().reset_index()\n", + "most_recent_registrations\n" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
relay_namecount
0Aestus1994
1Agnostic Gnosis12105
2BloXroute Max Profit43775
3BloXroute Regulated43515
4Eden Network16
5Flashbots12401
6Manifold4673
7Titan Relay735983
8Ultra Sound175433
9Wenmerge6608
\n", + "
" + ], + "text/plain": [ + " relay_name count\n", + "0 Aestus 1994\n", + "1 Agnostic Gnosis 12105\n", + "2 BloXroute Max Profit 43775\n", + "3 BloXroute Regulated 43515\n", + "4 Eden Network 16\n", + "5 Flashbots 12401\n", + "6 Manifold 4673\n", + "7 Titan Relay 735983\n", + "8 Ultra Sound 175433\n", + "9 Wenmerge 6608" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Start building out the data we want to write to file\n", + "\n", + "total_validators_registered = len(most_recent_registrations)\n", + "total_active_validators = len(active_validators)\n", + "\n", + "## Count the number of validators registered to each relay\n", + "relay_totals = most_recent_registrations.groupby('relay_name').size().reset_index(name='count')\n", + "relay_totals\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "entity\n", + "solo_stakers 7756\n", + "whale_0x24d6 1014\n", + "whale_0xe43c 1011\n", + "abyss_finance 616\n", + "whale_0xefa0 507\n", + "whale_0x39fd 329\n", + "whale_0x900c 309\n", + "whale_0x1d5b 308\n", + "whale_0x10d5 304\n", + "whale_0xe3f7 290\n", + "dtype: int64" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Get the number of validators who are not registered to any relay and their entities\n", + "non_registered_validators = active_validators[~active_validators['index'].isin(most_recent_registrations['validator_index'])]\n", + "non_registered_validators = non_registered_validators.merge(validator_entities, left_on='index', right_on='validator_index')\n", + "\n", + "# Count per entity, show the top 10\n", + "non_registered_validators.groupby('entity').size().sort_values(ascending=False).head(10)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'total_active_validators': 1070507,\n", + " 'total_validators_registered': 1036503,\n", + " 'relay_registrations': [{'relay_name': 'Aestus', 'count': 1994},\n", + " {'relay_name': 'Agnostic Gnosis', 'count': 12105},\n", + " {'relay_name': 'BloXroute Max Profit', 'count': 43775},\n", + " {'relay_name': 'BloXroute Regulated', 'count': 43515},\n", + " {'relay_name': 'Eden Network', 'count': 16},\n", + " {'relay_name': 'Flashbots', 'count': 12401},\n", + " {'relay_name': 'Manifold', 'count': 4673},\n", + " {'relay_name': 'Titan Relay', 'count': 735983},\n", + " {'relay_name': 'Ultra Sound', 'count': 175433},\n", + " {'relay_name': 'Wenmerge', 'count': 6608}],\n", + " 'top_unregistered_entities': {'solo_stakers': 7756,\n", + " 'whale_0x24d6': 1014,\n", + " 'whale_0xe43c': 1011,\n", + " 'abyss_finance': 616,\n", + " 'whale_0xefa0': 507,\n", + " 'whale_0x39fd': 329,\n", + " 'whale_0x900c': 309,\n", + " 'whale_0x1d5b': 308,\n", + " 'whale_0x10d5': 304,\n", + " 'whale_0xe3f7': 290}}" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Write summary data to JSON\n", + "summary = {\n", + " \"total_active_validators\": int(total_active_validators),\n", + " \"total_validators_registered\": int(total_validators_registered),\n", + " \"relay_registrations\": relay_totals.to_dict('records'),\n", + " \"top_unregistered_entities\": non_registered_validators.groupby('entity').size().sort_values(ascending=False).head(10).to_dict()\n", + "}\n", + "\n", + "\n", + "lab.write_json('mev-relays-summary.json', summary)\n", + "\n", + "\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.5" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}