Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ FROM alpine:latest
WORKDIR /app
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /build/relayscan /app/relayscan
COPY --from=builder /build/config-* /app/
COPY --from=builder /build/services/website/templates/ /app/services/website/templates/
COPY --from=builder /build/static/ /app/static/

Expand Down
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,25 @@ https://bidarchive.relayscan.io

* Uses PostgreSQL as data store
* Configuration:
* Relays in [`/vars/relays.go`](/vars/relays.go)
* Relays and builder addresses in [`config-mainnet.yaml`](/config-mainnet.yaml)
* Builder aliases in [`/vars/builder_aliases.go`](/vars/builder_aliases.go)
* Version and common env vars in [`/vars/vars.go`](/vars/vars.go)
* Some environment variables are required, see [`.env.example`](/.env.example)

### Config file

Relay URLs and builder addresses are configured via a YAML config file. By default, `config-mainnet.yaml` is used.

```bash
# Use default config (config-mainnet.yaml)
./relayscan <command>

# Use a custom config file
./relayscan --config config-hoodi.yaml <command>

# Or via environment variable
CONFIG_FILE=config-hoodi.yaml ./relayscan <command>
```
* Saving and checking payloads is split into phases/commands:
* [`data-api-backfill`](/cmd/core/data-api-backfill.go) -- queries the data API of all relays and puts that data into the database
* [`check-payload-value`](/cmd/core/check-payload-value.go) -- checks all new database entries for payment validity
Expand Down
12 changes: 12 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,27 @@ import (
"github.com/spf13/cobra"
)

var configFile string

var rootCmd = &cobra.Command{
Short: "relayscan",
Long: `https://github.com/flashbots/relayscan`,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if configFile == "" {
configFile = "config-mainnet.yaml"
}
return vars.LoadConfig(configFile)
},
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("relayscan %s\n", vars.Version)
_ = cmd.Help()
},
}

func init() {
rootCmd.PersistentFlags().StringVar(&configFile, "config", os.Getenv("CONFIG_FILE"), "path to config file (default: config-mainnet.yaml)")
}

