Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions .hack/devnet/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,26 @@ fi
## Generate Dora config
ENCLAVE_UUID=$(kurtosis enclave inspect "$ENCLAVE_NAME" --full-uuids | grep 'UUID:' | awk '{print $2}')

# Local kurtosis buildoor container, when present, overrides the network-derived URL.
BUILDOOR_CONTAINER=$(docker ps -aq -f "label=kurtosis_enclave_uuid=$ENCLAVE_UUID" \
# Local kurtosis buildoor containers, when present, override the network-derived URL.
# Matches both the legacy shared "buildoor" service and per-participant instances
# named "buildoor-<cl>-<el>-<n>" (ethereum-package buildoor_params.instances).
BUILDOOR_CONTAINERS=$(docker ps -aq -f "label=kurtosis_enclave_uuid=$ENCLAVE_UUID" \
-f "label=com.kurtosistech.app-id=kurtosis" \
-f "label=com.kurtosistech.id=buildoor" | head -1)
if [ -n "$BUILDOOR_CONTAINER" ]; then
BUILDOOR_PORT=$(docker inspect --format='{{ (index (index .NetworkSettings.Ports "8080/tcp") 0).HostPort }}' "$BUILDOOR_CONTAINER" 2>/dev/null)
# kurtosis service name (e.g. "buildoor") so dora shows it instead of the forwarded IP:port
BUILDOOR_NAME=$(docker inspect --format='{{ index .Config.Labels "kurtosis_service_name" }}' "$BUILDOOR_CONTAINER" 2>/dev/null)
-f "name=buildoor")
BUILDOOR_URLS=""
for container in $BUILDOOR_CONTAINERS; do
BUILDOOR_PORT=$(docker inspect --format='{{ (index (index .NetworkSettings.Ports "8080/tcp") 0).HostPort }}' "$container" 2>/dev/null)
if [ -z "$BUILDOOR_PORT" ]; then
continue
fi
# kurtosis service name (e.g. "buildoor-lighthouse-geth-1") so dora shows it instead of the forwarded IP:port
BUILDOOR_NAME=$(docker inspect --format='{{ index .Config.Labels "com.kurtosistech.id" }}' "$container" 2>/dev/null)
if [ -z "$BUILDOOR_NAME" ]; then BUILDOOR_NAME="buildoor"; fi
if [ -n "$BUILDOOR_PORT" ]; then
BUILDOOR_CONFIG="buildoorUrls:
BUILDOOR_URLS="${BUILDOOR_URLS}
- \"${BUILDOOR_NAME}|http://127.0.0.1:${BUILDOOR_PORT}\""
fi
done
if [ -n "$BUILDOOR_URLS" ]; then
BUILDOOR_CONFIG="buildoorUrls:${BUILDOOR_URLS}"
fi

