Skip to content

Commit

Permalink
rearranged index page & added recent slots panel
Browse files Browse the repository at this point in the history
  • Loading branch information
pk910 committed Aug 25, 2023
1 parent 52f1c65 commit 3461810
Show file tree
Hide file tree
Showing 7 changed files with 298 additions and 15 deletions.
167 changes: 161 additions & 6 deletions handlers/index.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package handlers

import (
"bytes"
"fmt"
"math"
"net/http"
Expand All @@ -23,6 +24,7 @@ func Index(w http.ResponseWriter, r *http.Request) {
"index/networkOverview.html",
"index/recentBlocks.html",
"index/recentEpochs.html",
"index/recentSlots.html",
"_svg/professor.html",
"_svg/timeline.html",
)
Expand Down Expand Up @@ -52,8 +54,9 @@ func getIndexPageData() *models.IndexPageData {
func buildIndexPageData() (*models.IndexPageData, time.Duration) {
logrus.Printf("index page called")

recentEpochCount := 15
recentBlockCount := 15
recentEpochCount := 7
recentBlockCount := 7
recentSlotsCount := 16

// network overview
now := time.Now()
Expand Down Expand Up @@ -160,8 +163,20 @@ func buildIndexPageData() (*models.IndexPageData, time.Duration) {
}

// load recent epochs
buildIndexPageRecentEpochsData(pageData, uint64(currentEpoch), finalizedEpoch, recentEpochCount)

// load recent blocks
buildIndexPageRecentBlocksData(pageData, currentSlot, recentBlockCount)

// load recent slots
buildIndexPageRecentSlotsData(pageData, currentSlot, recentSlotsCount)

return pageData, 12 * time.Second
}

func buildIndexPageRecentEpochsData(pageData *models.IndexPageData, currentEpoch uint64, finalizedEpoch int64, recentEpochCount int) {
pageData.RecentEpochs = make([]*models.IndexPageDataEpochs, 0)
epochsData := services.GlobalBeaconService.GetDbEpochs(uint64(currentEpoch), uint32(recentEpochCount))
epochsData := services.GlobalBeaconService.GetDbEpochs(currentEpoch, uint32(recentEpochCount))
for i := 0; i < len(epochsData); i++ {
epochData := epochsData[i]
if epochData == nil {
Expand All @@ -183,8 +198,9 @@ func buildIndexPageData() (*models.IndexPageData, time.Duration) {
})
}
pageData.RecentEpochCount = uint64(len(pageData.RecentEpochs))
}

// load recent blocks
func buildIndexPageRecentBlocksData(pageData *models.IndexPageData, currentSlot uint64, recentBlockCount int) {
pageData.RecentBlocks = make([]*models.IndexPageDataBlocks, 0)
blocksData := services.GlobalBeaconService.GetDbBlocks(uint64(currentSlot), int32(recentBlockCount), false)
for i := 0; i < len(blocksData); i++ {
Expand All @@ -204,10 +220,149 @@ func buildIndexPageData() (*models.IndexPageData, time.Duration) {
Proposer: blockData.Proposer,
ProposerName: services.GlobalBeaconService.GetValidatorName(blockData.Proposer),
Status: uint64(blockStatus),
BlockRoot: fmt.Sprintf("0x%x", blockData.Root),
BlockRoot: blockData.Root,
})
}
pageData.RecentBlockCount = uint64(len(pageData.RecentBlocks))
}

return pageData, 12 * time.Second
func buildIndexPageRecentSlotsData(pageData *models.IndexPageData, firstSlot uint64, slotLimit int) {
var lastSlot uint64
if firstSlot >= uint64(slotLimit) {
lastSlot = firstSlot - uint64(slotLimit)
} else {
lastSlot = 0
}

// get slot assignments
firstEpoch := utils.EpochOfSlot(firstSlot)
lastEpoch := utils.EpochOfSlot(lastSlot)
slotAssignments, _ := services.GlobalBeaconService.GetProposerAssignments(firstEpoch, lastEpoch)

// load slots
pageData.RecentSlots = make([]*models.IndexPageDataSlots, 0)
dbSlots := services.GlobalBeaconService.GetDbBlocksForSlots(uint64(firstSlot), uint32(slotLimit), true)
dbIdx := 0
dbCnt := len(dbSlots)
blockCount := uint64(0)
openForks := map[int][]byte{}
maxOpenFork := 0
for slotIdx := int64(firstSlot); slotIdx >= int64(lastSlot); slotIdx-- {
slot := uint64(slotIdx)
haveBlock := false
for dbIdx < dbCnt && dbSlots[dbIdx] != nil && dbSlots[dbIdx].Slot == slot {
dbSlot := dbSlots[dbIdx]
dbIdx++
blockStatus := uint64(1)
if dbSlot.Orphaned {
blockStatus = 2
}

slotData := &models.IndexPageDataSlots{
Slot: slot,
Epoch: utils.EpochOfSlot(slot),
Ts: utils.SlotToTime(slot),
Status: blockStatus,
Proposer: dbSlot.Proposer,
ProposerName: services.GlobalBeaconService.GetValidatorName(dbSlot.Proposer),
BlockRoot: dbSlot.Root,
ParentRoot: dbSlot.ParentRoot,
ForkGraph: make([]*models.IndexPageDataForkGraph, 0),
}
pageData.RecentSlots = append(pageData.RecentSlots, slotData)
blockCount++
haveBlock = true
buildIndexPageSlotGraph(pageData, slotData, &maxOpenFork, openForks)
}

if !haveBlock {
epoch := utils.EpochOfSlot(slot)
slotData := &models.IndexPageDataSlots{
Slot: slot,
Epoch: epoch,
Ts: utils.SlotToTime(slot),
Status: 0,
Proposer: slotAssignments[slot],
ProposerName: services.GlobalBeaconService.GetValidatorName(slotAssignments[slot]),
ForkGraph: make([]*models.IndexPageDataForkGraph, 0),
}
pageData.RecentSlots = append(pageData.RecentSlots, slotData)
blockCount++
buildIndexPageSlotGraph(pageData, slotData, &maxOpenFork, openForks)
}
}
pageData.RecentSlotCount = uint64(blockCount)

}

func buildIndexPageSlotGraph(pageData *models.IndexPageData, slotData *models.IndexPageDataSlots, maxOpenFork *int, openForks map[int][]byte) {
// fork tree
var forkGraphIdx int = -1
var freeForkIdx int = -1
getForkGraph := func(slotData *models.IndexPageDataSlots, forkIdx int) *models.IndexPageDataForkGraph {
forkGraph := &models.IndexPageDataForkGraph{}
graphCount := len(slotData.ForkGraph)
if graphCount > forkIdx {
forkGraph = slotData.ForkGraph[forkIdx]
} else {
for graphCount <= forkIdx {
forkGraph = &models.IndexPageDataForkGraph{
Index: graphCount,
Left: 10 + (graphCount * 20),
Tiles: map[string]bool{},
}
slotData.ForkGraph = append(slotData.ForkGraph, forkGraph)
graphCount++
}
}
return forkGraph
}

for forkIdx := 0; forkIdx < *maxOpenFork; forkIdx++ {
forkGraph := getForkGraph(slotData, forkIdx)
if openForks[forkIdx] == nil {
if freeForkIdx == -1 {
freeForkIdx = forkIdx
}
continue
} else {
forkGraph.Tiles["vline"] = true
if bytes.Equal(openForks[forkIdx], slotData.BlockRoot) {
if forkGraphIdx != -1 {
continue
}
forkGraphIdx = forkIdx
openForks[forkIdx] = slotData.ParentRoot
forkGraph.Block = true
for targetIdx := forkIdx + 1; targetIdx < *maxOpenFork; targetIdx++ {
if openForks[targetIdx] == nil || !bytes.Equal(openForks[targetIdx], slotData.BlockRoot) {
continue
}
for idx := forkIdx + 1; idx <= targetIdx; idx++ {
splitGraph := getForkGraph(slotData, idx)
if idx == targetIdx {
splitGraph.Tiles["tline"] = true
splitGraph.Tiles["lline"] = true
splitGraph.Tiles["fork"] = true
} else {
splitGraph.Tiles["hline"] = true
}
}
forkGraph.Tiles["rline"] = true
openForks[targetIdx] = nil
}
}
}
}
if forkGraphIdx == -1 && slotData.Status > 0 {
// fork head
if freeForkIdx == -1 {
freeForkIdx = *maxOpenFork
*maxOpenFork++
}
openForks[freeForkIdx] = slotData.ParentRoot
forkGraph := getForkGraph(slotData, freeForkIdx)
forkGraph.Block = true
forkGraph.Tiles["bline"] = true
}
}
27 changes: 25 additions & 2 deletions templates/index/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,38 @@
{{ template "networkOverview" . }}
<div class="row">
<div class="col-lg-6 mt-3 pr-lg-2">
{{ template "recentEpochs" . }}
<div class="startpage-panel">
{{ template "recentEpochs" . }}
</div>
<div class="startpage-panel">
{{ template "recentBlocks" . }}
</div>
</div>
<div class="col-lg-6 mt-3 pl-lg-2">
{{ template "recentBlocks" . }}
<div class="startpage-panel">
{{ template "recentSlots" . }}
</div>
</div>
</div>
</div>
{{ end }}
{{ define "js" }}
{{ end }}
{{ define "css" }}
<link rel="stylesheet" href="/css/forkgraph.css" />
<style>
#recent-epochs, #recent-blocks, #recent-slots {
margin-bottom: 0;
}
.startpage-panel {
margin-bottom: 30px;
}
.startpage-panel .card-header {
padding-top: 2px;
padding-bottom: 2px;
}
.startpage-panel .card-header i {
margin-right: 5px;
}
</style>
{{ end }}
6 changes: 3 additions & 3 deletions templates/index/recentBlocks.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{{ define "recentBlocks" }}
<div class="card">
<div class="card-header">
<h3 class="card-title d-flex justify-content-between align-items-center" style="margin: .5rem 0;">
<h5 class="card-title d-flex justify-content-between align-items-center" style="margin: .4rem 0;">
<span><i class="fa fa-cubes"></i> Most recent blocks</span>
<a class="btn btn-primary btn-sm float-right text-white" href="/slots">View more</a>
</h3>
</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
Expand All @@ -25,7 +25,7 @@ <h3 class="card-title d-flex justify-content-between align-items-center" style="
<tr>
<td><a href="/epoch/{{ $block.Epoch }}">{{ formatAddCommas $block.Epoch }}</a></td>
{{ if eq .Status 2 }}
<td><a href="/slot/{{ $block.BlockRoot }}">{{ formatAddCommas $block.Slot }}</a></td>
<td><a href="/slot/0x{{ printf "%x" $block.BlockRoot }}">{{ formatAddCommas $block.Slot }}</a></td>
{{ else }}
<td><a href="/slot/{{ $block.Slot }}">{{ formatAddCommas $block.Slot }}</a></td>
{{ end }}
Expand Down
4 changes: 2 additions & 2 deletions templates/index/recentEpochs.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{{ define "recentEpochs" }}
<div class="card">
<div class="card-header">
<h3 class="card-title d-flex justify-content-between align-items-center" style="margin: .5rem 0;">
<h5 class="card-title d-flex justify-content-between align-items-center" style="margin: .4rem 0;">
<span> <i class="fas fa-history"></i> Most recent epochs </span>
<a class="btn btn-primary btn-sm float-right text-white" href="/epochs">View more</a>
</h3>
</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
Expand Down
82 changes: 82 additions & 0 deletions templates/index/recentSlots.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{{ define "recentSlots" }}
<div class="card">
<div class="card-header">
<h5 class="card-title d-flex justify-content-between align-items-center" style="margin: .4rem 0;">
<span><i class="fa fa-cubes"></i> Most recent slots</span>
<a class="btn btn-primary btn-sm float-right text-white" href="/slots">View more</a>
</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-nobr" id="recent-slots">
<thead>
<tr>
<th>Chain</th>
<th>Epoch</th>
<th>Slot</th>
<th>Status</th>
<th data-timecol="duration">Time</th>
<th>Proposer</th>
</tr>
</thead>
{{ if gt .RecentSlotCount 0 }}
<tbody>
{{ $treeWidth := .ForkTreeWidth }}
{{ range $i, $slot := .RecentSlots }}
<tr>
<td class="graph-container" style="width: {{ $treeWidth }}px;">
{{ range $j, $graph := $slot.ForkGraph }}
<div class="graph-fork" data-index="{{ $graph.Index }}" style="left: {{ $graph.Left }}px;">
{{- range $tile, $val := $graph.Tiles -}}
<div class="graph-layer graph-layer-{{ $tile }}"></div>
{{- end -}}
{{- if $graph.Block }}
<div class="graph-layer graph-layer-block">
<i class="fas fa-circle"></i>
</div>
{{ end -}}
</div>
{{ end }}
</td>
<td><a href="/epoch/{{ $slot.Epoch }}">{{ formatAddCommas $slot.Epoch }}</a></td>
{{ if eq .Status 2 }}
<td><a href="/slot/0x{{ printf "%x" $slot.BlockRoot }}">{{ formatAddCommas $slot.Slot }}</a></td>
{{ else }}
<td><a href="/slot/{{ $slot.Slot }}">{{ formatAddCommas $slot.Slot }}</a></td>
{{ end }}
<td>
{{ if eq $slot.Slot 0 }}
<span class="badge rounded-pill text-bg-info">Genesis</span>
{{ else if eq .Status 0 }}
<span class="badge rounded-pill text-bg-warning">Missed</span>
{{ else if eq .Status 1 }}
<span class="badge rounded-pill text-bg-success">Proposed</span>
{{ else if eq .Status 2 }}
<span class="badge rounded-pill text-bg-info">Missed (Orphaned)</span>
{{ else }}
<span class="badge rounded-pill text-bg-dark">Unknown</span>
{{ end }}
</td>
<td data-timer="{{ $slot.Ts.Unix }}"><span data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="{{ $slot.Ts }}">{{ formatRecentTimeShort $slot.Ts }}</span></td>
<td>{{ formatValidator $slot.Proposer $slot.ProposerName }}</td>
</tr>
{{ end }}
</tbody>
{{ else }}
<tbody>
<tr style="height: 430px;">
<td></td>
<td style="vertical-align: middle;" colspan="4">
<div class="img-fluid mx-auto p-3 d-flex align-items-center" style="max-height: 400px; width: auto; overflow: hidden;">
{{ template "timeline_svg" }}
</div>
</td>
<td></td>
</tr>
</tbody>
{{ end }}
</table>
</div>
</div>
</div>
{{ end }}
2 changes: 1 addition & 1 deletion templates/slots/slots.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ <h1 class="h4 mb-1 mb-md-0"><i class="fas fa-cube mx-2"></i>Slots</h1>
<thead>
<tr>
{{ if .ShowForkTree -}}
<th>Graph</th>
<th>Chain</th>
{{- end }}
<th>Epoch</th>
<th>Slot</th>
Expand Down
Loading

0 comments on commit 3461810

Please sign in to comment.