Skip to content

Commit

Permalink
Merge pull request #276 from chainbound/naman/feat/mev-boost/constrai…
Browse files Browse the repository at this point in the history
…nts-api

feat(mev-boost): update constraints api
  • Loading branch information
thedevbirb authored Oct 10, 2024
2 parents 11cd077 + eb47e26 commit b9b38f1
Show file tree
Hide file tree
Showing 7 changed files with 421 additions and 145 deletions.
9 changes: 8 additions & 1 deletion mev-boost/server/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,18 @@ const (
// Router paths
pathStatus = "/eth/v1/builder/status"
pathRegisterValidator = "/eth/v1/builder/validators"
pathSubmitConstraint = "/eth/v1/builder/constraints"
pathGetHeader = "/eth/v1/builder/header/{slot:[0-9]+}/{parent_hash:0x[a-fA-F0-9]+}/{pubkey:0x[a-fA-F0-9]+}"
pathGetHeaderWithProofs = "/eth/v1/builder/header_with_proofs/{slot:[0-9]+}/{parent_hash:0x[a-fA-F0-9]+}/{pubkey:0x[a-fA-F0-9]+}"
pathGetPayload = "/eth/v1/builder/blinded_blocks"

// Constraints namespace paths
// Ref: https://docs.boltprotocol.xyz/api/builder#constraints
pathSubmitConstraint = "/constraints/v1/builder/constraints"
// Ref: https://docs.boltprotocol.xyz/api/builder#delegate
pathDelegate = "/constraints/v1/builder/delegate"
// Ref: https://docs.boltprotocol.xyz/api/builder#revoke
pathRevoke = "/constraints/v1/builder/revoke"

// // Relay Monitor paths
// pathAuctionTranscript = "/monitor/v1/transcript"
)
98 changes: 55 additions & 43 deletions mev-boost/server/constraints.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,25 @@ import (
lru "github.com/hashicorp/golang-lru/v2"
)

type BatchedSignedConstraints = []*SignedConstraints
type (
BatchedSignedConstraints = []*SignedConstraints
HashToTransactionDecoded = map[gethCommon.Hash]*types.Transaction
)

// SignedConstraints represents the signed constraints.
// Reference: https://docs.boltprotocol.xyz/api/builder
type SignedConstraints struct {
Message ConstraintsMessage `json:"message"`
Signature phase0.BLSSignature `json:"signature"`
}

// ConstraintsMessage represents the constraints message.
// Reference: https://docs.boltprotocol.xyz/api/builder
type ConstraintsMessage struct {
ValidatorIndex uint64 `json:"validator_index"`
Slot uint64 `json:"slot"`
Constraints []*Constraint `json:"constraints"`
}

type Constraint struct {
Tx Transaction `json:"tx"`
Index *uint64 `json:"index"`
Pubkey phase0.BLSPubKey `json:"pubkey"`
Slot uint64 `json:"slot"`
Top bool `json:"top"`
Transactions []Transaction `json:"transactions"`
}

