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 15 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
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 Optimistic:
return "optimistic"
case HighPrio:
return "high-prio"
case Blacklisted:
return "blacklisted"
default:
return "low-prio"
}
}
90 changes: 82 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(bidTrace *common.BidTraceV2, 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,74 @@ func (s *DatabaseService) DeleteExecutionPayloads(idFirst, idLast uint64) error
_, err := s.DB.Exec(query, idFirst, idLast)
return err
}

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

_bidTrace, err := json.Marshal(bidTrace)
if err != nil {
return err
}
builderDemotionEntry := BuilderDemotionEntry{
UnsignedBidTrace: NewNullString(string(_bidTrace)),

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 + `
(unsigned_bid_trace, signed_blinded_beacon_block, signed_validator_registration, slot, epoch, builder_pubkey, proposer_pubkey, value, fee_recipient, gas_limit, block_hash) VALUES
(:unsigned_bid_trace, :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 + `
(unsigned_bid_trace, signed_blinded_beacon_block, signed_validator_registration, slot, epoch, builder_pubkey, proposer_pubkey, value, fee_recipient, gas_limit, block_hash) VALUES
(:unsigned_bid_trace, :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,

unsigned_bid_trace 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
10 changes: 9 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.BuilderStatus) error {
return nil
}

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

func (db MockDB) UpsertBuilderDemotion(bidTrace *common.BidTraceV2, signedBlindedBeaconBlock *types.SignedBlindedBeaconBlock, signedValidatorRegistration *types.SignedValidatorRegistration) error {
return nil
}

func (db MockDB) GetBlockBuildersFromCollateralID(collateralID uint64) ([]*BlockBuilderEntry, error) {
return nil, 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"`
Collateral 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"`

UnsignedBidTrace sql.NullString `db:"unsigned_bid_trace"`
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"
)
57 changes: 34 additions & 23 deletions datastore/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,6 @@ var (
ErrFailedUpdatingTopBidNoBids = errors.New("failed to update top bid because no bids were found")
)

type BlockBuilderStatus string

var (
RedisBlockBuilderStatusLowPrio BlockBuilderStatus = ""
RedisBlockBuilderStatusHighPrio BlockBuilderStatus = "high-prio"
RedisBlockBuilderStatusBlacklisted BlockBuilderStatus = "blacklisted"
)

func PubkeyHexToLowerStr(pk types.PubkeyHex) string {
return strings.ToLower(string(pk))
}
Expand Down Expand Up @@ -77,10 +69,11 @@ type RedisCache struct {
keyKnownValidators string
keyValidatorRegistrationTimestamp string

keyRelayConfig string
keyStats string
keyProposerDuties string
keyBlockBuilderStatus string
keyRelayConfig string
keyStats string
keyProposerDuties string
keyBuilderStatus string
keyBuilderCollateral string
}

func NewRedisCache(redisURI, prefix string) (*RedisCache, error) {
Expand All @@ -105,9 +98,10 @@ func NewRedisCache(redisURI, prefix string) (*RedisCache, error) {
keyValidatorRegistrationTimestamp: fmt.Sprintf("%s/%s:validator-registration-timestamp", redisPrefix, prefix),
keyRelayConfig: fmt.Sprintf("%s/%s:relay-config", redisPrefix, prefix),

keyStats: fmt.Sprintf("%s/%s:stats", redisPrefix, prefix),
keyProposerDuties: fmt.Sprintf("%s/%s:proposer-duties", redisPrefix, prefix),
keyBlockBuilderStatus: fmt.Sprintf("%s/%s:block-builder-status", redisPrefix, prefix),
keyStats: fmt.Sprintf("%s/%s:stats", redisPrefix, prefix),
keyProposerDuties: fmt.Sprintf("%s/%s:proposer-duties", redisPrefix, prefix),
keyBuilderStatus: fmt.Sprintf("%s/%s:block-builder-status", redisPrefix, prefix),
keyBuilderCollateral: fmt.Sprintf("%s/%s:block-builder-collateral", redisPrefix, prefix),
}, nil
}

Expand Down Expand Up @@ -323,18 +317,35 @@ func (r *RedisCache) GetBidTrace(slot uint64, proposerPubkey, blockHash string)
return resp, err
}

func (r *RedisCache) SetBlockBuilderStatus(builderPubkey string, status BlockBuilderStatus) (err error) {
return r.client.HSet(context.Background(), r.keyBlockBuilderStatus, builderPubkey, string(status)).Err()
func (r *RedisCache) SetBuilderStatus(builderPubkey string, status common.BuilderStatus) (err error) {
return r.client.HSet(context.Background(), r.keyBuilderStatus, builderPubkey, status).Err()
}

func (r *RedisCache) GetBuilderStatus(builderPubkey string) (status common.BuilderStatus, err error) {
res, err := r.client.HGet(context.Background(), r.keyBuilderStatus, builderPubkey).Result()
if errors.Is(err, redis.Nil) {
return status, nil
}
in, err := strconv.Atoi(res)
if err != nil {
return status, err
}
return common.BuilderStatus(in), nil
}

func (r *RedisCache) SetBuilderCollateral(builderPubkey, value string) (err error) {
return r.client.HSet(context.Background(), r.keyBuilderCollateral, builderPubkey, value).Err()
}

func (r *RedisCache) GetBlockBuilderStatus(builderPubkey string) (isHighPrio, isBlacklisted bool, err error) {
res, err := r.client.HGet(context.Background(), r.keyBlockBuilderStatus, builderPubkey).Result()
func (r *RedisCache) GetBuilderCollateral(builderPubkey string) (value string, err error) {
res, err := r.client.HGet(context.Background(), r.keyBuilderCollateral, builderPubkey).Result()
if errors.Is(err, redis.Nil) {
return false, false, nil
return "", nil
}
if err != nil {
return "", err
}
isHighPrio = BlockBuilderStatus(res) == RedisBlockBuilderStatusHighPrio
isBlacklisted = BlockBuilderStatus(res) == RedisBlockBuilderStatusBlacklisted
return isHighPrio, isBlacklisted, err
return res, nil
}

func (r *RedisCache) GetBuilderLatestPayloadReceivedAt(slot uint64, builderPubkey, parentHash, proposerPubkey string) (int64, error) {
Expand Down
11 changes: 0 additions & 11 deletions datastore/utils.go

This file was deleted.

Loading