-
Notifications
You must be signed in to change notification settings - Fork 13
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
Improve builder profit estimation by taking bid adjustments into account #55
Open
ababino
wants to merge
24
commits into
flashbots:main
Choose a base branch
from
ababino:bid-adjustments
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
cba2f27
feat: Add support for bid adjustment data in backfill process
ababino 774bb53
fix: Add adjustment data retrieval and storage
ababino 6b8a969
feat: add backfill adjustments functionality
ababino ea5c884
fix migration file name
ababino 6a0d8e8
keep migration style
ababino 3e0123d
centralize var names in vars.go file
ababino 3182cbc
fix url. use vars. fix func args
ababino 901aa8c
fix relay url. add logs
ababino 563e2dc
fix: Update data-api-backfill to handle adjustment data correctly
ababino e095d93
feat: create new bid-adjustments-backfill command
ababino ee355ec
del old code
ababino 74fc493
del old code
ababino 922f12c
add command in core.go
ababino c96f89c
fix minSlot flag
ababino 50f180b
stop when 403. fix min-slot flag
ababino 81f37df
speed up
ababino 872e19d
amend bulder profit query
ababino debb807
remove unused var
ababino 88dde5b
add slot index to adjustements table
ababino 546c7d7
fix lint issues
ababino 593f6b1
optimize adjustments table index
ababino e2ce26f
optimize profit query
ababino 13cb34a
add backfill_adjustments script
ababino ce680ea
add new commands to README
ababino File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,4 +24,5 @@ | |
/deploy* | ||
/test.csv | ||
/csv/ | ||
/build/ | ||
/build/ | ||
.aider* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
package core | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
"time" | ||
|
||
"github.com/flashbots/relayscan/common" | ||
"github.com/flashbots/relayscan/database" | ||
"github.com/flashbots/relayscan/vars" | ||
"github.com/sirupsen/logrus" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var bidAdjustmentRelay string | ||
|
||
func init() { | ||
bidAdjustmentsBackfillCmd.Flags().StringVar(&bidAdjustmentRelay, "relay", "relay.ultrasound.money", "relay to fetch bid adjustments from") | ||
bidAdjustmentsBackfillCmd.Flags().Int64Var(&minSlot, "min-slot", 0, "minimum slot (if unset, backfill until the merge, negative number for that number of slots before latest)") | ||
} | ||
|
||
var bidAdjustmentsBackfillCmd = &cobra.Command{ | ||
Use: "bid-adjustments-backfill", | ||
Short: "Backfill bid adjustments data", | ||
Run: func(cmd *cobra.Command, args []string) { | ||
db := database.MustConnectPostgres(log, vars.DefaultPostgresDSN) | ||
defer db.Close() | ||
|
||
relay, err := common.NewRelayEntry(bidAdjustmentRelay, false) | ||
if err != nil { | ||
log.WithError(err).Fatal("failed to create relay entry") | ||
} | ||
|
||
log.Infof("minSlot %d", minSlot) | ||
// If needed, get latest slot (i.e. if min-slot is negative) | ||
if minSlot < 0 { | ||
log.Infof("Getting latest slot from beaconcha.in for offset %d", minSlot) | ||
latestSlotOnBeaconChain := common.MustGetLatestSlot() | ||
log.Infof("Latest slot from beaconcha.in: %d", latestSlotOnBeaconChain) | ||
minSlot = int64(latestSlotOnBeaconChain) + minSlot | ||
} | ||
|
||
if minSlot != 0 { | ||
log.Infof("Using min slot: %d", minSlot) | ||
} | ||
|
||
backfiller := newBidAdjustmentsBackfiller(db, relay, uint64(minSlot)) | ||
err = backfiller.backfillAdjustments() | ||
if err != nil { | ||
log.WithError(err).Fatal("failed to backfill adjustments") | ||
} | ||
}, | ||
} | ||
|
||
type bidAdjustmentsBackfiller struct { | ||
db *database.DatabaseService | ||
relay common.RelayEntry | ||
minSlot uint64 | ||
} | ||
|
||
func newBidAdjustmentsBackfiller(db *database.DatabaseService, relay common.RelayEntry, minSlot uint64) *bidAdjustmentsBackfiller { | ||
return &bidAdjustmentsBackfiller{ | ||
db: db, | ||
relay: relay, | ||
minSlot: minSlot, | ||
} | ||
} | ||
|
||
func (bf *bidAdjustmentsBackfiller) backfillAdjustments() error { | ||
_log := log.WithField("relay", bf.relay.Hostname()) | ||
_log.Info("Backfilling adjustments...") | ||
|
||
baseURL := bf.relay.GetURI("/ultrasound/v1/data/adjustments") | ||
latestSlot, err := bf.db.GetLatestAdjustmentSlot() | ||
if err != nil { | ||
return fmt.Errorf("failed to get latest adjustment slot: %w", err) | ||
} | ||
|
||
if bf.minSlot < latestSlot { | ||
bf.minSlot = latestSlot | ||
} | ||
|
||
// Hardcoded ultrasoiund first slot with data see https://github.com/ultrasoundmoney/docs/blob/main/bid_adjustment.md#data-api | ||
const ultrasoundFirstBidAdjustmentSlot = 7869470 | ||
if bf.minSlot < ultrasoundFirstBidAdjustmentSlot { | ||
bf.minSlot = ultrasoundFirstBidAdjustmentSlot | ||
} | ||
|
||
const ultrasoundEndStatusCode = 403 | ||
for slot := bf.minSlot; ; slot++ { | ||
_log.WithField("slot", slot).Info("Fetching adjustments...") | ||
url := fmt.Sprintf("%s?slot=%d", baseURL, slot) | ||
|
||
var response common.UltrasoundAdjustmentResponse | ||
statusCode, err := common.SendHTTPRequest(context.Background(), *http.DefaultClient, http.MethodGet, url, nil, &response) | ||
_log.WithField("status code", statusCode).Info("Response") | ||
if statusCode == ultrasoundEndStatusCode { | ||
_log.WithField("Status Code", statusCode).Info("Stopping backfill due to 403") | ||
break | ||
} | ||
if err != nil { | ||
_log.WithError(err).Error("Failed to fetch adjustments") | ||
return nil | ||
} | ||
|
||
if len(response.Data) > 0 { | ||
adjustments := make([]*database.AdjustmentEntry, len(response.Data)) | ||
for i, adjustment := range response.Data { | ||
submittedReceivedAt, err := time.Parse(time.RFC3339, adjustment.SubmittedReceivedAt) | ||
if err != nil { | ||
_log.WithError(err).Error("Failed to parse SubmittedReceivedAt") | ||
continue | ||
} | ||
adjustments[i] = &database.AdjustmentEntry{ | ||
Slot: slot, | ||
AdjustedBlockHash: adjustment.AdjustedBlockHash, | ||
AdjustedValue: adjustment.AdjustedValue, | ||
BlockNumber: adjustment.BlockNumber, | ||
BuilderPubkey: adjustment.BuilderPubkey, | ||
Delta: adjustment.Delta, | ||
SubmittedBlockHash: adjustment.SubmittedBlockHash, | ||
SubmittedReceivedAt: submittedReceivedAt, | ||
SubmittedValue: adjustment.SubmittedValue, | ||
} | ||
} | ||
|
||
err = bf.db.SaveAdjustments(adjustments) | ||
if err != nil { | ||
_log.WithError(err).Error("Failed to save adjustments") | ||
} else { | ||
for _, entry := range adjustments { | ||
_log.WithFields(logrus.Fields{ | ||
"Slot": entry.Slot, | ||
"SubmittedValue": entry.SubmittedValue, | ||
"AdjustedValue": entry.AdjustedValue, | ||
"Delta": entry.Delta, | ||
}).Info("Adjustment data") | ||
} | ||
_log.WithField("count", len(adjustments)).Info("Saved adjustments") | ||
} | ||
} else { | ||
_log.Info("No adjustments found for this slot") | ||
// break | ||
} | ||
|
||
time.Sleep(time.Duration(50) * time.Microsecond) // Rate limiting | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package migrations | ||
|
||
import ( | ||
"github.com/flashbots/relayscan/database/vars" | ||
migrate "github.com/rubenv/sql-migrate" | ||
) | ||
|
||
var migration005SQL = `CREATE TABLE IF NOT EXISTS ` + vars.TableAdjustments + ` ( | ||
id SERIAL PRIMARY KEY, | ||
inserted_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), | ||
slot BIGINT NOT NULL, | ||
adjusted_block_hash TEXT NOT NULL, | ||
adjusted_value TEXT NOT NULL, | ||
block_number BIGINT NOT NULL, | ||
builder_pubkey TEXT NOT NULL, | ||
delta TEXT NOT NULL, | ||
submitted_block_hash TEXT NOT NULL, | ||
submitted_received_at TIMESTAMP WITH TIME ZONE NOT NULL, | ||
submitted_value TEXT NOT NULL, | ||
UNIQUE(slot, adjusted_block_hash) | ||
);` | ||
|
||
var Migration005CreateAdjustmentsTable = &migrate.Migration{ | ||
Id: "005-create-adjustments-table", | ||
Up: []string{migration005SQL}, | ||
|
||
DisableTransactionUp: false, | ||
DisableTransactionDown: true, | ||
} |
16 changes: 16 additions & 0 deletions
16
database/migrations/006_add_slot_block_index_to_bid_adjustments.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package migrations | ||
|
||
import ( | ||
"github.com/flashbots/relayscan/database/vars" | ||
migrate "github.com/rubenv/sql-migrate" | ||
) | ||
|
||
var migration006SQL = `CREATE INDEX IF NOT EXISTS idx_` + vars.TableAdjustments + `_slot_block ON ` + vars.TableAdjustments + ` (slot, adjusted_block_hash);` | ||
|
||
var Migration006AddSlotBlockIndexToAdjustments = &migrate.Migration{ | ||
Id: "006-add-slot-block-index-to-adjustments", | ||
Up: []string{migration006SQL}, | ||
|
||
DisableTransactionUp: false, | ||
DisableTransactionDown: true, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#!/bin/bash | ||
set -e | ||
dir=$( dirname -- "$0"; ) | ||
cd $dir | ||
cd .. | ||
source .env.prod | ||
./relayscan core bid-adjustments-backfill 2>&1 | /usr/bin/tee -a /var/log/relayscan.log |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This query worries me a little bit -- how much more expensive is it to run? Not sure if this could be a bottleneck. Do you have any data or estimates on query performance?