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

feat: take pay bid tx as block identifier #6

Merged
merged 2 commits into from
Apr 1, 2024
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
62 changes: 60 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,62 @@
# BSC-MEV-Sentry

BSC-MEV-Sentry is a proxy service within the BSC MEV architecture designed to shield the validator network.
It functions to forward requests and pay to builders.
BSC-MEV-Sentry serves as the proxy service for BSC MEV architecture, It has the following features:

1. Forward RPC requests: mev_sendBid, mev_params, mev_running, mev_bestBidGasFee to validators.
2. Forward RPC request: mev_reportIssue to builders.
3. Pay builders on behalf of validators for their bids.
4. Monitor validators' status and health.

See also: https://github.com/bnb-chain/BEPs/pull/322

For the details of mev_params, here are some notices:

1. The builder can call mev_params to obtain the delayLeftOver and bidSimulationLeftOver time settings, and then call
the [BidBetterBefore](https://github.com/bnb-chain/bsc/blob/master/common/bidutil/bidutil.go) to calculate the
deadline for sending the bid.
2. The builder can call mev_params to obtain the gasCeil of the validator, to generate a valid header in the block
building settlement.
3. The builder can call mev_params to obtain the builderFeeCeil of the validator, to help to decide the builder fee.

# Usage
unclezoro marked this conversation as resolved.
Show resolved Hide resolved

1. `make build`
2. `.build/sentry -config ./configs/config.toml`

Sentry settings are configured in the `config.toml` file. The following is an example of a `config.toml` file:

```
[Service]
HTTPListenAddr = "localhost:8555" # The address to listen on for HTTP requests.
RPCConcurrency = 100 # The maximum number of concurrent requests.
RPCTimeout = "10s" # The timeout for RPC requests.

[[Validators]] # A list of validators to forward requests to.
PrivateURL = "https://bsc-fuji" # The private rpc url of the validator, it can only been accessed in the local network.
PublicHostName = "bsc-fuji" # The domain name of the validator, if a request's HOST info is same with this, it will be forwarded to the validator.
PayAccountMode = "privateKey" # The unlock mode of the pay bid account.
unclezoro marked this conversation as resolved.
Show resolved Hide resolved
PrivateKey = "59ba8068eb256d520179e903f43dacf6d8d57d72bd306e1bd603fdb8c8da10e8" # The private key of the pay bid account.

[[Validators]]
PrivateURL = "https://bsc-mathwallet"
PublicHostName = "bsc-mathwallet"
PayAccountMode = "keystore"
KeystorePath = "./keystore" # The keystore file path of the pay bid account.
PasswordFilePath = "./password.txt" # The path of the pay bid account's password file.
PayAccountAddress = "0x12c86Bf9...845B98F23" # The address of the pay bid account.

[[Validators]]
PrivateURL = "https://bsc-trustwallet"
PublicHostName = "bsc-trustwallet"
PayAccountMode = "privateKey" # The unlock mode of the pay account.
PrivateKey = "59ba8068eb256d520179e903f43dacf6d8d57d72bd306e1bd603fdb8c8da10e8" # The private key of the pay account.

[[Builders]]
Address = "0x45EbEBe8...664D59c12" # The address of the builder.
URL = "http://bsc-builder-1" # The public URL of the builder.

[[Builders]]
Address = "0x980A75eC...fc9b863D5"
URL = "http://bsc-builder-2"

```
94 changes: 46 additions & 48 deletions account/account.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package account

import (
"context"
"crypto/ecdsa"
"errors"
"math/big"
"os"
"strings"

"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore"
Expand All @@ -13,7 +14,6 @@ import (
"github.com/ethereum/go-ethereum/crypto"

"github.com/bnb-chain/bsc-mev-sentry/log"
"github.com/bnb-chain/bsc-mev-sentry/node"
)

unclezoro marked this conversation as resolved.
Show resolved Hide resolved
type Mode string
Expand All @@ -24,17 +24,18 @@ const (
)

type Account interface {
PayBidTx(context.Context, node.FullNode, common.Address, *big.Int) ([]byte, error)
Address() common.Address
SignTx(tx *types.Transaction, chainID *big.Int) (*types.Transaction, error)
}

func New(config *Config) (Account, error) {
switch config.Mode {
case privateKeyMode:
return newPrivateKeyAccount(config.PrivateKey)
case keystoreMode:
return newKeystoreAccount(config.KeystorePath, config.Password, config.Address)
return newKeystoreAccount(config.KeystorePath, config.PasswordFilePath, config.Address)
default:
return nil, errors.New("invalid account mode")
return nil, errors.New("invalid pay account mode")
}
}

Expand All @@ -44,60 +45,64 @@ type Config struct {
PrivateKey string
// KeystorePath path of keystore
KeystorePath string
// Password keystore password
Password string
// PasswordFilePath stores keystore password
PasswordFilePath string
// Address public address of sentry wallet
Address string
}

type baseAccount struct {
address common.Address
}

func (a *baseAccount) Address() common.Address {
return a.address
}

type keystoreAccount struct {
keystore *keystore.KeyStore
account accounts.Account
*baseAccount
}

func newKeystoreAccount(keystorePath, password, opAccount string) (*keystoreAccount, error) {
func newKeystoreAccount(keystorePath, passwordFilePath, opAccount string) (*keystoreAccount, error) {
address := common.HexToAddress(opAccount)
ks := keystore.NewKeyStore(keystorePath, keystore.StandardScryptN, keystore.StandardScryptP)
account, err := ks.Find(accounts.Account{Address: common.HexToAddress(opAccount)})
account, err := ks.Find(accounts.Account{Address: address})
if err != nil {
log.Errorw("failed to create key store account", "err", err)
return nil, err
}

password := MakePasswordFromPath(passwordFilePath)

err = ks.Unlock(account, password)
if err != nil {
log.Errorw("failed to unlock account", "err", err)
return nil, err
}

return &keystoreAccount{ks, account}, nil
}

func (k *keystoreAccount) PayBidTx(ctx context.Context, fullNode node.FullNode, receiver common.Address, amount *big.Int) ([]byte, error) {
nonce, err := fetchNonce(ctx, fullNode, k.account.Address)
err = os.Remove(passwordFilePath)
if err != nil {
return nil, err
log.Errorw("failed to remove password file", "err", err)
}

tx := types.NewTx(&types.LegacyTx{
Nonce: nonce,
GasPrice: big.NewInt(0),
Gas: 25000,
To: &receiver,
Value: amount,
})
return &keystoreAccount{ks, account, &baseAccount{address: address}}, nil
}

signedTx, err := k.keystore.SignTx(k.account, tx, fullNode.ChainID())
func (k *keystoreAccount) SignTx(tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
signedTx, err := k.keystore.SignTx(k.account, tx, chainID)
if err != nil {
log.Errorw("failed to sign tx", "err", err)
return nil, err
}

return signedTx.MarshalBinary()
return signedTx, nil
}

type privateKeyAccount struct {
key *ecdsa.PrivateKey
address common.Address
key *ecdsa.PrivateKey
*baseAccount
}

func newPrivateKeyAccount(privateKey string) (*privateKeyAccount, error) {
Expand All @@ -116,38 +121,31 @@ func newPrivateKeyAccount(privateKey string) (*privateKeyAccount, error) {

addr := crypto.PubkeyToAddress(*pubKeyECDSA)

return &privateKeyAccount{key, addr}, nil
return &privateKeyAccount{key, &baseAccount{address: addr}}, nil
}

func (p *privateKeyAccount) PayBidTx(ctx context.Context, fullNode node.FullNode, receiver common.Address, amount *big.Int) ([]byte, error) {
nonce, err := fetchNonce(ctx, fullNode, p.address)
if err != nil {
return nil, err
}

tx := types.NewTx(&types.LegacyTx{
Nonce: nonce,
GasPrice: big.NewInt(0),
Gas: 25000,
To: &receiver,
Value: amount,
})

signedTx, err := types.SignTx(tx, types.LatestSignerForChainID(fullNode.ChainID()), p.key)
func (p *privateKeyAccount) SignTx(tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
signedTx, err := types.SignTx(tx, types.LatestSignerForChainID(chainID), p.key)
if err != nil {
log.Errorw("failed to sign tx", "err", err)
return nil, err
}

return signedTx.MarshalBinary()
return signedTx, nil
}

func fetchNonce(ctx context.Context, fullNode node.FullNode, address common.Address) (uint64, error) {
nonce, err := fullNode.PendingNonceAt(ctx, address)
func MakePasswordFromPath(path string) string {
if path == "" {
return ""
}
text, err := os.ReadFile(path)
if err != nil {
log.Errorw("failed to get nonce", "err", err)
return 0, err
log.Panicw("failed to read password file: %v", err)
}
lines := strings.Split(string(text), "\n")
if len(lines) == 0 {
return ""
}

return nonce, err
return strings.TrimRight(lines[0], "\r")
}
18 changes: 5 additions & 13 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus/promhttp"

"github.com/bnb-chain/bsc-mev-sentry/account"
"github.com/bnb-chain/bsc-mev-sentry/config"
ginutils "github.com/bnb-chain/bsc-mev-sentry/gin"
"github.com/bnb-chain/bsc-mev-sentry/log"
Expand Down Expand Up @@ -40,32 +39,25 @@ func main() {

log.Infow("bsc mev-sentry start", "configPath", *configPath, "config", cfg)

acc, err := account.New(&cfg.Account)
if err != nil {
log.Panicw("failed to create account", "err", err)
}

validators := make(map[string]node.Validator)
for _, v := range cfg.Validators {
validator := node.NewValidator(&v)
validator := node.NewValidator(v)
if validator != nil {
validators[v.PublicHostName] = validator
}
}

builders := make(map[common.Address]node.Builder)
for _, b := range cfg.Builders {
builder := node.NewBuilder(&b)
builder := node.NewBuilder(b)
if builder != nil {
builders[b.Address] = builder
}
}

fullNode := node.NewFullNode(&cfg.FullNode)

rpcServer := rpc.NewServer()
sentryService := service.NewMevSentry(&cfg.Service, acc, validators, builders, fullNode)
if err = rpcServer.RegisterName("mev", sentryService); err != nil {
sentryService := service.NewMevSentry(&cfg.Service, validators, builders)
if err := rpcServer.RegisterName("mev", sentryService); err != nil {
panic(err)
}

Expand All @@ -78,7 +70,7 @@ func main() {

app.POST("/", gin.WrapH(rpcServer))

if err = app.Run(cfg.Service.HTTPListenAddr); err != nil {
if err := app.Run(cfg.Service.HTTPListenAddr); err != nil {
log.Errorf("fail to run rpc server, err:%v", err)
}
}
Expand Down
3 changes: 0 additions & 3 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,14 @@ import (

"github.com/naoina/toml"

"github.com/bnb-chain/bsc-mev-sentry/account"
"github.com/bnb-chain/bsc-mev-sentry/node"
"github.com/bnb-chain/bsc-mev-sentry/service"
)

type Config struct {
Service service.Config
Account account.Config
Validators []node.ValidatorConfig
Builders []node.BuilderConfig
FullNode node.FullNodeConfig

Debug DebugConfig
Log LogConfig
Expand Down
38 changes: 17 additions & 21 deletions configs/config-example.toml
Original file line number Diff line number Diff line change
@@ -1,28 +1,24 @@
[Service]
HTTPListenAddr = "localhost:3000"
RPCConcurrency = 10
RPCTimeout = "10s"
HTTPListenAddr = "localhost:8555" # The address to listen on for HTTP requests.
RPCConcurrency = 100 # The maximum number of concurrent requests.
RPCTimeout = "10s" # The timeout for RPC requests.

[Account]
Mode = "keystore"
KeystorePath = "./keystore"
Password = "sentry"
Address = "0x837060bd423eFcDd5B7b6B92aB3CFc74B9CD0df4"
[[Validators]]
PrivateURL = "http://10.200.31.36:8545"
PublicHostName = "bsc-testnet-elbrus.bnbchain.org"
PayAccountMode = "privateKey"
PrivateKey = "b1fed931ad503ba9d029e86c2bd957cccbeb54f5995441f34796ddbee68a53cf"

[[Validators]]
PrivateURL = "http://127.0.0.1:8546"
PublicHostName = "127.0.0.1"
PrivateURL = "http://10.200.33.92:8545"
PublicHostName = "bsc-testnet-ararat.bnbchain.org"
PayAccountMode = "privateKey"
PrivateKey = "ce3f1b7573842f80764ec12573a049612bc49c8f940c00fb71d755f66f647503"

[[Builders]]
Address = "0x837060bd423eFcDd5B7b6B92aB3CFc74B9CD0df4"
URL = "http://localhost:8555"

[FullNode]
URL = "http://localhost:8545"
Address = "0x980A75eCd1309eA12fa2ED87A8744fBfc9b863D5" # The address of the builder.
URL = "http://bsc-builder-1" # The public URL of the builder.

[Debug]
ListenAddr = "localhost:8090"

[Log]
RootDir = "./logs"
Level = "debug"
[[Builders]]
Address = "0x980A75eCd1309eA12fa2ED87A8744fBfc9b863D5"
URL = "http://bsc-builder-2"
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ require (
github.com/goccy/go-json v0.10.2 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
github.com/google/uuid v1.4.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
Expand Down Expand Up @@ -144,7 +144,7 @@ require (
golang.org/x/tools v0.16.0 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
google.golang.org/grpc v1.56.3 // indirect
google.golang.org/protobuf v1.31.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
rsc.io/tmplfunc v0.0.3 // indirect
Expand All @@ -153,7 +153,7 @@ require (
replace (
github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.23.0
github.com/cometbft/cometbft => github.com/bnb-chain/greenfield-tendermint v0.0.0-20230417032003-4cda1f296fb2
github.com/ethereum/go-ethereum => github.com/irrun/bsc v0.0.0-20240307063536-491ddfc5f814
github.com/ethereum/go-ethereum => github.com/bnb-chain/bsc v1.4.1-alpha.0.20240401053830-3b7ee60e140b
github.com/grpc-ecosystem/grpc-gateway/v2 => github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20210702154020-550e1cd83ec1
github.com/syndtr/goleveldb v1.0.1 => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
github.com/tendermint/tendermint => github.com/bnb-chain/tendermint v0.31.16
Expand Down
Loading
Loading