Skip to content

Commit 688fafa

Browse files
authored
Merge pull request #531 from ethpandaops/bbusa/fix-blob-math
fix: blob math
2 parents 71a48f7 + 8f89116 commit 688fafa

File tree

6 files changed

+84
-62
lines changed

6 files changed

+84
-62
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ tmp-*
1010

1111
.hack/devnet/generated-**
1212
.hack/devnet/custom-**
13+
dora-explorer
Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
participants_matrix:
22
el:
33
- el_type: geth
4-
el_image: ethpandaops/geth:master
54

65
cl:
76
- cl_type: lighthouse
8-
cl_image: ethpandaops/lighthouse:unstable
97
# - cl_type: prysm
108
# - cl_type: teku
119
# - cl_type: nimbus
1210
# - cl_type: grandine
1311
# - cl_type: lodestar
1412

1513
network_params:
16-
network: fusaka-devnet-3
14+
preset: minimal
1715

1816
additional_services:
1917
- dora # needed for config exctraction
18+
- spamoor
2019

2120
# mev_type: flashbots
22-
# snooper_enabled: true
21+
# snooper_enabled: true

clients/consensus/chainspec.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,15 @@ type ChainSpecConfig struct {
109109
MaxRequestBlobSidecarsElectra uint64 `yaml:"MAX_REQUEST_BLOB_SIDECARS_ELECTRA" check-if-fork:"ElectraForkEpoch"`
110110

111111
// Fulu
112-
MinEpochsForDataColumnSidecars uint64 `yaml:"MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS" check-if-fork:"FuluForkEpoch"`
113-
DataColumnSidecarSubnetCount *uint64 `yaml:"DATA_COLUMN_SIDECAR_SUBNET_COUNT" check-if-fork:"FuluForkEpoch"`
114-
CustodyRequirement *uint64 `yaml:"CUSTODY_REQUIREMENT" check-if-fork:"FuluForkEpoch"`
115-
BlobSchedule []BlobScheduleEntry `yaml:"BLOB_SCHEDULE" check-if-fork:"FuluForkEpoch"`
112+
MinEpochsForDataColumnSidecars uint64 `yaml:"MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS" check-if-fork:"FuluForkEpoch"`
113+
NumberOfCustodyGroups *uint64 `yaml:"NUMBER_OF_CUSTODY_GROUPS" check-if-fork:"FuluForkEpoch"`
114+
DataColumnSidecarSubnetCount *uint64 `yaml:"DATA_COLUMN_SIDECAR_SUBNET_COUNT" check-if-fork:"FuluForkEpoch"`
115+
MaxRequestDataColumnSidecars uint64 `yaml:"MAX_REQUEST_DATA_COLUMN_SIDECARS" check-if-fork:"FuluForkEpoch"`
116+
SamplesPerSlot uint64 `yaml:"SAMPLES_PER_SLOT" check-if-fork:"FuluForkEpoch"`
117+
CustodyRequirement *uint64 `yaml:"CUSTODY_REQUIREMENT" check-if-fork:"FuluForkEpoch"`
118+
ValidatorCustodyRequirement *uint64 `yaml:"VALIDATOR_CUSTODY_REQUIREMENT" check-if-fork:"FuluForkEpoch"`
119+
BalancePerAdditionalCustodyGroup *uint64 `yaml:"BALANCE_PER_ADDITIONAL_CUSTODY_GROUP" check-if-fork:"FuluForkEpoch"`
120+
BlobSchedule []BlobScheduleEntry `yaml:"BLOB_SCHEDULE" check-if-fork:"FuluForkEpoch"`
116121
}
117122