func Execute() {
rootCmd.AddCommand(versionCmd)
rootCmd.AddCommand(core.CoreCmd)
Expand Down
18 changes: 18 additions & 0 deletions config-hoodi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Hoodi beacon chain genesis timestamp (Mar/17, 2025, 12:10 UTC) - https://github.com/eth-clients/hoodi
genesis: 1742213400

relays:
flashbots: "https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@boost-relay-hoodi.flashbots.net"
ultrasound: "https://0xb1559beef7b5ba3127485bbbb090362d9f497ba64e177ee2c8e7db74746306efad687f2cf8574e38d70067d40ef136dc@relay-hoodi.ultrasound.money"
all:
- "https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@boost-relay-hoodi.flashbots.net"
- "https://0xb1559beef7b5ba3127485bbbb090362d9f497ba64e177ee2c8e7db74746306efad687f2cf8574e38d70067d40ef136dc@relay-hoodi.ultrasound.money"
- "https://0x821f2a65afb70e7f2e820a925a9b4c80a159620582c1766b1b09729fec178b11ea22abb3a51f07b288be815a1a2ff516@bloxroute.hoodi.blxrbdn.com"
- "https://0xaa58208899c6105603b74396734a6263cc7d947f444f396a90f7b7d3e65d102aec7e5e5291b27e08d02c50a050825c2f@hoodi.titanrelay.xyz"
- "https://0x98f0ef62f00780cf8eb06701a7d22725b9437d4768bb19b363e882ae87129945ec206ec2dc16933f31d983f8225772b6@hoodi.aestus.live"
- "https://0xb20c3fe59db9c3655088839ef3d972878d182eb745afd8abb1dd2abf6c14f93cd5934ed4446a5fe1ba039e2bc0cf1011@hoodi-relay.ethgas.com"
# haven't had success getting data from TOOL + interstate, but these endpoints are supposed to work...
# - "https://0x9110847c15a7f5c80a9fdd5db989a614cc01104e53bd8c252b6f46a4842c7fdef6b9593336035b5094878deff386804c@hoodi-builder-proxy-alpha.interstate.so:443"
# - "https://0xa0f46566247ceb1f259a7189d5ac8bf2f0f07c135f081b0b5a9f226ef864bf6362c74306fcd02a87b7941f6feac57dc7@relay-hoodi.nuconstruct.xyz"

builder_addresses:
32 changes: 32 additions & 0 deletions config-mainnet.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Mainnet beacon chain genesis timestamp (Dec 1, 2020)
genesis: 1606824023

relays:
flashbots: "https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net"
ultrasound: "https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money"
all:
- "https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net"
- "https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money"
- "https://0x8b5d2e73e2a3a55c6c87b8b6eb92e0149a125c852751db1422fa951e42a09b82c142c3ea98d0d9930b056a3bc9896b8f@bloxroute.max-profit.blxrbdn.com"
- "https://0xb0b07cd0abef743db4260b0ed50619cf6ad4d82064cb4fbec9d3ec530f7c5e6793d9f286c4e082c0244ffb9f2658fe88@bloxroute.regulated.blxrbdn.com"
- "https://0xb3ee7afcf27f1f1259ac1787876318c6584ee353097a50ed84f51a1f21a323b3736f271a895c7ce918c038e4265918be@relay.edennetwork.io"
- "https://0xa7ab7a996c8584251c8f925da3170bdfd6ebc75d50f5ddc4050a6fdc77f2a3b5fce2cc750d0865e05d7228af97d69561@agnostic-relay.net"
- "https://0xa15b52576bcbf1072f4a011c0f99f9fb6c66f3e1ff321f11f461d15e31b1cb359caa092c71bbded0bae5b5ea401aab7e@aestus.live"
- "https://0x8c4ed5e24fe5c6ae21018437bde147693f68cda427cd1122cf20819c30eda7ed74f72dece09bb313f2a1855595ab677d@titanrelay.xyz"
- "https://0x88ef3061f598101ca713d556cf757763d9be93d33c3092d3ab6334a36855b6b4a4020528dd533a62d25ea6648251e62e@relay.ethgas.com"
- "https://0xb66921e917a8f4cfc3c52e10c1e5c77b1255693d9e6ed6f5f444b71ca4bb610f2eff4fa98178efbf4dd43a30472c497e@relay.btcs.com"

builder_addresses:
# Coinbase addresses mapped to their owned addresses
"0xdadb0d80178819f2319190d340ce9a924f783711":
- "0x59cadf9199248b50d40a6891c9e329ea13a88d31"
- "0x75cc09358f100583d66f5277138bfb476345dc1b"
- "0x397b28d85d77fef1576e129bb35b322c2bee1ba1"
"0x4838b106fce9647bdf1e7877bf73ce8b0bad5f97":
- "0x9fc3da866e7df3a1c57ade1a97c9f00a70f010c8"
- "0xb29b9fd58cdb2e3bb068bc8560d8c13b2454684d"
"0x1f9090aae28b8a3dceadf281b0f12828e676c326":
- "0x0affb0a96fbefaa97dce488dfd97512346cf3ab8"
"0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5":
- "0xa83114a443da1cecefc50368531cace9f37fcccb"
- "0x28c74c0f29b686f21ea731bd2a8b88b6954475ba"
5 changes: 3 additions & 2 deletions database/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"net/url"
"time"

"github.com/flashbots/relayscan/vars"
"github.com/sirupsen/logrus"
)

Expand All @@ -22,10 +23,10 @@ func MustConnectPostgres(log *logrus.Entry, dsn string) *DatabaseService {
}

func slotToTime(slot uint64) time.Time {
timestamp := (slot * 12) + 1606824023 // mainnet
timestamp := (slot * 12) + uint64(vars.Genesis)
return time.Unix(int64(timestamp), 0).UTC() //nolint:gosec
}

