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
8 changes: 7 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ func init() {
rootCmd.PersistentFlags().Bool("epbs-enabled", false, "Enable ePBS bidding/revealing at startup")
rootCmd.PersistentFlags().Bool("builder-api-enabled", defaults.BuilderAPIEnabled, "Enable traditional Builder API at startup (served on --api-port)")
rootCmd.PersistentFlags().Uint64("builder-api-subsidy", defaults.BuilderAPI.BlockValueSubsidyGwei, "Block value subsidy added to bids in Gwei")
rootCmd.PersistentFlags().Uint64("gloas-builder-api-subsidy", defaults.BuilderAPI.GloasBuilderApiSubsidy, "Gwei added to block value to form ExecutionPayment in Gloas Builder API bids")
rootCmd.PersistentFlags().String("builder-api-url", defaults.BuilderAPI.BuilderURL, "Publicly reachable URL of this builder (e.g. https://builder.example.com); used to validate builder_url in SignedRequestAuthV1")
rootCmd.PersistentFlags().Bool("builder-api-require-auth", defaults.BuilderAPI.RequireRequestAuth, "Require SignedRequestAuthV1 on getExecutionPayloadBid requests; reject unauthenticated requests with 401")
rootCmd.PersistentFlags().Uint64("deposit-amount", defaults.DepositAmount, "Builder deposit amount in Gwei")
rootCmd.PersistentFlags().Uint64("topup-threshold", defaults.TopupThreshold, "Balance threshold for auto top-up in Gwei")
rootCmd.PersistentFlags().Uint64("topup-amount", defaults.TopupAmount, "Amount to top-up in Gwei")
Expand Down Expand Up @@ -162,7 +165,10 @@ func initConfig() error {
EPBSEnabled: v.GetBool("epbs-enabled"),
BuilderAPIEnabled: v.GetBool("builder-api-enabled"),
BuilderAPI: builder.BuilderAPIConfig{
BlockValueSubsidyGwei: v.GetUint64("builder-api-subsidy"),
BuilderURL: v.GetString("builder-api-url"),
RequireRequestAuth: v.GetBool("builder-api-require-auth"),
BlockValueSubsidyGwei: v.GetUint64("builder-api-subsidy"),
GloasBuilderApiSubsidy: v.GetUint64("gloas-builder-api-subsidy"),
},
DepositAmount: v.GetUint64("deposit-amount"),
TopupThreshold: v.GetUint64("topup-threshold"),
Expand Down
10 changes: 9 additions & 1 deletion cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ and begins building blocks according to configuration.`,
}

genesisForkVersion := g.GenesisForkVersion
genesisValidatorsRoot := phase0.Root{}
genesisValidatorsRoot := g.GenesisValidatorsRoot

logger.WithFields(logrus.Fields{
"genesis_fork_version": fmt.Sprintf("0x%x", genesisForkVersion[:]),
Expand All @@ -296,7 +296,9 @@ and begins building blocks according to configuration.`,

builderAPISrv = builderapi.NewServer(&cfg.BuilderAPI, logger, builderSvc, blsSigner, validatorStore, genesisForkVersion, forkVersion, genesisValidatorsRoot)
builderAPISrv.SetFuluPublisher(clClient)
builderAPISrv.SetCLClient(clClient)
builderAPISrv.SetEnabled(cfg.BuilderAPIEnabled)
builderAPISrv.SetChainService(chainSvc)
builderAPISrv.SetStateDB(stateDB)
}

Expand All @@ -307,6 +309,9 @@ and begins building blocks according to configuration.`,
propPrefSvc = proposerpreferences.NewService(clClient, logger)
propPrefSvc.GetCache().SetStateDB(stateDB, logger)
builderSvc.SetProposerPreferencesCache(propPrefSvc.GetCache())
if builderAPISrv != nil {
builderAPISrv.SetProposerPreferencesCache(propPrefSvc.GetCache())
}
chainSvc.SetProposerPreferencesCache(propPrefSvc.GetCache())
}

Expand Down Expand Up @@ -371,6 +376,9 @@ and begins building blocks according to configuration.`,
})
lifecycleMgr.SetRegistrationCallback(func(index uint64) {
epbsSvc.SetBuilderRegistered(index)
if builderAPISrv != nil {
builderAPISrv.SetBuilderIndex(index)
}
})
}