118123
type ChainSpecPreset struct {

handlers/blobs.go

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,19 +58,31 @@ func buildBlobsPageData() (*models.BlobsPageData, time.Duration) {
5858
logrus.Debugf("blobs page called")
5959

6060
chainState := services.GlobalBeaconService.GetChainState()
61+
specs := chainState.GetSpecs()
6162
currentSlot := chainState.CurrentSlot()
6263
finalizedEpoch, _ := services.GlobalBeaconService.GetFinalizedEpoch()
6364

65+
// Calculate thresholds based on MAX_EFFECTIVE_BALANCE
66+
// MinEth = 0 (allow non-validators)
67+
// MaxEth = full custody at TotalColumns validators
68+
// Each validator (32 ETH) = 1 column after the free threshold
69+
minEth := uint64(0)
70+
maxEffectiveBalanceEth := specs.MaxEffectiveBalance / 1e9
71+
maxEth := *specs.NumberOfColumns * specs.MaxEffectiveBalance / 1e9
72+
defaultEth := maxEffectiveBalanceEth
73+
6474
pageData := &models.BlobsPageData{
6575
StorageCalculator: &models.StorageCalculatorData{
66-
MinEth: 32,
67-
MaxEth: 4196,
68-
DefaultEth: 256,
69-
ColumnSize: 2.0,
70-
TotalColumns: 128,
71-
MinColumnsNonVal: 4,
72-
MinColumnsVal: 8,
73-
FreeValidatorCount: 8,
76+
MinEth: minEth,
77+
MaxEth: maxEth,
78+
DefaultEth: defaultEth,
79+
MaxEffectiveBalanceEth: float64(maxEffectiveBalanceEth),
80+
ColumnSizeBytes: float64(specs.FieldElementsPerCell * 32),
81+
TotalColumns: *specs.NumberOfColumns,
82+
CustodyRequirement: float64(*specs.CustodyRequirement),
83+
ValidatorCustodyRequirement: float64(*specs.ValidatorCustodyRequirement),
84+
SlotsPerEpoch: specs.SlotsPerEpoch,
85+
MinEpochsForBlobSidecarsRequests: specs.MinEpochsForBlobSidecarsRequests,
7486
},
7587
}
7688

templates/blobs/blobs.html

Lines changed: 41 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,6 @@ <h5 class="mb-0"><i class="fas fa-calculator"></i> Blob Storage Calculator (Peer
6666
<div class="card-body">
6767
<div class="row">
6868
<div class="col-md-12">
69-
<p class="mb-3">
70-
Calculate storage requirements based on PeerDAS custody model.
71-
<a href="https://ethereum.org/roadmap/fusaka/#peerdas" target="_blank" class="text-decoration-none">
72-
Learn more about PeerDAS <i class="fas fa-external-link-alt fa-xs"></i>
73-
</a>
74-
</p>
75-
7669
<div class="mb-4">
7770
<label for="ethSlider" class="form-label">
7871
<span>ETH Staked:</span>
@@ -134,13 +127,17 @@ <h6 class="d-inline-flex align-items-center">
134127
</h6>
135128
<div class="collapse" id="howItWorksCollapse">
136129
<ul class="small mb-0 mt-2">
137-
<li>Non-validating nodes: <strong>4 columns minimum</strong></li>
138-
<li>Validating nodes (0-256 ETH): <strong>8 columns (free threshold)</strong></li>
139-
<li>256-4096 ETH: <strong>+1 column per additional 32 ETH</strong></li>
140-
<li>4096+ ETH: <strong>128 columns (full custody)</strong></li>
141-
<li>Blob retention: <strong>4096 epochs (~18 days)</strong></li>
142-
<li>Column size: <strong>~2 KB per blob</strong></li>
130+
<li>Non-validating nodes (0 ETH): <strong>{{ .StorageCalculator.CustodyRequirement }} columns minimum</strong></li>
131+
<li>Validating nodes ({{ .StorageCalculator.MaxEffectiveBalanceEth }}-{{ mul .StorageCalculator.ValidatorCustodyRequirement .StorageCalculator.MaxEffectiveBalanceEth }} ETH): <strong>{{ .StorageCalculator.ValidatorCustodyRequirement }} columns (free threshold)</strong></li>
132+
<li>{{ mul .StorageCalculator.ValidatorCustodyRequirement .StorageCalculator.MaxEffectiveBalanceEth }}-{{ .StorageCalculator.MaxEth }} ETH: <strong>+1 column per additional {{ .StorageCalculator.MaxEffectiveBalanceEth }} ETH</strong></li>
133+
<li>{{ .StorageCalculator.MaxEth }}+ ETH: <strong>{{ .StorageCalculator.TotalColumns }} columns (full custody)</strong></li>
134+
<li>Blob retention: <strong>{{ .StorageCalculator.MinEpochsForBlobSidecarsRequests }} epochs (~18 days)</strong></li>
135+
<li>Blobs are erasure coded: <strong>128 KiB → 256 KiB ({{ .StorageCalculator.TotalColumns }} columns × {{ div .StorageCalculator.ColumnSizeBytes 1024 }} KiB each)</strong></li>
136+
<li>Storage per blob: <strong>{{ div .StorageCalculator.ColumnSizeBytes 1024 }} KiB × columns custodied</strong></li>
143137
</ul>
138+
<p class="small text-muted mt-2 mb-0">
139+
Learn more: <a href="https://ethereum.org/roadmap/fusaka/#peerdas" target="_blank" rel="noopener">PeerDAS on ethereum.org</a>
140+
</p>
144141
</div>
145142
</div>
146143
</div>
@@ -202,12 +199,16 @@ <h5 class="mb-0"><i class="fas fa-list"></i> Latest Blob Transactions</h5>
202199

203200
{{ define "js" }}
204201
<script type="text/javascript">
205-
const RETENTION_EPOCHS = 4096;
206-
const SLOTS_PER_EPOCH = 32;
202+
const RETENTION_EPOCHS = {{ .StorageCalculator.MinEpochsForBlobSidecarsRequests }};
203+
const SLOTS_PER_EPOCH = {{ .StorageCalculator.SlotsPerEpoch }};
207204
const RETENTION_SLOTS = RETENTION_EPOCHS * SLOTS_PER_EPOCH;
208-
const COLUMN_SIZE_KB = 2;
205+
const COLUMN_SIZE_BYTES = {{ .StorageCalculator.ColumnSizeBytes }};
209206
const TOTAL_COLUMNS = {{ .StorageCalculator.TotalColumns }};
210-
const BLOB_SIZE_KB = 128;
207+
const MAX_EFFECTIVE_BALANCE_ETH = {{ .StorageCalculator.MaxEffectiveBalanceEth }};
208+
const CUSTODY_REQUIREMENT = {{ .StorageCalculator.CustodyRequirement }};
209+
const VALIDATOR_CUSTODY_REQUIREMENT = {{ .StorageCalculator.ValidatorCustodyRequirement }};
210+
const FREE_THRESHOLD_ETH = VALIDATOR_CUSTODY_REQUIREMENT * MAX_EFFECTIVE_BALANCE_ETH;
211+
const MAX_ETH = {{ .StorageCalculator.MaxEth }};
211212

212213
const blobsInRetentionWindow = {{ .BlobsLast30d }};
213214
const blobsLast24h = {{ .BlobsLast24h }};
@@ -267,37 +268,39 @@ <h5 class="mb-0"><i class="fas fa-list"></i> Latest Blob Transactions</h5>
267268
}
268269

269270
function calculateCustodyColumns(eth) {
270-
if (eth < 32) {
271-
return 4;
272-
} else if (eth <= 256) {
273-
return 8;
274-
} else if (eth <= 4096) {
275-
return 8 + Math.floor((eth - 256) / 32);
271+
if (eth === 0) {
272+
return CUSTODY_REQUIREMENT;
273+
} else if (eth < MAX_EFFECTIVE_BALANCE_ETH) {
274+
return CUSTODY_REQUIREMENT;
275+
} else if (eth <= FREE_THRESHOLD_ETH) {
276+
return VALIDATOR_CUSTODY_REQUIREMENT;
277+
} else if (eth <= MAX_ETH) {
278+
return VALIDATOR_CUSTODY_REQUIREMENT + Math.floor((eth - FREE_THRESHOLD_ETH) / MAX_EFFECTIVE_BALANCE_ETH);
276279
} else {
277-
return 128;
280+
return TOTAL_COLUMNS;
278281
}
279282
}
280283

281284
function calculateStorage(eth) {
282-
const validators = Math.floor(eth / 32);
285+
const validators = Math.floor(eth / MAX_EFFECTIVE_BALANCE_ETH);
283286
const columns = calculateCustodyColumns(eth);
284287
const custodyPercent = ((columns / TOTAL_COLUMNS) * 100).toFixed(2);
285288

286-
const custodyRatio = columns / TOTAL_COLUMNS;
287-
288289
const blobsToStore = currentBlobCount > 0 ? currentBlobCount : 0;
289290

290-
const storageMB = (blobsToStore * BLOB_SIZE_KB * custodyRatio) / 1024;
291-
const storageGB = storageMB / 1024;
292-
const storageTB = storageGB / 1024;
291+
const storageBytes = blobsToStore * columns * COLUMN_SIZE_BYTES;
292+
const storageKiB = storageBytes / 1024;
293+
const storageMiB = storageKiB / 1024;
294+
const storageGiB = storageMiB / 1024;
295+
const storageTiB = storageGiB / 1024;
293296

294297
return {
295298
validators: validators,
296299
columns: columns,
297300
custodyPercent: custodyPercent,
298-
storageGB: storageGB.toFixed(2),
299-
storageTB: storageTB.toFixed(3),
300-
storageMB: storageMB.toFixed(2)
301+
storageGiB: storageGiB.toFixed(2),
302+
storageTiB: storageTiB.toFixed(3),
303+
storageMiB: storageMiB.toFixed(2)
301304
};
302305
}
303306

@@ -324,12 +327,12 @@ <h5 class="mb-0"><i class="fas fa-list"></i> Latest Blob Transactions</h5>
324327
document.getElementById('custodyPercent').textContent = result.custodyPercent + '%';
325328

326329
let storageText;
327-
if (parseFloat(result.storageMB) < 1024) {
328-
storageText = result.storageMB + ' MB';
329-
} else if (parseFloat(result.storageGB) < 1000) {
330-
storageText = result.storageGB + ' GB';
330+
if (parseFloat(result.storageMiB) < 1024) {
331+
storageText = result.storageMiB + ' MiB';
332+
} else if (parseFloat(result.storageGiB) < 1024) {
333+
storageText = result.storageGiB + ' GiB';
331334
} else {
332-
storageText = result.storageTB + ' TB';
335+
storageText = result.storageTiB + ' TiB';
333336
}
334337

335338
document.getElementById('storageResult').textContent = storageText;

types/models/blobs.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,14 @@ type LatestBlobBlock struct {
3333
}
3434

3535
type StorageCalculatorData struct {
36-
MinEth uint32 `json:"min_eth"`
37-
MaxEth uint32 `json:"max_eth"`
38-
DefaultEth uint32 `json:"default_eth"`
39-
ColumnSize float64 `json:"column_size"`
40-
TotalColumns uint32 `json:"total_columns"`
41-
MinColumnsNonVal uint32 `json:"min_columns_non_val"`
42-
MinColumnsVal uint32 `json:"min_columns_val"`
43-
FreeValidatorCount uint32 `json:"free_validator_count"`
36+
MinEth uint64 `json:"min_eth"`
37+
MaxEth uint64 `json:"max_eth"`
38+
DefaultEth uint64 `json:"default_eth"`
39+
MaxEffectiveBalanceEth float64 `json:"max_effective_balance_eth"`
40+
ColumnSizeBytes float64 `json:"column_size_bytes"`
41+
TotalColumns uint64 `json:"total_columns"`
42+
CustodyRequirement float64 `json:"custody_requirement"`
43+
ValidatorCustodyRequirement float64 `json:"validator_custody_requirement"`
44+
SlotsPerEpoch uint64 `json:"slots_per_epoch"`
45+
MinEpochsForBlobSidecarsRequests uint64 `json:"min_epochs_for_blob_sidecars_requests"`
4446
}

0 commit comments

Comments
 (0)