Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
57fc0fb
EIP-8282 decoupled builder deposits & exits
pk910 Jun 17, 2026
50c2deb
show builder requests and existing execution requests on a new combin…
pk910 Jun 17, 2026
543baf9
fix deposit index matching for eip-8282 behaviour
pk910 Jun 17, 2026
613fd21
add submission pages for builder operations
pk910 Jun 17, 2026
6a2224a
bump go-eth2-client
pk910 Jun 19, 2026
abbd103
fix el client readiness checks
pk910 Jun 19, 2026
2496721
various fixes for builder deposits & builder details UI
pk910 Jun 19, 2026
eb72c7d
split builder & validator pubkey and check builder indexes for index …
pk910 Jun 19, 2026
ab71256
build(deps): bump the ui-package-dependencies group across 1 director…
dependabot[bot] Jun 15, 2026
2048c81
feat(slots): show payload build source icon in proposer column
barnabasbusa Jun 19, 2026
360502e
fix(slots): no build-source icon for scheduled/missing slots
barnabasbusa Jun 19, 2026
10bd1cf
fix(slots): no proposer icon for unknown/missing payloads
barnabasbusa Jun 19, 2026
84d88ed
feat(blocks): show payload build source icon in proposer column
barnabasbusa Jun 19, 2026
0048a05
Merge pull request #747 from ethpandaops/bbusa/slots-proposer-build-s…
barnabasbusa Jun 19, 2026
9c4798f
add gloas fork transition to state transition
pk910 Jun 19, 2026
f46df70
bump go-eth2-client
pk910 Jun 20, 2026
20ee5da
bump dynamic-ssz
pk910 Jun 21, 2026
ee7b9a1
show early-onboarded builder deposits
pk910 Jun 21, 2026
23c519d
display early builder deposits
pk910 Jun 22, 2026
aa39937
Merge branch 'master' into glamsterdam-devnet-6
barnabasbusa Jun 22, 2026
4915cd2
reduce log verbosity for page call errors
pk910 Jun 22, 2026
38752ad
fix cache issue with value types
pk910 Jun 22, 2026
80c8af3
fix `GetHighestElBlockNumber` for blocks without payloads
pk910 Jun 23, 2026
6608e1e
`go fmt`
pk910 Jun 23, 2026
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
17 changes: 16 additions & 1 deletion blockdb/types/execdata_sections_ssz.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 7 additions & 5 deletions clients/consensus/chainspec.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,11 +228,13 @@ type ChainSpecPreset struct {
NumberOfColumns *uint64 `yaml:"NUMBER_OF_COLUMNS" check-if-fork:"FuluForkEpoch"`

// Gloas
PtcSize uint64 `yaml:"PTC_SIZE" check-if-fork:"GloasForkEpoch"`
MaxPayloadAttestations uint64 `yaml:"MAX_PAYLOAD_ATTESTATIONS" check-if-fork:"GloasForkEpoch"`
BuilderRegistryLimit uint64 `yaml:"BUILDER_REGISTRY_LIMIT" check-if-fork:"GloasForkEpoch"`
BuilderPendingWithdrawalsLimit uint64 `yaml:"BUILDER_PENDING_WITHDRAWALS_LIMIT" check-if-fork:"GloasForkEpoch"`
MaxBuildersPerWithdrawalsSweep uint64 `yaml:"MAX_BUILDERS_PER_WITHDRAWALS_SWEEP" check-if-fork:"GloasForkEpoch"`
PtcSize uint64 `yaml:"PTC_SIZE" check-if-fork:"GloasForkEpoch"`
MaxPayloadAttestations uint64 `yaml:"MAX_PAYLOAD_ATTESTATIONS" check-if-fork:"GloasForkEpoch"`
BuilderRegistryLimit uint64 `yaml:"BUILDER_REGISTRY_LIMIT" check-if-fork:"GloasForkEpoch"`
BuilderPendingWithdrawalsLimit uint64 `yaml:"BUILDER_PENDING_WITHDRAWALS_LIMIT" check-if-fork:"GloasForkEpoch"`
MaxBuildersPerWithdrawalsSweep uint64 `yaml:"MAX_BUILDERS_PER_WITHDRAWALS_SWEEP" check-if-fork:"GloasForkEpoch"`
MaxBuilderDepositRequestsPerPayload uint64 `yaml:"MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD" check-if-fork:"GloasForkEpoch"`
MaxBuilderExitRequestsPerPayload uint64 `yaml:"MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD" check-if-fork:"GloasForkEpoch"`

// Heze
InclusionListCommitteeSize uint64 `yaml:"INCLUSION_LIST_COMMITTEE_SIZE" check-if-fork:"HezeForkEpoch"`
Expand Down
10 changes: 6 additions & 4 deletions clients/execution/chainstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ import (
)

var DefaultSystemContractAddresses = map[string]common.Address{
rpc.ConsolidationRequestContract: common.HexToAddress("0x0000BBdDc7CE488642fb579F8B00f3a590007251"),
rpc.WithdrawalRequestContract: common.HexToAddress("0x00000961Ef480Eb55e80D19ad83579A64c007002"),
rpc.BeaconRootsContract: common.HexToAddress("0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02"),
rpc.HistoryStorageContract: common.HexToAddress("0x0000F90827F1C53a10cb7A02335B175320002935"),
rpc.ConsolidationRequestContract: common.HexToAddress("0x0000BBdDc7CE488642fb579F8B00f3a590007251"),
rpc.WithdrawalRequestContract: common.HexToAddress("0x00000961Ef480Eb55e80D19ad83579A64c007002"),
rpc.BuilderDepositRequestContract: common.HexToAddress("0x0000884d2AA32eAa155F59A2f24eFa73D9008282"),
rpc.BuilderExitRequestContract: common.HexToAddress("0x000014574A74c805590AFF9499fc7A690f008282"),
rpc.BeaconRootsContract: common.HexToAddress("0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02"),
rpc.HistoryStorageContract: common.HexToAddress("0x0000F90827F1C53a10cb7A02335B175320002935"),
}

type ChainState struct {
Expand Down
12 changes: 4 additions & 8 deletions clients/execution/clientlogic.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,20 +270,16 @@ func (client *Client) pollClientHead() error {
ctx, cancel := context.WithTimeout(client.clientCtx, 10*time.Second)
defer cancel()

latestHeader, err := client.rpcClient.GetLatestHeader(ctx)
headNumber, headHash, err := client.rpcClient.GetLatestHead(ctx)
if err != nil {
return fmt.Errorf("could not get latest header: %v", err)
}

if latestHeader == nil {
return fmt.Errorf("could not find latest header")
return fmt.Errorf("could not get latest head: %v", err)
}

client.headMutex.Lock()
defer client.headMutex.Unlock()

client.headNumber = latestHeader.Number.Uint64()
client.headHash = latestHeader.Hash()
client.headNumber = headNumber
client.headHash = headHash

return nil
}
Expand Down
12 changes: 7 additions & 5 deletions clients/execution/rpc/ethconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import (
)

const (
DepositContract = "DEPOSIT_CONTRACT_ADDRESS"
ConsolidationRequestContract = "CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS"
WithdrawalRequestContract = "WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS"
BeaconRootsContract = "BEACON_ROOTS_ADDRESS"
HistoryStorageContract = "HISTORY_STORAGE_ADDRESS"
DepositContract = "DEPOSIT_CONTRACT_ADDRESS"
ConsolidationRequestContract = "CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS"
WithdrawalRequestContract = "WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS"
BuilderDepositRequestContract = "BUILDER_DEPOSIT_REQUEST_PREDEPLOY_ADDRESS"
BuilderExitRequestContract = "BUILDER_EXIT_REQUEST_PREDEPLOY_ADDRESS"
BeaconRootsContract = "BEACON_ROOTS_ADDRESS"
HistoryStorageContract = "HISTORY_STORAGE_ADDRESS"
)

type EthConfigFork struct {
Expand Down
22 changes: 18 additions & 4 deletions clients/execution/rpc/executionapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strconv"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/p2p"
Expand Down Expand Up @@ -192,13 +193,26 @@ func (ec *ExecutionClient) UninstallBlockFilter(ctx context.Context, filterId Bl
return result, err
}

func (ec *ExecutionClient) GetLatestHeader(ctx context.Context) (*types.Header, error) {
header, err := ec.ethClient.HeaderByNumber(ctx, nil)
// GetLatestHead returns the latest block's number and hash as reported by the
// execution node. The hash is read from the node's response rather than
// recomputed from the header locally, which would be wrong whenever the header
// carries fields the local go-ethereum types do not know about.
func (ec *ExecutionClient) GetLatestHead(ctx context.Context) (uint64, common.Hash, error) {
var head struct {
Number *hexutil.Big `json:"number"`
Hash common.Hash `json:"hash"`
}

err := ec.rpcClient.CallContext(ctx, &head, "eth_getBlockByNumber", "latest", false)
if err != nil {
return nil, err
return 0, common.Hash{}, err
}

return header, nil
if head.Number == nil {
return 0, common.Hash{}, fmt.Errorf("no latest block returned")
}

return head.Number.ToInt().Uint64(), head.Hash, nil
}

func (ec *ExecutionClient) GetLatestBlock(ctx context.Context) (*types.Block, error) {
Expand Down
4 changes: 4 additions & 0 deletions cmd/dora-explorer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,10 @@ func startFrontend(router *mux.Router) {
router.HandleFunc("/validator/{idxOrPubKey}", handlers.Validator).Methods("GET")
router.HandleFunc("/validator/{index}/slots", handlers.ValidatorSlots).Methods("GET")
router.HandleFunc("/builders", handlers.Builders).Methods("GET")
router.HandleFunc("/builders/deposits", handlers.BuilderDeposits).Methods("GET")
router.HandleFunc("/builders/exits", handlers.BuilderExits).Methods("GET")
router.HandleFunc("/builders/submit_deposit", handlers.SubmitBuilderDeposit).Methods("GET")
router.HandleFunc("/builders/submit_exit", handlers.SubmitBuilderExit).Methods("GET")
router.HandleFunc("/builder/{idxOrPubKey}", handlers.BuilderDetail).Methods("GET")

if utils.Config.Frontend.Pprof {
Expand Down
192 changes: 192 additions & 0 deletions db/builder_deposit_request_txs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
package db

import (
"context"
"fmt"
"strings"

"github.com/ethpandaops/dora/dbtypes"
"github.com/jmoiron/sqlx"
)

func InsertBuilderDepositTxs(ctx context.Context, tx *sqlx.Tx, depositTxs []*dbtypes.BuilderDepositTx) error {
var sql strings.Builder
fmt.Fprint(&sql,
EngineQuery(map[dbtypes.DBEngineType]string{
dbtypes.DBEnginePgsql: "INSERT INTO builder_deposit_request_txs ",
dbtypes.DBEngineSqlite: "INSERT OR REPLACE INTO builder_deposit_request_txs ",
}),
"(block_number, block_index, block_time, block_root, fork_id, public_key, withdrawal_credentials, amount, signature, builder_index, tx_hash, tx_sender, tx_target, dequeue_block)",
" VALUES ",
)
argIdx := 0
fieldCount := 14

args := make([]any, len(depositTxs)*fieldCount)
for i, depositTx := range depositTxs {
if i > 0 {
fmt.Fprintf(&sql, ", ")
}
fmt.Fprintf(&sql, "(")
for f := 0; f < fieldCount; f++ {
if f > 0 {
fmt.Fprintf(&sql, ", ")
}
fmt.Fprintf(&sql, "$%v", argIdx+f+1)
}
fmt.Fprintf(&sql, ")")

args[argIdx+0] = depositTx.BlockNumber
args[argIdx+1] = depositTx.BlockIndex
args[argIdx+2] = depositTx.BlockTime
args[argIdx+3] = depositTx.BlockRoot
args[argIdx+4] = depositTx.ForkId
args[argIdx+5] = depositTx.PublicKey
args[argIdx+6] = depositTx.WithdrawalCredentials
args[argIdx+7] = depositTx.Amount
args[argIdx+8] = depositTx.Signature
args[argIdx+9] = depositTx.BuilderIndex
args[argIdx+10] = depositTx.TxHash
args[argIdx+11] = depositTx.TxSender
args[argIdx+12] = depositTx.TxTarget
args[argIdx+13] = depositTx.DequeueBlock
argIdx += fieldCount
}
fmt.Fprint(&sql, EngineQuery(map[dbtypes.DBEngineType]string{
dbtypes.DBEnginePgsql: " ON CONFLICT (block_root, block_index) DO UPDATE SET builder_index = excluded.builder_index, dequeue_block = excluded.dequeue_block, fork_id = excluded.fork_id",
dbtypes.DBEngineSqlite: "",
}))

_, err := tx.ExecContext(ctx, sql.String(), args...)
if err != nil {
return err
}
return nil
}

func GetBuilderDepositTxsByDequeueRange(ctx context.Context, dequeueFirst uint64, dequeueLast uint64) []*dbtypes.BuilderDepositTx {
depositTxs := []*dbtypes.BuilderDepositTx{}

err := ReaderDb.SelectContext(ctx, &depositTxs, `SELECT builder_deposit_request_txs.*
FROM builder_deposit_request_txs
WHERE dequeue_block >= $1 AND dequeue_block <= $2
ORDER BY dequeue_block ASC, block_number ASC, block_index ASC
`, dequeueFirst, dequeueLast)
if err != nil {
logger.Errorf("Error while fetching builder deposit txs: %v", err)
return nil
}

return depositTxs
}

func GetBuilderDepositTxsByTxHashes(ctx context.Context, txHashes [][]byte) []*dbtypes.BuilderDepositTx {
var sql strings.Builder
args := make([]any, len(txHashes))

fmt.Fprint(&sql, `SELECT builder_deposit_request_txs.*
FROM builder_deposit_request_txs
WHERE tx_hash IN (
`)

for idx, txHash := range txHashes {
args[idx] = txHash
}
appendDollarPlaceholders(&sql, 1, len(txHashes), ", ")
fmt.Fprintf(&sql, ")")

depositTxs := []*dbtypes.BuilderDepositTx{}
err := ReaderDb.SelectContext(ctx, &depositTxs, sql.String(), args...)
if err != nil {
logger.Errorf("Error while fetching builder deposit txs: %v", err)
return nil
}

return depositTxs
}

func GetBuilderDepositTxsFiltered(ctx context.Context, offset uint64, limit uint32, filter *dbtypes.BuilderDepositTxFilter) ([]*dbtypes.BuilderDepositTx, uint64, error) {
var sql strings.Builder
args := []interface{}{}
fmt.Fprint(&sql, `
WITH cte AS (
SELECT
block_number, block_index, block_time, block_root, fork_id, public_key, withdrawal_credentials, amount, signature, builder_index, tx_hash, tx_sender, tx_target, dequeue_block
FROM builder_deposit_request_txs
`)

filterOp := "WHERE"
if filter.MinDequeue > 0 {
args = append(args, filter.MinDequeue)
fmt.Fprintf(&sql, " %v dequeue_block >= $%v", filterOp, len(args))
filterOp = "AND"
}
if filter.MaxDequeue > 0 {
args = append(args, filter.MaxDequeue)
fmt.Fprintf(&sql, " %v dequeue_block <= $%v", filterOp, len(args))
filterOp = "AND"
}
if len(filter.PublicKey) > 0 {
args = append(args, filter.PublicKey)
fmt.Fprintf(&sql, " %v public_key = $%v", filterOp, len(args))
filterOp = "AND"
}
if filter.MinIndex > 0 {
args = append(args, filter.MinIndex)
fmt.Fprintf(&sql, " %v builder_index >= $%v", filterOp, len(args))
filterOp = "AND"
}
if filter.MaxIndex > 0 {
args = append(args, filter.MaxIndex)
fmt.Fprintf(&sql, " %v builder_index <= $%v", filterOp, len(args))
filterOp = "AND"
}
if filter.MinAmount != nil {
args = append(args, *filter.MinAmount)
fmt.Fprintf(&sql, " %v amount >= $%v", filterOp, len(args))
filterOp = "AND"
}
if filter.MaxAmount != nil {
args = append(args, *filter.MaxAmount)
fmt.Fprintf(&sql, " %v amount <= $%v", filterOp, len(args))
}

args = append(args, limit)
fmt.Fprintf(&sql, `)
SELECT
count(*) AS block_number,
0 AS block_index,
0 AS block_time,
null AS block_root,
0 AS fork_id,
null AS public_key,
null AS withdrawal_credentials,
0 AS amount,
null AS signature,
null AS builder_index,
null AS tx_hash,
null AS tx_sender,
null AS tx_target,
0 AS dequeue_block
FROM cte
UNION ALL SELECT * FROM (
SELECT * FROM cte
ORDER BY block_time DESC, block_index DESC
LIMIT $%v
`, len(args))

if offset > 0 {
args = append(args, offset)
fmt.Fprintf(&sql, " OFFSET $%v ", len(args))
}
fmt.Fprintf(&sql, ") AS t1")

depositTxs := []*dbtypes.BuilderDepositTx{}
err := ReaderDb.SelectContext(ctx, &depositTxs, sql.String(), args...)
if err != nil {
logger.Errorf("Error while fetching filtered builder deposit txs: %v", err)
return nil, 0, err
}

return depositTxs[1:], depositTxs[0].BlockNumber, nil
}
Loading