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

init commit optimistic relay #1

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
e57024c
init commit optimistic relay
michaelneuder Dec 29, 2022
95e937a
optimistic relay updates
michaelneuder Dec 31, 2022
e666a4b
db updates
michaelneuder Dec 31, 2022
26ad103
flow (c) update database with new table to persist refunds
michaelneuder Dec 31, 2022
3dddf4b
adding collateral check and DB field
michaelneuder Jan 2, 2023
e7aa032
remove db update
michaelneuder Jan 2, 2023
234ff04
add block builder demotion in the case of a simulation error after a …
michaelneuder Jan 2, 2023
c36ef85
comments from Justin
michaelneuder Jan 2, 2023
8379b4e
adding signedValidatorRegistration to the refund table
michaelneuder Jan 2, 2023
442a7bf
normalize usage of BuilderStatus and builder_status instead of Builde…
michaelneuder Jan 2, 2023
c04edc8
rename refund to demotion
michaelneuder Jan 4, 2023
66b14f7
s/TableBuidlerDemotions/TableBuilderDemotions/g
michaelneuder Jan 4, 2023
6bb8bf3
normalizing use of builder instead of block builder except in the cas…
michaelneuder Jan 4, 2023
3a37075
collateral id and demotions
michaelneuder Jan 4, 2023
cae6c95
replacing $3 with $2 in SetBlockBuilderStatus
michaelneuder Jan 4, 2023
d9845af
unit test initial pass
michaelneuder Jan 5, 2023
fe81a12
remove bad test
michaelneuder Jan 5, 2023
8267845
Justin's comments round 2
michaelneuder Jan 5, 2023
ac4aaa2
Unit testing block simulation path
michaelneuder Jan 7, 2023
def09c6
unit test get payload optimistic
michaelneuder Jan 8, 2023
6692741
save full request from builder to justify demotion
michaelneuder Jan 8, 2023
a2c9662
temporarily set optimistic builders as high-prio if the winning block…
michaelneuder Jan 12, 2023
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
53 changes: 53 additions & 0 deletions beaconclient/mock_multi_beacon_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package beaconclient

import (
"sync"

"github.com/flashbots/go-boost-utils/types"
)

type MockMultiBeaconClient struct {
mu sync.RWMutex
}

func NewMockMultiBeaconClient() *MockMultiBeaconClient {
return &MockMultiBeaconClient{
mu: sync.RWMutex{},
}
}

func (*MockMultiBeaconClient) SubscribeToHeadEvents(slotC chan HeadEventData) {}

func (*MockMultiBeaconClient) BestSyncStatus() (*SyncStatusPayloadData, error) {
return &SyncStatusPayloadData{HeadSlot: 1}, nil
}

func (*MockMultiBeaconClient) FetchValidators(headSlot uint64) (map[types.PubkeyHex]ValidatorResponseEntry, error) {
return nil, nil
}

func (*MockMultiBeaconClient) GetProposerDuties(epoch uint64) (*ProposerDutiesResponse, error) {
return nil, nil
}

func (*MockMultiBeaconClient) PublishBlock(block *types.SignedBeaconBlock) (code int, err error) {
return 0, nil
}

func (*MockMultiBeaconClient) GetGenesis() (*GetGenesisResponse, error) {
resp := &GetGenesisResponse{}
resp.Data.GenesisTime = 0
return resp, nil
}

func (*MockMultiBeaconClient) GetSpec() (spec *GetSpecResponse, err error) {
return nil, nil
}

func (*MockMultiBeaconClient) GetBlock(blockID string) (block *GetBlockResponse, err error) {
return nil, nil
}

func (*MockMultiBeaconClient) GetRandao(slot uint64) (spec *GetRandaoResponse, err error) {
return nil, nil
}
22 changes: 22 additions & 0 deletions common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,25 @@ type HTTPServerTimeouts struct {
Write time.Duration // Timeout for writes. None if 0.
Idle time.Duration // Timeout to disconnect idle client connections. None if 0.
}

type BuilderStatus uint8

const (
LowPrio BuilderStatus = iota
HighPrio
Optimistic
Blacklisted
)

func (b BuilderStatus) String() string {
switch b {
case HighPrio:
return "high-prio"
case Optimistic:
return "optimistic"
case Blacklisted:
return "blacklisted"
default:
return "low-prio"
}
}
91 changes: 83 additions & 8 deletions database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,12 @@ type IDatabaseService interface {

GetBlockBuilders() ([]*BlockBuilderEntry, error)
GetBlockBuilderByPubkey(pubkey string) (*BlockBuilderEntry, error)
SetBlockBuilderStatus(pubkey string, isHighPrio, isBlacklisted bool) error
SetBlockBuilderStatus(pubkey string, builderStatus common.BuilderStatus) error
UpsertBlockBuilderEntryAfterSubmission(lastSubmission *BuilderBlockSubmissionEntry, isError bool) error
IncBlockBuilderStatsAfterGetPayload(builderPubkey string) error
GetBlockBuildersFromCollateralID(collateralID uint64) ([]*BlockBuilderEntry, error)

UpsertBuilderDemotion(submitBlockRequest *types.BuilderSubmitBlockRequest, signedBlindedBeaconBlock *types.SignedBlindedBeaconBlock, signedValidatorRegistration *types.SignedValidatorRegistration) error
}