BEACON_NODES=$(docker ps -aq -f "label=kurtosis_enclave_uuid=$ENCLAVE_UUID" \
Expand Down
14 changes: 8 additions & 6 deletions handlers/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,15 +399,17 @@ func buildIndexPageRecentEpochsData(ctx context.Context, pageData *models.IndexP

// resolveBuildSource maps a db builder index (-1 = self-built) to the model fields
// driving the proposer build-source icon (house / hard-hat), matching the slots page.
func resolveBuildSource(dbBuilderIndex int64) (hasBuilder bool, builderIndex uint64, builderURL string) {
func resolveBuildSource(dbBuilderIndex int64) (hasBuilder bool, builderIndex uint64, builderName string, builderURL string) {
if dbBuilderIndex == -1 {
return true, math.MaxUint64, ""
return true, math.MaxUint64, "", ""
}
if dbBuilderIndex < 0 {
return false, 0, ""
return false, 0, "", ""
}
builderIndex = uint64(dbBuilderIndex)
return true, builderIndex, services.GlobalBeaconService.GetBuilderURL(builderIndex)
builderName = services.GlobalBeaconService.GetValidatorName(builderIndex | services.BuilderIndexFlag)
builderURL = services.GlobalBeaconService.GetBuilderURL(builderIndex)
return true, builderIndex, builderName, builderURL
}

func buildIndexPageRecentBlocksData(ctx context.Context, pageData *models.IndexPageData, recentBlockCount int) {
Expand Down Expand Up @@ -447,7 +449,7 @@ func buildIndexPageRecentBlocksData(ctx context.Context, pageData *models.IndexP
PayloadStatus: uint8(payloadStatus),
BlockRoot: blockData.Root,
}
blockModel.HasBuilder, blockModel.BuilderIndex, blockModel.BuilderURL = resolveBuildSource(blockData.BuilderIndex)
blockModel.HasBuilder, blockModel.BuilderIndex, blockModel.BuilderName, blockModel.BuilderURL = resolveBuildSource(blockData.BuilderIndex)
if blockData.EthBlockNumber != nil {
blockModel.WithEthBlock = true
blockModel.EthBlock = *blockData.EthBlockNumber
Expand Down Expand Up @@ -507,7 +509,7 @@ func buildIndexPageRecentSlotsData(ctx context.Context, pageData *models.IndexPa
ForkGraph: make([]*models.IndexPageDataForkGraph, 0),
}
if dbSlot.Status > 0 {
slotData.HasBuilder, slotData.BuilderIndex, slotData.BuilderURL = resolveBuildSource(dbSlot.BuilderIndex)
slotData.HasBuilder, slotData.BuilderIndex, slotData.BuilderName, slotData.BuilderURL = resolveBuildSource(dbSlot.BuilderIndex)
}
pageData.RecentSlots = append(pageData.RecentSlots, slotData)
blockCount++
Expand Down
12 changes: 4 additions & 8 deletions static/js/page-index.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@

// mirrors utils.FormatProposerWithBuildSource: house = self-built payload,
// hard-hat (linking to the builder) = builder-built payload
function formatProposerWithBuildSource(status, idx, name, hasBuilder, builderIdx, builderUrl) {
function formatProposerWithBuildSource(status, idx, name, hasBuilder, builderIdx, builderName) {
if(status == 0 || idx >= 9223372036854775807n) {
if(idx >= 9223372036854775807n) {
return `<span class="validator-label validator-index">unknown</span>`;
Expand All @@ -246,13 +246,9 @@
if(builderIdx >= 18446744073709551615n) {
iconHtml = `<i class="fas fa-house mr-2" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Self-built payload"></i>`;
} else {
var builderLink = "/builder/" + builderIdx;
var external = "";
if(builderUrl) {
builderLink = escapeHtml(builderUrl);
external = ` target="_blank" rel="noopener noreferrer"`;
}
iconHtml = `<a href="` + builderLink + `"` + external + ` class="builder-source-link" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Builder-built payload (builder ` + builderIdx + `)"><i class="fas fa-hard-hat mr-2"></i></a>`;
// the icon links to the builder details page; the tooltip names the builder when known
var builderLabel = builderName ? escapeHtml(builderName) + " (" + builderIdx + ")" : "builder " + builderIdx;
iconHtml = `<a href="/builder/` + builderIdx + `" class="builder-source-link" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Builder-built payload by ` + builderLabel + `"><i class="fas fa-hard-hat mr-2"></i></a>`;
}

if(name != "") {
Expand Down
2 changes: 1 addition & 1 deletion templates/blocks/blocks.html
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ <h1 class="h4 mb-1 mb-md-0"><i class="fas fa-cube mx-2"></i>Blocks</h1>
{{ end }}
{{ if $g.DisplayTime }}<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>{{ end }}
{{ if $slot.Synchronized }}
{{ if $g.DisplayProposer }}<td>{{ if gt $slot.Slot 0 }}{{ formatProposerWithBuildSource $slot.Status $slot.Proposer $slot.ProposerName $slot.HasBuilder $slot.BuilderIndex $slot.BuilderURL }}{{ end }}</td>{{ end }}
{{ if $g.DisplayProposer }}<td>{{ if gt $slot.Slot 0 }}{{ formatProposerWithBuildSource $slot.Status $slot.Proposer $slot.ProposerName $slot.HasBuilder $slot.BuilderIndex $slot.BuilderName }}{{ end }}</td>{{ end }}
{{ if $g.DisplayAttestations }}<td class="d-none d-md-table-cell">{{ if not (eq $slot.Status 0) }}{{ $slot.AttestationCount }}{{ end }}</td>{{ end }}
{{ if $g.DisplayDeposits }}<td>{{ if not (eq $slot.Status 0) }}{{ $slot.DepositCount }} / {{ $slot.ExitCount }}{{ end }}</td>{{ end }}
{{ if $g.DisplaySlashings }}<td>{{ if not (eq $slot.Status 0) }}{{ $slot.ProposerSlashingCount }} / {{ $slot.AttesterSlashingCount }}{{ end }}</td>{{ end }}
Expand Down
4 changes: 2 additions & 2 deletions templates/index/recentBlocks.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ <h5 class="card-title d-flex justify-content-between align-items-center" style="
<td data-bind="attr: {'data-timer': $root.unixtime(ts)}">
<span data-bs-toggle="tooltip" data-bs-placement="top" data-bind="attr: {'data-bs-title': $root.timestamp(ts)}, text: $root.formatRecentTimeShort(ts)"></span>
</td>
<td data-bind="html: $root.formatProposerWithBuildSource(status, proposer, proposer_name, has_builder, builder_index, builder_url)"></td>
<td data-bind="html: $root.formatProposerWithBuildSource(status, proposer, proposer_name, has_builder, builder_index, builder_name)"></td>
</tr>
{{ html "<!-- /ko -->" }}
{{ html "<!-- ko if: blocks().length == 0 -->" }}
Expand Down Expand Up @@ -82,7 +82,7 @@ <h5 class="card-title d-flex justify-content-between align-items-center" style="
{{ end }}
</td>
<td data-timer="{{ $block.Ts.Unix }}"><span data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="{{ $block.Ts }}">{{ formatRecentTimeShort $block.Ts }}</span></td>
<td>{{ formatProposerWithBuildSource $block.Status $block.Proposer $block.ProposerName $block.HasBuilder $block.BuilderIndex $block.BuilderURL }}</td>
<td>{{ formatProposerWithBuildSource $block.Status $block.Proposer $block.ProposerName $block.HasBuilder $block.BuilderIndex $block.BuilderName }}</td>
</tr>
{{ end }}
{{ else }}
Expand Down
4 changes: 2 additions & 2 deletions templates/index/recentSlots.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ <h5 class="card-title d-flex justify-content-between align-items-center" style="
</td>
<td>
<span data-bind="if: slot > 0">
<span data-bind="html: $root.formatProposerWithBuildSource(status, proposer, proposer_name, has_builder, builder_index, builder_url)"></span>
<span data-bind="html: $root.formatProposerWithBuildSource(status, proposer, proposer_name, has_builder, builder_index, builder_name)"></span>
</span>
</td>
</tr>
Expand Down Expand Up @@ -109,7 +109,7 @@ <h5 class="card-title d-flex justify-content-between align-items-center" style="
{{ 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>{{ if gt $slot.Slot 0 }}{{ formatProposerWithBuildSource $slot.Status $slot.Proposer $slot.ProposerName $slot.HasBuilder $slot.BuilderIndex $slot.BuilderURL }}{{ end }}</td>
<td>{{ if gt $slot.Slot 0 }}{{ formatProposerWithBuildSource $slot.Status $slot.Proposer $slot.ProposerName $slot.HasBuilder $slot.BuilderIndex $slot.BuilderName }}{{ end }}</td>
</tr>
{{ end }}
{{ else }}
Expand Down
2 changes: 1 addition & 1 deletion templates/slots/slots.html
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ <h1 class="h4 mb-1 mb-md-0"><i class="fas fa-table-list mx-2"></i>Slots</h1>
{{ end }}
{{ if $g.DisplayTime }}<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>{{ end }}
{{ if $slot.Synchronized }}
{{ if $g.DisplayProposer }}<td>{{ if gt $slot.Slot 0 }}{{ formatProposerWithBuildSource $slot.Status $slot.Proposer $slot.ProposerName $slot.HasBuilder $slot.BuilderIndex $slot.BuilderURL }}{{ end }}</td>{{ end }}
{{ if $g.DisplayProposer }}<td>{{ if gt $slot.Slot 0 }}{{ formatProposerWithBuildSource $slot.Status $slot.Proposer $slot.ProposerName $slot.HasBuilder $slot.BuilderIndex $slot.BuilderName }}{{ end }}</td>{{ end }}
{{ if $g.DisplayAttestations }}<td class="d-none d-md-table-cell">{{ if not (eq $slot.Status 0) }}{{ $slot.AttestationCount }}{{ end }}</td>{{ end }}
{{ if $g.DisplayDeposits }}<td>{{ if not (eq $slot.Status 0) }}{{ $slot.DepositCount }} / {{ $slot.ExitCount }}{{ end }}</td>{{ end }}
{{ if $g.DisplaySlashings }}<td>{{ if not (eq $slot.Status 0) }}{{ $slot.ProposerSlashingCount }} / {{ $slot.AttesterSlashingCount }}{{ end }}</td>{{ end }}
Expand Down
2 changes: 1 addition & 1 deletion templates/slots_filtered/slots_filtered.html
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ <h1 class="h4 mb-1 mb-md-0"><i class="fas fa-cube mx-2"></i>Filtered Slots</h1>
<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>
{{- end }}
{{- if $g.DisplayProposer }}
<td>{{ if gt $slot.Slot 0 }}{{ formatProposerWithBuildSource $slot.Status $slot.Proposer $slot.ProposerName $slot.HasBuilder $slot.BuilderIndex $slot.BuilderURL }}{{ end }}</td>
<td>{{ if gt $slot.Slot 0 }}{{ formatProposerWithBuildSource $slot.Status $slot.Proposer $slot.ProposerName $slot.HasBuilder $slot.BuilderIndex $slot.BuilderName }}{{ end }}</td>
{{- end }}
{{- if $g.DisplayAttestations }}
<td class="d-none d-md-table-cell">{{ if not (eq $slot.Status 0) }}{{ $slot.AttestationCount }}{{ end }}</td>
Expand Down
2 changes: 2 additions & 0 deletions types/models/indexPage.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ type IndexPageDataBlocks struct {
PayloadStatus uint8 `json:"payload_status"`
HasBuilder bool `json:"has_builder"`
BuilderIndex uint64 `json:"builder_index"`
BuilderName string `json:"builder_name"`
BuilderURL string `json:"builder_url"`
BlockRoot []byte `json:"block_root" ssz-size:"32"`
}
Expand All @@ -100,6 +101,7 @@ type IndexPageDataSlots struct {
PayloadStatus uint8 `json:"payload_status"`
HasBuilder bool `json:"has_builder"`
BuilderIndex uint64 `json:"builder_index"`
BuilderName string `json:"builder_name"`
BuilderURL string `json:"builder_url"`
Safe bool `json:"safe"`
BlockRoot []byte `json:"block_root" ssz-size:"32"`
Expand Down
35 changes: 19 additions & 16 deletions utils/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -894,7 +894,7 @@ func formatValidator(index uint64, name string, icon string, withIndex bool) tem
//
// Scheduled/missing slots (status == 0) and unknown proposers have no
// determinable build source and are rendered without any leading icon.
func FormatProposerWithBuildSource(status uint8, index uint64, name string, hasBuilder bool, builderIndex uint64, builderURL string) template.HTML {
func FormatProposerWithBuildSource(status uint8, index uint64, name string, hasBuilder bool, builderIndex uint64, builderName string) template.HTML {
if status == 0 || index == math.MaxInt64 {
if index == math.MaxInt64 {
return template.HTML(`<span class="validator-label validator-index">unknown</span>`)
Expand All @@ -914,15 +914,9 @@ func FormatProposerWithBuildSource(status uint8, index uint64, name string, hasB
// self-built payload
iconHTML = `<i class="fas fa-house mr-2" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Self-built payload"></i>`
} else {
// builder-built payload - link the icon to the builder URL when known,
// otherwise to the internal builder page
builderLink := fmt.Sprintf("/builder/%v", builderIndex)
external := ""
if builderURL != "" {
builderLink = html.EscapeString(builderURL)
external = ` target="_blank" rel="noopener noreferrer"`
}
iconHTML = fmt.Sprintf(`<a href="%v"%v class="builder-source-link" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Builder-built payload (builder %v)"><i class="fas fa-hard-hat mr-2"></i></a>`, builderLink, external, builderIndex)
// builder-built payload - the icon links to the builder details page and
// names the builder in the tooltip when the buildoor inventory knows it
iconHTML = fmt.Sprintf(`<a href="/builder/%v" class="builder-source-link" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Builder-built payload by %v"><i class="fas fa-hard-hat mr-2"></i></a>`, builderIndex, html.EscapeString(builderTooltipLabel(builderIndex, builderName)))
}

nameLabel := fmt.Sprintf("%v", index)
Expand All @@ -934,6 +928,15 @@ func FormatProposerWithBuildSource(status uint8, index uint64, name string, hasB
return template.HTML(fmt.Sprintf(`<span class="validator-label %v">%v <a href="/validator/%v">%v</a></span>`, labelClass, iconHTML, index, nameLabel))
}

// builderTooltipLabel renders "name (index)" when the builder has a known name and
// "builder <index>" otherwise.
func builderTooltipLabel(index uint64, name string) string {
if name != "" {
return fmt.Sprintf("%v (%v)", name, index)
}
return fmt.Sprintf("builder %v", index)
}

func FormatValidatorNameWithIndex(index uint64, name string) template.HTML {
if name != "" {
return template.HTML(fmt.Sprintf("<span class=\"validator-label validator-name\">%v (%v)</span>", html.EscapeString(name), index))
Expand Down Expand Up @@ -970,11 +973,11 @@ func formatBuilder(index uint64, name string, externalURL string, icon string, w
return template.HTML("<span class=\"builder-label builder-index\"><i class=\"fas fa-house mr-2\"></i> Self-built</span>")
}

// When the builder exposes an external URL, its "name" is often the full API URL, which is
// far too long for the table columns. Collapse it to the hyperlinked builder index and show
// the full API URL on hover instead of printing it inline.
// The label always links to the builder details page. When the buildoor inventory knows the
// instance's API URL it is shown on hover only, never printed inline or linked to.
tooltip := ""
if externalURL != "" {
return template.HTML(fmt.Sprintf("<span class=\"builder-label builder-index\"><i class=\"fas %v\"></i> <a href=\"/builder/%v\" data-bs-toggle=\"tooltip\" data-bs-placement=\"top\" data-bs-title=\"%v\">%v</a></span>", icon, index, html.EscapeString(externalURL), index))
tooltip = fmt.Sprintf(" data-bs-toggle=\"tooltip\" data-bs-placement=\"top\" data-bs-title=\"%v\"", html.EscapeString(externalURL))
}

if name != "" {
Expand All @@ -984,9 +987,9 @@ func formatBuilder(index uint64, name string, externalURL string, icon string, w
} else {
nameLabel = html.EscapeString(name)
}
return template.HTML(fmt.Sprintf("<span class=\"builder-label builder-name\"><i class=\"fas %v\"></i> <a href=\"/builder/%v\">%v</a></span>", icon, index, nameLabel))
return template.HTML(fmt.Sprintf("<span class=\"builder-label builder-name\"><i class=\"fas %v\"></i> <a href=\"/builder/%v\"%v>%v</a></span>", icon, index, tooltip, nameLabel))
}
return template.HTML(fmt.Sprintf("<span class=\"builder-label builder-index\"><i class=\"fas %v\"></i> <a href=\"/builder/%v\">%v</a></span>", icon, index, index))
return template.HTML(fmt.Sprintf("<span class=\"builder-label builder-index\"><i class=\"fas %v\"></i> <a href=\"/builder/%v\"%v>%v</a></span>", icon, index, tooltip, index))
}

func FormatRecentTimeShort(ts time.Time) template.HTML {
Expand Down