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

release: v1.3.9 validator #7

Closed
wants to merge 1 commit into from
Closed
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
17 changes: 17 additions & 0 deletions blxr/blxerr/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package blxerr

import (
"fmt"
"math/big"
)

// ProposedBlockLessProfitableErr happens when a proposed block cannot be accepted because of the block is less profitable
// than a cached block.
type ProposedBlockLessProfitableErr struct {
RewardThreshold *big.Int
}

func (err ProposedBlockLessProfitableErr) Error() string {
// do not change error message as it's sent to validator's clients and builders parse it!
return fmt.Sprintf("block cannot be accepted. Reward threshold is %d", err.RewardThreshold)
}
39 changes: 39 additions & 0 deletions blxr/blxerr/errors_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package blxerr

import (
"math/big"
"testing"
)

func TestProposedBlockLessProfitableErr_Error(t *testing.T) {
type fields struct {
RewardThreshold *big.Int
}
tests := []struct {
name string
fields fields
want string
}{
{
"with reward value",
fields{big.NewInt(10_000)},
"block cannot be accepted. Reward threshold is 10000",
},

{
"without reward value",
fields{nil},
"block cannot be accepted. Reward threshold is <nil>",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ProposedBlockLessProfitableErr{
RewardThreshold: tt.fields.RewardThreshold,
}
if got := err.Error(); got != tt.want {
t.Errorf("Error() = %v, want %v", got, tt.want)
}
})
}
}
19 changes: 19 additions & 0 deletions blxr/version/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package version

import (
"runtime/debug"
)

var commitHash = func() string {
if info, ok := debug.ReadBuildInfo(); ok {
for _, setting := range info.Settings {
if setting.Key == "vcs.revision" {
return setting.Value
}
}
}
return ""
}()

// CommitHash returns the commit hash of the current build
func CommitHash() string { return commitHash }
3 changes: 2 additions & 1 deletion build/ci.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,13 +354,14 @@ func doLint(cmdline []string) {

linter := downloadLinter(*cachedir)
lflags := []string{"run", "--config", ".golangci.yml"}
build.MustRunCommand("./build/goimports.sh") // BX: add run of default goimports
build.MustRunCommand(linter, append(lflags, packages...)...)
fmt.Println("You have achieved perfection.")
}

// downloadLinter downloads and unpacks golangci-lint.
func downloadLinter(cachedir string) string {
const version = "1.52.2"
const version = "1.55.2"

csdb := build.MustLoadChecksums("build/checksums.txt")
arch := runtime.GOARCH
Expand Down
2 changes: 1 addition & 1 deletion build/goimports.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ find_files() {
-o -path './crypto/bn256' \
-o -path '*/vendor/*' \
\) -prune \
\) -name '*.go'
\) -name '*.go' -not -name '*.pb.go' -not -name '*_rlp.go'
}

GOFMT="gofmt -s -w"
Expand Down
2 changes: 1 addition & 1 deletion cmd/clef/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,7 @@ func signer(c *cli.Context) error {
if err != nil {
utils.Fatalf("Could not register API: %w", err)
}
handler := node.NewHTTPHandlerStack(srv, cors, vhosts, nil)
handler := node.NewHTTPHandlerStack(srv, cors, vhosts, nil, nil)

// set port
port := c.Int(rpcPortFlag.Name)
Expand Down
2 changes: 1 addition & 1 deletion cmd/geth/consolecmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
)

const (
ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 parlia:1.0 rpc:1.0 txpool:1.0 web3:1.0"
ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 mev:1.0 miner:1.0 net:1.0 parlia:1.0 rpc:1.0 txpool:1.0 web3:1.0"
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
)

Expand Down
2 changes: 1 addition & 1 deletion cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ var (
utils.BLSPasswordFileFlag,
utils.BLSWalletDirFlag,
utils.VoteJournalDirFlag,
}, utils.NetworkFlags, utils.DatabasePathFlags)
}, utils.NetworkFlags, utils.DatabasePathFlags, utils.HTTPSecuredFlags, utils.MinerMEVFlags)