type DatabaseService struct {
Expand Down Expand Up @@ -436,8 +439,8 @@ func (s *DatabaseService) UpsertBlockBuilderEntryAfterSubmission(lastSubmission

// Upsert
query := `INSERT INTO ` + vars.TableBlockBuilder + `
(builder_pubkey, description, is_high_prio, is_blacklisted, last_submission_id, last_submission_slot, num_submissions_total, num_submissions_simerror) VALUES
(:builder_pubkey, :description, :is_high_prio, :is_blacklisted, :last_submission_id, :last_submission_slot, :num_submissions_total, :num_submissions_simerror)
(builder_pubkey, description, status, collateral_value, collateral_id, last_submission_id, last_submission_slot, num_submissions_total, num_submissions_simerror) VALUES
(:builder_pubkey, :description, :status, :collateral_value, :collateral_id, :last_submission_id, :last_submission_slot, :num_submissions_total, :num_submissions_simerror)
ON CONFLICT (builder_pubkey) DO UPDATE SET
last_submission_id = :last_submission_id,
last_submission_slot = :last_submission_slot,
Expand All @@ -448,22 +451,22 @@ func (s *DatabaseService) UpsertBlockBuilderEntryAfterSubmission(lastSubmission
}

func (s *DatabaseService) GetBlockBuilders() ([]*BlockBuilderEntry, error) {
query := `SELECT id, inserted_at, builder_pubkey, description, is_high_prio, is_blacklisted, last_submission_id, last_submission_slot, num_submissions_total, num_submissions_simerror, num_sent_getpayload FROM ` + vars.TableBlockBuilder + ` ORDER BY id ASC;`
query := `SELECT id, inserted_at, builder_pubkey, description, status, collateral_value, collateral_id, last_submission_id, last_submission_slot, num_submissions_total, num_submissions_simerror, num_sent_getpayload FROM ` + vars.TableBlockBuilder + ` ORDER BY id ASC;`
entries := []*BlockBuilderEntry{}
err := s.DB.Select(&entries, query)
return entries, err
}

func (s *DatabaseService) GetBlockBuilderByPubkey(pubkey string) (*BlockBuilderEntry, error) {
query := `SELECT id, inserted_at, builder_pubkey, description, is_high_prio, is_blacklisted, last_submission_id, last_submission_slot, num_submissions_total, num_submissions_simerror, num_sent_getpayload FROM ` + vars.TableBlockBuilder + ` WHERE builder_pubkey=$1;`
query := `SELECT id, inserted_at, builder_pubkey, description, status, collateral_value, collateral_id, last_submission_id, last_submission_slot, num_submissions_total, num_submissions_simerror, num_sent_getpayload FROM ` + vars.TableBlockBuilder + ` WHERE builder_pubkey=$1;`
entry := &BlockBuilderEntry{}
err := s.DB.Get(entry, query, pubkey)
return entry, err
}

func (s *DatabaseService) SetBlockBuilderStatus(pubkey string, isHighPrio, isBlacklisted bool) error {
query := `UPDATE ` + vars.TableBlockBuilder + ` SET is_high_prio=$1, is_blacklisted=$2 WHERE builder_pubkey=$3;`
_, err := s.DB.Exec(query, isHighPrio, isBlacklisted, pubkey)
func (s *DatabaseService) SetBlockBuilderStatus(pubkey string, builderStatusCode common.BuilderStatus) error {
query := `UPDATE ` + vars.TableBlockBuilder + ` SET status=$1 WHERE builder_pubkey=$2;`
_, err := s.DB.Exec(query, uint8(builderStatusCode), pubkey)
return err
}

Expand All @@ -486,3 +489,75 @@ func (s *DatabaseService) DeleteExecutionPayloads(idFirst, idLast uint64) error
_, err := s.DB.Exec(query, idFirst, idLast)
return err
}

func (s *DatabaseService) UpsertBuilderDemotion(submitBlockRequest *types.BuilderSubmitBlockRequest, signedBlindedBeaconBlock *types.SignedBlindedBeaconBlock, signedValidatorRegistration *types.SignedValidatorRegistration) error {
if submitBlockRequest == nil {
return fmt.Errorf("nil submitBlockRequest invalid for UpsertBuilderDemotion")
}

_submitBlockRequest, err := json.Marshal(submitBlockRequest)
if err != nil {
return err
}
bidTrace := submitBlockRequest.Message
builderDemotionEntry := BuilderDemotionEntry{
SubmitBlockRequest: NewNullString(string(_submitBlockRequest)),

Slot: bidTrace.Slot,
Epoch: bidTrace.Slot / uint64(common.SlotsPerEpoch),

BuilderPubkey: bidTrace.BuilderPubkey.String(),
ProposerPubkey: bidTrace.ProposerPubkey.String(),

Value: bidTrace.Value.String(),

BlockHash: bidTrace.BlockHash.String(),
}

if signedBlindedBeaconBlock != nil {
_signedBlindedBeaconBlock, err := json.Marshal(signedBlindedBeaconBlock)
if err != nil {
return err
}
builderDemotionEntry.SignedBlindedBeaconBlock = NewNullString(string(_signedBlindedBeaconBlock))
}

if signedValidatorRegistration != nil {
_signedValidatorRegistration, err := json.Marshal(signedValidatorRegistration)
if err != nil {
return err
}
builderDemotionEntry.SignedValidatorRegistration = NewNullString(string(_signedValidatorRegistration))
builderDemotionEntry.FeeRecipient = signedValidatorRegistration.Message.FeeRecipient.String()
builderDemotionEntry.GasLimit = signedValidatorRegistration.Message.GasLimit
}

var query string
// If block_hash conflicts and we have a published block, fill in fields needed for the refund.
if signedBlindedBeaconBlock != nil && signedValidatorRegistration != nil {
query = `INSERT INTO ` + vars.TableBuilderDemotions + `
(submit_block_request, signed_blinded_beacon_block, signed_validator_registration, slot, epoch, builder_pubkey, proposer_pubkey, value, fee_recipient, gas_limit, block_hash) VALUES
(:submit_block_request, :signed_blinded_beacon_block, :signed_validator_registration, :slot, :epoch, :builder_pubkey, :proposer_pubkey, :value, :fee_recipient, :gas_limit, :block_hash)
ON CONFLICT (block_hash) DO UPDATE SET
signed_blinded_beacon_block = :signed_blinded_beacon_block,
signed_validator_registration = :signed_validator_registration,
fee_recipient = :fee_recipient,
gas_limit = :gas_limit;
`
} else {
// If the block_hash conflicts, then all the relevant data must be there already.
query = `INSERT INTO ` + vars.TableBuilderDemotions + `
(submit_block_request, signed_blinded_beacon_block, signed_validator_registration, slot, epoch, builder_pubkey, proposer_pubkey, value, fee_recipient, gas_limit, block_hash) VALUES
(:submit_block_request, :signed_blinded_beacon_block, :signed_validator_registration, :slot, :epoch, :builder_pubkey, :proposer_pubkey, :value, :fee_recipient, :gas_limit, :block_hash)
ON CONFLICT (block_hash) DO NOTHING`
}
_, err = s.DB.NamedExec(query, builderDemotionEntry)
return err
}

func (s *DatabaseService) GetBlockBuildersFromCollateralID(collateralID uint64) ([]*BlockBuilderEntry, error) {
query := `SELECT builder_pubkey FROM ` + vars.TableBlockBuilder + ` WHERE collateral_id=$1 ORDER BY id ASC;`
entries := []*BlockBuilderEntry{}
err := s.DB.Select(&entries, query, collateralID)
return entries, err
}
28 changes: 26 additions & 2 deletions database/migrations/001_init_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,9 @@ var Migration001InitDatabase = &migrate.Migration{
builder_pubkey varchar(98) NOT NULL,
description text NOT NULL,

is_high_prio boolean NOT NULL,
is_blacklisted boolean NOT NULL,
status bigint NOT NULL,
collateral_value NUMERIC(48, 0),
collateral_id bigint NOT NULL,

last_submission_id bigint references ` + vars.TableBuilderBlockSubmission + `(id) on delete set null,
last_submission_slot bigint NOT NULL,
Expand All @@ -134,13 +135,36 @@ var Migration001InitDatabase = &migrate.Migration{

UNIQUE (builder_pubkey)
);

CREATE TABLE IF NOT EXISTS ` + vars.TableBuilderDemotions + `(
id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
inserted_at timestamp NOT NULL default current_timestamp,

submit_block_request json,
signed_blinded_beacon_block json,
signed_validator_registration json,

epoch bigint NOT NULL,
slot bigint NOT NULL,

builder_pubkey varchar(98) NOT NULL,
proposer_pubkey varchar(98) NOT NULL,

value NUMERIC(48, 0),

fee_recipient varchar(42) NOT NULL,
gas_limit bigint NOT NULL,

block_hash varchar(66) NOT NULL,
);
`},
Down: []string{`
DROP TABLE IF EXISTS ` + vars.TableBuilderBlockSubmission + `;
DROP TABLE IF EXISTS ` + vars.TableDeliveredPayload + `;
DROP TABLE IF EXISTS ` + vars.TableBlockBuilder + `;
DROP TABLE IF EXISTS ` + vars.TableExecutionPayload + `;
DROP TABLE IF EXISTS ` + vars.TableValidatorRegistration + `;
DROP TABLE IF EXISTS ` + vars.TableBuilderDemotions + `;
`},
DisableTransactionUp: false,
DisableTransactionDown: false,
Expand Down
33 changes: 30 additions & 3 deletions database/mockdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import (
"github.com/flashbots/mev-boost-relay/common"
)

type MockDB struct{}
type MockDB struct {
Builders map[string]*BlockBuilderEntry
Demotions map[string]bool
Refunds map[string]bool
}

func (db MockDB) NumRegisteredValidators() (count uint64, err error) {
return 0, nil
Expand Down Expand Up @@ -86,10 +90,12 @@ func (db MockDB) GetBlockBuilders() ([]*BlockBuilderEntry, error) {
}

func (db MockDB) GetBlockBuilderByPubkey(pubkey string) (*BlockBuilderEntry, error) {
return nil, nil
return db.Builders[pubkey], nil
}

func (db MockDB) SetBlockBuilderStatus(pubkey string, isHighPrio, isBlacklisted bool) error {
func (db MockDB) SetBlockBuilderStatus(pubkey string, builderStatus common.BuilderStatus) error {
builder := db.Builders[pubkey]
builder.Status = uint8(builderStatus)
return nil
}

Expand All @@ -100,3 +106,24 @@ func (db MockDB) IncBlockBuilderStatsAfterGetHeader(slot uint64, blockhash strin
func (db MockDB) IncBlockBuilderStatsAfterGetPayload(builderPubkey string) error {
return nil
}

func (db MockDB) UpsertBuilderDemotion(submitBlockRequest *types.BuilderSubmitBlockRequest, signedBlindedBeaconBlock *types.SignedBlindedBeaconBlock, signedValidatorRegistration *types.SignedValidatorRegistration) error {
pk := submitBlockRequest.Message.BuilderPubkey.String()
db.Demotions[pk] = true

// Refundable case.
if signedBlindedBeaconBlock != nil && signedValidatorRegistration != nil {
db.Refunds[pk] = true
}
return nil
}

func (db MockDB) GetBlockBuildersFromCollateralID(collateralID uint64) ([]*BlockBuilderEntry, error) {
res := []*BlockBuilderEntry{}
for _, v := range db.Builders {
if v.CollateralID == collateralID {
res = append(res, v)
}
}
return res, nil
}
27 changes: 25 additions & 2 deletions database/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,9 @@ type BlockBuilderEntry struct {
BuilderPubkey string `db:"builder_pubkey" json:"builder_pubkey"`
Description string `db:"description" json:"description"`

IsHighPrio bool `db:"is_high_prio" json:"is_high_prio"`
IsBlacklisted bool `db:"is_blacklisted" json:"is_blacklisted"`
Status uint8 `db:"status" json:"status"`
CollateralValue string `db:"collateral_value" json:"collateral_value"`
CollateralID uint64 `db:"collateral_id" json:"collateral_id"`

LastSubmissionID sql.NullInt64 `db:"last_submission_id" json:"last_submission_id"`
LastSubmissionSlot uint64 `db:"last_submission_slot" json:"last_submission_slot"`
Expand All @@ -199,3 +200,25 @@ type BlockBuilderEntry struct {

NumSentGetPayload uint64 `db:"num_sent_getpayload" json:"num_sent_getpayload"`
}

type BuilderDemotionEntry struct {
ID int64 `db:"id"`
InsertedAt time.Time `db:"inserted_at"`

SubmitBlockRequest sql.NullString `db:"submit_block_request"`
SignedBlindedBeaconBlock sql.NullString `db:"signed_blinded_beacon_block"`
SignedValidatorRegistration sql.NullString `db:"signed_validator_registration"`

Slot uint64 `db:"slot"`
Epoch uint64 `db:"epoch"`

BuilderPubkey string `db:"builder_pubkey"`
ProposerPubkey string `db:"proposer_pubkey"`

Value string `db:"value"`

FeeRecipient string `db:"fee_recipient"`
GasLimit uint64 `db:"gas_limit"`

BlockHash string `db:"block_hash"`
}
1 change: 1 addition & 0 deletions database/vars/tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ var (
TableBuilderBlockSubmission = tableBase + "_builder_block_submission"
TableDeliveredPayload = tableBase + "_payload_delivered"
TableBlockBuilder = tableBase + "_blockbuilder"
TableBuilderDemotions = tableBase + "_builder_demotions"
)
Loading