Expand Down
14 changes: 8 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ require (
github.com/ethpandaops/go-eth2-client v0.1.3
github.com/ethpandaops/service-authenticatoor v0.0.1
github.com/glebarez/go-sqlite v1.22.0
github.com/goccy/go-yaml v1.19.2
github.com/golang-jwt/jwt/v5 v5.3.1
github.com/gorilla/mux v1.8.1
github.com/herumi/bls-eth-go-binary v1.37.0
github.com/holiman/uint256 v1.3.2
github.com/jmoiron/sqlx v1.4.0
github.com/pk910/dynamic-ssz v1.3.2-0.20260505131440-111bcb265c8f
github.com/pkg/errors v0.9.1
github.com/pressly/goose/v3 v3.27.1
github.com/prometheus/client_golang v1.23.2
github.com/rs/zerolog v1.35.1
Expand Down Expand Up @@ -46,7 +48,7 @@ require (
github.com/deckarep/golang-set/v2 v2.6.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/emicklei/dot v1.6.2 // indirect
github.com/emicklei/dot v1.6.4 // indirect
github.com/ethereum/c-kzg-4844/v2 v2.1.6 // indirect
github.com/ferranbt/fastssz v0.1.4 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
Expand All @@ -58,21 +60,20 @@ require (
github.com/go-openapi/spec v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/goccy/go-yaml v1.19.2 // indirect
github.com/gofrs/flock v0.12.1 // indirect
github.com/golang/snappy v1.0.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/huandu/go-clone v1.6.0 // indirect
github.com/huandu/go-clone v1.7.2 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.21 // indirect
github.com/mfridman/interpolate v0.0.2 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
Expand All @@ -81,7 +82,6 @@ require (
github.com/pion/transport/v2 v2.2.10 // indirect
github.com/pion/transport/v3 v3.0.7 // indirect
github.com/pk910/hashtree-bindings v0.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.66.1 // indirect
Expand Down Expand Up @@ -122,3 +122,5 @@ require (
modernc.org/memory v1.11.0 // indirect
modernc.org/sqlite v1.49.1 // indirect
)

tool github.com/pk910/dynamic-ssz/dynssz-gen
17 changes: 8 additions & 9 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvw
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A=
github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s=
github.com/emicklei/dot v1.6.4 h1:cG9ycT67d9Yw22G+mAb4XiuUz6E6H1S0zePp/5Cwe/c=
github.com/emicklei/dot v1.6.4/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s=
github.com/ethereum/c-kzg-4844/v2 v2.1.6 h1:xQymkKCT5E2Jiaoqf3v4wsNgjZLY0lRSkZn27fRjSls=
github.com/ethereum/c-kzg-4844/v2 v2.1.6/go.mod h1:8HMkUZ5JRv4hpw/XUrYWSQNAUzhHMg2UDb/U+5m+XNw=
github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk=
Expand Down Expand Up @@ -143,8 +143,8 @@ github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA
github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c=
github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U=
github.com/huandu/go-clone v1.6.0 h1:HMo5uvg4wgfiy5FoGOqlFLQED/VGRm2D9Pi8g1FXPGc=
github.com/huandu/go-clone v1.6.0/go.mod h1:ReGivhG6op3GYr+UY3lS6mxjKp7MIGTknuU5TbTVaXE=
github.com/huandu/go-clone v1.7.2 h1:3+Aq0Ed8XK+zKkLjE2dfHg0XrpIfcohBE1K+c8Usxoo=
github.com/huandu/go-clone v1.7.2/go.mod h1:ReGivhG6op3GYr+UY3lS6mxjKp7MIGTknuU5TbTVaXE=
github.com/huandu/go-clone/generic v1.6.0 h1:Wgmt/fUZ28r16F2Y3APotFD59sHk1p78K0XLdbUYN5U=
github.com/huandu/go-clone/generic v1.6.0/go.mod h1:xgd9ZebcMsBWWcBx5mVMCoqMX24gLWr5lQicr+nVXNs=
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
Expand All @@ -159,7 +159,6 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
Expand All @@ -182,10 +181,10 @@ github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg=
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
Expand Down
68 changes: 68 additions & 0 deletions pkg/builderapi/builder_preferences.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package builderapi

import (
"maps"
"sync"

"github.com/ethpandaops/go-eth2-client/spec/phase0"
)

// BuilderPreferencesStore holds the latest per-validator builder preferences
// submitted via the submitBuilderPreferences API. It keeps only the most recent
// max_execution_payment for each validator pubkey (a later submission overwrites
// an earlier one).
//
// Per the Gloas builder-specs, if no preferences have been submitted for a
// validator, the builder MUST treat its max_execution_payment as 0; GetOrDefault
// encodes that rule.
type BuilderPreferencesStore struct {
mu sync.RWMutex
prefs map[phase0.BLSPubKey]phase0.Gwei
}

// NewBuilderPreferencesStore creates an empty BuilderPreferencesStore.
func NewBuilderPreferencesStore() *BuilderPreferencesStore {
return &BuilderPreferencesStore{
prefs: make(map[phase0.BLSPubKey]phase0.Gwei),
}
}

// Set records the latest max_execution_payment for a validator, overwriting any
// previously stored value.
func (s *BuilderPreferencesStore) Set(pubkey phase0.BLSPubKey, maxExecutionPayment phase0.Gwei) {
s.mu.Lock()
defer s.mu.Unlock()
s.prefs[pubkey] = maxExecutionPayment
}

// Get returns the stored max_execution_payment for a validator and whether a
// preference was found.
func (s *BuilderPreferencesStore) Get(pubkey phase0.BLSPubKey) (phase0.Gwei, bool) {
s.mu.RLock()
defer s.mu.RUnlock()
v, ok := s.prefs[pubkey]
return v, ok
}

// GetOrDefault returns the stored max_execution_payment for a validator, or 0 if
// none has been submitted — the spec-mandated default that disallows execution
// layer payments.
func (s *BuilderPreferencesStore) GetOrDefault(pubkey phase0.BLSPubKey) phase0.Gwei {
s.mu.RLock()
defer s.mu.RUnlock()
prefs, ok := s.prefs[pubkey]
if !ok {
return 0
}
return prefs
}

// GetAll returns a snapshot copy of all stored builder preferences, keyed by
// validator pubkey.
func (s *BuilderPreferencesStore) GetAll() map[phase0.BLSPubKey]phase0.Gwei {
s.mu.RLock()
defer s.mu.RUnlock()
out := make(map[phase0.BLSPubKey]phase0.Gwei, len(s.prefs))
maps.Copy(out, s.prefs)
return out
}
Loading