Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(mev-boost): update constraints api #276

Merged
merged 11 commits into from
Oct 10, 2024
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add reference link here?

// 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