func timeToSlot(t time.Time) uint64 {
return uint64(t.UTC().Unix()-1606824023) / 12 //nolint:gosec // mainnet
return uint64(t.UTC().Unix()-int64(vars.Genesis)) / 12 //nolint:gosec
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ require (
go.uber.org/atomic v1.11.0
go.uber.org/zap v1.24.0
golang.org/x/text v0.31.0
gopkg.in/yaml.v3 v3.0.1
)

require (
Expand Down Expand Up @@ -93,5 +94,4 @@ require (
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
21 changes: 3 additions & 18 deletions vars/builder_addresses.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,5 @@
package vars

var BuilderAddresses = map[string]map[string]bool{ // coinbase: owned addresses
"0xdadb0d80178819f2319190d340ce9a924f783711": {
"0x59cadf9199248b50d40a6891c9e329ea13a88d31": true,
"0x75cc09358f100583d66f5277138bfb476345dc1b": true,
"0x397b28d85d77fef1576e129bb35b322c2bee1ba1": true,
},
"0x4838b106fce9647bdf1e7877bf73ce8b0bad5f97": {
"0x9fc3da866e7df3a1c57ade1a97c9f00a70f010c8": true,
"0xb29b9fd58cdb2e3bb068bc8560d8c13b2454684d": true,
},
"0x1f9090aae28b8a3dceadf281b0f12828e676c326": {
"0x0affb0a96fbefaa97dce488dfd97512346cf3ab8": true,
},
"0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5": {
"0xa83114a443da1cecefc50368531cace9f37fcccb": true,
"0x28c74c0f29b686f21ea731bd2a8b88b6954475ba": true,
},
}
// BuilderAddresses maps coinbase addresses to their owned addresses
// Populated from config file
var BuilderAddresses map[string]map[string]bool
72 changes: 72 additions & 0 deletions vars/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package vars

import (
"fmt"
"os"

"gopkg.in/yaml.v3"
)

// Config holds the application configuration loaded from YAML
type Config struct {
Genesis int64 `yaml:"genesis"`
Relays RelaysConfig `yaml:"relays"`
BuilderAddresses map[string][]string `yaml:"builder_addresses"`
}

// RelaysConfig holds relay URL configuration
type RelaysConfig struct {
Flashbots string `yaml:"flashbots"`
Ultrasound string `yaml:"ultrasound"`
All []string `yaml:"all"`
}

var loadedConfig *Config

// LoadConfig loads the configuration from a YAML file
func LoadConfig(path string) error {
data, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("failed to read config file %s: %w", path, err)
}

var cfg Config
if err := yaml.Unmarshal(data, &cfg); err != nil {
return fmt.Errorf("failed to parse config file %s: %w", path, err)
}

loadedConfig = &cfg

// Populate package-level variables for backwards compatibility
Genesis = int(cfg.Genesis)
RelayFlashbots = cfg.Relays.Flashbots
RelayUltrasound = cfg.Relays.Ultrasound
RelayURLs = cfg.Relays.All
BuilderAddresses = buildAddressMap(cfg.BuilderAddresses)

return nil
}

// MustLoadConfig loads the configuration or panics on error
func MustLoadConfig(path string) {
if err := LoadConfig(path); err != nil {
panic(err)
}
}

// GetConfig returns the loaded configuration
func GetConfig() *Config {
return loadedConfig
}

// buildAddressMap converts the config format to the expected map[coinbase]map[address]bool format
func buildAddressMap(addresses map[string][]string) map[string]map[string]bool {
result := make(map[string]map[string]bool)
for coinbase, addrs := range addresses {
result[coinbase] = make(map[string]bool)
for _, addr := range addrs {
result[coinbase][addr] = true
}
}
return result
}
23 changes: 4 additions & 19 deletions vars/relays.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,8 @@
package vars

// Relay URLs - populated from config file
var (
RelayFlashbots = "https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net"
RelayUltrasound = "https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money"
RelayURLs = []string{
RelayFlashbots,
RelayUltrasound,
"https://0x8b5d2e73e2a3a55c6c87b8b6eb92e0149a125c852751db1422fa951e42a09b82c142c3ea98d0d9930b056a3bc9896b8f@bloxroute.max-profit.blxrbdn.com",
"https://0xb0b07cd0abef743db4260b0ed50619cf6ad4d82064cb4fbec9d3ec530f7c5e6793d9f286c4e082c0244ffb9f2658fe88@bloxroute.regulated.blxrbdn.com",
"https://0xb3ee7afcf27f1f1259ac1787876318c6584ee353097a50ed84f51a1f21a323b3736f271a895c7ce918c038e4265918be@relay.edennetwork.io",
"https://0xa7ab7a996c8584251c8f925da3170bdfd6ebc75d50f5ddc4050a6fdc77f2a3b5fce2cc750d0865e05d7228af97d69561@agnostic-relay.net",
"https://0xa15b52576bcbf1072f4a011c0f99f9fb6c66f3e1ff321f11f461d15e31b1cb359caa092c71bbded0bae5b5ea401aab7e@aestus.live",
"https://0x8c4ed5e24fe5c6ae21018437bde147693f68cda427cd1122cf20819c30eda7ed74f72dece09bb313f2a1855595ab677d@titanrelay.xyz", // added 2024-02-22
"https://0x88ef3061f598101ca713d556cf757763d9be93d33c3092d3ab6334a36855b6b4a4020528dd533a62d25ea6648251e62e@relay.ethgas.com", // added 2025-09-24
"https://0xb66921e917a8f4cfc3c52e10c1e5c77b1255693d9e6ed6f5f444b71ca4bb610f2eff4fa98178efbf4dd43a30472c497e@relay.btcs.com", // added 2025-09-24
// "https://0x95a0a6af2566fa7db732020bb2724be61963ac1eb760aa1046365eb443bd4e3cc0fba0265d40a2d81dd94366643e986a@blockspace.frontier.tech", // data API doesn't work anymore (as of June 1, 2024)
// "https://0xad0a8bb54565c2211cee576363f3a347089d2f07cf72679d16911d740262694cadb62d7fd7483f27afd714ca0f1b9118@bloxroute.ethical.blxrbdn.com", // deactivated aug 2023: https://twitter.com/bloXrouteLabs/status/1690065892778926080
// "https://0x9000009807ed12c1f08bf4e81c6da3ba8e3fc3d953898ce0102433094e5f22f21102ec057841fcb81978ed1ea0fa8246@builder-relay-mainnet.blocknative.com", // deactivated sept. 27, 2023: https://twitter.com/blocknative/status/1706685103286485364
// "https://0x98650451ba02064f7b000f5768cf0cf4d4e492317d82871bdc87ef841a0743f69f0f1eea11168503240ac35d101c9135@mainnet-relay.securerpc.com",
// "https://0x8c7d33605ecef85403f8b7289c8058f440cbb6bf72b055dfe2f3e2c6695b6a1ea5a9cd0eb3a7982927a463feb4c3dae2@relay.wenmerge.com",
}
RelayFlashbots string
RelayUltrasound string
RelayURLs []string
)
2 changes: 1 addition & 1 deletion vars/vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var (
Version = "dev" // is set during build process
LogDebug = os.Getenv("DEBUG") != ""
LogJSON = os.Getenv("LOG_JSON") != ""
Genesis = cli.GetEnvInt("GENESIS", 1_606_824_023)
Genesis = 1_606_824_023 // mainnet default, overwritten by config file

DefaultBeaconURI = relaycommon.GetEnv("BEACON_URI", "http://localhost:3500")
DefaultPostgresDSN = relaycommon.GetEnv("POSTGRES_DSN", "postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable")
Expand Down
Loading