Skip to content

Commit 5cf9008

Browse files
authored
Merge pull request #449 from ethpandaops/pk910/tx-and-blob-count-filters
add tx & blob count filters to slots list
2 parents 20900a5 + 332478c commit 5cf9008

File tree

8 files changed

+168
-13
lines changed

8 files changed

+168
-13
lines changed

db/slots.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,26 @@ func GetFilteredSlots(filter *dbtypes.BlockFilter, firstSlot uint64, offset uint
404404
fmt.Fprintf(&sql, ` AND slots.max_exec_time <= $%v `, argIdx)
405405
args = append(args, *filter.MaxExecTime)
406406
}
407+
if filter.MinTxCount != nil {
408+
argIdx++
409+
fmt.Fprintf(&sql, ` AND slots.eth_transaction_count >= $%v `, argIdx)
410+
args = append(args, *filter.MinTxCount)
411+
}
412+
if filter.MaxTxCount != nil {
413+
argIdx++
414+
fmt.Fprintf(&sql, ` AND slots.eth_transaction_count <= $%v `, argIdx)
415+
args = append(args, *filter.MaxTxCount)
416+
}
417+
if filter.MinBlobCount != nil {
418+
argIdx++
419+
fmt.Fprintf(&sql, ` AND slots.blob_count >= $%v `, argIdx)
420+
args = append(args, *filter.MinBlobCount)
421+
}
422+
if filter.MaxBlobCount != nil {
423+
argIdx++
424+
fmt.Fprintf(&sql, ` AND slots.blob_count <= $%v `, argIdx)
425+
args = append(args, *filter.MaxBlobCount)
426+
}
407427

408428
fmt.Fprintf(&sql, ` ORDER BY slots.slot DESC `)
409429
fmt.Fprintf(&sql, ` LIMIT $%v OFFSET $%v `, argIdx+1, argIdx+2)

dbtypes/other.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ type BlockFilter struct {
5050
MaxSyncParticipation *float32
5151
MinExecTime *uint32
5252
MaxExecTime *uint32
53+
MinTxCount *uint64
54+
MaxTxCount *uint64
55+
MinBlobCount *uint64
56+
MaxBlobCount *uint64
5357
Slot *uint64 // Filter by specific slot number
5458
BlockRoot []byte // Filter by specific block root
5559
}

