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 4 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
9 changes: 9 additions & 0 deletions common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,12 @@ 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 BlockBuilderStatusCode uint8

const (
LowPrio BlockBuilderStatusCode = iota
HighPrio
Optimistic
Blacklisted
)
44 changes: 36 additions & 8 deletions database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@ type IDatabaseService interface {

GetBlockBuilders() ([]*BlockBuilderEntry, error)
GetBlockBuilderByPubkey(pubkey string) (*BlockBuilderEntry, error)
SetBlockBuilderStatus(pubkey string, isHighPrio, isBlacklisted bool) error
SetBlockBuilderStatus(pubkey string, status common.BlockBuilderStatusCode) error
UpsertBlockBuilderEntryAfterSubmission(lastSubmission *BuilderBlockSubmissionEntry, isError bool) error
IncBlockBuilderStatsAfterGetPayload(builderPubkey string) error

SaveValidatorRefund(bidTrace *common.BidTraceV2, signedBlindedBeaconBlock *types.SignedBlindedBeaconBlock) error
}

type DatabaseService struct {
Expand Down Expand Up @@ -436,8 +438,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, builder_status, last_submission_id, last_submission_slot, num_submissions_total, num_submissions_simerror) VALUES
(:builder_pubkey, :description, :builder_status, :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 +450,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, builder_status, 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, builder_status, 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, builderStatus common.BlockBuilderStatusCode) error {
query := `UPDATE ` + vars.TableBlockBuilder + ` SET builder_status=$1 WHERE builder_pubkey=$3;`
_, err := s.DB.Exec(query, uint8(builderStatus), pubkey)
return err
}

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

func (s *DatabaseService) SaveValidatorRefund(bidTrace *common.BidTraceV2, signedBlindedBeaconBlock *types.SignedBlindedBeaconBlock) error {
_signedBlindedBeaconBlock, err := json.Marshal(signedBlindedBeaconBlock)
if err != nil {
return err
}

validatorRefundEntry := ValidatorRefundEntry{
SignedBlindedBeaconBlock: NewNullString(string(_signedBlindedBeaconBlock)),

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

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

Value: bidTrace.Value.String(),
}

query := `INSERT INTO ` + vars.TableValidatorRefunds + `
(signed_blinded_beacon_block, slot, epoch, builder_pubkey, proposer_pubkey, value) VALUES
(:signed_blinded_beacon_block, :slot, :epoch, :builder_pubkey, :proposer_pubkey, :value)
ON CONFLICT DO NOTHING`
_, err = s.DB.NamedExec(query, validatorRefundEntry)
return err
}
18 changes: 16 additions & 2 deletions database/migrations/001_init_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,7 @@ 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,
builder_status bigint NOT NULL,

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

UNIQUE (builder_pubkey)
);

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

signed_blinded_beacon_block 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),
);
`},
Down: []string{`
DROP TABLE IF EXISTS ` + vars.TableBuilderBlockSubmission + `;
Expand Down
6 changes: 5 additions & 1 deletion database/mockdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func (db MockDB) GetBlockBuilderByPubkey(pubkey string) (*BlockBuilderEntry, err
return nil, nil
}

func (db MockDB) SetBlockBuilderStatus(pubkey string, isHighPrio, isBlacklisted bool) error {
func (db MockDB) SetBlockBuilderStatus(pubkey string, builderStatus common.BlockBuilderStatusCode) error {
return nil
}

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

func (db MockDB) SaveValidatorRefund(bidTrace *common.BidTraceV2, signedBlindedBeaconBlock *types.SignedBlindedBeaconBlock) error {
return nil
}
18 changes: 16 additions & 2 deletions database/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,7 @@ 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"`
BuilderStatus uint8 `db:"builder_status" json:"builder_status"`

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 +198,18 @@ type BlockBuilderEntry struct {

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

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

SignedBlindedBeaconBlock sql.NullString `db:"signed_blinded_beacon_block"`

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

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

Value string `db:"value"`
}
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"
TableValidatorRefunds = tableBase + "_validator_refunds"
)
31 changes: 26 additions & 5 deletions datastore/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,23 @@ type BlockBuilderStatus string
var (
RedisBlockBuilderStatusLowPrio BlockBuilderStatus = ""
RedisBlockBuilderStatusHighPrio BlockBuilderStatus = "high-prio"
RedisBlockBuilderStatusOptimistic BlockBuilderStatus = "optimistic"
RedisBlockBuilderStatusBlacklisted BlockBuilderStatus = "blacklisted"
)

func StatusStringFromCode(b common.BlockBuilderStatusCode) string {
switch b {
case common.Optimistic:
return string(RedisBlockBuilderStatusOptimistic)
case common.HighPrio:
return string(RedisBlockBuilderStatusHighPrio)
case common.Blacklisted:
return string(RedisBlockBuilderStatusBlacklisted)
default:
return string(RedisBlockBuilderStatusLowPrio)
}
}

func PubkeyHexToLowerStr(pk types.PubkeyHex) string {
return strings.ToLower(string(pk))
}
Expand Down Expand Up @@ -327,14 +341,21 @@ func (r *RedisCache) SetBlockBuilderStatus(builderPubkey string, status BlockBui
return r.client.HSet(context.Background(), r.keyBlockBuilderStatus, builderPubkey, string(status)).Err()
}

func (r *RedisCache) GetBlockBuilderStatus(builderPubkey string) (isHighPrio, isBlacklisted bool, err error) {
func (r *RedisCache) GetBlockBuilderStatus(builderPubkey string) (code common.BlockBuilderStatusCode, err error) {
res, err := r.client.HGet(context.Background(), r.keyBlockBuilderStatus, builderPubkey).Result()
if errors.Is(err, redis.Nil) {
return false, false, nil
return code, nil
}
switch status := BlockBuilderStatus(res); status {
case RedisBlockBuilderStatusHighPrio:
return common.HighPrio, nil
case RedisBlockBuilderStatusOptimistic:
return common.Optimistic, nil
case RedisBlockBuilderStatusBlacklisted:
return common.Blacklisted, nil
default:
return common.LowPrio, nil
}
isHighPrio = BlockBuilderStatus(res) == RedisBlockBuilderStatusHighPrio
isBlacklisted = BlockBuilderStatus(res) == RedisBlockBuilderStatusBlacklisted
return isHighPrio, isBlacklisted, err
}

func (r *RedisCache) GetBuilderLatestPayloadReceivedAt(slot uint64, builderPubkey, parentHash, proposerPubkey string) (int64, error) {
Expand Down
15 changes: 10 additions & 5 deletions datastore/utils.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package datastore

func MakeBlockBuilderStatus(isHighPrio, isBlacklisted bool) BlockBuilderStatus {
if isBlacklisted {
return RedisBlockBuilderStatusBlacklisted
} else if isHighPrio {
import "github.com/flashbots/mev-boost-relay/common"

func MakeBlockBuilderStatus(c common.BlockBuilderStatusCode) BlockBuilderStatus {
switch c {
case common.HighPrio:
return RedisBlockBuilderStatusHighPrio
} else {
case common.Optimistic:
return RedisBlockBuilderStatusOptimistic
case common.Blacklisted:
return RedisBlockBuilderStatusBlacklisted
default:
return RedisBlockBuilderStatusLowPrio
}
}
Loading