rpcFlags = []cli.Flag{
utils.HTTPEnabledFlag,
Expand Down
2 changes: 2 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -1522,6 +1522,7 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) {
SetP2PConfig(ctx, &cfg.P2P)
setIPC(ctx, cfg)
setHTTP(ctx, cfg)
setHTTPSecuredIP(ctx, cfg)
setGraphQL(ctx, cfg)
setWS(ctx, cfg)
setNodeUserIdent(ctx, cfg)
Expand Down Expand Up @@ -1800,6 +1801,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
setMiner(ctx, &cfg.Miner)
setRequiredBlocks(ctx, cfg)
setLes(ctx, cfg)
setMEV(ctx, stack, &cfg.Miner)

// Cap the cache allowance and tune the garbage collector
mem, err := gopsutil.VirtualMemory()
Expand Down
195 changes: 195 additions & 0 deletions cmd/utils/flags_blxr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
package utils

import (
"strings"

"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/node"
"github.com/urfave/cli/v2"
)

var (
HTTPSecuredIPPortFlag = &cli.IntFlag{
Name: "http.securedipport",
Usage: "HTTP-RPC server secured by IP listening port",
Value: node.DefaultHTTPSecuredIPPort,
Category: flags.APICategory,
}
HTTPSecuredIPAllowedIPsFlag = &cli.StringFlag{
Name: "http.securedipvallowedipss",
Usage: "Comma separated list of IPs from which to accept requests (server enforced). Accepts '*' wildcard.",
Value: strings.Join(node.DefaultConfig.HTTPSecuredIPAllowedIPs, ","),
Category: flags.APICategory,
}
HTTPSecuredIPApiFlag = &cli.StringFlag{
Name: "http.securedipapi",
Usage: "Comma separated list of API's offered over the HTTP-RPC secured by IP interface",
Value: "",
Category: flags.APICategory,
}

HTTPSecuredFlags = []cli.Flag{
HTTPSecuredIPPortFlag,
HTTPSecuredIPAllowedIPsFlag,
HTTPSecuredIPApiFlag,
}
)

// setHTTPSecuredIP creates the HTTP MEV RPC listener interface string from the set
// command line flags, returning empty if the HTTP endpoint is disabled.
func setHTTPSecuredIP(ctx *cli.Context, cfg *node.Config) {
if ctx.Bool(HTTPEnabledFlag.Name) {
if cfg.HTTPHost == "" {
cfg.HTTPHost = "127.0.0.1"
}
if ctx.IsSet(HTTPListenAddrFlag.Name) {
cfg.HTTPHost = ctx.String(HTTPListenAddrFlag.Name)
}
}

if ctx.IsSet(HTTPSecuredIPPortFlag.Name) {
cfg.HTTPSecuredIPPort = ctx.Int(HTTPSecuredIPPortFlag.Name)
}

if ctx.IsSet(HTTPCORSDomainFlag.Name) {
cfg.HTTPCors = SplitAndTrim(ctx.String(HTTPCORSDomainFlag.Name))
}

if ctx.IsSet(HTTPSecuredIPApiFlag.Name) {
cfg.HTTPSecuredIPModules = SplitAndTrim(ctx.String(HTTPSecuredIPApiFlag.Name))
}

if ctx.IsSet(HTTPSecuredIPAllowedIPsFlag.Name) {
cfg.HTTPSecuredIPAllowedIPs = SplitAndTrim(ctx.String(HTTPSecuredIPAllowedIPsFlag.Name))
}

if ctx.IsSet(HTTPPathPrefixFlag.Name) {
cfg.HTTPPathPrefix = ctx.String(HTTPPathPrefixFlag.Name)
}

if ctx.IsSet(AllowUnprotectedTxs.Name) {
cfg.AllowUnprotectedTxs = ctx.Bool(AllowUnprotectedTxs.Name)
}
}

var (
MinerMEVRelaysFlag = &cli.StringSliceFlag{
Name: "miner.mevrelays",
Usage: "Destinations to register the validator each epoch. The miner will accept proposed blocks from these urls, if they are profitable.",
Category: flags.MinerCategory,
}
MinerMEVProposedBlockUriFlag = &cli.StringFlag{
Name: "miner.mevproposedblockuri",
Usage: "The uri MEV relays should send the proposedBlock to.",
Category: flags.MinerCategory,
}
MinerMEVProposedBlockNamespaceFlag = &cli.StringFlag{
Name: "miner.mevproposedblocknamespace",
Usage: "The namespace implements the proposedBlock function (default = eth). ",
Value: "eth",
Category: flags.MinerCategory,
}
MinerPreferMEVRelays = &cli.StringSliceFlag{
Name: "miner.prefer-mev-relays",
Usage: "Enable preferring specific mev-relays",
Category: flags.MinerCategory,
}

MinerMEVFlags = []cli.Flag{
MinerMEVRelaysFlag,
MinerMEVProposedBlockUriFlag,
MinerMEVProposedBlockNamespaceFlag,
MinerPreferMEVRelays,
}
)

func setMEV(ctx *cli.Context, stack *node.Node, cfg *miner.Config) {
if ctx.IsSet(MinerMEVRelaysFlag.Name) {
cfg.MEVRelays = ctx.StringSlice(MinerMEVRelaysFlag.Name)
}

if len(cfg.MEVRelays) != 0 {
if ctx.IsSet(MinerPreferMEVRelays.Name) {
cfg.PreferMEVRelays = miner.NewAcceptRelayMap(ctx.StringSlice(MinerPreferMEVRelays.Name)...)
} else {
cfg.PreferMEVRelays = miner.NewAcceptRelayMap()
}
}

if len(cfg.MEVRelays) == 0 {
return
}

keystores := stack.AccountManager().Backends(keystore.KeyStoreType)
if len(keystores) == 0 {
return
}

ks, ok := keystores[0].(*keystore.KeyStore)
if !ok {
return
}

if ctx.IsSet(MinerMEVProposedBlockUriFlag.Name) {
cfg.ProposedBlockUri = ctx.String(MinerMEVProposedBlockUriFlag.Name)
}

if cfg.ProposedBlockNamespace == "" && ctx.IsSet(MinerMEVProposedBlockNamespaceFlag.Name) {
cfg.ProposedBlockNamespace = ctx.String(MinerMEVProposedBlockNamespaceFlag.Name)
}

account, err := ks.Find(accounts.Account{Address: cfg.Etherbase})
if err != nil {
Fatalf("Could not find the validator public address %v to sign the registerValidator message, %v", cfg.Etherbase, err)
}

registerHash := accounts.TextHash([]byte(cfg.ProposedBlockUri))
passwordList := MakePasswordList(ctx)
if passwordList == nil {
cfg.RegisterValidatorSignedHash, err = ks.SignHash(account, registerHash)
if err != nil {
Fatalf("Failed sign registerValidator message unlocked with error: %v", err)
}
} else {
passwordFound := false
for _, password := range passwordList {
cfg.RegisterValidatorSignedHash, err = ks.SignHashWithPassphrase(account, password, registerHash)
if err == nil {
passwordFound = true
break
}
}
if !passwordFound {
Fatalf("Failed sign registerValidator message with passphrase with error")
}
}

signature := make([]byte, crypto.SignatureLength)
copy(signature, cfg.RegisterValidatorSignedHash)
// verify the validator public address used to sign the registerValidator message
if len(signature) != crypto.SignatureLength {
Fatalf("signature used to sign registerValidator must be %d bytes long", crypto.SignatureLength)
}

if signature[crypto.RecoveryIDOffset] == 27 || signature[crypto.RecoveryIDOffset] == 28 {
signature[crypto.RecoveryIDOffset] -= 27 // Transform yellow paper V from 27/28 to 0/1
}

if signature[crypto.RecoveryIDOffset] != 0 && signature[crypto.RecoveryIDOffset] != 1 {
Fatalf("invalid Ethereum signature of the registerValidator (V is not 0, or 1, or 27 or 28), it is %v", cfg.RegisterValidatorSignedHash[crypto.RecoveryIDOffset])
}

rpk, err := crypto.SigToPub(registerHash, signature)
if err != nil {
Fatalf("Failed to get validator public address from the registerValidator signed message %v", err)
}

addr := crypto.PubkeyToAddress(*rpk)
if addr != account.Address {
Fatalf("Validator public Etherbase %v was not used to sign the registerValidator %v", account.Address, addr)
}
}
38 changes: 38 additions & 0 deletions eth/api_backend_blxr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package eth

import (
"context"
"math/big"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rpc"
)

func (b *EthAPIBackend) ProposedBlock(ctx context.Context, mevRelay string, blockNumber *big.Int, prevBlockHash common.Hash, reward *big.Int, gasLimit uint64, gasUsed uint64, txs types.Transactions, unRevertedHashes map[common.Hash]struct{}) (simDuration time.Duration, err error) {
return b.eth.miner.ProposedBlock(ctx, mevRelay, blockNumber, prevBlockHash, reward, gasLimit, gasUsed, txs, unRevertedHashes)
}

func (b *EthAPIBackend) AddRelay(ctx context.Context, mevRelay string) error {
select {
case <-ctx.Done():
return ctx.Err()
default:
return b.eth.miner.AddRelay(ctx, mevRelay)
}
}

func (b *EthAPIBackend) RemoveRelay(ctx context.Context, mevRelay string) error {
select {
case <-ctx.Done():
return ctx.Err()
default:
return b.eth.miner.RemoveRelay(mevRelay)
}
}

func (b *EthAPIBackend) BlockNumber(ctx context.Context) uint64 {
header, _ := b.HeaderByNumber(ctx, rpc.LatestBlockNumber) // latest header should always be available
return header.Number.Uint64()
}
Loading
Loading