handlers/slots_filtered.go

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ func SlotsFiltered(w http.ResponseWriter, r *http.Request) {
5656
var maxSyncAgg string
5757
var minExecTime string
5858
var maxExecTime string
59+
var minTxCount string
60+
var maxTxCount string
61+
var minBlobCount string
62+
var maxBlobCount string
5963

6064
if urlArgs.Has("f") {
6165
if urlArgs.Has("f.graffiti") {
@@ -97,14 +101,26 @@ func SlotsFiltered(w http.ResponseWriter, r *http.Request) {
97101
if urlArgs.Has("f.maxexec") {
98102
maxExecTime = urlArgs.Get("f.maxexec")
99103
}
104+
if urlArgs.Has("f.mintx") {
105+
minTxCount = urlArgs.Get("f.mintx")
106+
}
107+
if urlArgs.Has("f.maxtx") {
108+
maxTxCount = urlArgs.Get("f.maxtx")
109+
}
110+
if urlArgs.Has("f.minblob") {
111+
minBlobCount = urlArgs.Get("f.minblob")
112+
}
113+
if urlArgs.Has("f.maxblob") {
114+
maxBlobCount = urlArgs.Get("f.maxblob")
115+
}
100116
} else {
101117
withOrphaned = 1
102118
withMissing = 1
103119
}
104120
var pageError error
105121
pageError = services.GlobalCallRateLimiter.CheckCallLimit(r, 2)
106122
if pageError == nil {
107-
data.Data, pageError = getFilteredSlotsPageData(pageIdx, pageSize, graffiti, invertgraffiti, extradata, invertextradata, proposer, pname, invertproposer, uint8(withOrphaned), uint8(withMissing), minSyncAgg, maxSyncAgg, minExecTime, maxExecTime, displayColumns)
123+
data.Data, pageError = getFilteredSlotsPageData(pageIdx, pageSize, graffiti, invertgraffiti, extradata, invertextradata, proposer, pname, invertproposer, uint8(withOrphaned), uint8(withMissing), minSyncAgg, maxSyncAgg, minExecTime, maxExecTime, minTxCount, maxTxCount, minBlobCount, maxBlobCount, displayColumns)
108124
}
109125
if pageError != nil {
110126
handlePageError(w, r, pageError)
@@ -116,11 +132,11 @@ func SlotsFiltered(w http.ResponseWriter, r *http.Request) {
116132
}
117133
}
118134

119-
func getFilteredSlotsPageData(pageIdx uint64, pageSize uint64, graffiti string, invertgraffiti bool, extradata string, invertextradata bool, proposer string, pname string, invertproposer bool, withOrphaned uint8, withMissing uint8, minSyncAgg string, maxSyncAgg string, minExecTime string, maxExecTime string, displayColumns string) (*models.SlotsFilteredPageData, error) {
135+
func getFilteredSlotsPageData(pageIdx uint64, pageSize uint64, graffiti string, invertgraffiti bool, extradata string, invertextradata bool, proposer string, pname string, invertproposer bool, withOrphaned uint8, withMissing uint8, minSyncAgg string, maxSyncAgg string, minExecTime string, maxExecTime string, minTxCount string, maxTxCount string, minBlobCount string, maxBlobCount string, displayColumns string) (*models.SlotsFilteredPageData, error) {
120136
pageData := &models.SlotsFilteredPageData{}
121-
pageCacheKey := fmt.Sprintf("slots_filtered:%v:%v:%v:%v:%v:%v:%v:%v:%v:%v:%v:%v:%v:%v:%v:%v", pageIdx, pageSize, graffiti, invertgraffiti, extradata, invertextradata, proposer, pname, invertproposer, withOrphaned, withMissing, minSyncAgg, maxSyncAgg, minExecTime, maxExecTime, displayColumns)
137+
pageCacheKey := fmt.Sprintf("slots_filtered:%v:%v:%v:%v:%v:%v:%v:%v:%v:%v:%v:%v:%v:%v:%v:%v:%v:%v:%v:%v", pageIdx, pageSize, graffiti, invertgraffiti, extradata, invertextradata, proposer, pname, invertproposer, withOrphaned, withMissing, minSyncAgg, maxSyncAgg, minExecTime, maxExecTime, minTxCount, maxTxCount, minBlobCount, maxBlobCount, displayColumns)
122138
pageRes, pageErr := services.GlobalFrontendCache.ProcessCachedPage(pageCacheKey, true, pageData, func(_ *services.FrontendCacheProcessingPage) interface{} {
123-
return buildFilteredSlotsPageData(pageIdx, pageSize, graffiti, invertgraffiti, extradata, invertextradata, proposer, pname, invertproposer, withOrphaned, withMissing, minSyncAgg, maxSyncAgg, minExecTime, maxExecTime, displayColumns)
139+
return buildFilteredSlotsPageData(pageIdx, pageSize, graffiti, invertgraffiti, extradata, invertextradata, proposer, pname, invertproposer, withOrphaned, withMissing, minSyncAgg, maxSyncAgg, minExecTime, maxExecTime, minTxCount, maxTxCount, minBlobCount, maxBlobCount, displayColumns)
124140
})
125141
if pageErr == nil && pageRes != nil {
126142
resData, resOk := pageRes.(*models.SlotsFilteredPageData)
@@ -132,7 +148,7 @@ func getFilteredSlotsPageData(pageIdx uint64, pageSize uint64, graffiti string,
132148
return pageData, pageErr
133149
}
134150

135-
func buildFilteredSlotsPageData(pageIdx uint64, pageSize uint64, graffiti string, invertgraffiti bool, extradata string, invertextradata bool, proposer string, pname string, invertproposer bool, withOrphaned uint8, withMissing uint8, minSyncAgg string, maxSyncAgg string, minExecTime string, maxExecTime string, displayColumns string) *models.SlotsFilteredPageData {
151+
func buildFilteredSlotsPageData(pageIdx uint64, pageSize uint64, graffiti string, invertgraffiti bool, extradata string, invertextradata bool, proposer string, pname string, invertproposer bool, withOrphaned uint8, withMissing uint8, minSyncAgg string, maxSyncAgg string, minExecTime string, maxExecTime string, minTxCount string, maxTxCount string, minBlobCount string, maxBlobCount string, displayColumns string) *models.SlotsFilteredPageData {
136152
chainState := services.GlobalBeaconService.GetChainState()
137153
filterArgs := url.Values{}
138154
if graffiti != "" {
@@ -174,6 +190,18 @@ func buildFilteredSlotsPageData(pageIdx uint64, pageSize uint64, graffiti string
174190
if maxExecTime != "" {
175191
filterArgs.Add("f.maxexec", maxExecTime)
176192
}
193+
if minTxCount != "" {
194+
filterArgs.Add("f.mintx", minTxCount)
195+
}
196+
if maxTxCount != "" {
197+
filterArgs.Add("f.maxtx", maxTxCount)
198+
}
199+
if minBlobCount != "" {
200+
filterArgs.Add("f.minblob", minBlobCount)
201+
}
202+
if maxBlobCount != "" {
203+
filterArgs.Add("f.maxblob", maxBlobCount)
204+
}
177205

178206
// Check if snooper clients are configured
179207
hasSnooperClients := false
@@ -244,6 +272,10 @@ func buildFilteredSlotsPageData(pageIdx uint64, pageSize uint64, graffiti string
244272
FilterMaxSyncAgg: maxSyncAgg,
245273
FilterMinExecTime: minExecTime,
246274
FilterMaxExecTime: maxExecTime,
275+
FilterMinTxCount: minTxCount,
276+
FilterMaxTxCount: maxTxCount,
277+
FilterMinBlobCount: minBlobCount,
278+
FilterMaxBlobCount: maxBlobCount,
247279

248280
DisplayEpoch: displayMap[1],
249281
DisplaySlot: displayMap[2],
@@ -336,6 +368,30 @@ func buildFilteredSlotsPageData(pageIdx uint64, pageSize uint64, graffiti string
336368
blockFilter.MaxExecTime = &maxExecUint32
337369
}
338370
}
371+
if minTxCount != "" {
372+
minTx, err := strconv.ParseUint(minTxCount, 10, 64)
373+
if err == nil {
374+
blockFilter.MinTxCount = &minTx
375+
}
376+
}
377+
if maxTxCount != "" {
378+
maxTx, err := strconv.ParseUint(maxTxCount, 10, 64)
379+
if err == nil {
380+
blockFilter.MaxTxCount = &maxTx
381+
}
382+
}
383+
if minBlobCount != "" {
384+
minBlob, err := strconv.ParseUint(minBlobCount, 10, 64)
385+
if err == nil {
386+
blockFilter.MinBlobCount = &minBlob
387+
}
388+
}
389+
if maxBlobCount != "" {
390+
maxBlob, err := strconv.ParseUint(maxBlobCount, 10, 64)
391+
if err == nil {
392+
blockFilter.MaxBlobCount = &maxBlob
393+
}
394+
}
339395

340396
withScheduledCount := chainState.GetSpecs().SlotsPerEpoch - uint64(chainState.SlotToSlotIndex(currentSlot)) - 1
341397
if withScheduledCount > 16 {

indexer/beacon/block.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,13 @@ type Block struct {
5454
// BlockBodyIndex holds important block properties that are used as index for cache lookups.
5555
// this structure should be preserved after pruning, so the block is still identifiable.
5656
type BlockBodyIndex struct {
57-
Graffiti [32]byte
58-
ExecutionExtraData []byte
59-
ExecutionHash phase0.Hash32
60-
ExecutionNumber uint64
61-
SyncParticipation float32
57+
Graffiti [32]byte
58+
ExecutionExtraData []byte
59+
ExecutionHash phase0.Hash32
60+
ExecutionNumber uint64
61+
SyncParticipation float32
62+
EthTransactionCount uint64
63+
BlobCount uint64
6264
}
6365

6466
// newBlock creates a new Block instance.
@@ -304,6 +306,15 @@ func (block *Block) setBlockIndex(body *spec.VersionedSignedBeaconBlock) {
304306
blockIndex.ExecutionExtraData, _ = executionPayload.ExtraData()
305307
blockIndex.ExecutionHash, _ = executionPayload.BlockHash()
306308
blockIndex.ExecutionNumber, _ = executionPayload.BlockNumber()
309+
310+
// Calculate transaction count
311+
executionTransactions, _ := executionPayload.Transactions()
312+
blockIndex.EthTransactionCount = uint64(len(executionTransactions))
313+
314+
// Calculate blob count
315+
blobKzgCommitments, _ := body.BlobKZGCommitments()
316+
blockIndex.BlobCount = uint64(len(blobKzgCommitments))
317+
307318
}
308319

309320
// Calculate sync participation

indexer/beacon/synchronizer.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,14 +235,14 @@ func (s *synchronizer) getSyncClients(epoch phase0.Epoch) []*Client {
235235

236236
sort.Slice(archiveClients, func(i, j int) bool {
237237
if archiveClients[i].priority == archiveClients[j].priority {
238-
return rand.UintN(1) == 0
238+
return rand.UintN(2) == 0
239239
}
240240
return archiveClients[i].priority > archiveClients[j].priority
241241
})
242242

243243
sort.Slice(normalClients, func(i, j int) bool {
244244
if normalClients[i].priority == normalClients[j].priority {
245-
return rand.UintN(1) == 0
245+
return rand.UintN(2) == 0
246246
}
247247
return normalClients[i].priority > normalClients[j].priority
248248
})

services/chainservice_blocks.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,28 @@ func (bs *ChainService) GetDbBlocksByFilter(filter *dbtypes.BlockFilter, pageIdx
734734
}
735735
}
736736

737+
// filter by transaction count
738+
if filter.MinTxCount != nil || filter.MaxTxCount != nil {
739+
txCount := blockIndex.EthTransactionCount
740+
if filter.MinTxCount != nil && txCount < *filter.MinTxCount {
741+
continue
742+
}
743+
if filter.MaxTxCount != nil && txCount > *filter.MaxTxCount {
744+
continue
745+
}
746+
}
747+
748+
// filter by blob count
749+
if filter.MinBlobCount != nil || filter.MaxBlobCount != nil {
750+
blobCount := blockIndex.BlobCount
751+
if filter.MinBlobCount != nil && blobCount < *filter.MinBlobCount {
752+
continue
753+
}
754+
if filter.MaxBlobCount != nil && blobCount > *filter.MaxBlobCount {
755+
continue
756+
}
757+
}
758+
737759
cachedMatches = append(cachedMatches, cachedDbBlock{
738760
slot: uint64(block.Slot),
739761
proposer: uint64(blockHeader.Message.ProposerIndex),
@@ -744,7 +766,7 @@ func (bs *ChainService) GetDbBlocksByFilter(filter *dbtypes.BlockFilter, pageIdx
744766

745767
// reconstruct missing blocks from epoch duties
746768
// For slot/root filtering, we still need to check if we need missing blocks for that specific slot
747-
shouldCheckMissing := filter.WithMissing != 0 && filter.Graffiti == "" && filter.ExtraData == "" && filter.WithOrphaned != 2 && filter.MinSyncParticipation == nil && filter.MaxSyncParticipation == nil && filter.MinExecTime == nil && filter.MaxExecTime == nil
769+
shouldCheckMissing := filter.WithMissing != 0 && filter.Graffiti == "" && filter.ExtraData == "" && filter.WithOrphaned != 2 && filter.MinSyncParticipation == nil && filter.MaxSyncParticipation == nil && filter.MinExecTime == nil && filter.MaxExecTime == nil && filter.MinTxCount == nil && filter.MaxTxCount == nil && filter.MinBlobCount == nil && filter.MaxBlobCount == nil
748770

749771
// If filtering by slot, only check missing for that specific slot
750772
if filter.Slot != nil {

templates/slots_filtered/slots_filtered.html

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,44 @@ <h1 class="h4 mb-1 mb-md-0"><i class="fas fa-cube mx-2"></i>Filtered Slots</h1>
140140
</div>
141141
</div>
142142
{{ end }}
143+
<div class="row mt-1">
144+
<div class="col-sm-12 col-md-6 col-lg-4">
145+
<nobr>Tx Count</nobr>
146+
</div>
147+
<div class="col-sm-12 col-md-6 col-lg-8 d-flex">
148+
<div class="flex-grow-1">
149+
<input name="f.mintx" type="number" class="form-control" placeholder="Min" aria-label="Min Transaction Count" min="0" value="{{ .FilterMinTxCount }}">
150+
</div>
151+
<div class="text-center filter-separator">
152+
-
153+
</div>
154+
<div class="flex-grow-1">
155+
<input name="f.maxtx" type="number" class="form-control" placeholder="Max" aria-label="Max Transaction Count" min="0" value="{{ .FilterMaxTxCount }}">
156+
</div>
157+
<div class="text-center" style="width: 30px;">
158+
159+
</div>
160+
</div>
161+
</div>
162+
<div class="row mt-1">
163+
<div class="col-sm-12 col-md-6 col-lg-4">
164+
<nobr>Blob Count</nobr>
165+
</div>
166+
<div class="col-sm-12 col-md-6 col-lg-8 d-flex">
167+
<div class="flex-grow-1">
168+
<input name="f.minblob" type="number" class="form-control" placeholder="Min" aria-label="Min Blob Count" min="0" value="{{ .FilterMinBlobCount }}">
169+
</div>
170+
<div class="text-center filter-separator">
171+
-
172+
</div>
173+
<div class="flex-grow-1">
174+
<input name="f.maxblob" type="number" class="form-control" placeholder="Max" aria-label="Max Blob Count" min="0" value="{{ .FilterMaxBlobCount }}">
175+
</div>
176+
<div class="text-center" style="width: 30px;">
177+
178+
</div>
179+
</div>
180+
</div>
143181
</div>
144182
</div>
145183

types/models/slots_filtered.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ type SlotsFilteredPageData struct {
1919
FilterMaxSyncAgg string `json:"filter_max_sync"`
2020
FilterMinExecTime string `json:"filter_min_exec"`
2121
FilterMaxExecTime string `json:"filter_max_exec"`
22+
FilterMinTxCount string `json:"filter_min_tx"`
23+
FilterMaxTxCount string `json:"filter_max_tx"`
24+
FilterMinBlobCount string `json:"filter_min_blob"`
25+
FilterMaxBlobCount string `json:"filter_max_blob"`
2226

2327
DisplayEpoch bool `json:"dp_epoch"`
2428
DisplaySlot bool `json:"dp_slot"`

0 commit comments

Comments
 (0)