func (s *SignedConstraints) String() string {
Expand All @@ -33,29 +36,25 @@ func (m *ConstraintsMessage) String() string {
return JSONStringify(m)
}

func (c *Constraint) String() string {
return JSONStringify(c)
}

// ConstraintCache is a cache for constraints.
type ConstraintCache struct {
// ConstraintsCache is a cache for constraints.
type ConstraintsCache struct {
// map of slots to all constraints for that slot
constraints *lru.Cache[uint64, map[gethCommon.Hash]*Constraint]
constraints *lru.Cache[uint64, map[gethCommon.Hash]*Transaction]
}

// NewConstraintCache creates a new constraint cache.
// NewConstraintsCache creates a new constraint cache.
// cap is the maximum number of slots to store constraints for.
func NewConstraintCache(cap int) *ConstraintCache {
constraints, _ := lru.New[uint64, map[gethCommon.Hash]*Constraint](cap)
return &ConstraintCache{
func NewConstraintsCache(cap int) *ConstraintsCache {
constraints, _ := lru.New[uint64, map[gethCommon.Hash]*Transaction](cap)
return &ConstraintsCache{
constraints: constraints,
}
}

// AddInclusionConstraint adds an inclusion constraint to the cache at the given slot for the given transaction.
func (c *ConstraintCache) AddInclusionConstraint(slot uint64, tx Transaction, index *uint64) error {
func (c *ConstraintsCache) AddInclusionConstraint(slot uint64, tx Transaction, index *uint64) error {
if _, exists := c.constraints.Get(slot); !exists {
c.constraints.Add(slot, make(map[gethCommon.Hash]*Constraint))
c.constraints.Add(slot, make(map[gethCommon.Hash]*Transaction))
}

// parse transaction to get its hash and store it in the cache
Expand All @@ -67,52 +66,65 @@ func (c *ConstraintCache) AddInclusionConstraint(slot uint64, tx Transaction, in
}

m, _ := c.constraints.Get(slot)
m[parsedTx.Hash()] = &Constraint{
Tx: tx,
Index: index,
}
m[parsedTx.Hash()] = &tx

return nil
}

// AddInclusionConstraints adds multiple inclusion constraints to the cache at the given slot
func (c *ConstraintCache) AddInclusionConstraints(slot uint64, constraints []*Constraint) error {
func (c *ConstraintsCache) AddInclusionConstraints(slot uint64, transactions []Transaction) error {
if _, exists := c.constraints.Get(slot); !exists {
c.constraints.Add(slot, make(map[gethCommon.Hash]*Constraint))
c.constraints.Add(slot, make(map[gethCommon.Hash]*Transaction))
}

m, _ := c.constraints.Get(slot)
for _, constraint := range constraints {
for _, tx := range transactions {
parsedTx := new(types.Transaction)
err := parsedTx.UnmarshalBinary(constraint.Tx)
err := parsedTx.UnmarshalBinary(tx)
if err != nil {
return err
}
m[parsedTx.Hash()] = constraint
m[parsedTx.Hash()] = &tx
}

return nil
}

// Get gets the constraints at the given slot.
func (c *ConstraintCache) Get(slot uint64) (map[gethCommon.Hash]*Constraint, bool) {
func (c *ConstraintsCache) Get(slot uint64) (map[gethCommon.Hash]*Transaction, bool) {
return c.constraints.Get(slot)
}

// FindTransactionByHash finds the constraint for the given transaction hash and returns it.
func (c *ConstraintCache) FindTransactionByHash(txHash gethCommon.Hash) (*Constraint, bool) {
for _, hashToConstraint := range c.constraints.Values() {
if constraint, exists := hashToConstraint[txHash]; exists {
return constraint, true
func (c *ConstraintsCache) FindTransactionByHash(txHash gethCommon.Hash) (*Transaction, bool) {
for _, hashToTx := range c.constraints.Values() {
if tx, exists := hashToTx[txHash]; exists {
return tx, true
}
}
return nil, false
}

type (
HashToConstraintDecoded = map[gethCommon.Hash]*ConstraintDecoded
ConstraintDecoded struct {
Index *uint64
Tx *types.Transaction
}
)
// Ref: https://docs.boltprotocol.xyz/api/builder#delegate
type SignedDelegation struct {
Message Delegation `json:"message"`
Signature phase0.BLSSignature `json:"signature"`
}

// Ref: https://docs.boltprotocol.xyz/api/builder#delegate
type Delegation struct {
ValidatorPubkey phase0.BLSPubKey `json:"validator_pubkey"`
DelegateePubkey phase0.BLSPubKey `json:"delegatee_pubkey"`
}

// Ref: https://docs.boltprotocol.xyz/api/builder#revoke
type SignedRevocation struct {
Message Revocation `json:"message"`
Signature phase0.BLSSignature `json:"signature"`
}

// Ref: https://docs.boltprotocol.xyz/api/builder#revoke
type Revocation struct {
ValidatorPubkey phase0.BLSPubKey `json:"validator_pubkey"`
DelegateePubkey phase0.BLSPubKey `json:"delegatee_pubkey"`
}
40 changes: 32 additions & 8 deletions mev-boost/server/mock_relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ type mockRelay struct {

// Default responses placeholders, used if overrider does not exist
GetHeaderResponse *builderSpec.VersionedSignedBuilderBid
GetHeaderWithProofsResponse *BidWithInclusionProofs
GetHeaderWithProofsResponse *VersionedSignedBuilderBidWithProofs
GetPayloadResponse *builderApi.VersionedSubmitBlindedBlockResponse

// Server section
Expand Down Expand Up @@ -123,6 +123,8 @@ func (m *mockRelay) getRouter() http.Handler {
r.HandleFunc(pathGetHeader, m.handleGetHeader).Methods(http.MethodGet)
r.HandleFunc(pathGetHeaderWithProofs, m.handleGetHeaderWithProofs).Methods(http.MethodGet)
r.HandleFunc(pathSubmitConstraint, m.handleSubmitConstraint).Methods(http.MethodPost)
r.HandleFunc(pathDelegate, m.handleDelegate).Methods(http.MethodPost)
r.HandleFunc(pathRevoke, m.handleRevoke).Methods(http.MethodPost)
r.HandleFunc(pathGetPayload, m.handleGetPayload).Methods(http.MethodPost)

return m.newTestMiddleware(r)
Expand Down Expand Up @@ -172,6 +174,28 @@ func (m *mockRelay) defaultHandleRegisterValidator(w http.ResponseWriter, req *h
w.WriteHeader(http.StatusOK)
}

func (m *mockRelay) handleDelegate(w http.ResponseWriter, req *http.Request) {
payload := SignedDelegation{}
if err := DecodeJSON(req.Body, &payload); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}

func (m *mockRelay) handleRevoke(w http.ResponseWriter, req *http.Request) {
payload := SignedRevocation{}
if err := DecodeJSON(req.Body, &payload); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}

func (m *mockRelay) handleSubmitConstraint(w http.ResponseWriter, req *http.Request) {
m.mu.Lock()
defer m.mu.Unlock()
Expand All @@ -197,7 +221,7 @@ func (m *mockRelay) MakeGetHeaderWithConstraintsResponse(value uint64, blockHash
tx Transaction
hash phase0.Hash32
},
) *BidWithInclusionProofs {
) *VersionedSignedBuilderBidWithProofs {
transactions := new(utilbellatrix.ExecutionPayloadTransactions)

for _, con := range constraints {
Expand Down Expand Up @@ -288,7 +312,7 @@ func (m *mockRelay) MakeGetHeaderResponse(value uint64, blockHash, parentHash, p

// MakeGetHeaderWithProofsResponseWithTxsRoot is used to create the default or can be used to create a custom response to the getHeaderWithProofs
// method
func (m *mockRelay) MakeGetHeaderWithProofsResponseWithTxsRoot(value uint64, blockHash, parentHash, publicKey string, version spec.DataVersion, txsRoot phase0.Root) *BidWithInclusionProofs {
func (m *mockRelay) MakeGetHeaderWithProofsResponseWithTxsRoot(value uint64, blockHash, parentHash, publicKey string, version spec.DataVersion, txsRoot phase0.Root) *VersionedSignedBuilderBidWithProofs {
switch version {
case spec.DataVersionCapella:
// Fill the payload with custom values.
Expand All @@ -307,8 +331,8 @@ func (m *mockRelay) MakeGetHeaderWithProofsResponseWithTxsRoot(value uint64, blo
signature, err := ssz.SignMessage(message, ssz.DomainBuilder, m.secretKey)
require.NoError(m.t, err)

return &BidWithInclusionProofs{
Bid: &builderSpec.VersionedSignedBuilderBid{
return &VersionedSignedBuilderBidWithProofs{
VersionedSignedBuilderBid: &builderSpec.VersionedSignedBuilderBid{
Version: spec.DataVersionCapella,
Capella: &builderApiCapella.SignedBuilderBid{
Message: message,
Expand All @@ -335,8 +359,8 @@ func (m *mockRelay) MakeGetHeaderWithProofsResponseWithTxsRoot(value uint64, blo
signature, err := ssz.SignMessage(message, ssz.DomainBuilder, m.secretKey)
require.NoError(m.t, err)

return &BidWithInclusionProofs{
Bid: &builderSpec.VersionedSignedBuilderBid{
return &VersionedSignedBuilderBidWithProofs{
VersionedSignedBuilderBid: &builderSpec.VersionedSignedBuilderBid{
Version: spec.DataVersionDeneb,
Deneb: &builderApiDeneb.SignedBuilderBid{
Message: message,
Expand Down Expand Up @@ -411,7 +435,7 @@ func (m *mockRelay) defaultHandleGetHeaderWithProofs(w http.ResponseWriter) {
"0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249",
spec.DataVersionCapella,
spec.DataVersionDeneb,
nil,
)

Expand Down
Loading

0 comments on commit b9b38f1

Please sign in to comment.